radius-spec 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,472 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Radius
4
+ module Spec
5
+ # Basic Model Factory
6
+ #
7
+ # This factory is **not** Rails specific. It works for any object type that
8
+ # responds to `new` with a hash of attributes or keywords; including
9
+ # `Struct` using the new Ruby 2.5 `keyword_init` flag.
10
+ #
11
+ # To make this feature available require it after the gem:
12
+ #
13
+ # ```ruby
14
+ # require 'radius/spec'
15
+ # require 'radius/spec/model_factory'
16
+ # ```
17
+ #
18
+ # ### Storing Factory Templates
19
+ #
20
+ # Our convention is to store all of a project's factory templates in the
21
+ # file `spec/support/model_factories.rb`. As this is our convention, when
22
+ # the model factory is required it will attempt to load this file
23
+ # automatically as a convenience.
24
+ #
25
+ # ### Including Helpers in Specs
26
+ #
27
+ # There are multiple ways you can build object instances using this model
28
+ # factory. Which method you choose depends on how much perceived
29
+ # magic/syntactic sugar you want:
30
+ #
31
+ # - call the model factory directly
32
+ # - manually include the factory helper methods in the specs
33
+ # - use metadata to auto load this feature and include it in the specs
34
+ #
35
+ # When using the metadata option you do not need to explicitly require the
36
+ # model factory feature. This gem registers metadata with the RSpec
37
+ # configuration when it loads and `RSpec` is defined. When the metadata is
38
+ # first used it will automatically require the model factory feature and
39
+ # include the helpers.
40
+ #
41
+ # Any of following metadata will include the factory helpers:
42
+ #
43
+ # - `:model_factory`
44
+ # - `:model_factories`
45
+ # - `type: :controller`
46
+ # - `type: :feature`
47
+ # - `type: :job`
48
+ # - `type: :model`
49
+ # - `type: :request`
50
+ # - `type: :system`
51
+ #
52
+ # @example defining a single factory template
53
+ # require 'radius/spec/model_factory'
54
+ #
55
+ # Radius::Spec::ModelFactory.define_factory(
56
+ # "AnyClass",
57
+ # attr1: :any_value,
58
+ # attr2: :another_value,
59
+ # )
60
+ # @example defining multiple templates
61
+ # require 'radius/spec/model_factory'
62
+ #
63
+ # Radius::Spec::ModelFactory.catalog do |c|
64
+ # c.factory "AnyClass", attr1: :any_value, attr2: :another_value
65
+ #
66
+ # c.factory "AnotherClass",
67
+ # attr1: :any_value,
68
+ # attr2: :another_value,
69
+ # attr3: %i[any list of values]
70
+ # end
71
+ # @example building a domain model from a factory template
72
+ # an_instance = Radius::Spec::ModelFactory.build("AnyClass")
73
+ # @example building a domain model with custom attributes
74
+ # an_instance = Radius::Spec::ModelFactory.build(
75
+ # "AnyClass",
76
+ # attr1: "Any Custom Value",
77
+ # attr2: %w[any custom array],
78
+ # )
79
+ # @example call the model factory directly in specs
80
+ # require 'radius/spec/model_factory'
81
+ #
82
+ # RSpec.describe AnyClass do
83
+ # it "includes the factory helpers" do
84
+ # an_object = Radius::Spec::ModelFactory.build("AnyClass")
85
+ # expect(an_object.name).to eq "Any Name"
86
+ # end
87
+ # end
88
+ # @example manually include the factory helper methods
89
+ # require 'radius/spec/model_factory'
90
+ #
91
+ # RSpec.describe AnyClass do
92
+ # include Radius::Spec::ModelFactory
93
+ #
94
+ # it "includes the factory helpers" do
95
+ # an_object = build(AnyClass)
96
+ # expect(an_object.name).to eq "Any Name"
97
+ # end
98
+ # end
99
+ # @example use metadata to auto include the factory helper methods
100
+ # RSpec.describe AnyClass, :model_factory do
101
+ # it "includes the factory helpers" do
102
+ # an_object = build("AnyClass")
103
+ # expect(an_object.name).to eq "Any Name"
104
+ # end
105
+ # end
106
+ # @since 0.1.0
107
+ module ModelFactory
108
+ # Indicates that a model does not have a template registered with the
109
+ # factory {Radius::Spec::ModelFactory.catalog}.
110
+ class TemplateNotFound < KeyError; end
111
+
112
+ class << self
113
+ # Suggested method for defining multiple factory templates at once.
114
+ #
115
+ # Most projects end up having many domain models which need factories
116
+ # defined. Having to reference the full module constant every time you
117
+ # want to define a factory is tedious. Use this to define all of your
118
+ # model templates within a block.
119
+ #
120
+ # @example
121
+ # require 'radius/spec/model_factory'
122
+ #
123
+ # Radius::Spec::ModelFactory.catalog do |c|
124
+ # c.factory "AnyClass", attr1: :any_value, attr2: :another_value
125
+ #
126
+ # c.factory "AnotherClass",
127
+ # attr1: :any_value,
128
+ # attr2: :another_value,
129
+ # attr3: %i[any list of values]
130
+ # end
131
+ # @yieldparam catalog current catalog storing the registered templates
132
+ # @return [void]
133
+ # @see .factory
134
+ def catalog
135
+ yield self
136
+ end
137
+
138
+ # Convenience helper for registering a template to the current catalog.
139
+ #
140
+ # Registers the `class_name` in the catalog mapped to the provided
141
+ # `attrs` attribute template.
142
+ #
143
+ # ### Lazy Class Loading
144
+ #
145
+ # When testing in isolation we often don't want to wait a long time for
146
+ # a lot of unnecessary project/app code to load. With that in mind we
147
+ # want to keep loading the model factory and all factory templates as
148
+ # fast as possible. This mean not loading the associated project/app
149
+ # code at factory template definition time. This way if you only need
150
+ # one or two factories your remaining domain model code won't be
151
+ # loaded.
152
+ #
153
+ # Lazy class loading occurs when you register factory template using a
154
+ # string or symbol for the fully qualified `class_name`. The only
155
+ # requirement for this feature is that the class must be loaded by the
156
+ # project/app, or made available via some auto-loading mechanism, by
157
+ # the time the first instance is built by the factory.
158
+ #
159
+ # ### Template Attribute Keys
160
+ #
161
+ # Attribute keys may be defined using either strings or symbols.
162
+ # However, they will be stored internally as symbols. This means that
163
+ # when an object instance is create using the factory the **attribute
164
+ # hash will be provided to `new` with _symbol_ keys**.
165
+ #
166
+ # ### Dynamic Attribute Values (i.e. Generators)
167
+ #
168
+ # Dynamic attributes values may be registered by providing a `Proc` for
169
+ # the value. For any template attribute which has a `Proc` for a value
170
+ # making an instance through the factory will send `call` to the proc
171
+ # with no args.
172
+ #
173
+ # <div class="note notetag">
174
+ # <strong>Note:</strong>
175
+ # <div class="inline">
176
+ # <p>
177
+ # This only applies to template values which are instances of
178
+ # <code>Proc</code>. If you define a template value using another
179
+ # object which responds to <code>call</code> that object will be set as
180
+ # the built instance's attribute value without receiving
181
+ # <code>call</code>.
182
+ # </p>
183
+ # </div>
184
+ # </div>
185
+ #
186
+ # While this is a powerful technique we suggest keeping it's use to a
187
+ # minimum. There's a lot of benefit to generative, mutation, and fuzzy
188
+ # testing. We just aren't convinced it should be the default when you
189
+ # generate unit / general integration test data.
190
+ #
191
+ # ### Optional and Required attributes
192
+ #
193
+ # Templates may use the special symbols `:optional` and `:required` as
194
+ # a means of documenting attributes. These special symbols are meant as
195
+ # descriptive placeholders for developers reading the factory
196
+ # definition. Any template attribute with a value of `:optional`, which
197
+ # is not overwritten by a custom value, will be removed just prior to
198
+ # building a new instance.
199
+ #
200
+ # Those attributes marked as `:required` will not be removed. Instead
201
+ # the symbol `:required` will be set as the attribute's value if it
202
+ # isn't overwritten by the custom data. This type of value is a _benign
203
+ # default_ meant to cause errors to provide a more helpful description
204
+ # (i.e. this attribute is required).
205
+ #
206
+ # For Rails projects, we suggest using `:required` for any association
207
+ # that is necessary for the object to be valid. We do not recommend
208
+ # attempting to generate default records within the factory as this can
209
+ # lead to unexpected database state; and hide relevant information away
210
+ # from the specs which may depend on it.
211
+ #
212
+ # ### "Safe" Attribute Duplication
213
+ #
214
+ # In an effort to help limit accidental state leak between instances
215
+ # the factory will duplicate all non-frozen template values prior to
216
+ # building the instance. Duplication is only applied to the values
217
+ # registered for the templates. Custom values provided when building
218
+ # the instance are not duplicated.
219
+ #
220
+ # @example register a domain template using class constant
221
+ # Radius::Spec::ModelFactory.define_factory AnyClass,
222
+ # any_attr: :any_value
223
+ # @example register a domain template using lazy class loading
224
+ # Radius::Spec::ModelFactory.define_factory :AnyClass,
225
+ # any_attr: :any_value
226
+ # @example register a nested class using lazy class loading
227
+ # Radius::Spec::ModelFactory.define_factory "AnyModule::AnyClass",
228
+ # any_attr: :any_value
229
+ # @example advanced example using additional features
230
+ # Radius::Spec::ModelFactory.define_factory(
231
+ # "AnyClass",
232
+ # dynamic: -> { rand(0..100) },
233
+ # safe_array: [1, 2, 3],
234
+ # )
235
+ #
236
+ # AnyClass = Struct.new(:dynamic, :safe_array, keyword_init: true)
237
+ #
238
+ # instance_a = Radius::Spec::ModelFactory.build("AnyClass")
239
+ # # => #<struct AnyClass dynamic=10, safe_array=[1, 2, 3]>
240
+ #
241
+ # instance_a.safe_array << 4
242
+ # # => #<struct AnyClass dynamic=10, safe_array=[1, 2, 3, 4]>
243
+ #
244
+ # instance_b = Radius::Spec::ModelFactory.build("AnyClass")
245
+ # # => #<struct AnyClass dynamic=32, safe_array=[1, 2, 3]>
246
+ # @param class_name [Class, String, Symbol] fully qualified domain
247
+ # model class name or constant
248
+ # @param attrs [Hash{String,Symbol => Object}] hash of attributes and
249
+ # default values to register
250
+ # @return [void]
251
+ def define_factory(class_name, attrs = {})
252
+ templates[class_name.to_s] = attrs.transform_keys(&:to_sym).freeze
253
+ end
254
+ alias_method :factory, :define_factory
255
+
256
+ # @private
257
+ def safe_transform(value)
258
+ return value.call if value.is_a?(Proc)
259
+ return value if value.frozen?
260
+ value.dup
261
+ end
262
+
263
+ # @private
264
+ def template(name)
265
+ templates.fetch(name) {
266
+ raise TemplateNotFound, "template not found: #{name}"
267
+ }
268
+ end
269
+
270
+ # @private
271
+ def templates
272
+ @templates ||= {}
273
+ end
274
+ end
275
+
276
+ module_function
277
+
278
+ # Convenience wrapper for building a model template.
279
+ #
280
+ # All `custom_attrs` values are provided as is to the class initializer
281
+ # (i.e. they are **not** duplicate or modified in any way). When an
282
+ # attribute exists in both the registered template and `custom_attrs` the
283
+ # value in `custom_attrs` will be used. The `custom_attrs` may also
284
+ # include new attributes not defined in the factory template.
285
+ #
286
+ # ### Optional Block
287
+ #
288
+ # The `block` is optional. When provided it is passed directly to `new`
289
+ # when initializing the instance. This is to support the common Ruby
290
+ # idiom of yielding `self` within initialize:
291
+ #
292
+ # ```ruby
293
+ # class AnyClass
294
+ # def initialize(attrs = {})
295
+ # # setup attrs
296
+ # yield self if block_given?
297
+ # end
298
+ # end
299
+ # ```
300
+ #
301
+ # <div class="note notetag">
302
+ # <strong>Note:</strong>
303
+ # <div class="inline">
304
+ # <p>
305
+ # Since Ruby always supports passing a block to a method, even if the
306
+ # method does not use the block, it's possible the block will not run if
307
+ # the class being instantiated does yield to it.
308
+ # </p>
309
+ # <p>
310
+ # Also, while the common idiom is to <code>yield self</code> classes are
311
+ # free to yield anything. You need to be aware of how the class normally
312
+ # behaves when passing a block to <code>new</code>.
313
+ # </p>
314
+ # </div>
315
+ # </div>
316
+ #
317
+ # The examples below show different ways of interacting with the
318
+ # following domain model and registered factory template:
319
+ #
320
+ # ```ruby
321
+ # Radius::Spec::ModelFactory.factory "AnyClass",
322
+ # simple_attr: "any value",
323
+ # array_attr: %w[any value],
324
+ # optional_attr: :optional,
325
+ # dynamic_attr: -> { rand(0..100) }
326
+ #
327
+ # class AnyClass
328
+ # def initialize(**opts)
329
+ # opts.each do |k, v|
330
+ # public_send "#{k}=", v
331
+ # end
332
+ # yield self if block_given?
333
+ # end
334
+ #
335
+ # attr_accessor :array_attr, :dynamic_attr, :optional_attr, :simple_attr
336
+ # end
337
+ # ```
338
+ #
339
+ # @example building the default template using lazy class loading
340
+ # Radius::Spec::ModelFactory.build("AnyClass")
341
+ # # => #<AnyClass @array_attr=["any", "value"],
342
+ # # @dynamic_attr=88,
343
+ # # @simple_attr="any value">
344
+ # @example building the default template using class constant
345
+ # Radius::Spec::ModelFactory.build(AnyClass)
346
+ # # => #<AnyClass @array_attr=["any", "value"],
347
+ # # @dynamic_attr=3,
348
+ # # @simple_attr="any value">
349
+ # @example building the default template with a block
350
+ # Radius::Spec::ModelFactory.build("AnyClass") { |instance|
351
+ # instance.simple_attr = "Block Value"
352
+ # }
353
+ # # => #<AnyClass @array_attr=["any", "value"],
354
+ # # @dynamic_attr=27,
355
+ # # @simple_attr="Block Value">
356
+ # @example building an instance with custom attributes
357
+ # Radius::Spec::ModelFactory.build(
358
+ # "AnyClass",
359
+ # simple_attr: "Custom Value",
360
+ # dynamic_attr: "Static Value",
361
+ # optional_attr: "Optional Value",
362
+ # )
363
+ # # => #<AnyClass @array_attr=["any", "value"],
364
+ # # @dynamic_attr="Static Value",
365
+ # # @optional_attr="Optional Value",
366
+ # # @simple_attr="Custom Value">
367
+ # @example registered template values are safe from modification
368
+ # instance_a = Radius::Spec::ModelFactory.build("AnyClass")
369
+ # instance_b = Radius::Spec::ModelFactory.build("AnyClass")
370
+ # instance_a.simple_attr.upcase!
371
+ # instance_a.array_attr << "modified"
372
+ # puts "#{instance_a.simple_attr}: #{instance_a.array_attr}"
373
+ # puts "#{instance_b.simple_attr}: #{instance_b.array_attr}"
374
+ #
375
+ # # Outputs:
376
+ # # ANY VALUE: ["any", "value", "modified"]
377
+ # # any value: ["any", "value"]
378
+ # @example building instances with custom shared data
379
+ # shared_array = %w[this is shared]
380
+ # instance_a = Radius::Spec::ModelFactory.build(
381
+ # "AnyClass",
382
+ # array_attr: shared_array,
383
+ # simple_attr: "Instance A",
384
+ # )
385
+ # instance_b = Radius::Spec::ModelFactory.build(
386
+ # "AnyClass",
387
+ # array_attr: shared_array,
388
+ # simple_attr: "Instance B",
389
+ # )
390
+ # instance_a.array_attr << "modified"
391
+ # puts "#{instance_a.simple_attr}: #{instance_a.array_attr}"
392
+ # puts "#{instance_b.simple_attr}: #{instance_b.array_attr}"
393
+ #
394
+ # # Outputs:
395
+ # # Instance A: ["this", "is", "shared", "modified"]
396
+ # # Instance B: ["this", "is", "shared", "modified"]
397
+ # @param name [Class, String, Symbol] fully qualified domain model class
398
+ # name or constant
399
+ # @param custom_attrs [Hash{String,Symbol => Object}] hash of custom
400
+ # attributes to replace registered template default values
401
+ # @param block optional block which is passed through to `new` when
402
+ # instantiating `name`
403
+ # @return instance of `name` instantiated with `custom_attrs` and the
404
+ # registered template attributes
405
+ # @raise [TemplateNotFound] when no template is defined for `name`
406
+ # @see .define_factory
407
+ def build(name, custom_attrs = {}, &block)
408
+ name = name.to_s
409
+ template = ::Radius::Spec::ModelFactory.template(name)
410
+ template_only = template.keys - custom_attrs.keys
411
+ attrs = template.slice(*template_only)
412
+ .delete_if { |_, v| :optional == v }
413
+ .transform_values! { |v|
414
+ ::Radius::Spec::ModelFactory.safe_transform(v)
415
+ }
416
+ .merge(custom_attrs)
417
+ # TODO: Always yield to the provided block even if new doesn't
418
+ ::Object.const_get(name).new(attrs, &block)
419
+ end
420
+
421
+ # Convenience wrapper for building, and persisting, a model template.
422
+ #
423
+ # This is a thin wrapper around `build(name, attrs).tap(&:save!)`. The
424
+ # persistence message `save!` will only be called on objects which
425
+ # respond to it.
426
+ #
427
+ # ### Avoid for New Code
428
+ #
429
+ # It is strongly suggested that you avoid using `create` for new code.
430
+ # Instead be explicit about when and how objects are persisted. This
431
+ # allows you to have fine grain control over how your data is setup.
432
+ #
433
+ # We suggest that you create instances which need to be persisted before
434
+ # your specs using the following syntax:
435
+ #
436
+ # ```ruby
437
+ # let(:an_instance) { build("AnyClass") }
438
+ #
439
+ # before do
440
+ # an_instance.save!
441
+ # end
442
+ # ```
443
+ #
444
+ # Alternatively if you really want for the instance be lazy instantiated,
445
+ # and persisted, pass the appropriate persistence method as the block:
446
+ #
447
+ # ```ruby
448
+ # let(:an_instance) { build("AnyClass", &:save!) }
449
+ # ```
450
+ #
451
+ # @param (see .build)
452
+ # @return (see .build)
453
+ # @raise (see .build)
454
+ # @see .build
455
+ # @see .define_factory
456
+ def create(name, custom_attrs = {}, &block)
457
+ instance = build(name, custom_attrs, &block)
458
+ instance.save! if instance.respond_to?(:save!)
459
+ instance
460
+ end
461
+ end
462
+ end
463
+ end
464
+
465
+ # Try to load the factories defined for the specs
466
+ # rubocop:disable Lint/HandleExceptions
467
+ begin
468
+ require 'support/model_factories'
469
+ rescue LoadError
470
+ # Ignore as this is an optional convenience feature
471
+ end
472
+ # rubocop:enable Lint/HandleExceptions
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Ensure the gem, and default RSpec config, are already loaded
4
+ require 'radius/spec'
5
+ require 'radius/spec/rspec'
6
+ require 'rspec/rails'
7
+
8
+ RSpec.configure do
9
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
10
+ config.fixture_path = ::Rails.root.join("spec", "fixtures")
11
+
12
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
13
+ # examples within a transaction, remove the following line or assign false
14
+ # instead of true.
15
+ config.use_transactional_fixtures = true
16
+
17
+ # Filter lines from Rails gems in backtraces.
18
+ config.filter_rails_from_backtrace!
19
+ # arbitrary gems may also be filtered via:
20
+ # config.filter_gems_from_backtrace("gem name")
21
+
22
+ # Skip system tests by default.
23
+ #
24
+ # This is what Rails does by default:
25
+ #
26
+ # > By default, running `bin/rails` test won't run your system tests. Make
27
+ # > sure to run `bin/rails test:system` to actually run them.
28
+ #
29
+ # Running system tests often requires additional external dependencies. Not
30
+ # every project is setup to install all of the system test dependencies by
31
+ # default. To avoid issues across projects we default to excluding these
32
+ # specs. Projects are free to overwrite this filter in their custom RSpec
33
+ # configuration.
34
+ #
35
+ # This can be overridden on the command line:
36
+ #
37
+ # bin/rspec -t type:system
38
+ #
39
+ # See:
40
+ # - http://guides.rubyonrails.org/v5.1.4/testing.html#implementing-a-system-test
41
+ # - https://relishapp.com/rspec/rspec-core/v/3-7/docs/filtering/exclusion-filters
42
+ # - http://rspec.info/documentation/3.7/rspec-core/RSpec/Core/Configuration.html#filter_run_excluding-instance_method
43
+ config.filter_run_excluding type: "system"
44
+
45
+ # Always clear the cache before specs to avoid state leak problems
46
+ config.before do
47
+ Rails.cache.clear
48
+ end
49
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Given that it is always loaded, you are encouraged to keep this file as
4
+ # light-weight as possible. Requiring heavyweight dependencies from this file
5
+ # will add to the boot time of your test suite on EVERY test run, even for an
6
+ # individual file that may not need all of that loaded. Instead, consider making
7
+ # a separate helper file that requires the additional dependencies and performs
8
+ # the additional setup, and require it from the spec files that actually need
9
+ # it.
10
+ #
11
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
12
+ RSpec.configure do |config|
13
+ # rspec-expectations config goes here. You can use an alternate
14
+ # assertion/expectation library such as wrong or the stdlib/minitest
15
+ # assertions if you prefer.
16
+ config.expect_with :rspec do |expectations|
17
+ # This option will default to `true` in RSpec 4. It makes the `description`
18
+ # and `failure_message` of custom matchers include text for helper methods
19
+ # defined using `chain`, e.g.:
20
+ # be_bigger_than(2).and_smaller_than(4).description
21
+ # # => "be bigger than 2 and smaller than 4"
22
+ # ...rather than:
23
+ # # => "be bigger than 2"
24
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
25
+ end
26
+
27
+ # rspec-mocks config goes here. You can use an alternate test double
28
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
29
+ config.mock_with :rspec do |mocks|
30
+ # Prevents you from mocking or stubbing a method that does not exist on
31
+ # a real object. This is generally recommended, and will default to
32
+ # `true` in RSpec 4.
33
+ mocks.verify_partial_doubles = true
34
+ mocks.allow_message_expectations_on_nil = false
35
+ mocks.verify_doubled_constant_names = (
36
+ ENV.key?("CI") || !config.files_to_run.one?
37
+ )
38
+ end
39
+
40
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
41
+ # have no way to turn it off -- the option exists only for backwards
42
+ # compatibility in RSpec 3). It causes shared context metadata to be
43
+ # inherited by the metadata hash of host groups and examples, rather than
44
+ # triggering implicit auto-inclusion in groups with matching metadata.
45
+ config.shared_context_metadata_behavior = :apply_to_host_groups
46
+
47
+ # This allows you to limit a spec run to individual examples or groups
48
+ # you care about by tagging them with `:focus` metadata. When nothing
49
+ # is tagged with `:focus`, all examples get run. RSpec also provides
50
+ # aliases for `it`, `describe`, and `context` that include `:focus`
51
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
52
+ config.filter_run_when_matching :focus
53
+
54
+ # Allows RSpec to persist some state between runs in order to support
55
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
56
+ # you configure your source control system to ignore this file.
57
+ config.example_status_persistence_file_path = ".rspec_status"
58
+
59
+ # Limits the available syntax to the non-monkey patched syntax that is
60
+ # recommended. For more details, see:
61
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
62
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
63
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
64
+ config.disable_monkey_patching!
65
+
66
+ # This setting enables warnings. It's recommended, but in some cases may
67
+ # be too noisy due to issues in dependencies.
68
+ config.warnings = true
69
+
70
+ # Many RSpec users commonly either run the entire suite or an individual
71
+ # file, and it's useful to allow more verbose output when running an
72
+ # individual spec file.
73
+ if config.files_to_run.one?
74
+ # Use the documentation formatter for detailed output,
75
+ # unless a formatter has already been configured
76
+ # (e.g. via a command-line flag).
77
+ config.default_formatter = "doc"
78
+ end
79
+
80
+ # RSpec will exit with code 0 indicating success if no examples are defined.
81
+ # This option allows you to configure RSpec to exit with code 1 indicating
82
+ # failure. This is useful in CI environments, as it helps detect when you've
83
+ # misconfigured RSpec to look for specs in the wrong place or with the wrong
84
+ # pattern. See http://rspec.info/blog/2017/05/rspec-3-6-has-been-released/#core-configfailifnoexamples
85
+ config.fail_if_no_examples = true
86
+
87
+ # Print the 10 slowest examples and example groups at the
88
+ # end of the spec run, to help surface which specs are running
89
+ # particularly slow.
90
+ config.profile_examples = 10 if ENV["CI"]
91
+
92
+ # Run specs in random order to surface order dependencies. If you find an
93
+ # order dependency and want to debug it, you can fix the order by providing
94
+ # the seed, which is printed after each run.
95
+ # --seed 1234
96
+ config.order = :random
97
+
98
+ # Seed global randomization in this process using the `--seed` CLI option.
99
+ # Setting this allows you to use `--seed` to deterministically reproduce
100
+ # test failures related to randomization by passing the same `--seed` value
101
+ # as the one that triggered the failure.
102
+ Kernel.srand config.seed
103
+
104
+ config.when_first_matching_example_defined(
105
+ :model_factory,
106
+ :model_factories,
107
+ ) do
108
+ require 'radius/spec/model_factory'
109
+ config.include Radius::Spec::ModelFactory, :model_factory, :model_factories
110
+ end
111
+
112
+ config.when_first_matching_example_defined(type: :controller) do
113
+ require 'radius/spec/model_factory'
114
+ config.include Radius::Spec::ModelFactory, type: :controller
115
+ end
116
+
117
+ config.when_first_matching_example_defined(type: :feature) do
118
+ require 'radius/spec/model_factory'
119
+ config.include Radius::Spec::ModelFactory, type: :feature
120
+ end
121
+
122
+ config.when_first_matching_example_defined(type: :job) do
123
+ require 'radius/spec/model_factory'
124
+ config.include Radius::Spec::ModelFactory, type: :job
125
+ end
126
+
127
+ config.when_first_matching_example_defined(type: :model) do
128
+ require 'radius/spec/model_factory'
129
+ config.include Radius::Spec::ModelFactory, type: :model
130
+ end
131
+
132
+ config.when_first_matching_example_defined(type: :request) do
133
+ require 'radius/spec/model_factory'
134
+ config.include Radius::Spec::ModelFactory, type: :request
135
+ end
136
+
137
+ config.when_first_matching_example_defined(type: :system) do
138
+ require 'radius/spec/model_factory'
139
+ config.include Radius::Spec::ModelFactory, type: :system
140
+ end
141
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Radius
4
+ module Spec
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "radius/spec/version"
4
+
5
+ module Radius
6
+ # Namespace for RSpec plug-ins and helpers
7
+ module Spec
8
+ end
9
+ end
10
+
11
+ require "radius/spec/rspec" if defined?(RSpec)