Class: Servactory::TestKit::Rspec::Matchers::HaveServiceOutputMatcher

Inherits:
Object
  • Object
show all
Includes:
RSpec::Matchers::Composable
Defined in:
lib/servactory/test_kit/rspec/matchers/have_service_output_matcher.rb

Overview

RSpec matcher for validating service result output values.

## Purpose

Validates that a service result contains an expected output value with specific type, nested attributes, and content. Unlike input/internal matchers that validate definitions, this matcher validates actual runtime output values on a service result object.

## Usage

“‘ruby RSpec.describe MyService, type: :service do

let(:result) { described_class.call(user_id: 123) }

it "returns expected output" do
  expect(result).to have_service_output(:user)
    .instance_of(User)
    .contains(name: "John")
end

it "validates nested attributes" do
  expect(result).to have_service_output(:data)
    .nested(:settings, :theme)
    .contains("dark")
end

end “‘

## Chain Methods

  • ‘.instance_of(Class)` - validates output is instance of class

  • ‘.nested(*methods)` - traverses nested attributes before comparison

  • ‘.contains(value)` - validates output value or structure

## Value Comparison

The ‘.contains` method uses type-aware comparison:

  • Array - uses RSpec’s ‘contain_exactly`

  • Hash - uses RSpec’s ‘match`

  • Boolean - uses RSpec’s ‘equal` (identity)

  • nil - uses RSpec’s ‘be_nil`

  • Other - uses RSpec’s ‘eq` (equality)

Instance Method Summary collapse

Constructor Details

#initialize(output_name) ⇒ HaveServiceOutputMatcher

Creates a new output matcher for the given output name.

Parameters:

  • output_name (Symbol)

    The name of the output to validate



57
58
59
60
61
62
63
# File 'lib/servactory/test_kit/rspec/matchers/have_service_output_matcher.rb', line 57

def initialize(output_name)
  @output_name = output_name
  @instance_of_class = nil
  @nested_methods = []
  @expected_value = nil
  @value_defined = false
end

Instance Method Details

#contains(value) ⇒ self

Specifies the expected value or structure of the output.

Parameters:

  • value (Object)

    Expected value (uses type-aware comparison)

Returns:

  • (self)

    For method chaining



135
136
137
138
139
# File 'lib/servactory/test_kit/rspec/matchers/have_service_output_matcher.rb', line 135

def contains(value)
  @expected_value = value
  @value_defined = true
  self
end

#descriptionString

Returns a description of what this matcher validates.

Returns:

  • (String)

    Human-readable matcher description



86
87
88
# File 'lib/servactory/test_kit/rspec/matchers/have_service_output_matcher.rb', line 86

def description
  "service output #{output_name}"
end

#failure_messageString

Returns the failure message when the match fails.

Returns:

  • (String)

    Detailed failure message from RSpec matcher



93
94
95
# File 'lib/servactory/test_kit/rspec/matchers/have_service_output_matcher.rb', line 93

def failure_message
  match_for_failure
end

#failure_message_when_negatedString

Returns the failure message for negated expectations.

Returns:

  • (String)

    Negated failure message



100
101
102
# File 'lib/servactory/test_kit/rspec/matchers/have_service_output_matcher.rb', line 100

def failure_message_when_negated
  "Expected result not to have output #{output_name}"
end

#instance_of(class_or_name) ⇒ self

Specifies the expected class of the output value.

Parameters:

  • class_or_name (Class, String)

    Expected class or class name

Returns:

  • (self)

    For method chaining



111
112
113
114
# File 'lib/servactory/test_kit/rspec/matchers/have_service_output_matcher.rb', line 111

def instance_of(class_or_name)
  @instance_of_class = Servactory::Utils.constantize_class(class_or_name)
  self
end

#matches?(actual) ⇒ Boolean

Performs the match against the actual service result.

Parameters:

Returns:

  • (Boolean)

    True if all checks pass



76
77
78
79
80
81
# File 'lib/servactory/test_kit/rspec/matchers/have_service_output_matcher.rb', line 76

def matches?(actual)
  @actual = actual
  @given_value = actual.public_send(output_name)

  check_instance_of && check_nested && check_contains
end

#nested(*methods) ⇒ self

Specifies nested method chain to traverse before comparison.

Allows validating deeply nested attributes by chaining method calls on the output value before performing the final comparison.

Examples:

Validate nested attribute

expect(result).to have_output(:user).nested(:profile, :settings).contains(theme: "dark")

Parameters:

  • methods (Array<Symbol>)

    Method names to call in sequence

Returns:

  • (self)

    For method chaining



126
127
128
129
# File 'lib/servactory/test_kit/rspec/matchers/have_service_output_matcher.rb', line 126

def nested(*methods)
  @nested_methods = methods
  self
end

#supports_block_expectations?Boolean

Indicates this matcher does not support block expectations.

Returns:

  • (Boolean)

    Always false



68
69
70
# File 'lib/servactory/test_kit/rspec/matchers/have_service_output_matcher.rb', line 68

def supports_block_expectations?
  false
end