test_assistant 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +155 -71
- data/lib/test_assistant/configuration.rb +5 -0
- data/lib/test_assistant/email/expectation.rb +153 -46
- data/lib/test_assistant/json/expectation.rb +57 -20
- data/lib/test_assistant/version.rb +1 -1
- data/spec/email_expectation_spec.rb +369 -0
- data/spec/eql_json_spec.rb +58 -0
- data/spec/support/email_mock.rb +27 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b1c5794fb9961343ed9b9c926125a1e7f4128bb
|
4
|
+
data.tar.gz: 8dfad5f30319bffaac95db75a76c99228bbe3fad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e8db6c937c7895f188fc16c03f2fbf2344cfbd0e8621ccd42521cc380819ac259a05eac1e869e5036e9e1ec2f4ee1e57bf23ad13098ef32496abacd0adea298
|
7
|
+
data.tar.gz: f841a64f96693ebc1fd9422c931c8f626531f74e38935049bfc2851a3d0de7cae8250c84f5b84be276943f883a6eb12efa102297ef16b0f3ac19dcd751072c5e
|
data/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# TestAssistant
|
2
2
|
|
3
|
-
|
3
|
+
RSpec toolbox for writing and diagnosing Ruby on Rails tests, faster - especially emails and JSON APIs.
|
4
4
|
|
5
|
-
##
|
6
|
-
|
7
|
-
TestAssistant is in its infancy and should be considered unstable. The API and behaviour is likely to change.
|
5
|
+
## Features
|
8
6
|
|
7
|
+
* Light-weight, scoped, lazily executed and composable tool-box, so you only include the features you want to use, when you want to use them with no unnecessary overhead
|
8
|
+
* JSON assertion that gives noise-free reports on complex nested structures, so you can find out exactly what has changed with your JSON API without having to manually diff large objects
|
9
|
+
* Expressive email assertions that let you succinctly describe when emails should and should not sent
|
10
|
+
* Automatic reporting of the context around failing tests, so you don't have to re-run them with additional logging or a debugger
|
9
11
|
|
10
12
|
## Installation
|
11
13
|
|
@@ -19,10 +21,6 @@ And then execute:
|
|
19
21
|
|
20
22
|
$ bundle
|
21
23
|
|
22
|
-
Or install it yourself as:
|
23
|
-
|
24
|
-
$ gem install test_assistant
|
25
|
-
|
26
24
|
## Usage
|
27
25
|
|
28
26
|
Test assistant requires access to the RSpec configuration object, so add the following to either `rails_helper.rb` or `spec_helper.rb`:
|
@@ -30,131 +28,217 @@ Test assistant requires access to the RSpec configuration object, so add the fol
|
|
30
28
|
```ruby
|
31
29
|
RSpec.configure do |config|
|
32
30
|
# other rspec configuration
|
33
|
-
|
31
|
+
|
34
32
|
TestAssistant.configure(config) do |ta_config|
|
35
33
|
# test assistant configuration here
|
36
34
|
end
|
37
35
|
end
|
38
36
|
```
|
39
37
|
|
40
|
-
|
38
|
+
## JSON expectations
|
39
|
+
|
40
|
+
Test Assistant lets you include helpers in your controller and request specs to get succinct declarative methods for defining the expected results for JSON responses.
|
41
41
|
|
42
|
-
|
42
|
+
### Setup
|
43
43
|
|
44
44
|
```ruby
|
45
45
|
TestAssistant.configure(config) do |ta_config|
|
46
|
-
ta_config.
|
46
|
+
ta_config.include_json_helpers type: :request
|
47
47
|
end
|
48
48
|
```
|
49
49
|
|
50
|
+
### Asserting JSON responses
|
51
|
+
|
52
|
+
Among the helpers provided are `json_response`, which automatically parses the last response object as json, and a custom assertion `eql_json` that reports failures in a format that is much clearer than anything provided by RSpec.
|
53
|
+
|
54
|
+
The full `expected` and `actual` values are still reported, but below is a separate report that only includes the paths to the failed nested values and their differences, removing the need to manually compare the two complete objects to find the difference.
|
55
|
+
|
50
56
|
```ruby
|
51
57
|
RSpec.describe 'making some valid request', type: :request do
|
52
58
|
context 'some important context' do
|
53
|
-
it 'should return
|
54
|
-
|
59
|
+
it 'should return some complicated JSON' do
|
60
|
+
|
61
|
+
perform_request
|
62
|
+
|
63
|
+
expect(json_response).to eql_json([
|
64
|
+
{
|
65
|
+
"a" => [
|
66
|
+
1, 2, 3
|
67
|
+
],
|
68
|
+
"c" => { "d" => "d'"}
|
69
|
+
},
|
70
|
+
{
|
71
|
+
"b" => [
|
72
|
+
1, 2, 3
|
73
|
+
],
|
74
|
+
"c" => { "d" => "d'"}
|
75
|
+
}
|
76
|
+
])
|
55
77
|
end
|
56
78
|
end
|
57
79
|
end
|
58
80
|
```
|
59
81
|
|
60
|
-
|
61
|
-
|
62
|
-
It's possible to invoke a debugger (`pry` is default, but fallback is to `byebug` and then `debugger`) if a test fails. This gives you access to some of the scope that the failing test ran in, allowing you to inspect objects and test variations of the failing assertion.
|
82
|
+
## Email expectations
|
63
83
|
|
64
|
-
|
84
|
+
Test Assistant provides a declarative API for describing when emails should be sent and their characteristics.
|
65
85
|
|
66
|
-
|
67
|
-
* `type: :<spec_type>` (default: nil - matches all test types) options.
|
86
|
+
### Setup
|
68
87
|
|
69
88
|
```ruby
|
70
89
|
TestAssistant.configure(config) do |ta_config|
|
71
|
-
|
90
|
+
ta_config.include_email_helpers type: :request
|
91
|
+
end
|
92
|
+
```
|
72
93
|
|
73
|
-
|
74
|
-
|
94
|
+
### Clearing emails
|
95
|
+
|
96
|
+
Emails can be cleared at any point by calling `clear_emails` in your tests. This is helpful when you are testing a user workflow that may trigger multiple emails.
|
97
|
+
|
98
|
+
Emails are automatically cleared between each request spec.
|
99
|
+
|
100
|
+
### Email receiver address
|
101
|
+
|
102
|
+
It's possible to assert an email was sent to one or more or more addresses using the following format:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
expect(email).to have_been_sent.to('user@email.com')
|
75
106
|
```
|
76
107
|
|
108
|
+
### Email sender address
|
109
|
+
|
110
|
+
Similarly, you can assert an email was sent from an address:
|
111
|
+
|
77
112
|
```ruby
|
78
|
-
|
79
|
-
context 'some important context' do
|
80
|
-
it 'should return a correct result', debugger: true do
|
81
|
-
# failing assertions
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
113
|
+
expect(email).to have_been_sent.from('user@email.com')
|
85
114
|
```
|
86
115
|
|
87
|
-
|
116
|
+
### Email subject
|
117
|
+
|
118
|
+
You can assert an email's subject:
|
88
119
|
|
89
|
-
|
90
|
-
|
120
|
+
```ruby
|
121
|
+
expect(email).to have_been_sent.with_subject('Welcome!')
|
122
|
+
```
|
91
123
|
|
92
|
-
|
124
|
+
|
125
|
+
### Email body
|
126
|
+
|
127
|
+
You can assert the body of an email by text:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
expect(email).to have_been_sent.with_text('Welcome, user@email.com')
|
131
|
+
```
|
132
|
+
|
133
|
+
Or using a selector on the email's HTML:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
expect(email).to have_been_sent.with_selector('#password')
|
137
|
+
```
|
138
|
+
|
139
|
+
Or look for links:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
expect(email).to have_been_sent.with_link('www.site.com/onboarding/1')
|
143
|
+
```
|
144
|
+
|
145
|
+
Or images:
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
expect(email).to have_been_sent.with_image('www.site.com/assets/images/welcome.png')
|
149
|
+
```
|
150
|
+
|
151
|
+
### Chaining assertions
|
152
|
+
|
153
|
+
You can chain any combination of the above that you want for ultra specific assertions:
|
154
|
+
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
expect(email).to have_been_sent
|
158
|
+
.to('user@email.com')
|
159
|
+
.from('admin@site.com')
|
160
|
+
.with_subject('Welcome!')
|
161
|
+
.with_text('Welcome, user@email.com')
|
162
|
+
.with_selector('#password').and('#username')
|
163
|
+
.with_link('www.site.com/onboarding/1')
|
164
|
+
.with_image('www.site.com/assets/images/welcome.png')
|
165
|
+
|
166
|
+
```
|
167
|
+
|
168
|
+
You can also chain multiple assertions of the the same type with the `and` method:
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
expect(email).to have_been_sent
|
172
|
+
.with_text('Welcome, user@email.com').and('Thanks for signing up')
|
173
|
+
```
|
174
|
+
|
175
|
+
### Asserting emails are NOT sent
|
176
|
+
|
177
|
+
The `have_sent_email` assertion works with the negative case as well:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
expect(email).to_not have_been_sent.with_text('Secret token')
|
181
|
+
```
|
182
|
+
|
183
|
+
## Failure Reporting
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
### Rendering a response context when a test fails
|
188
|
+
|
189
|
+
Test Assistant can automatically render the server response in your browser when a test fails and you have applied a nominated tag.
|
93
190
|
|
94
191
|
```ruby
|
95
192
|
TestAssistant.configure(config) do |ta_config|
|
96
|
-
ta_config.
|
193
|
+
ta_config.render_failed_responses tag: :focus, type: :request
|
97
194
|
end
|
98
195
|
```
|
99
196
|
|
100
197
|
```ruby
|
101
198
|
RSpec.describe 'making some valid request', type: :request do
|
102
199
|
context 'some important context' do
|
103
|
-
it 'should return
|
104
|
-
|
105
|
-
perform_request
|
106
|
-
|
107
|
-
expect(json_response).to eql_json([
|
108
|
-
{
|
109
|
-
"a" => [
|
110
|
-
1, 2, 3
|
111
|
-
],
|
112
|
-
"c" => { "d" => "d'"}
|
113
|
-
},
|
114
|
-
{
|
115
|
-
"b" => [
|
116
|
-
1, 2, 3
|
117
|
-
],
|
118
|
-
"c" => { "d" => "d'"}
|
119
|
-
}
|
120
|
-
])
|
200
|
+
it 'should return a correct result', focus: true do
|
201
|
+
# failing assertions
|
121
202
|
end
|
122
203
|
end
|
123
204
|
end
|
124
205
|
```
|
125
206
|
|
126
|
-
|
207
|
+
### Invoking a debugger when a test fails
|
127
208
|
|
209
|
+
It's possible to invoke a debugger (`pry` is default, but fallback is to `byebug` and then `debugger`) if a test fails. This gives you access to some of the scope that the failing test ran in, allowing you to inspect objects and test variations of the failing assertion.
|
210
|
+
|
211
|
+
The `debug_failed_responses` accepts a the following options:
|
212
|
+
|
213
|
+
* `tag: :<tag_name>` (default is `:debugger`)
|
214
|
+
* `type: :<spec_type>` (default: nil - matches all test types) options.
|
128
215
|
|
129
216
|
```ruby
|
130
217
|
TestAssistant.configure(config) do |ta_config|
|
131
|
-
|
132
|
-
|
218
|
+
ta_config.include_json_helpers type: :request
|
219
|
+
|
220
|
+
ta_config.debug_failed_responses tag: :debugger
|
221
|
+
end
|
133
222
|
```
|
134
223
|
|
135
224
|
```ruby
|
136
225
|
RSpec.describe 'making some valid request', type: :request do
|
137
226
|
context 'some important context' do
|
138
|
-
it 'should
|
139
|
-
|
140
|
-
.to('user@email.com')
|
141
|
-
.from('admin@site.com')
|
142
|
-
.with_subject('Welcome!')
|
143
|
-
.with_text('Welcome, user@email.com').and('Thanks for signing up')
|
144
|
-
.with_selector('#password').and('#username')
|
145
|
-
.with_link('www.site.com/onboarding/1')
|
146
|
-
.with_image('www.site.com/assets/images/welcome.png')
|
147
|
-
|
148
|
-
clear_emails
|
149
|
-
|
150
|
-
# further actions
|
151
|
-
|
152
|
-
expect(email).to have_been_sent.to('user@email.com')
|
227
|
+
it 'should return a correct result', debugger: true do
|
228
|
+
# failing assertions
|
153
229
|
end
|
154
230
|
end
|
155
231
|
end
|
156
232
|
```
|
157
233
|
|
234
|
+
## Test suite
|
235
|
+
|
236
|
+
TestAssistant comes with close to complete test coverage. You can run the test suite as follows:
|
237
|
+
|
238
|
+
```bash
|
239
|
+
rspec
|
240
|
+
```
|
241
|
+
|
158
242
|
## Contributing
|
159
243
|
|
160
244
|
1. Fork it ( https://github.com/greena13/test_assistant/fork )
|
@@ -14,6 +14,11 @@ module TestAssistant
|
|
14
14
|
|
15
15
|
def include_email_helpers(options = {})
|
16
16
|
@rspec_config.include Email::Helpers, options
|
17
|
+
|
18
|
+
@rspec_config.after :each, type: :request do
|
19
|
+
# clear emails after every request spec
|
20
|
+
ActionMailer::Base.deliveries = []
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
24
|
def render_failed_responses(options = {})
|
@@ -2,6 +2,7 @@ require 'capybara/rspec'
|
|
2
2
|
|
3
3
|
module TestAssistant::Email
|
4
4
|
class Expectation
|
5
|
+
|
5
6
|
def initialize
|
6
7
|
@expectations = {}
|
7
8
|
@failure_message = 'Expected email to be sent'
|
@@ -16,7 +17,7 @@ module TestAssistant::Email
|
|
16
17
|
match: ->(_, email, value){ value.all?{|text| email.has_content?(text) }},
|
17
18
|
actual: ->(_, email){ email.text}
|
18
19
|
},
|
19
|
-
|
20
|
+
matching_selector: {
|
20
21
|
match: ->(_, email, value){ value.all?{|text| email.has_selector?(text) }},
|
21
22
|
actual: ->(_, email){ email.native },
|
22
23
|
actual_name: :with_body
|
@@ -55,11 +56,10 @@ module TestAssistant::Email
|
|
55
56
|
end
|
56
57
|
|
57
58
|
def from(email_address)
|
58
|
-
if
|
59
|
-
|
59
|
+
if @expectations[:from]
|
60
|
+
raise ArgumentError('An email can only have one from address, but you tried to assert the presence of 2 or more values')
|
60
61
|
else
|
61
|
-
@expectations[:from]
|
62
|
-
@expectations[:from] << email_address
|
62
|
+
@expectations[:from] = email_address
|
63
63
|
end
|
64
64
|
|
65
65
|
@and_scope = :from
|
@@ -74,6 +74,8 @@ module TestAssistant::Email
|
|
74
74
|
@expectations[:with_subject] = subject
|
75
75
|
end
|
76
76
|
|
77
|
+
@and_scope = :with_subject
|
78
|
+
|
77
79
|
self
|
78
80
|
end
|
79
81
|
|
@@ -85,11 +87,11 @@ module TestAssistant::Email
|
|
85
87
|
self
|
86
88
|
end
|
87
89
|
|
88
|
-
def
|
89
|
-
@expectations[:
|
90
|
-
@expectations[:
|
90
|
+
def matching_selector(selector)
|
91
|
+
@expectations[:matching_selector] ||= []
|
92
|
+
@expectations[:matching_selector].push(selector)
|
91
93
|
|
92
|
-
@and_scope = :
|
94
|
+
@and_scope = :matching_selector
|
93
95
|
self
|
94
96
|
end
|
95
97
|
|
@@ -118,70 +120,169 @@ module TestAssistant::Email
|
|
118
120
|
|
119
121
|
matching_emails = @emails
|
120
122
|
|
121
|
-
@expectations.
|
122
|
-
|
123
|
-
matching_emails =
|
124
|
-
matching_emails.select do |email|
|
125
|
-
email_matches?(email, MATCHERS[attribute], expected)
|
126
|
-
end
|
127
|
-
|
128
|
-
if matching_emails.empty?
|
123
|
+
if @expectations.any?
|
124
|
+
@expectations.each do |attribute, expected|
|
129
125
|
@failed_attribute = attribute
|
130
126
|
@failed_expected = expected
|
131
|
-
|
127
|
+
|
128
|
+
matching_emails =
|
129
|
+
matching_emails.select do |email|
|
130
|
+
email_matches?(email, MATCHERS[attribute], expected)
|
131
|
+
end
|
132
|
+
|
133
|
+
if matching_emails.empty?
|
134
|
+
return false
|
135
|
+
end
|
132
136
|
end
|
133
|
-
end
|
134
137
|
|
135
|
-
|
138
|
+
true
|
139
|
+
else
|
140
|
+
@emails.any?
|
141
|
+
end
|
136
142
|
end
|
137
143
|
|
138
144
|
def failure_message
|
139
|
-
|
140
|
-
|
141
|
-
case @failed_expected
|
142
|
-
when String
|
143
|
-
"'#{@failed_expected}'"
|
144
|
-
when Array
|
145
|
-
@failed_expected.map{|val| "'#{val}'"}.to_sentence
|
146
|
-
else
|
147
|
-
@failed_expected
|
148
|
-
end
|
145
|
+
field_descs = attribute_descriptions
|
146
|
+
value_descs = value_descriptions
|
149
147
|
|
150
|
-
base_clause =
|
148
|
+
base_clause = expectation_description(
|
149
|
+
'Expected an email to be sent',
|
150
|
+
field_descs,
|
151
|
+
value_descs
|
152
|
+
)
|
151
153
|
|
152
154
|
if @emails.length == 0
|
153
|
-
base_clause
|
155
|
+
"#{base_clause} However, no emails were sent."
|
154
156
|
else
|
155
|
-
|
157
|
+
email_values = sent_email_values
|
158
|
+
|
159
|
+
if email_values.any?
|
160
|
+
base_clause + " However, #{email_pluralisation(@emails)} sent #{result_description(field_descs, [to_sentence(email_values)])}."
|
161
|
+
else
|
162
|
+
base_clause
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def result_description(field_descriptions, values)
|
168
|
+
to_sentence(
|
169
|
+
field_descriptions.map.with_index do |field_description, index|
|
170
|
+
value = values[index]
|
171
|
+
|
172
|
+
if [ 'matching selector', 'with link', 'with image' ].include?(field_description)
|
173
|
+
"with body #{value}"
|
174
|
+
else
|
175
|
+
"#{field_description} #{value}"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
)
|
179
|
+
end
|
180
|
+
|
181
|
+
def failure_message_when_negated
|
182
|
+
field_descs = attribute_descriptions(negated: true)
|
183
|
+
value_descs = value_descriptions(negated: true)
|
184
|
+
|
185
|
+
expectation_description(
|
186
|
+
'Expected no emails to be sent',
|
187
|
+
field_descs,
|
188
|
+
value_descs
|
189
|
+
)
|
190
|
+
end
|
191
|
+
|
192
|
+
private
|
193
|
+
|
194
|
+
def sent_email_values
|
195
|
+
@emails.inject([]) do |memo, email|
|
156
196
|
|
157
|
-
|
197
|
+
if [ :matching_selector, :with_link, :with_image ].include?(@failed_attribute)
|
198
|
+
memo << email_body(email)
|
199
|
+
else
|
158
200
|
matcher = MATCHERS[@failed_attribute]
|
159
201
|
|
160
202
|
value =
|
161
203
|
case matcher
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
204
|
+
when String, Symbol
|
205
|
+
email.send(matcher)
|
206
|
+
when Hash
|
207
|
+
field_description = matcher[:actual_name] if matcher[:actual_name]
|
208
|
+
matcher[:actual].(email, parsed_emails(email))
|
167
209
|
end
|
168
210
|
|
169
211
|
value = value.kind_of?(String) ? "'#{value}'" : value
|
170
212
|
memo << value
|
213
|
+
end
|
214
|
+
|
215
|
+
memo
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def expectation_description(base_clause, field_descriptions, value_descriptions)
|
220
|
+
description = base_clause
|
171
221
|
|
172
|
-
|
222
|
+
additional_clauses = []
|
223
|
+
|
224
|
+
field_descriptions.each.with_index do |field_description, index|
|
225
|
+
clause = ''
|
226
|
+
clause += " #{field_description}" if field_description.length > 0
|
227
|
+
|
228
|
+
if (value_description = value_descriptions[index])
|
229
|
+
clause += " #{value_description}"
|
173
230
|
end
|
174
231
|
|
232
|
+
additional_clauses.push(clause) if clause.length > 0
|
233
|
+
end
|
175
234
|
|
176
|
-
|
177
|
-
|
235
|
+
description + additional_clauses.join('') + '.'
|
236
|
+
end
|
237
|
+
|
238
|
+
def attribute_descriptions(negated: false)
|
239
|
+
attributes_to_describe =
|
240
|
+
if negated
|
241
|
+
@expectations.keys
|
242
|
+
else
|
243
|
+
[ @failed_attribute ]
|
244
|
+
end
|
245
|
+
|
246
|
+
attributes_to_describe.map do |attribute|
|
247
|
+
attribute.to_s.gsub('_', ' ')
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def value_descriptions(negated: false)
|
252
|
+
values_to_describe =
|
253
|
+
if negated
|
254
|
+
@expectations.values
|
255
|
+
else
|
256
|
+
[ @failed_expected ]
|
257
|
+
end
|
258
|
+
|
259
|
+
values_to_describe.map do |value|
|
260
|
+
case value
|
261
|
+
when String
|
262
|
+
"'#{value}'"
|
263
|
+
when Array
|
264
|
+
to_sentence(value.map{|val| "'#{val}'"})
|
178
265
|
else
|
179
|
-
|
266
|
+
value
|
180
267
|
end
|
181
268
|
end
|
269
|
+
|
182
270
|
end
|
183
271
|
|
184
|
-
|
272
|
+
def email_pluralisation(emails)
|
273
|
+
emails.length > 2 ? "#{emails.length} were": "1 was"
|
274
|
+
end
|
275
|
+
|
276
|
+
def to_sentence(items)
|
277
|
+
case items.length
|
278
|
+
when 0, 1
|
279
|
+
items.join('')
|
280
|
+
when 2
|
281
|
+
items.join(' and ')
|
282
|
+
else
|
283
|
+
items[0..(items.length-3)].join(', ') + items[(items.length-3)..items.length-1].join(' and ')
|
284
|
+
end
|
285
|
+
end
|
185
286
|
|
186
287
|
def parsed_emails(email)
|
187
288
|
@parsed_emails ||= {}
|
@@ -190,13 +291,19 @@ module TestAssistant::Email
|
|
190
291
|
end
|
191
292
|
|
192
293
|
def parser(email)
|
193
|
-
Capybara::Node::Simple.new(email
|
294
|
+
Capybara::Node::Simple.new(email_body(email))
|
295
|
+
end
|
296
|
+
|
297
|
+
def email_body(email)
|
298
|
+
email.parts.first.body.decoded
|
194
299
|
end
|
195
300
|
|
196
301
|
def email_matches?(email, assertion, expected)
|
197
302
|
case assertion
|
303
|
+
when :to
|
304
|
+
expected.include?(email.send(assertion))
|
198
305
|
when String, Symbol
|
199
|
-
email.send(assertion)
|
306
|
+
expected == email.send(assertion)
|
200
307
|
when Hash
|
201
308
|
assertion[:match].(email, parsed_emails(email), expected)
|
202
309
|
else
|
@@ -5,6 +5,8 @@ module TestAssistant::Json
|
|
5
5
|
class Expectation
|
6
6
|
def initialize(expected)
|
7
7
|
@expected = expected
|
8
|
+
@message = ''
|
9
|
+
@reported_differences = {}
|
8
10
|
end
|
9
11
|
|
10
12
|
def diffable?
|
@@ -12,9 +14,6 @@ module TestAssistant::Json
|
|
12
14
|
end
|
13
15
|
|
14
16
|
def matches?(actual)
|
15
|
-
@message = ''
|
16
|
-
@reported_differences = {}
|
17
|
-
|
18
17
|
@actual = actual
|
19
18
|
@expected.eql?(@actual)
|
20
19
|
end
|
@@ -24,36 +23,71 @@ module TestAssistant::Json
|
|
24
23
|
@message += "Actual: #{@actual}\n\n"
|
25
24
|
@message += "Differences\n\n"
|
26
25
|
|
27
|
-
|
26
|
+
add_diff_to_message(@actual, @expected)
|
28
27
|
|
29
|
-
|
30
|
-
|
28
|
+
@message
|
29
|
+
end
|
31
30
|
|
32
|
-
|
33
|
-
when '-'
|
34
|
-
attribute, value = operands
|
31
|
+
private
|
35
32
|
|
36
|
-
|
37
|
-
|
33
|
+
def add_diff_to_message(original_actual, original_expected, parent_prefix = '')
|
34
|
+
differences = HashDiff
|
35
|
+
.diff(original_actual, original_expected)
|
36
|
+
.sort{|diff1, diff2| diff1[1] <=> diff2[1]}
|
38
37
|
|
39
|
-
|
40
|
-
|
38
|
+
grouped_differences =
|
39
|
+
differences.inject({}) do |memo, diff|
|
40
|
+
operator, name, value = diff
|
41
|
+
memo[name] ||= {}
|
42
|
+
memo[name][operator] = value
|
43
|
+
memo
|
44
|
+
end
|
41
45
|
|
42
|
-
|
46
|
+
grouped_differences.each do |name, difference|
|
47
|
+
removed_value = difference['-']
|
48
|
+
added_value = difference['+']
|
49
|
+
swapped_value = difference['~']
|
43
50
|
|
44
|
-
|
51
|
+
full_name = parent_prefix.length > 0 ? "#{parent_prefix}.#{name}" : name
|
45
52
|
|
46
|
-
|
47
|
-
|
53
|
+
if non_empty_hash?(removed_value) && non_empty_hash?(added_value)
|
54
|
+
add_diff_to_message(removed_value, added_value, full_name)
|
55
|
+
|
56
|
+
elsif non_empty_array?(removed_value) && non_empty_array?(added_value)
|
48
57
|
|
49
|
-
|
58
|
+
[removed_value.length, added_value.length].max.times do |i|
|
59
|
+
add_diff_to_message(removed_value[i], added_value[i], full_name)
|
60
|
+
end
|
61
|
+
else
|
62
|
+
if difference.has_key?('~')
|
63
|
+
add_diff_description(full_name,
|
64
|
+
format_diff(
|
65
|
+
full_name,
|
66
|
+
attribute_value(original_expected, name),
|
67
|
+
swapped_value
|
68
|
+
)
|
69
|
+
)
|
70
|
+
else
|
71
|
+
add_diff_description(full_name,
|
72
|
+
format_diff(
|
73
|
+
full_name,
|
74
|
+
added_value || attribute_value(original_expected, name),
|
75
|
+
removed_value || attribute_value(original_actual, name)
|
76
|
+
)
|
77
|
+
)
|
78
|
+
end
|
50
79
|
end
|
80
|
+
|
51
81
|
end
|
82
|
+
end
|
52
83
|
|
53
|
-
|
84
|
+
def non_empty_hash?(target)
|
85
|
+
target.kind_of?(Hash) && target.any?
|
54
86
|
end
|
55
87
|
|
56
|
-
|
88
|
+
def non_empty_array?(target)
|
89
|
+
target.kind_of?(Array) && target.any?
|
90
|
+
end
|
57
91
|
|
58
92
|
def add_diff_description(attribute, difference_description)
|
59
93
|
unless already_reported_difference?(attribute)
|
@@ -79,10 +113,13 @@ module TestAssistant::Json
|
|
79
113
|
|
80
114
|
result = target
|
81
115
|
|
116
|
+
|
82
117
|
keys.each do |key|
|
118
|
+
|
83
119
|
unless key == ''
|
84
120
|
result = result[key]
|
85
121
|
end
|
122
|
+
|
86
123
|
end
|
87
124
|
|
88
125
|
result
|
@@ -0,0 +1,369 @@
|
|
1
|
+
require 'test_assistant/email/helpers'
|
2
|
+
require_relative './support/email_mock'
|
3
|
+
|
4
|
+
RSpec.describe 'have_sent_email' do
|
5
|
+
include TestAssistant::Email::Helpers
|
6
|
+
|
7
|
+
context "when no emails have been sent" do
|
8
|
+
subject { [] }
|
9
|
+
|
10
|
+
it "then the positive assertion fails" do
|
11
|
+
expect {
|
12
|
+
expect(subject).to have_been_sent
|
13
|
+
}.to raise_error.with_message('Expected an email to be sent. However, no emails were sent.')
|
14
|
+
end
|
15
|
+
|
16
|
+
it "then the negative assertion passes" do
|
17
|
+
expect {
|
18
|
+
expect(subject).to_not have_been_sent
|
19
|
+
}.to_not raise_error
|
20
|
+
end
|
21
|
+
|
22
|
+
it "then a non-matching 'to' assertion fails" do
|
23
|
+
expect {
|
24
|
+
expect(subject).to have_been_sent.to('test@email.com')
|
25
|
+
}.to raise_error.with_message('Expected an email to be sent to \'test@email.com\'. However, no emails were sent.')
|
26
|
+
end
|
27
|
+
|
28
|
+
it "then a non-matching 'from' assertion fails" do
|
29
|
+
expect {
|
30
|
+
expect(subject).to have_been_sent.from('test@email.com')
|
31
|
+
}.to raise_error.with_message('Expected an email to be sent from \'test@email.com\'. However, no emails were sent.')
|
32
|
+
end
|
33
|
+
|
34
|
+
it "then a non-matching 'with_subject' assertion fails" do
|
35
|
+
expect {
|
36
|
+
expect(subject).to have_been_sent.with_subject('Subject')
|
37
|
+
}.to raise_error.with_message('Expected an email to be sent with subject \'Subject\'. However, no emails were sent.')
|
38
|
+
end
|
39
|
+
|
40
|
+
it "then a non-matching 'with_text' assertion fails" do
|
41
|
+
expect {
|
42
|
+
expect(subject).to have_been_sent.with_text('Text')
|
43
|
+
}.to raise_error.with_message('Expected an email to be sent with text \'Text\'. However, no emails were sent.')
|
44
|
+
end
|
45
|
+
|
46
|
+
it "then a non-matching 'matching_selector' assertion fails" do
|
47
|
+
expect {
|
48
|
+
expect(subject).to have_been_sent.matching_selector('h1')
|
49
|
+
}.to raise_error.with_message('Expected an email to be sent matching selector \'h1\'. However, no emails were sent.')
|
50
|
+
end
|
51
|
+
|
52
|
+
it "then a non-matching 'with_link' assertion fails" do
|
53
|
+
expect {
|
54
|
+
expect(subject).to have_been_sent.with_link('www.example.com')
|
55
|
+
}.to raise_error.with_message('Expected an email to be sent with link \'www.example.com\'. However, no emails were sent.')
|
56
|
+
end
|
57
|
+
|
58
|
+
it "then a non-matching 'with_image' assertion fails" do
|
59
|
+
expect {
|
60
|
+
expect(subject).to have_been_sent.with_image('www.example.com')
|
61
|
+
}.to raise_error.with_message('Expected an email to be sent with image \'www.example.com\'. However, no emails were sent.')
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
context "when an email has been sent" do
|
67
|
+
subject { [ EmailMock.new ] }
|
68
|
+
|
69
|
+
it "then the unqualified assertion passes" do
|
70
|
+
expect {
|
71
|
+
expect(subject).to have_been_sent
|
72
|
+
}.to_not raise_error
|
73
|
+
end
|
74
|
+
|
75
|
+
it "then the unqualified negative assertion fails" do
|
76
|
+
expect {
|
77
|
+
expect(subject).to_not have_been_sent
|
78
|
+
}.to raise_error("Expected no emails to be sent.")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "when a matching email has been sent" do
|
83
|
+
subject { [ EmailMock.new ] }
|
84
|
+
|
85
|
+
it "then a positive 'to' assertion passes" do
|
86
|
+
expect {
|
87
|
+
expect(subject).to have_been_sent.to(subject[0].to)
|
88
|
+
}.to_not raise_error
|
89
|
+
end
|
90
|
+
|
91
|
+
it "then a negative 'to' assertion fails" do
|
92
|
+
expect {
|
93
|
+
expect(subject).to_not have_been_sent.to(subject[0].to)
|
94
|
+
}.to raise_error.with_message("Expected no emails to be sent to '#{subject[0].to}'.")
|
95
|
+
end
|
96
|
+
|
97
|
+
it "then a positive 'from' assertion passes" do
|
98
|
+
expect {
|
99
|
+
expect(subject).to have_been_sent.from(subject[0].from)
|
100
|
+
}.to_not raise_error
|
101
|
+
end
|
102
|
+
|
103
|
+
it "then a negative 'from' assertion fails" do
|
104
|
+
expect {
|
105
|
+
expect(subject).to_not have_been_sent.from(subject[0].from)
|
106
|
+
}.to raise_error.with_message("Expected no emails to be sent from '#{subject[0].from}'.")
|
107
|
+
end
|
108
|
+
|
109
|
+
it "then a positive 'with_subject' assertion passes" do
|
110
|
+
expect {
|
111
|
+
expect(subject).to have_been_sent.with_subject(subject[0].subject)
|
112
|
+
}.to_not raise_error
|
113
|
+
end
|
114
|
+
|
115
|
+
it "then a negative 'with_subject' assertion fails" do
|
116
|
+
expect {
|
117
|
+
expect(subject).to_not have_been_sent.with_subject(subject[0].subject)
|
118
|
+
}.to raise_error.with_message("Expected no emails to be sent with subject '#{subject[0].subject}'.")
|
119
|
+
end
|
120
|
+
|
121
|
+
it "then a positive 'with_text' assertion passes" do
|
122
|
+
expect {
|
123
|
+
expect(subject).to have_been_sent.with_text(subject[0].text)
|
124
|
+
}.to_not raise_error
|
125
|
+
end
|
126
|
+
|
127
|
+
it "then a negative 'with_text' assertion fails" do
|
128
|
+
expect {
|
129
|
+
expect(subject).to_not have_been_sent.with_text(subject[0].text)
|
130
|
+
}.to raise_error.with_message("Expected no emails to be sent with text '#{subject[0].text}'.")
|
131
|
+
end
|
132
|
+
|
133
|
+
it "then a positive 'matching_selector' assertion passes" do
|
134
|
+
expect {
|
135
|
+
expect(subject).to have_been_sent.matching_selector('h1')
|
136
|
+
}.to_not raise_error
|
137
|
+
end
|
138
|
+
|
139
|
+
it "then a negative 'matching_selector' assertion fails" do
|
140
|
+
expect {
|
141
|
+
expect(subject).to_not have_been_sent.matching_selector('h1')
|
142
|
+
}.to raise_error.with_message("Expected no emails to be sent matching selector 'h1'.")
|
143
|
+
end
|
144
|
+
|
145
|
+
it "then a positive 'with_link' assertion passes" do
|
146
|
+
expect {
|
147
|
+
expect(subject).to have_been_sent.with_link('www.test.com')
|
148
|
+
}.to_not raise_error
|
149
|
+
end
|
150
|
+
|
151
|
+
it "then a negative 'with_link' assertion fails" do
|
152
|
+
expect {
|
153
|
+
expect(subject).to_not have_been_sent.with_link('www.test.com')
|
154
|
+
}.to raise_error.with_message("Expected no emails to be sent with link 'www.test.com'.")
|
155
|
+
end
|
156
|
+
|
157
|
+
it "then a positive 'with_image' assertion passes" do
|
158
|
+
expect {
|
159
|
+
expect(subject).to have_been_sent.with_image('www.test.com')
|
160
|
+
}.to_not raise_error
|
161
|
+
end
|
162
|
+
|
163
|
+
it "then a negative 'with_image' assertion fails" do
|
164
|
+
expect {
|
165
|
+
expect(subject).to_not have_been_sent.with_image('www.test.com')
|
166
|
+
}.to raise_error.with_message("Expected no emails to be sent with image 'www.test.com'.")
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context "when a non-matching email has been sent" do
|
171
|
+
subject { [ EmailMock.new ] }
|
172
|
+
|
173
|
+
it "then a positive 'to' assertion fails" do
|
174
|
+
expect {
|
175
|
+
expect(subject).to have_been_sent.to('other@email.com')
|
176
|
+
}.to raise_error.with_message("Expected an email to be sent to 'other@email.com'. However, 1 was sent to '#{subject[0].to}'.")
|
177
|
+
end
|
178
|
+
|
179
|
+
it "then a negative 'to' assertion passes" do
|
180
|
+
expect {
|
181
|
+
expect(subject).to_not have_been_sent.to('other@email.com')
|
182
|
+
}.to_not raise_error
|
183
|
+
end
|
184
|
+
|
185
|
+
it "then a positive 'from' assertion fails" do
|
186
|
+
expect {
|
187
|
+
expect(subject).to have_been_sent.from('other@email.com')
|
188
|
+
}.to raise_error.with_message("Expected an email to be sent from 'other@email.com'. However, 1 was sent from '#{subject[0].from}'.")
|
189
|
+
end
|
190
|
+
|
191
|
+
it "then a negative 'from' assertion passes" do
|
192
|
+
expect {
|
193
|
+
expect(subject).to_not have_been_sent.from('other@email.com')
|
194
|
+
}.to_not raise_error
|
195
|
+
end
|
196
|
+
|
197
|
+
it "then a positive 'with_subject' assertion fails" do
|
198
|
+
expect {
|
199
|
+
expect(subject).to have_been_sent.with_subject('Other Subject')
|
200
|
+
}.to raise_error.with_message("Expected an email to be sent with subject 'Other Subject'. However, 1 was sent with subject '#{subject[0].subject}'.")
|
201
|
+
end
|
202
|
+
|
203
|
+
it "then a negative 'with_subject' assertion passes" do
|
204
|
+
expect {
|
205
|
+
expect(subject).to_not have_been_sent.with_subject('Other Subject')
|
206
|
+
}.to_not raise_error
|
207
|
+
end
|
208
|
+
|
209
|
+
it "then a positive 'with_text' assertion fails" do
|
210
|
+
expect {
|
211
|
+
expect(subject).to have_been_sent.with_text('Other text')
|
212
|
+
}.to raise_error.with_message("Expected an email to be sent with text 'Other text'. However, 1 was sent with text '#{subject[0].text}'.")
|
213
|
+
end
|
214
|
+
|
215
|
+
it "then a negative 'with_text' assertion passes" do
|
216
|
+
expect {
|
217
|
+
expect(subject).to_not have_been_sent.with_text('Other text')
|
218
|
+
}.to_not raise_error
|
219
|
+
end
|
220
|
+
|
221
|
+
it "then a positive 'matching_selector' assertion fails" do
|
222
|
+
expect {
|
223
|
+
expect(subject).to have_been_sent.matching_selector('.other')
|
224
|
+
}.to raise_error.with_message("Expected an email to be sent matching selector '.other'. However, 1 was sent with body #{subject[0].body}.")
|
225
|
+
end
|
226
|
+
|
227
|
+
it "then a negative 'matching_selector' assertion passes" do
|
228
|
+
expect {
|
229
|
+
expect(subject).to_not have_been_sent.matching_selector('.other')
|
230
|
+
}.to_not raise_error
|
231
|
+
end
|
232
|
+
|
233
|
+
it "then a positive 'with_link' assertion fails"do
|
234
|
+
expect {
|
235
|
+
expect(subject).to have_been_sent.with_link('www.other.com')
|
236
|
+
}.to raise_error.with_message("Expected an email to be sent with link 'www.other.com'. However, 1 was sent with body #{subject[0].body}.")
|
237
|
+
end
|
238
|
+
|
239
|
+
it "then a negative 'with_link' assertion passes" do
|
240
|
+
expect {
|
241
|
+
expect(subject).to_not have_been_sent.with_link('www.other.com')
|
242
|
+
}.to_not raise_error
|
243
|
+
end
|
244
|
+
|
245
|
+
it "then a positive 'with_image' assertion fails" do
|
246
|
+
expect {
|
247
|
+
expect(subject).to have_been_sent.with_image('www.other.com')
|
248
|
+
}.to raise_error.with_message("Expected an email to be sent with image 'www.other.com'. However, 1 was sent with body #{subject[0].body}.")
|
249
|
+
end
|
250
|
+
|
251
|
+
it "then a negative 'with_image' assertion passes" do
|
252
|
+
expect {
|
253
|
+
expect(subject).to_not have_been_sent.with_image('www.other.com')
|
254
|
+
}.to_not raise_error
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
context "when multiple emails have been sent" do
|
259
|
+
subject { [ EmailMock.new, EmailMock.new(to: 'other@email.com') ] }
|
260
|
+
|
261
|
+
it "then a positive assertion matching the first email passes" do
|
262
|
+
expect {
|
263
|
+
expect(subject).to have_been_sent.to(subject[0].to)
|
264
|
+
}.to_not raise_error
|
265
|
+
end
|
266
|
+
|
267
|
+
it "then a negative assertion matching the first email fails" do
|
268
|
+
expect {
|
269
|
+
expect(subject).to_not have_been_sent.to(subject[0].to)
|
270
|
+
}.to raise_error.with_message("Expected no emails to be sent to '#{subject[0].to}'.")
|
271
|
+
end
|
272
|
+
|
273
|
+
it "then a positive assertion matching the second email passes" do
|
274
|
+
expect {
|
275
|
+
expect(subject).to have_been_sent.to(subject[1].to)
|
276
|
+
}.to_not raise_error
|
277
|
+
end
|
278
|
+
|
279
|
+
it "then a negative assertion matching the second email fails" do
|
280
|
+
expect {
|
281
|
+
expect(subject).to_not have_been_sent.to(subject[1].to)
|
282
|
+
}.to raise_error.with_message("Expected no emails to be sent to '#{subject[1].to}'.")
|
283
|
+
end
|
284
|
+
|
285
|
+
end
|
286
|
+
|
287
|
+
context "when using multiple qualifiers" do
|
288
|
+
subject { [ EmailMock.new ] }
|
289
|
+
|
290
|
+
it "then a positive assertions correctly matches a matching email" do
|
291
|
+
expect {
|
292
|
+
expect(subject).to have_been_sent.to(subject[0].to).from(subject[0].from)
|
293
|
+
}.to_not raise_error
|
294
|
+
end
|
295
|
+
|
296
|
+
it "then a positive assertions don't match an email if the first qualifier isn't satisfied" do
|
297
|
+
expect {
|
298
|
+
expect(subject).to have_been_sent.to('other@email.com').from(subject[0].from)
|
299
|
+
}.to raise_error.with_message("Expected an email to be sent to 'other@email.com'. However, 1 was sent to '#{subject[0].to}'.")
|
300
|
+
end
|
301
|
+
|
302
|
+
it "then a positive assertions don't match an email if the last qualifier isn't satisfied" do
|
303
|
+
expect {
|
304
|
+
expect(subject).to have_been_sent.to(subject[0].to).from('other@email.com')
|
305
|
+
}.to raise_error.with_message("Expected an email to be sent from 'other@email.com'. However, 1 was sent from '#{subject[0].from}'.")
|
306
|
+
end
|
307
|
+
|
308
|
+
it "then a negative assertions correctly matches a matching email" do
|
309
|
+
expect {
|
310
|
+
expect(subject).to_not have_been_sent.to(subject[0].to).from(subject[0].from)
|
311
|
+
}.to raise_error.with_message("Expected no emails to be sent to '#{subject[0].to}' from '#{subject[0].from}'.")
|
312
|
+
end
|
313
|
+
|
314
|
+
it "then a negative assertions don't match an email if the first qualifier isn't satisfied" do
|
315
|
+
expect {
|
316
|
+
expect(subject).to_not have_been_sent.to('other@email.com').from(subject[0].from)
|
317
|
+
}.to_not raise_error
|
318
|
+
end
|
319
|
+
|
320
|
+
it "then a negative assertions don't match an email if the last qualifier isn't satisfied" do
|
321
|
+
expect {
|
322
|
+
expect(subject).to_not have_been_sent.to(subject[0].to).from('other@email.com')
|
323
|
+
}.to_not raise_error
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
context "when using the and method" do
|
328
|
+
subject { [ EmailMock.new ] }
|
329
|
+
|
330
|
+
it "then a positive assertion will fail if the first qualifier is not satisfied" do
|
331
|
+
expect {
|
332
|
+
expect(subject).to have_been_sent.with_text('Other').and('Email')
|
333
|
+
}.to raise_error.with_message("Expected an email to be sent with text 'Other' and 'Email'. However, 1 was sent with text '#{subject[0].text}'.")
|
334
|
+
end
|
335
|
+
|
336
|
+
it "then a positive assertion will fail if the second qualifier is not satisfied" do
|
337
|
+
expect {
|
338
|
+
expect(subject).to have_been_sent.with_text('Test').and('Other')
|
339
|
+
}.to raise_error.with_message("Expected an email to be sent with text 'Test' and 'Other'. However, 1 was sent with text '#{subject[0].text}'.")
|
340
|
+
end
|
341
|
+
|
342
|
+
it "then a positive assertion will pass if both qualifiers are satisfied" do
|
343
|
+
expect {
|
344
|
+
expect(subject).to have_been_sent.with_text('Test').and('Email')
|
345
|
+
}.to_not raise_error
|
346
|
+
end
|
347
|
+
|
348
|
+
it "then a negative assertion will pass if the first qualifier is not satisfied" do
|
349
|
+
expect {
|
350
|
+
expect(subject).to_not have_been_sent.with_text('Other').and('Email')
|
351
|
+
}.to_not raise_error
|
352
|
+
end
|
353
|
+
|
354
|
+
it "then a negative assertion will pass if the second qualifier is not satisfied" do
|
355
|
+
expect {
|
356
|
+
expect(subject).to_not have_been_sent.with_text('Test').and('Other')
|
357
|
+
}.to_not raise_error
|
358
|
+
end
|
359
|
+
|
360
|
+
it "then a negative assertion will fail if both qualifiers are satisfied" do
|
361
|
+
expect {
|
362
|
+
expect(subject).to_not have_been_sent.with_text('Test').and('Email')
|
363
|
+
}.to raise_error.with_message('Expected no emails to be sent with text \'Test\' and \'Email\'.')
|
364
|
+
end
|
365
|
+
|
366
|
+
end
|
367
|
+
|
368
|
+
|
369
|
+
end
|
data/spec/eql_json_spec.rb
CHANGED
@@ -104,6 +104,64 @@ RSpec.describe "eql_json" do
|
|
104
104
|
|
105
105
|
end
|
106
106
|
|
107
|
+
context "when comparing arrays of objects" do
|
108
|
+
let(:expected) {
|
109
|
+
{
|
110
|
+
'alpha' => 'alpha',
|
111
|
+
'beta' => [ 1, 2, 3],
|
112
|
+
'gamma' => [
|
113
|
+
{ 'i' => 'a', 'j' => 'b' },
|
114
|
+
{ 'i' => 'c', 'j' => 'd' },
|
115
|
+
{ 'i' => 'e', 'j' => 'f' },
|
116
|
+
]
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
let(:actual) {
|
121
|
+
{
|
122
|
+
'alpha' => 'alpha',
|
123
|
+
'beta' => [ 1, 2, 3],
|
124
|
+
'gamma' => [
|
125
|
+
{ 'j' => 'b' },
|
126
|
+
{ 'i' => 'c', 'j' => 'D' },
|
127
|
+
{ 'i' => 'e', 'j' => 'f', 'k' => 'k' },
|
128
|
+
]
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
it "then correctly reports the elements that have changed" do
|
133
|
+
|
134
|
+
expect(actual).to eql(actual)
|
135
|
+
|
136
|
+
expect(actual).to_not eql(expected)
|
137
|
+
|
138
|
+
begin
|
139
|
+
expect(actual).to eql_json(expected)
|
140
|
+
rescue RSpec::Expectations::ExpectationNotMetError => e
|
141
|
+
|
142
|
+
expect(e.message).to eql(error_message(expected, actual, {
|
143
|
+
|
144
|
+
'gamma[0].i' => {
|
145
|
+
expected: "'a'",
|
146
|
+
actual: ''
|
147
|
+
},
|
148
|
+
'gamma[1].j' => {
|
149
|
+
expected: "'d'",
|
150
|
+
actual: "'D'"
|
151
|
+
},
|
152
|
+
'gamma[2].k' => {
|
153
|
+
expected: '',
|
154
|
+
actual: "'k'"
|
155
|
+
}
|
156
|
+
|
157
|
+
}))
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
107
165
|
context "when comparing objects" do
|
108
166
|
let(:expected) { {
|
109
167
|
'a' => 'a',
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class EmailMock
|
2
|
+
attr_reader :to, :from, :subject, :text, :body
|
3
|
+
|
4
|
+
def initialize(to: 'receiver@email.com', from: 'sender@email.com', subject: 'Subject', text: 'Test Email', body: "<body><h1>Test Email</h1><a href='www.test.com' /><img src='www.test.com' /></body>")
|
5
|
+
@to, @from, @subject, @text, @body = to, from, subject, text, body
|
6
|
+
end
|
7
|
+
|
8
|
+
def parts
|
9
|
+
[
|
10
|
+
EmailBodyMock.new(@body)
|
11
|
+
]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class EmailBodyMock
|
16
|
+
def initialize(text)
|
17
|
+
@text = text
|
18
|
+
end
|
19
|
+
|
20
|
+
def body
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def decoded
|
25
|
+
@text
|
26
|
+
end
|
27
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: test_assistant
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aleck Greenham
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-07-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|
@@ -137,8 +137,10 @@ files:
|
|
137
137
|
- lib/test_assistant/json/expectation.rb
|
138
138
|
- lib/test_assistant/json/helpers.rb
|
139
139
|
- lib/test_assistant/version.rb
|
140
|
+
- spec/email_expectation_spec.rb
|
140
141
|
- spec/eql_json_spec.rb
|
141
142
|
- spec/spec_helper.rb
|
143
|
+
- spec/support/email_mock.rb
|
142
144
|
- test_assistant.gemspec
|
143
145
|
homepage: https://github.com/greena13/test_assistant
|
144
146
|
licenses:
|
@@ -160,10 +162,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
162
|
version: '0'
|
161
163
|
requirements: []
|
162
164
|
rubyforge_project:
|
163
|
-
rubygems_version: 2.
|
165
|
+
rubygems_version: 2.5.1
|
164
166
|
signing_key:
|
165
167
|
specification_version: 4
|
166
168
|
summary: A toolbox for increased testing efficiency with RSpec
|
167
169
|
test_files:
|
170
|
+
- spec/email_expectation_spec.rb
|
168
171
|
- spec/eql_json_spec.rb
|
169
172
|
- spec/spec_helper.rb
|
173
|
+
- spec/support/email_mock.rb
|