mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 22:43:33 +08:00
DEV: Move chat service objects into core (#26506)
This commit is contained in:
27
app/helpers/with_service_helper.rb
Normal file
27
app/helpers/with_service_helper.rb
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module WithServiceHelper
|
||||||
|
def result
|
||||||
|
@_result
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param service [Class] A class including {Service::Base}
|
||||||
|
# @param dependencies [kwargs] Any additional params to load into the service context,
|
||||||
|
# in addition to controller @params.
|
||||||
|
def with_service(service, **dependencies, &block)
|
||||||
|
object = self
|
||||||
|
ServiceRunner.call(
|
||||||
|
service,
|
||||||
|
object,
|
||||||
|
**dependencies,
|
||||||
|
&proc { instance_exec(&(block || proc {})) }
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_service(service, dependencies)
|
||||||
|
params = self.try(:params) || ActionController::Parameters.new
|
||||||
|
|
||||||
|
@_result =
|
||||||
|
service.call(params.to_unsafe_h.merge(guardian: self.try(:guardian) || nil, **dependencies))
|
||||||
|
end
|
||||||
|
end
|
@ -61,7 +61,7 @@ module Service
|
|||||||
end
|
end
|
||||||
|
|
||||||
def inspect_steps
|
def inspect_steps
|
||||||
Chat::StepsInspector.new(self)
|
StepsInspector.new(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
124
lib/steps_inspector.rb
Normal file
124
lib/steps_inspector.rb
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# = StepsInspector
|
||||||
|
#
|
||||||
|
# This class takes a {Service::Base::Context} object and inspects it.
|
||||||
|
# It will output a list of steps and what is their known state.
|
||||||
|
class StepsInspector
|
||||||
|
# @!visibility private
|
||||||
|
class Step
|
||||||
|
attr_reader :step, :result, :nesting_level
|
||||||
|
|
||||||
|
delegate :name, to: :step
|
||||||
|
delegate :failure?, :success?, :error, to: :step_result, allow_nil: true
|
||||||
|
|
||||||
|
def self.for(step, result, nesting_level: 0)
|
||||||
|
class_name =
|
||||||
|
"#{module_parent_name}::#{step.class.name.split("::").last.sub(/^(\w+)Step$/, "\\1")}"
|
||||||
|
class_name.constantize.new(step, result, nesting_level: nesting_level)
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(step, result, nesting_level: 0)
|
||||||
|
@step = step
|
||||||
|
@result = result
|
||||||
|
@nesting_level = nesting_level
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
self.class.name.split("::").last.downcase
|
||||||
|
end
|
||||||
|
|
||||||
|
def emoji
|
||||||
|
"#{result_emoji}#{unexpected_result_emoji}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def steps
|
||||||
|
[self]
|
||||||
|
end
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
"#{" " * nesting_level}[#{type}] '#{name}' #{emoji}".rstrip
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def step_result
|
||||||
|
result["result.#{type}.#{name}"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def result_emoji
|
||||||
|
return "❌" if failure?
|
||||||
|
return "✅" if success?
|
||||||
|
""
|
||||||
|
end
|
||||||
|
|
||||||
|
def unexpected_result_emoji
|
||||||
|
" ⚠️#{unexpected_result_text}" if step_result.try(:[], "spec.unexpected_result")
|
||||||
|
end
|
||||||
|
|
||||||
|
def unexpected_result_text
|
||||||
|
return " <= expected to return true but got false instead" if failure?
|
||||||
|
" <= expected to return false but got true instead"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# @!visibility private
|
||||||
|
class Model < Step
|
||||||
|
def error
|
||||||
|
return result[name].errors.inspect if step_result.invalid
|
||||||
|
step_result.exception.full_message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# @!visibility private
|
||||||
|
class Contract < Step
|
||||||
|
def error
|
||||||
|
step_result.errors.inspect
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# @!visibility private
|
||||||
|
class Policy < Step
|
||||||
|
def error
|
||||||
|
step_result.reason
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# @!visibility private
|
||||||
|
class Transaction < Step
|
||||||
|
def steps
|
||||||
|
[self, *step.steps.map { Step.for(_1, result, nesting_level: nesting_level + 1).steps }]
|
||||||
|
end
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
"#{" " * nesting_level}[#{type}]"
|
||||||
|
end
|
||||||
|
|
||||||
|
def step_result
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :steps, :result
|
||||||
|
|
||||||
|
def initialize(result)
|
||||||
|
@steps = result.__steps__.map { Step.for(_1, result).steps }.flatten
|
||||||
|
@result = result
|
||||||
|
end
|
||||||
|
|
||||||
|
# Inspect the provided result object.
|
||||||
|
# Example output:
|
||||||
|
# [1/4] [model] 'channel' ✅
|
||||||
|
# [2/4] [contract] 'default' ✅
|
||||||
|
# [3/4] [policy] 'check_channel_permission' ❌
|
||||||
|
# [4/4] [step] 'change_status'
|
||||||
|
# @return [String] the steps of the result object with their state
|
||||||
|
def inspect
|
||||||
|
steps.map.with_index { |step, index| "[#{index + 1}/#{steps.size}] #{step.inspect}" }.join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [String, nil] the first available error, if any.
|
||||||
|
def error
|
||||||
|
steps.detect(&:failure?)&.error
|
||||||
|
end
|
||||||
|
end
|
@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
module Chat
|
module Chat
|
||||||
class ApiController < ::Chat::BaseController
|
class ApiController < ::Chat::BaseController
|
||||||
include Chat::WithServiceHelper
|
include WithServiceHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module Chat
|
module Chat
|
||||||
class IncomingWebhooksController < ::ApplicationController
|
class IncomingWebhooksController < ::ApplicationController
|
||||||
include Chat::WithServiceHelper
|
include WithServiceHelper
|
||||||
|
|
||||||
requires_plugin Chat::PLUGIN_NAME
|
requires_plugin Chat::PLUGIN_NAME
|
||||||
|
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
module Chat
|
|
||||||
module WithServiceHelper
|
|
||||||
def result
|
|
||||||
@_result
|
|
||||||
end
|
|
||||||
|
|
||||||
# @param service [Class] A class including {Chat::Service::Base}
|
|
||||||
# @param dependencies [kwargs] Any additional params to load into the service context,
|
|
||||||
# in addition to controller @params.
|
|
||||||
def with_service(service, **dependencies, &block)
|
|
||||||
object = self
|
|
||||||
ServiceRunner.call(
|
|
||||||
service,
|
|
||||||
object,
|
|
||||||
**dependencies,
|
|
||||||
&proc { instance_exec(&(block || proc {})) }
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def run_service(service, dependencies)
|
|
||||||
params = self.try(:params) || ActionController::Parameters.new
|
|
||||||
|
|
||||||
@_result =
|
|
||||||
service.call(params.to_unsafe_h.merge(guardian: self.try(:guardian) || nil, **dependencies))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,7 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ServiceJob < ::Jobs::Base
|
class ServiceJob < ::Jobs::Base
|
||||||
include Chat::WithServiceHelper
|
include WithServiceHelper
|
||||||
|
|
||||||
def run_service(service, dependencies)
|
def run_service(service, dependencies)
|
||||||
@_result = service.call(dependencies)
|
@_result = service.call(dependencies)
|
||||||
|
@ -1,129 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Chat
|
|
||||||
# = Chat::StepsInspector
|
|
||||||
#
|
|
||||||
# This class takes a {Service::Base::Context} object and inspects it.
|
|
||||||
# It will output a list of steps and what is their known state.
|
|
||||||
class StepsInspector
|
|
||||||
# @!visibility private
|
|
||||||
class Step
|
|
||||||
attr_reader :step, :result, :nesting_level
|
|
||||||
|
|
||||||
delegate :name, to: :step
|
|
||||||
delegate :failure?, :success?, :error, to: :step_result, allow_nil: true
|
|
||||||
|
|
||||||
def self.for(step, result, nesting_level: 0)
|
|
||||||
class_name =
|
|
||||||
"#{module_parent_name}::#{step.class.name.split("::").last.sub(/^(\w+)Step$/, "\\1")}"
|
|
||||||
class_name.constantize.new(step, result, nesting_level: nesting_level)
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(step, result, nesting_level: 0)
|
|
||||||
@step = step
|
|
||||||
@result = result
|
|
||||||
@nesting_level = nesting_level
|
|
||||||
end
|
|
||||||
|
|
||||||
def type
|
|
||||||
self.class.name.split("::").last.downcase
|
|
||||||
end
|
|
||||||
|
|
||||||
def emoji
|
|
||||||
"#{result_emoji}#{unexpected_result_emoji}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def steps
|
|
||||||
[self]
|
|
||||||
end
|
|
||||||
|
|
||||||
def inspect
|
|
||||||
"#{" " * nesting_level}[#{type}] '#{name}' #{emoji}".rstrip
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def step_result
|
|
||||||
result["result.#{type}.#{name}"]
|
|
||||||
end
|
|
||||||
|
|
||||||
def result_emoji
|
|
||||||
return "❌" if failure?
|
|
||||||
return "✅" if success?
|
|
||||||
""
|
|
||||||
end
|
|
||||||
|
|
||||||
def unexpected_result_emoji
|
|
||||||
" ⚠️#{unexpected_result_text}" if step_result.try(:[], "spec.unexpected_result")
|
|
||||||
end
|
|
||||||
|
|
||||||
def unexpected_result_text
|
|
||||||
return " <= expected to return true but got false instead" if failure?
|
|
||||||
" <= expected to return false but got true instead"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# @!visibility private
|
|
||||||
class Model < Step
|
|
||||||
def error
|
|
||||||
return result[name].errors.inspect if step_result.invalid
|
|
||||||
step_result.exception.full_message
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# @!visibility private
|
|
||||||
class Contract < Step
|
|
||||||
def error
|
|
||||||
step_result.errors.inspect
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# @!visibility private
|
|
||||||
class Policy < Step
|
|
||||||
def error
|
|
||||||
step_result.reason
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# @!visibility private
|
|
||||||
class Transaction < Step
|
|
||||||
def steps
|
|
||||||
[self, *step.steps.map { Step.for(_1, result, nesting_level: nesting_level + 1).steps }]
|
|
||||||
end
|
|
||||||
|
|
||||||
def inspect
|
|
||||||
"#{" " * nesting_level}[#{type}]"
|
|
||||||
end
|
|
||||||
|
|
||||||
def step_result
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_reader :steps, :result
|
|
||||||
|
|
||||||
def initialize(result)
|
|
||||||
@steps = result.__steps__.map { Step.for(_1, result).steps }.flatten
|
|
||||||
@result = result
|
|
||||||
end
|
|
||||||
|
|
||||||
# Inspect the provided result object.
|
|
||||||
# Example output:
|
|
||||||
# [1/4] [model] 'channel' ✅
|
|
||||||
# [2/4] [contract] 'default' ✅
|
|
||||||
# [3/4] [policy] 'check_channel_permission' ❌
|
|
||||||
# [4/4] [step] 'change_status'
|
|
||||||
# @return [String] the steps of the result object with their state
|
|
||||||
def inspect
|
|
||||||
steps
|
|
||||||
.map
|
|
||||||
.with_index { |step, index| "[#{index + 1}/#{steps.size}] #{step.inspect}" }
|
|
||||||
.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
# @return [String, nil] the first available error, if any.
|
|
||||||
def error
|
|
||||||
steps.detect(&:failure?)&.error
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module ChatSDK
|
module ChatSDK
|
||||||
class Channel
|
class Channel
|
||||||
include Chat::WithServiceHelper
|
include WithServiceHelper
|
||||||
|
|
||||||
# Retrieves messages from a specified channel.
|
# Retrieves messages from a specified channel.
|
||||||
#
|
#
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module ChatSDK
|
module ChatSDK
|
||||||
class Message
|
class Message
|
||||||
include Chat::WithServiceHelper
|
include WithServiceHelper
|
||||||
|
|
||||||
# Creates a new message in a chat channel.
|
# Creates a new message in a chat channel.
|
||||||
#
|
#
|
||||||
@ -159,7 +159,7 @@ module ChatSDK
|
|||||||
end
|
end
|
||||||
|
|
||||||
class StreamHelper
|
class StreamHelper
|
||||||
include Chat::WithServiceHelper
|
include WithServiceHelper
|
||||||
|
|
||||||
attr_reader :message
|
attr_reader :message
|
||||||
attr_reader :guardian
|
attr_reader :guardian
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module ChatSDK
|
module ChatSDK
|
||||||
class Thread
|
class Thread
|
||||||
include Chat::WithServiceHelper
|
include WithServiceHelper
|
||||||
|
|
||||||
# Updates the title of a specified chat thread.
|
# Updates the title of a specified chat thread.
|
||||||
#
|
#
|
||||||
|
@ -130,8 +130,8 @@ end
|
|||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
config.include ChatSystemHelpers, type: :system
|
config.include ChatSystemHelpers, type: :system
|
||||||
config.include ChatSpecHelpers
|
config.include ChatSpecHelpers
|
||||||
config.include Chat::WithServiceHelper
|
config.include WithServiceHelper
|
||||||
config.include Chat::ServiceMatchers
|
config.include ServiceMatchers
|
||||||
|
|
||||||
config.expect_with :rspec do |c|
|
config.expect_with :rspec do |c|
|
||||||
# Or a very large value, if you do want to truncate at some point
|
# Or a very large value, if you do want to truncate at some point
|
||||||
|
@ -1,153 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Chat
|
|
||||||
module ServiceMatchers
|
|
||||||
class RunServiceSuccessfully
|
|
||||||
attr_reader :result
|
|
||||||
|
|
||||||
def matches?(result)
|
|
||||||
@result = result
|
|
||||||
result.success?
|
|
||||||
end
|
|
||||||
|
|
||||||
def failure_message
|
|
||||||
inspector = StepsInspector.new(result)
|
|
||||||
"Expected to run the service sucessfully but failed:\n\n#{inspector.inspect}\n\n#{inspector.error}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class FailStep
|
|
||||||
attr_reader :name, :result
|
|
||||||
|
|
||||||
def initialize(name)
|
|
||||||
@name = name
|
|
||||||
end
|
|
||||||
|
|
||||||
def matches?(result)
|
|
||||||
@result = result
|
|
||||||
step_exists? && step_failed? && service_failed?
|
|
||||||
end
|
|
||||||
|
|
||||||
def failure_message
|
|
||||||
set_unexpected_result
|
|
||||||
message =
|
|
||||||
if !step_exists?
|
|
||||||
"Expected #{type} '#{name}' (key: '#{step}') was not found in the result object."
|
|
||||||
elsif !step_failed?
|
|
||||||
"Expected #{type} '#{name}' (key: '#{step}') to fail but it succeeded."
|
|
||||||
else
|
|
||||||
"expected the service to fail but it succeeded."
|
|
||||||
end
|
|
||||||
error_message_with_inspection(message)
|
|
||||||
end
|
|
||||||
|
|
||||||
def failure_message_when_negated
|
|
||||||
set_unexpected_result
|
|
||||||
message = "Expected #{type} '#{name}' (key: '#{step}') to succeed but it failed."
|
|
||||||
error_message_with_inspection(message)
|
|
||||||
end
|
|
||||||
|
|
||||||
def description
|
|
||||||
"fail a #{type} named '#{name}'"
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def step_exists?
|
|
||||||
result[step].present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def step_failed?
|
|
||||||
result[step].failure?
|
|
||||||
end
|
|
||||||
|
|
||||||
def service_failed?
|
|
||||||
result.failure?
|
|
||||||
end
|
|
||||||
|
|
||||||
def type
|
|
||||||
self.class.name.split("::").last.sub("Fail", "").downcase
|
|
||||||
end
|
|
||||||
|
|
||||||
def step
|
|
||||||
"result.#{type}.#{name}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def error_message_with_inspection(message)
|
|
||||||
inspector = StepsInspector.new(result)
|
|
||||||
"#{message}\n\n#{inspector.inspect}\n\n#{inspector.error}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_unexpected_result
|
|
||||||
return unless result[step]
|
|
||||||
result[step]["spec.unexpected_result"] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class FailContract < FailStep
|
|
||||||
end
|
|
||||||
|
|
||||||
class FailPolicy < FailStep
|
|
||||||
end
|
|
||||||
|
|
||||||
class FailToFindModel < FailStep
|
|
||||||
def type
|
|
||||||
"model"
|
|
||||||
end
|
|
||||||
|
|
||||||
def description
|
|
||||||
"fail to find a model named '#{name}'"
|
|
||||||
end
|
|
||||||
|
|
||||||
def step_failed?
|
|
||||||
super && result[name].blank?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class FailWithInvalidModel < FailStep
|
|
||||||
def type
|
|
||||||
"model"
|
|
||||||
end
|
|
||||||
|
|
||||||
def description
|
|
||||||
"fail to have a valid model named '#{name}'"
|
|
||||||
end
|
|
||||||
|
|
||||||
def step_failed?
|
|
||||||
super && result[step].invalid
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def fail_a_policy(name)
|
|
||||||
FailPolicy.new(name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def fail_a_contract(name = "default")
|
|
||||||
FailContract.new(name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def fail_to_find_a_model(name = "model")
|
|
||||||
FailToFindModel.new(name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def fail_with_an_invalid_model(name = "model")
|
|
||||||
FailWithInvalidModel.new(name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def fail_a_step(name = "model")
|
|
||||||
FailStep.new(name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def run_service_successfully
|
|
||||||
RunServiceSuccessfully.new
|
|
||||||
end
|
|
||||||
|
|
||||||
def inspect_steps(result)
|
|
||||||
inspector = Chat::StepsInspector.new(result)
|
|
||||||
puts "Steps:"
|
|
||||||
puts inspector.inspect
|
|
||||||
puts "\nFirst error:"
|
|
||||||
puts inspector.error
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,6 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
RSpec.describe Chat::StepsInspector do
|
RSpec.describe StepsInspector do
|
||||||
class DummyService
|
class DummyService
|
||||||
include Service::Base
|
include Service::Base
|
||||||
|
|
151
spec/support/service_matchers.rb
Normal file
151
spec/support/service_matchers.rb
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module ServiceMatchers
|
||||||
|
class RunServiceSuccessfully
|
||||||
|
attr_reader :result
|
||||||
|
|
||||||
|
def matches?(result)
|
||||||
|
@result = result
|
||||||
|
result.success?
|
||||||
|
end
|
||||||
|
|
||||||
|
def failure_message
|
||||||
|
inspector = StepsInspector.new(result)
|
||||||
|
"Expected to run the service sucessfully but failed:\n\n#{inspector.inspect}\n\n#{inspector.error}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FailStep
|
||||||
|
attr_reader :name, :result
|
||||||
|
|
||||||
|
def initialize(name)
|
||||||
|
@name = name
|
||||||
|
end
|
||||||
|
|
||||||
|
def matches?(result)
|
||||||
|
@result = result
|
||||||
|
step_exists? && step_failed? && service_failed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def failure_message
|
||||||
|
set_unexpected_result
|
||||||
|
message =
|
||||||
|
if !step_exists?
|
||||||
|
"Expected #{type} '#{name}' (key: '#{step}') was not found in the result object."
|
||||||
|
elsif !step_failed?
|
||||||
|
"Expected #{type} '#{name}' (key: '#{step}') to fail but it succeeded."
|
||||||
|
else
|
||||||
|
"expected the service to fail but it succeeded."
|
||||||
|
end
|
||||||
|
error_message_with_inspection(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def failure_message_when_negated
|
||||||
|
set_unexpected_result
|
||||||
|
message = "Expected #{type} '#{name}' (key: '#{step}') to succeed but it failed."
|
||||||
|
error_message_with_inspection(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def description
|
||||||
|
"fail a #{type} named '#{name}'"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def step_exists?
|
||||||
|
result[step].present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def step_failed?
|
||||||
|
result[step].failure?
|
||||||
|
end
|
||||||
|
|
||||||
|
def service_failed?
|
||||||
|
result.failure?
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
self.class.name.split("::").last.sub("Fail", "").downcase
|
||||||
|
end
|
||||||
|
|
||||||
|
def step
|
||||||
|
"result.#{type}.#{name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def error_message_with_inspection(message)
|
||||||
|
inspector = StepsInspector.new(result)
|
||||||
|
"#{message}\n\n#{inspector.inspect}\n\n#{inspector.error}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_unexpected_result
|
||||||
|
return unless result[step]
|
||||||
|
result[step]["spec.unexpected_result"] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FailContract < FailStep
|
||||||
|
end
|
||||||
|
|
||||||
|
class FailPolicy < FailStep
|
||||||
|
end
|
||||||
|
|
||||||
|
class FailToFindModel < FailStep
|
||||||
|
def type
|
||||||
|
"model"
|
||||||
|
end
|
||||||
|
|
||||||
|
def description
|
||||||
|
"fail to find a model named '#{name}'"
|
||||||
|
end
|
||||||
|
|
||||||
|
def step_failed?
|
||||||
|
super && result[name].blank?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FailWithInvalidModel < FailStep
|
||||||
|
def type
|
||||||
|
"model"
|
||||||
|
end
|
||||||
|
|
||||||
|
def description
|
||||||
|
"fail to have a valid model named '#{name}'"
|
||||||
|
end
|
||||||
|
|
||||||
|
def step_failed?
|
||||||
|
super && result[step].invalid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def fail_a_policy(name)
|
||||||
|
FailPolicy.new(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fail_a_contract(name = "default")
|
||||||
|
FailContract.new(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fail_to_find_a_model(name = "model")
|
||||||
|
FailToFindModel.new(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fail_with_an_invalid_model(name = "model")
|
||||||
|
FailWithInvalidModel.new(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fail_a_step(name = "model")
|
||||||
|
FailStep.new(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_service_successfully
|
||||||
|
RunServiceSuccessfully.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def inspect_steps(result)
|
||||||
|
inspector = StepsInspector.new(result)
|
||||||
|
puts "Steps:"
|
||||||
|
puts inspector.inspect
|
||||||
|
puts "\nFirst error:"
|
||||||
|
puts inspector.error
|
||||||
|
end
|
||||||
|
end
|
Reference in New Issue
Block a user