-
Notifications
You must be signed in to change notification settings - Fork 2
Declaring Fixtures
Fixture declarations can be named (file-backed), anonymous (inline block), or inherited (extending another fixture).
Reference a fixture file by name. FixtureKit loads the corresponding .rb file from your configured fixture_path:
RSpec.describe Project do
fixture "project_management"
it "loads the fixture data" do
expect(fixture.project).to be_present
end
endDefine fixture data inline when you don't need a reusable file:
RSpec.describe User do
fixture do
owner = User.create!(name: "Alice")
project = Project.create!(name: "Roadmap", owner: owner)
expose(owner: owner, project: project)
end
it "exposes the created records" do
expect(fixture.owner.name).to eq("Alice")
expect(fixture.project.owner).to eq(fixture.owner)
end
endAnonymous fixtures are cached using a context-derived identifier path. See Anonymous Fixtures and Identifiers.
Fixtures can extend other fixtures with extends:. The child fixture gets access to the parent's exposed records through a parent helper, and its cache includes all parent data so replay is self-contained.
Define a base fixture (spec/fixture_kit/company/base.rb):
FixtureKit.define do
company = Company.create!(name: "Acme Corp")
owner = User.create!(name: "Alice", company: company, role: "owner")
expose(company: company, owner: owner)
endThen extend it (spec/fixture_kit/company/with_employees.rb):
FixtureKit.define(extends: "company/base") do
employee = User.create!(name: "Bob", company: parent.company, role: "employee")
payroll = Payroll.create!(company: parent.company)
expose(employee: employee, payroll: payroll)
endUse it in a spec:
RSpec.describe Payroll do
fixture "company/with_employees"
it "belongs to the company" do
expect(fixture.payroll.company).to eq(fixture.employee.company)
end
endExtend a named fixture directly in a test without creating a separate file:
RSpec.describe "onboarding flow" do
fixture(extends: "company/base") do
onboarding = Onboarding.create!(company: parent.company, admin: parent.owner)
expose(onboarding: onboarding)
end
it "creates an onboarding for the company owner" do
expect(fixture.onboarding.admin).to eq(fixture.onboarding.company.users.find_by(role: "owner"))
end
endInheritance chains work to any depth. Each level extends the previous:
# spec/fixture_kit/company/with_payroll.rb
FixtureKit.define(extends: "company/with_employees") do
pay_period = PayPeriod.create!(payroll: parent.payroll, start_date: Date.current)
expose(pay_period: pay_period)
endParent fixtures are generated before their children automatically.
Only the child's explicitly exposed records are accessible via fixture.*. Parent records are not auto-exposed — you must re-expose them if you need direct access:
FixtureKit.define(extends: "company/base") do
employee = User.create!(name: "Bob", company: parent.company, role: "employee")
# fixture.company won't work unless you re-expose it:
expose(employee: employee, company: parent.company)
endHowever, parent records are present in the database and can be reached through associations (e.g., fixture.employee.company).
Circular chains (A extends B, B extends A) are detected at registration time and raise FixtureKit::CircularFixtureInheritance.
- Child contexts can override parent fixture declarations by declaring their own fixture.
- Override is framework-native:
- RSpec: nested example groups
- Minitest: subclasses of test classes
Within FixtureKit.define (or an anonymous declaration), use expose to define what tests can read:
FixtureKit.define do
account = Account.create!(name: "Acme")
users = User.where(account: account).to_a
expose(account: account, users: users)
endRules:
- Exposed names become repository reader methods.
- Duplicate exposed names raise
FixtureKit::DuplicateNameError.
- Exactly one of name or block is required.
- Providing both name and block silently uses the name (the block is ignored).
- Declaring more than one fixture in the same context/class raises
FixtureKit::MultipleFixtures.