CtrlK
BlogDocsLog inGet started
Tessl Logo

igmarin/hanakai-yaku

Curated library of atomic skills and personas for Hanami, dry-rb, and ROM Ruby development. Covers actions, slices, repositories, relations, changesets, providers, DI, operations, TDD, CLI, views, routing, validation, and 10 orchestration personas. Shared Ruby process skills have moved to ruby-core-skills. Uses Markdown + Front-matter architecture.

95

1.20x
Quality

95%

Does it follow best practices?

Impact

96%

1.20x

Average score across 45 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

SKILL.mdskills/testing/write-rom-spec/

name:
write-rom-spec
license:
MIT
type:
atomic
description:
Use when writing ROM specs in Hanami 2.x — configure transactional rollback via a shared `"db rollback"` RSpec context wrapping every spec with `transaction(rollback: :always, auto_savepoint: true)`, place relation specs under `spec/relations/` and repository specs under `spec/repos/`, test custom Relation query methods with fully defined test data via `relation.insert(...)`, verify Repository CRUD operations including `one!` raising `ROM::TupleCountMismatchError` for missing tuples, and run specs to confirm failure before implementing. Use when testing Relation query methods, Repository CRUD operations, or entity creation and lookup in a Hanami ROM-backed app.
metadata:
{"ecosystem_sources":["rspec/rspec","rom-rb/rom","hanami/hanami"],"tags":["testing","rspec","rom","database"],"version":"1.0.0"}

write-rom-spec

Use this skill when writing specs for ROM Relations and Repositories in Hanami 2.x.


Workflow

Follow these steps in order, treating each as a checkpoint:

Step 0 — Configure transactional rollback (prerequisite)

Before writing any spec, ensure every test is wrapped in a transaction that rolls back. Place this in a shared context (e.g., spec/support/db_rollback.rb) and include it in your repo/relation specs:

# spec/support/db_rollback.rb
RSpec.shared_context "db rollback" do
  around do |example|
    rom = Hanami.app["persistence.rom"]
    rom.gateways[:default].connection.transaction(rollback: :always, auto_savepoint: true) do
      example.run
    end
  end
end

Then include it via metadata in spec/spec_helper.rb:

RSpec.configure do |config|
  config.include_context "db rollback", type: :repo
  config.include_context "db rollback", type: :relation
end

Step 1 — Create the spec file

Place it under spec/relations/ or spec/repos/. Initialize relation or repo in a let block and define all test data inline:

# spec/repos/users_spec.rb
RSpec.describe MyApp::Repos::UserRepo, type: :repo do
  let(:repo) { described_class.new }

  it "creates and finds a user by email" do
    user = repo.create(email: "alice@example.com", name: "Alice")
    expect(user.id).not_to be_nil

    found = repo.find_by_email("alice@example.com")
    expect(found.name).to eq("Alice")
  end

  it "updates a user" do
    user = repo.create(email: "alice@example.com", first_name: "Alice")
    repo.update(user.id, first_name: "Alicia")
    expect(repo.by_id(user.id).one.first_name).to eq("Alicia")
  end

  it "raises when user is not found" do
    expect { repo.by_id(99999).one! }.to raise_error(ROM::TupleCountMismatchError)
  end
end
# spec/relations/users_spec.rb
RSpec.describe MyApp::Relations::Users, type: :relation do
  let(:relation) { Hanami.app["persistence.rom"].relations[:users] }
  let!(:alice) { relation.insert(email: "alice@example.com", active: true) }
  let!(:bob)   { relation.insert(email: "bob@example.com",   active: false) }

  it "returns active users" do
    active_users = relation.active.to_a
    expect(active_users.length).to eq(1)
    expect(active_users.first[:email]).to eq("alice@example.com")
  end
end

Step 2 — Run the test and implement

Confirm the spec fails, then write only the minimal ROM query or persistence logic to make it pass:

bundle exec rspec spec/repos/users_spec.rb   # expect failure
# implement the relation/repo method …
bundle exec rspec spec/repos/users_spec.rb   # expect green

Common Mistakes

  • Skipping Database Transactions: Failing to wrap specs in a transactional rollback pollutes test databases and creates flaky/order-dependent tests.
  • Persistent State Pollution: Using before(:all) for database data setup, which operates outside individual test transaction boundaries.
  • Direct Entity Instantiation: Manually instantiating ROM Structs instead of writing to the DB via repository/changeset calls to test lookup.

Integration

Related SkillWhen to chain
create-repositoryRepository creation precedes spec implementation.
define-relationRelation definitions are verified via custom specs.

skills

testing

write-rom-spec

README.md

tile.json