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

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.



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

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

.configurationObject



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

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

.definitionsObject



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

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

.handle_exitObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/openapi_first/test.rb', line 65

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



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/openapi_first/test.rb', line 97

def self.install
  return if @installed

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

      Coverage.track_request(validated_request, oad)
    end

    @after_response_validation = config.after_response_validation do |validated_response, rack_request, 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)


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

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



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

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

.raise_request_error?(validated_request) ⇒ Boolean

Returns:

  • (Boolean)


118
119
120
121
122
123
# File 'lib/openapi_first/test.rb', line 118

def self.raise_request_error?(validated_request)
  return false if validated_request.valid?
  return false if validated_request.known?

  !configuration.ignore_unknown_requests
end

.raise_response_error?(invalid_response) ⇒ Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/openapi_first/test.rb', line 125

def self.raise_response_error?(invalid_response)
  configuration.response_raise_error && !configuration.ignore_response?(invalid_response)
end

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

Print the coverage report

Parameters:

  • formatter (defaults to: Coverage::TerminalFormatter)

    A formatter to define the report.



85
86
87
# File 'lib/openapi_first/test.rb', line 85

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:



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/openapi_first/test.rb', line 38

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



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

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