Module: OpenapiFirst::Test

Defined in:
lib/openapi_first/test.rb,
lib/openapi_first/test/app.rb,
lib/openapi_first/test/methods.rb,
lib/openapi_first/test/observe.rb,
lib/openapi_first/test/callable.rb,
lib/openapi_first/test/coverage.rb,
lib/openapi_first/test/configuration.rb,
lib/openapi_first/test/coverage/plan.rb,
lib/openapi_first/test/plain_helpers.rb,
lib/openapi_first/test/coverage/tracker.rb,
lib/openapi_first/test/minitest_helpers.rb,
lib/openapi_first/test/coverage/route_task.rb,
lib/openapi_first/test/observer_middleware.rb,
lib/openapi_first/test/coverage/request_task.rb,
lib/openapi_first/test/coverage/response_task.rb,
lib/openapi_first/test/coverage/covered_request.rb,
lib/openapi_first/test/coverage/covered_response.rb,
lib/openapi_first/test/coverage/terminal_formatter.rb

Overview

Test integration

Defined Under Namespace

Modules: Callable, Coverage, Methods, MinitestHelpers, Observe, Observed, PlainHelpers Classes: App, Configuration, CoverageError, ObserveError, ObserverMiddleware, UnknownQueryParameterError

Constant Summary collapse

REQUEST =
'openapi.test.request'
RESPONSE =
'openapi.test.response'

Class Method Summary collapse

Class Method Details

.app(app, spec: nil, api: :default) ⇒ Object

Returns the Rack app wrapped with silent request, response validation You can use this if you want to track coverage via Test::Coverage, but don’t want to use the middlewares or manual request, response validation.



98
99
100
101
# File 'lib/openapi_first/test.rb', line 98

def self.app(app, spec: nil, api: :default)
  spec ||= self[api]
  App.new(app, api: spec)
end

.configurationObject



33
34
35
# File 'lib/openapi_first/test.rb', line 33

def self.configuration
  @configuration ||= Configuration.new
end

.definitionsObject



29
30
31
# File 'lib/openapi_first/test.rb', line 29

def self.definitions
  super.empty? ? OpenapiFirst.definitions : super
end

.handle_exitObject



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/openapi_first/test.rb', line 71

def self.handle_exit
  return unless configuration.report_coverage

  report_coverage(
    formatter: configuration.coverage_formatter,
    **configuration.coverage_formatter_options
  )
  return unless configuration.report_coverage == true

  coverage = Coverage.result.coverage
  return if coverage >= configuration.minimum_coverage

  puts "API Coverage fails with exit 2, because not all described requests and responses have been tested (#{coverage.round(4)}% covered)." # rubocop:disable Layout/LineLength

  exit 2
end

.installObject



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/openapi_first/test.rb', line 103

def self.install
  return if @installed

  OpenapiFirst.configure do |config|
    @after_request_validation = config.after_request_validation do |validated_request, oad|
      next unless registered?(oad)
      raise validated_request.error.exception if raise_request_error?(validated_request)

      check_unknown_query_parameters(validated_request)

      Coverage.track_request(validated_request, oad)
    end

    @after_response_validation = config.after_response_validation do |validated_response, rack_request, oad|
      next unless registered?(oad)
      if validated_response.invalid? && raise_response_error?(validated_response)
        raise validated_response.error.exception
      end

      Coverage.track_response(validated_response, rack_request, oad)
    end
  end
  @installed = true
end

.minitest?(base) ⇒ Boolean

Returns:

  • (Boolean)


23
24
25
26
27
# File 'lib/openapi_first/test.rb', line 23

def self.minitest?(base)
  base.include?(::Minitest::Assertions)
rescue NameError
  false
end

.observe(app, api: :default) ⇒ Object

Inject request/response validation in a rack app class



19
20
21
# File 'lib/openapi_first/test.rb', line 19

def self.observe(app, api: :default)
  Observe.observe(app, api:)
end

.registered?(oad) ⇒ Boolean

Returns:

  • (Boolean)


37
38
39
40
# File 'lib/openapi_first/test.rb', line 37

def self.registered?(oad)
  key = oad.key
  definitions.any? { |(_name, registered)| registered.key == key }
end

.report_coverage(formatter: Coverage::TerminalFormatter) ⇒ Object

Print the coverage report

Parameters:

  • formatter (defaults to: Coverage::TerminalFormatter)

    A formatter to define the report.



91
92
93
# File 'lib/openapi_first/test.rb', line 91

def self.report_coverage(formatter: Coverage::TerminalFormatter, **)
  puts formatter.new(**).format(Coverage.result)
end

.setup {|configuration| ... } ⇒ Object

Sets up OpenAPI test coverage and OAD registration.

Yield Parameters:



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/openapi_first/test.rb', line 44

def self.setup
  install
  yield configuration if block_given?

  Coverage.start(skip_response: configuration.skip_response_coverage, skip_route: configuration.skip_coverage)

  if definitions.empty?
    raise NotRegisteredError,
          'No API descriptions have been registered. ' \
          'Please register your API description via ' \
          "`OpenapiFirst.register('myopenapi.yaml)` or " \
          'in a block passed to `OpenapiFirst::Test.setup` like this: ' \
          "`OpenapiFirst::Test.setup { |test| test.register('myopenapi.yaml') }` " \

  end

  @exit_handler = method(:handle_exit)

  main_process = Process.pid
  @setup ||= at_exit do
    # :nocov:
    # Only handle exit once in the main process
    @exit_handler&.call if Process.pid == main_process
    # :nocov:
  end
end

.uninstallObject



128
129
130
131
132
133
134
135
136
# File 'lib/openapi_first/test.rb', line 128

def self.uninstall
  configuration = OpenapiFirst.configuration
  configuration.after_request_validation.delete(@after_request_validation)
  configuration.after_response_validation.delete(@after_response_validation)
  definitions.clear
  @configuration = nil
  @installed = nil
  @exit_handler = nil
end