Module: Acta::Testing::DSL
- Defined in:
- lib/acta/testing/dsl.rb
Instance Method Summary collapse
-
#acta_replay(events:, upcasters: []) ⇒ Object
End-to-end upcaster fixture: register upcasters, seed events at the given versions, run ‘Acta.rebuild!`.
-
#acta_seed_event(type:, payload:, event_version: 1, actor: nil, stream_type: nil, stream_key: nil, occurred_at: nil, uuid: nil) ⇒ Object
Insert an event row directly into the store, bypassing ‘Acta.emit`.
-
#ensure_replay_deterministic(&snapshot) ⇒ Object
Assert that running Acta.rebuild! twice produces the same projected state.
-
#given_events(&block) ⇒ Object
Seed prior events.
-
#then_emitted(event_class, **attributes) ⇒ Object
Assert that at least one of the captured events matches the class and attributes.
-
#then_emitted_nothing_else ⇒ Object
Assert no emissions remain unmatched.
-
#when_command(command) ⇒ Object
Invoke a command instance and capture what it emitted.
-
#when_event(&block) ⇒ Object
Evaluate a block that emits events, capturing them for assertions.
-
#with_actor(**attributes) ⇒ Object
Run the block with a different Acta::Current.actor, restoring the previous actor afterward (even if the block raises).
Instance Method Details
#acta_replay(events:, upcasters: []) ⇒ Object
End-to-end upcaster fixture: register upcasters, seed events at the given versions, run ‘Acta.rebuild!`. The caller asserts on whatever projection state matters for the migration under test.
acta_replay(
upcasters: [Scaff::WorkspaceMigrationUpcasters],
events: [
{ type: "Scaff::ItemCreated", event_version: 1,
payload: { "item_id" => "g_1", "item_type" => "goal", "title" => "Foo" } },
{ type: "Scaff::ItemCreated", event_version: 1,
payload: { "item_id" => "i_2", "parent_id" => "g_1", "title" => "Bar" } }
]
)
expect(Workspace.pluck(:id)).to eq(%w[g_1])
136 137 138 139 140 |
# File 'lib/acta/testing/dsl.rb', line 136 def acta_replay(events:, upcasters: []) upcasters.each { |u| Acta.register_upcaster(u) } events.each { |attrs| acta_seed_event(**attrs) } Acta.rebuild! end |
#acta_seed_event(type:, payload:, event_version: 1, actor: nil, stream_type: nil, stream_key: nil, occurred_at: nil, uuid: nil) ⇒ Object
Insert an event row directly into the store, bypassing ‘Acta.emit`. Used by upcaster specs to seed events at arbitrary `event_version` values — `Acta.emit` always stamps the current code’s version, so it can’t simulate a pre-migration row.
acta_seed_event(type: "ItemAdded", event_version: 1,
payload: { "item_id" => "g_1", "item_type" => "goal" })
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/acta/testing/dsl.rb', line 100 def acta_seed_event(type:, payload:, event_version: 1, actor: nil, stream_type: nil, stream_key: nil, occurred_at: nil, uuid: nil) actor ||= Acta::Current.actor || Acta::Actor.new( type: "system", id: "rspec", source: "test" ) Acta::Record.create!( uuid: uuid || SecureRandom.uuid, event_type: type.to_s, event_version: event_version, payload: payload, actor_type: actor.type, actor_id: actor.id, source: actor.source, metadata: actor..empty? ? nil : actor., stream_type: stream_type&.to_s, stream_key: stream_key, occurred_at: occurred_at || Time.current, recorded_at: Time.current ) end |
#ensure_replay_deterministic(&snapshot) ⇒ Object
Assert that running Acta.rebuild! twice produces the same projected state. The block returns a snapshot of the relevant state (whatever the app considers authoritative for this projection).
Implicitly exercises any registered upcasters — both passes go through the same pipeline, so impure upcasters (state leaking outside the per-replay context) surface as a diff.
79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/acta/testing/dsl.rb', line 79 def ensure_replay_deterministic(&snapshot) Acta.rebuild! first = snapshot.call Acta.rebuild! second = snapshot.call expect(second).to( eq(first), "replay is not deterministic\n" \ "first pass: #{first.inspect}\n" \ "second pass: #{second.inspect}" ) end |
#given_events(&block) ⇒ Object
Seed prior events. Anything emitted inside the block is treated as pre-existing history; the baseline is set after the block runs so subsequent assertions only see events from the ‘when’ phase.
9 10 11 12 |
# File 'lib/acta/testing/dsl.rb', line 9 def given_events(&block) block.call if block @_acta_baseline_count = Acta::Record.count end |
#then_emitted(event_class, **attributes) ⇒ Object
Assert that at least one of the captured events matches the class and attributes. Marks the matched event so ‘then_emitted_nothing_else` can verify the remainder.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/acta/testing/dsl.rb', line 33 def then_emitted(event_class, **attributes) @_acta_matched_events ||= [] event = @_acta_emitted_events.find do |e| e.is_a?(event_class) && attributes.all? { |k, v| e.public_send(k) == v } && !@_acta_matched_events.include?(e) end emitted_classes = @_acta_emitted_events.map(&:class).inspect expect(event).not_to( be_nil, "expected emission of #{event_class} matching #{attributes.inspect}, but emitted: #{emitted_classes}" ) @_acta_matched_events << event end |
#then_emitted_nothing_else ⇒ Object
Assert no emissions remain unmatched.
51 52 53 54 55 56 57 58 |
# File 'lib/acta/testing/dsl.rb', line 51 def then_emitted_nothing_else @_acta_matched_events ||= [] remaining = @_acta_emitted_events - @_acta_matched_events expect(remaining).to( be_empty, "expected no further emissions, but also emitted: #{remaining.map(&:class).inspect}" ) end |
#when_command(command) ⇒ Object
Invoke a command instance and capture what it emitted.
15 16 17 18 19 20 |
# File 'lib/acta/testing/dsl.rb', line 15 def when_command(command) @_acta_baseline_count ||= Acta::Record.count command.call @_acta_emitted_events = Acta.events.all.drop(@_acta_baseline_count) @_acta_matched_events = [] end |
#when_event(&block) ⇒ Object
Evaluate a block that emits events, capturing them for assertions.
23 24 25 26 27 28 |
# File 'lib/acta/testing/dsl.rb', line 23 def when_event(&block) @_acta_baseline_count ||= Acta::Record.count block.call @_acta_emitted_events = Acta.events.all.drop(@_acta_baseline_count) @_acta_matched_events = [] end |
#with_actor(**attributes) ⇒ Object
Run the block with a different Acta::Current.actor, restoring the previous actor afterward (even if the block raises). Useful for asserting an emit attributes the right user when the surrounding spec’s default actor would otherwise overwrite it.
64 65 66 67 68 69 70 |
# File 'lib/acta/testing/dsl.rb', line 64 def with_actor(**attributes) previous = Acta::Current.actor Acta::Current.actor = Acta::Actor.new(**attributes) yield ensure Acta::Current.actor = previous end |