Module: Yes::Core::TestSupport::Aggregate::CommandTestDsl

Defined in:
lib/yes/core/test_support/aggregate/command_test_dsl.rb

Overview

DSL for writing concise aggregate command specs.

Provides ‘command`, `success`, `invalid`, `no_change`, and `setup` methods that generate RSpec describe/context blocks with appropriate shared examples.

Examples:

RSpec.describe MyContext::MyAggregate::Aggregate, type: :aggregate do
  command 'do_something' do
    let(:command_data) { { name: 'test' } }
    let(:success_attributes) { { name: 'test' } }

    success
    invalid 'when precondition not met'
    no_change
  end
end

Instance Method Summary collapse

Instance Method Details

#command(command_name, *options) { ... } ⇒ Object

Defines a test block for a command

Parameters:

  • command_name (String, Symbol)

    the name of the command to test

  • options (Array<Hash>)

    additional options (e.g., ‘draft: true`, VCR cassettes)

Yields:

  • block for configuring test cases with success/invalid/no_change



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/yes/core/test_support/aggregate/command_test_dsl.rb', line 29

def command(command_name, *options, &block)
  describe command_name.to_s, *options do
    let(:draft) { options.first&.dig(:draft) }

    let(:aggregate) { described_class.new(draft:) } unless method_defined?(:aggregate)

    subject { aggregate.public_send(command, command_data, guards: !draft) }

    let(:command) { command_name.to_sym }
    let(:aggregate_class) { aggregate.class }
    let(:command_data_with_id) do
      { "#{aggregate_class.aggregate.underscore}_id" => aggregate.id }.merge(command_data)
    end
    let(:command_data) { {} }
    let(:expected_event_type) do
      "#{aggregate_class.context}::#{aggregate_class.aggregate}" \
        "#{'Draft' if draft}#{aggregate_class.commands[command].event_name.to_s.classify}"
    end
    let(:expected_event_data) { command_data_with_id }
    let(:expected_event_metadata) { nil }
    let(:success_attributes) { command_data.without(:locale) } unless method_defined?(:success_attributes)

    class_eval(&block) if block_given?
  end
end

#invalid(description, options = {}) { ... } ⇒ Object

Defines a test case for an invalid transition

Parameters:

  • description (String)

    description of the invalid scenario

  • options (Hash) (defaults to: {})

    additional options

Yields:

  • optional block for additional setup



88
89
90
91
92
93
94
# File 'lib/yes/core/test_support/aggregate/command_test_dsl.rb', line 88

def invalid(description, options = {}, &block)
  context "when #{description}", options do
    instance_eval(&block) if block_given?

    it_behaves_like 'invalid transition'
  end
end

#no_change(description = 'when command causes no change', options = {}) { ... } ⇒ Object

Defines a test case for a command that causes no state change

Parameters:

  • description (String) (defaults to: 'when command causes no change')

    optional description

  • options (Hash) (defaults to: {})

    additional options

Yields:

  • optional block for additional setup



73
74
75
76
77
78
79
80
81
# File 'lib/yes/core/test_support/aggregate/command_test_dsl.rb', line 73

def no_change(description = 'when command causes no change', options = {}, &block)
  context description.to_s, options do
    instance_eval(&block) if block_given?

    before { aggregate.public_send(command, command_data) }

    it_behaves_like 'no change transition'
  end
end

#setup { ... } ⇒ Object

Alias for ‘before` — used for readable aggregate setup within command blocks

Yields:

  • block for setup actions



99
100
101
# File 'lib/yes/core/test_support/aggregate/command_test_dsl.rb', line 99

def setup(&)
  before(&)
end

#success(description = 'when successfully executing command', options = {}) { ... } ⇒ Object

Defines a test case for a successful command execution

Parameters:

  • description (String) (defaults to: 'when successfully executing command')

    optional description

  • options (Hash) (defaults to: {})

    additional options (e.g., VCR cassettes)

Yields:

  • optional block for additional setup or custom assertions



60
61
62
63
64
65
66
# File 'lib/yes/core/test_support/aggregate/command_test_dsl.rb', line 60

def success(description = 'when successfully executing command', options = {}, &block)
  context description, options do
    instance_eval(&block) if block_given?

    it_behaves_like 'successful command'
  end
end