journaled 2.0.0.alpha1 → 2.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +95 -25
- data/app/models/concerns/journaled/changes.rb +41 -0
- data/app/models/journaled/actor_uri_provider.rb +22 -0
- data/app/models/journaled/change_definition.rb +17 -1
- data/app/models/journaled/change_writer.rb +3 -22
- data/app/models/journaled/event.rb +0 -4
- data/config/initializers/change_protection.rb +3 -0
- data/lib/journaled.rb +9 -1
- data/lib/journaled/relation_change_protection.rb +27 -0
- data/lib/journaled/rspec.rb +18 -0
- data/lib/journaled/version.rb +1 -1
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +26 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +21 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +78 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/migrate/20180606205114_create_delayed_jobs.rb +18 -0
- data/spec/dummy/db/schema.rb +31 -0
- data/spec/dummy/log/development.log +34 -0
- data/spec/dummy/log/test.log +34540 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/lib/journaled_spec.rb +51 -0
- data/spec/models/concerns/journaled/actor_spec.rb +46 -0
- data/spec/models/concerns/journaled/changes_spec.rb +94 -0
- data/spec/models/database_change_protection_spec.rb +106 -0
- data/spec/models/journaled/actor_uri_provider_spec.rb +41 -0
- data/spec/models/journaled/change_writer_spec.rb +276 -0
- data/spec/models/journaled/delivery_spec.rb +156 -0
- data/spec/models/journaled/event_spec.rb +145 -0
- data/spec/models/journaled/json_schema_model/validator_spec.rb +133 -0
- data/spec/models/journaled/writer_spec.rb +129 -0
- data/spec/rails_helper.rb +20 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/delayed_job_spec_helper.rb +11 -0
- data/spec/support/environment_spec_helper.rb +16 -0
- metadata +113 -4
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
RSpec.describe Journaled::Event do
|
4
|
+
let(:sample_journaled_event_class) do
|
5
|
+
SomeClassName = Class.new do
|
6
|
+
include Journaled::Event
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
after do
|
11
|
+
Object.send(:remove_const, :SomeClassName) if defined?(SomeClassName)
|
12
|
+
Object.send(:remove_const, :SomeModule) if defined?(SomeModule)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:sample_journaled_event) { sample_journaled_event_class.new }
|
16
|
+
|
17
|
+
describe '#journal!' do
|
18
|
+
let(:mock_journaled_writer) { instance_double(Journaled::Writer, journal!: nil) }
|
19
|
+
|
20
|
+
before do
|
21
|
+
allow(Journaled::Writer).to receive(:new).and_return(mock_journaled_writer)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'creates a Journaled::Writer with this event and journals it' do
|
25
|
+
sample_journaled_event.journal!
|
26
|
+
expect(Journaled::Writer).to have_received(:new).with(journaled_event: sample_journaled_event)
|
27
|
+
expect(mock_journaled_writer).to have_received(:journal!)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#journaled_schema_name' do
|
32
|
+
it 'returns the underscored version on the class name' do
|
33
|
+
expect(sample_journaled_event.journaled_schema_name).to eq 'some_class_name'
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when the class is modularized' do
|
37
|
+
let(:sample_journaled_event_class) do
|
38
|
+
SomeModule = Module.new
|
39
|
+
SomeModule::SomeClassName = Class.new do
|
40
|
+
include Journaled::Event
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns the underscored version on the class name' do
|
45
|
+
expect(sample_journaled_event.journaled_schema_name).to eq 'some_module/some_class_name'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#event_type' do
|
51
|
+
it 'returns the underscored version on the class name' do
|
52
|
+
expect(sample_journaled_event.event_type).to eq 'some_class_name'
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when the class is modularized' do
|
56
|
+
let(:sample_journaled_event_class) do
|
57
|
+
SomeModule = Module.new
|
58
|
+
SomeModule::SomeClassName = Class.new do
|
59
|
+
include Journaled::Event
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'returns the underscored version on the class name, with slashes replaced with underscores' do
|
64
|
+
expect(sample_journaled_event.event_type).to eq 'some_module_some_class_name'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#journaled_partition_key' do
|
70
|
+
it 'returns the #event_type' do
|
71
|
+
expect(sample_journaled_event.journaled_partition_key).to eq 'some_class_name'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#journaled_app_name' do
|
76
|
+
it 'returns nil in the base class so it can be set explicitly in apps spanning multiple app domains' do
|
77
|
+
expect(sample_journaled_event.journaled_app_name).to be_nil
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'returns the journaled default if set' do
|
81
|
+
allow(Journaled).to receive(:default_app_name).and_return("my_app")
|
82
|
+
expect(sample_journaled_event.journaled_app_name).to eq("my_app")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#journaled_attributes' do
|
87
|
+
let(:fake_uuid) { 'FAKE_UUID' }
|
88
|
+
let(:frozen_time) { Time.zone.parse('15/2/2017 13:00') }
|
89
|
+
before do
|
90
|
+
allow(SecureRandom).to receive(:uuid).and_return(fake_uuid).once
|
91
|
+
end
|
92
|
+
around do |example|
|
93
|
+
Timecop.freeze(frozen_time) { example.run }
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'when no additional attributes have been defined' do
|
97
|
+
it 'returns the base attributes, and memoizes them after the first call' do
|
98
|
+
expect(sample_journaled_event.journaled_attributes).to eq id: fake_uuid, created_at: frozen_time, event_type: 'some_class_name'
|
99
|
+
expect(sample_journaled_event.journaled_attributes).to eq id: fake_uuid, created_at: frozen_time, event_type: 'some_class_name'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'when there are additional attributes specified, but not defined' do
|
104
|
+
let(:sample_journaled_event_class) do
|
105
|
+
SomeClassName = Class.new do
|
106
|
+
include Journaled::Event
|
107
|
+
|
108
|
+
journal_attributes :foo
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'raises a no method error' do
|
113
|
+
expect { sample_journaled_event.journaled_attributes }.to raise_error NoMethodError
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when there are additional attributes specified and defined' do
|
118
|
+
let(:sample_journaled_event_class) do
|
119
|
+
SomeClassName = Class.new do
|
120
|
+
include Journaled::Event
|
121
|
+
|
122
|
+
journal_attributes :foo, :bar
|
123
|
+
|
124
|
+
def foo
|
125
|
+
'foo_return'
|
126
|
+
end
|
127
|
+
|
128
|
+
def bar
|
129
|
+
'bar_return'
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'returns the specified attributes plus the base ones' do
|
135
|
+
expect(sample_journaled_event.journaled_attributes).to eq(
|
136
|
+
id: fake_uuid,
|
137
|
+
created_at: frozen_time,
|
138
|
+
event_type: 'some_class_name',
|
139
|
+
foo: 'foo_return',
|
140
|
+
bar: 'bar_return'
|
141
|
+
)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
RSpec.describe Journaled::JsonSchemaModel::Validator do
|
4
|
+
subject { described_class.new schema_name }
|
5
|
+
|
6
|
+
describe '#validate!' do
|
7
|
+
let(:json_to_validate) { attributes_to_validate.to_json }
|
8
|
+
let(:attributes_to_validate) do
|
9
|
+
{
|
10
|
+
some_string: some_string_value,
|
11
|
+
some_decimal: 0.1.to_d,
|
12
|
+
some_time: Time.zone.parse('2017-01-20 15:16:17 -05:00'),
|
13
|
+
some_int: some_int_value,
|
14
|
+
some_optional_string: some_optional_string_value,
|
15
|
+
some_nullable_field: some_nullable_field
|
16
|
+
}
|
17
|
+
end
|
18
|
+
let(:some_int_value) { 3 }
|
19
|
+
let(:some_string_value) { 'SOME_STRING' }
|
20
|
+
let(:some_optional_string_value) { 'SOME_OPTIONAL_STRING' }
|
21
|
+
let(:some_nullable_field) { 'VALUE' }
|
22
|
+
|
23
|
+
subject { described_class.new schema_name }
|
24
|
+
|
25
|
+
context 'when the schema name matches a schema in journaled' do
|
26
|
+
let(:schema_name) { :fake_json_schema_name }
|
27
|
+
let(:gem_path) { Journaled::Engine.root.join "journaled_schemas/#{schema_name}.json" }
|
28
|
+
let(:schema_path) { Rails.root.join "journaled_schemas", "#{schema_name}.json" }
|
29
|
+
let(:schema_file_contents) do
|
30
|
+
<<-JSON
|
31
|
+
{
|
32
|
+
"title": "Person",
|
33
|
+
"type": "object",
|
34
|
+
"properties": {
|
35
|
+
"some_string": {
|
36
|
+
"type": "string"
|
37
|
+
},
|
38
|
+
"some_decimal": {
|
39
|
+
"type": "string"
|
40
|
+
},
|
41
|
+
"some_time": {
|
42
|
+
"type": "string"
|
43
|
+
},
|
44
|
+
"some_int": {
|
45
|
+
"type": "integer"
|
46
|
+
},
|
47
|
+
"some_optional_string": {
|
48
|
+
"type": "string"
|
49
|
+
},
|
50
|
+
"some_nullable_field": {
|
51
|
+
"type": ["string", "null"]
|
52
|
+
}
|
53
|
+
},
|
54
|
+
"required": ["some_string", "some_decimal", "some_time", "some_int", "some_nullable_field"]
|
55
|
+
}
|
56
|
+
JSON
|
57
|
+
end
|
58
|
+
|
59
|
+
before do
|
60
|
+
allow(File).to receive(:exist?).and_call_original
|
61
|
+
allow(File).to receive(:exist?).with(gem_path).and_return(false)
|
62
|
+
allow(File).to receive(:exist?).with(schema_path).and_return(true)
|
63
|
+
allow(File).to receive(:read).with(schema_path).and_return(schema_file_contents)
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when all the required fields are provided' do
|
67
|
+
context 'when all the fields are provided' do
|
68
|
+
it 'is valid' do
|
69
|
+
expect(subject.validate!(json_to_validate)).to eq true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when an optional field is missing' do
|
74
|
+
let(:attributes_to_validate) do
|
75
|
+
{
|
76
|
+
some_string: some_string_value,
|
77
|
+
some_decimal: 0.1.to_d,
|
78
|
+
some_time: Time.zone.parse('2017-01-20 15:16:17 -05:00'),
|
79
|
+
some_int: some_int_value,
|
80
|
+
some_nullable_field: some_nullable_field
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'is valid' do
|
85
|
+
expect(subject.validate!(json_to_validate)).to eq true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'when a nullable field is nil' do
|
90
|
+
let(:some_nullable_optional_field) { nil }
|
91
|
+
|
92
|
+
it 'is valid' do
|
93
|
+
expect(subject.validate!(json_to_validate)).to eq true
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'but one of the required fields is of the wrong type' do
|
98
|
+
let(:some_int_value) { 'NOT_AN_INTEGER' }
|
99
|
+
|
100
|
+
it 'is NOT valid' do
|
101
|
+
expect { subject.validate! json_to_validate }.to raise_error JSON::Schema::ValidationError
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'when not all the required fields are provided' do
|
107
|
+
let(:attributes_to_validate) do
|
108
|
+
{
|
109
|
+
some_string: some_string_value,
|
110
|
+
some_decimal: 0.1.to_d,
|
111
|
+
some_time: Time.zone.parse('2017-01-20 15:16:17 -05:00')
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'is NOT valid' do
|
116
|
+
expect { subject.validate! json_to_validate }.to raise_error JSON::Schema::ValidationError
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'when the schema name does not match a schema in journaled' do
|
122
|
+
let(:schema_name) { :nonexistent_avro_scehma }
|
123
|
+
|
124
|
+
before do
|
125
|
+
allow(File).to receive(:exist?).and_return(false)
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'raises an error loading the schema' do
|
129
|
+
expect { subject.validate! json_to_validate }.to raise_error(/not found in any of Journaled::Engine.root,/)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
RSpec.describe Journaled::Writer do
|
4
|
+
subject { described_class.new journaled_event: journaled_event }
|
5
|
+
|
6
|
+
describe '#initialize' do
|
7
|
+
context 'when the Journaled Event does not implement all the necessary methods' do
|
8
|
+
let(:journaled_event) { double }
|
9
|
+
|
10
|
+
it 'raises on initialization' do
|
11
|
+
expect { subject }.to raise_error RuntimeError, /An enqueued event must respond to/
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when the Journaled Event returns non-present values for some of the required methods' do
|
16
|
+
let(:journaled_event) do
|
17
|
+
double(
|
18
|
+
journaled_schema_name: nil,
|
19
|
+
journaled_attributes: {},
|
20
|
+
journaled_partition_key: '',
|
21
|
+
journaled_app_name: nil
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'raises on initialization' do
|
26
|
+
expect { subject }.to raise_error RuntimeError, /An enqueued event must have a non-nil response to/
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when the Journaled Event complies with the API' do
|
31
|
+
let(:journaled_event) do
|
32
|
+
double(
|
33
|
+
journaled_schema_name: :fake_schema_name,
|
34
|
+
journaled_attributes: { foo: :bar },
|
35
|
+
journaled_partition_key: 'fake_partition_key',
|
36
|
+
journaled_app_name: nil
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'does not raise on initialization' do
|
41
|
+
expect { subject }.to_not raise_error
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#journal!' do
|
47
|
+
let(:schema_path) { Journaled::Engine.root.join "journaled_schemas/fake_schema_name.json" }
|
48
|
+
let(:schema_file_contents) do
|
49
|
+
<<-JSON
|
50
|
+
{
|
51
|
+
"title": "Foo",
|
52
|
+
"type": "object",
|
53
|
+
"properties": {
|
54
|
+
"foo": {
|
55
|
+
"type": "string"
|
56
|
+
}
|
57
|
+
},
|
58
|
+
"required": ["foo"]
|
59
|
+
}
|
60
|
+
JSON
|
61
|
+
end
|
62
|
+
|
63
|
+
before do
|
64
|
+
allow(File).to receive(:exist?).and_call_original
|
65
|
+
allow(File).to receive(:exist?).with(schema_path).and_return(true)
|
66
|
+
allow(File).to receive(:read).and_call_original
|
67
|
+
allow(File).to receive(:read).with(schema_path).and_return(schema_file_contents)
|
68
|
+
end
|
69
|
+
|
70
|
+
let(:journaled_event) do
|
71
|
+
double(
|
72
|
+
journaled_schema_name: :fake_schema_name,
|
73
|
+
journaled_attributes: journaled_event_attributes,
|
74
|
+
journaled_partition_key: 'fake_partition_key',
|
75
|
+
journaled_app_name: 'my_app'
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
around do |example|
|
80
|
+
with_jobs_delayed { example.run }
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when the journaled event does NOT comply with the base_event schema' do
|
84
|
+
let(:journaled_event_attributes) { { foo: 1 } }
|
85
|
+
|
86
|
+
it 'raises an error and does not enqueue anything' do
|
87
|
+
expect { subject.journal! }.to raise_error JSON::Schema::ValidationError
|
88
|
+
expect(Delayed::Job.where('handler like ?', '%Journaled::Delivery%').count).to eq 0
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when the event complies with the base_event schema' do
|
93
|
+
context 'when the specific json schema is NOT valid' do
|
94
|
+
let(:journaled_event_attributes) { { id: 'FAKE_UUID', event_type: 'fake_event', created_at: Time.zone.now, foo: 1 } }
|
95
|
+
|
96
|
+
it 'raises an error and does not enqueue anything' do
|
97
|
+
expect { subject.journal! }.to raise_error JSON::Schema::ValidationError
|
98
|
+
expect(Delayed::Job.where('handler like ?', '%Journaled::Delivery%').count).to eq 0
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when the specific json schema is also valid' do
|
103
|
+
let(:journaled_event_attributes) { { id: 'FAKE_UUID', event_type: 'fake_event', created_at: Time.zone.now, foo: :bar } }
|
104
|
+
|
105
|
+
it 'creates a delivery with the app name passed through' do
|
106
|
+
allow(Journaled::Delivery).to receive(:new).and_call_original
|
107
|
+
subject.journal!
|
108
|
+
expect(Journaled::Delivery).to have_received(:new).with(hash_including(app_name: 'my_app'))
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'enqueues a Journaled::Delivery object with the serialized journaled_event at the lowest priority' do
|
112
|
+
expect { subject.journal! }.to change {
|
113
|
+
Delayed::Job.where('handler like ?', '%Journaled::Delivery%').where(priority: Journaled::JobPriority::EVENTUAL).count
|
114
|
+
}.from(0).to(1)
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when the Writer was initialized with a priority' do
|
118
|
+
subject { described_class.new journaled_event: journaled_event, priority: Journaled::JobPriority::INTERACTIVE }
|
119
|
+
|
120
|
+
it 'enqueues the event at the given priority' do
|
121
|
+
expect { subject.journal! }.to change {
|
122
|
+
Delayed::Job.where('handler like ?', '%Journaled::Delivery%').where(priority: Journaled::JobPriority::INTERACTIVE).count
|
123
|
+
}.from(0).to(1)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
2
|
+
ENV['RAILS_ENV'] ||= 'test'
|
3
|
+
require 'spec_helper'
|
4
|
+
require File.expand_path('../spec/dummy/config/environment', __dir__)
|
5
|
+
require 'rspec/rails'
|
6
|
+
require 'timecop'
|
7
|
+
require 'webmock/rspec'
|
8
|
+
require 'journaled/rspec'
|
9
|
+
require 'pry-rails'
|
10
|
+
|
11
|
+
Dir[Rails.root.join('..', 'support', '**', '*.rb')].each { |f| require f }
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.use_transactional_fixtures = true
|
15
|
+
|
16
|
+
config.infer_spec_type_from_file_location!
|
17
|
+
|
18
|
+
config.include DelayedJobSpecHelper
|
19
|
+
config.include EnvironmentSpecHelper
|
20
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'delayed_job_active_record'
|
2
|
+
rails_env = ENV['RAILS_ENV'] ||= 'test'
|
3
|
+
db_adapter = ENV['DB_ADAPTER'] ||= 'postgresql'
|
4
|
+
require File.expand_path('dummy/config/environment.rb', __dir__)
|
5
|
+
|
6
|
+
Rails.configuration.database_configuration[db_adapter][rails_env].tap do |c|
|
7
|
+
ActiveRecord::Tasks::DatabaseTasks.create(c)
|
8
|
+
ActiveRecord::Base.establish_connection(c)
|
9
|
+
load File.expand_path('dummy/db/schema.rb', __dir__)
|
10
|
+
end
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.expect_with :rspec do |expectations|
|
14
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
15
|
+
end
|
16
|
+
|
17
|
+
config.mock_with :rspec do |mocks|
|
18
|
+
mocks.verify_partial_doubles = true
|
19
|
+
end
|
20
|
+
|
21
|
+
config.order = :random
|
22
|
+
end
|