lighthouse 9.5.0-dev.20220808 → 9.5.0-dev.20220809
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.
|
@@ -64,9 +64,11 @@ Individual elements of an array can be asserted by using numeric properties in a
|
|
|
64
64
|
|
|
65
65
|
However, if an array literal is used as the expectation, an extra condition is enforced that the actual array _must_ have the same length as the provided expected array.
|
|
66
66
|
|
|
67
|
-
Arrays can be checked against a subset of elements using the special `_includes` property. The value of `_includes` _must_ be an array. Each assertion in `_includes` will remove the matching item from consideration for the rest.
|
|
67
|
+
Arrays and objects can be checked against a subset of elements using the special `_includes` property. The value of `_includes` _must_ be an array. Each assertion in `_includes` will remove the matching item from consideration for the rest.
|
|
68
68
|
|
|
69
|
-
Arrays can be asserted to not match any elements using the special `_excludes` property. The value of `_excludes` _must_ be an array. If an `_includes` check is defined before an `_excludes` check, only the element not matched under the previous will be considered.
|
|
69
|
+
Arrays and objects can be asserted to not match any elements using the special `_excludes` property. The value of `_excludes` _must_ be an array. If an `_includes` check is defined before an `_excludes` check, only the element not matched under the previous will be considered.
|
|
70
|
+
|
|
71
|
+
If an object is checked using `_includes` or `_excludes`, it will be checked against the `Object.entries` array.
|
|
70
72
|
|
|
71
73
|
**Examples**:
|
|
72
74
|
| Actual | Expected | Result |
|
|
@@ -79,6 +81,8 @@ Arrays can be asserted to not match any elements using the special `_excludes` p
|
|
|
79
81
|
| `[{timeInMs: 5}, {timeInMs: 15}]` | `{_includes: [{timeInMs: 5}], _excludes: [{timeInMs: 15}]}` | ❌ FAIL |
|
|
80
82
|
| `[{timeInMs: 5}, {timeInMs: 15}]` | `{_includes: [{timeInMs: 5}], _excludes: [{}]}` | ❌ FAIL |
|
|
81
83
|
| `[{timeInMs: 5}, {timeInMs: 15}]` | `[{timeInMs: 5}]` | ❌ FAIL |
|
|
84
|
+
| `{'foo': 1}` | `{_includes: [['foo', 1]]}` | ✅ PASS |
|
|
85
|
+
| `{'foo': 1, 'bar': 2}` | `{_includes: [['foo', 1]], _excludes: [['bar', 2]]}` | ❌ FAIL |
|
|
82
86
|
|
|
83
87
|
### Special environment checks
|
|
84
88
|
|
|
@@ -133,6 +133,14 @@ describe('findDiffersences', () => {
|
|
|
133
133
|
expected: {prices: {_includes: [/\d/, /\d/, /\d/, /\d/, /\d/, /\d/]}},
|
|
134
134
|
diffs: null,
|
|
135
135
|
},
|
|
136
|
+
'_includes (object)': {
|
|
137
|
+
actual: {'0-alpha': 1, '1-beta': 2, '3-gamma': 3},
|
|
138
|
+
expected: {_includes: [
|
|
139
|
+
['0-alpha', '<2'],
|
|
140
|
+
[/[0-9]-beta/, 2],
|
|
141
|
+
]},
|
|
142
|
+
diffs: null,
|
|
143
|
+
},
|
|
136
144
|
|
|
137
145
|
'_excludes (1)': {
|
|
138
146
|
actual: {prices: [0, 1, 2, 3, 4, 5]},
|
|
@@ -147,6 +155,16 @@ describe('findDiffersences', () => {
|
|
|
147
155
|
message: 'Expected to not find matching entry via _excludes',
|
|
148
156
|
}}],
|
|
149
157
|
},
|
|
158
|
+
'_excludes (object)': {
|
|
159
|
+
actual: {'0-alpha': 1, '1-beta': 2, '3-gamma': 3},
|
|
160
|
+
expected: {_excludes: [
|
|
161
|
+
[/[0-9]-beta/, 2],
|
|
162
|
+
]},
|
|
163
|
+
diffs: [{path: '', actual: ['1-beta', 2], expected: {
|
|
164
|
+
expectedExclusion: [/[0-9]-beta/, 2],
|
|
165
|
+
message: 'Expected to not find matching entry via _excludes',
|
|
166
|
+
}}],
|
|
167
|
+
},
|
|
150
168
|
|
|
151
169
|
'_includes and _excludes (1)': {
|
|
152
170
|
actual: {prices: [0, 1, 2, 3, 4, 5]},
|
|
@@ -170,6 +188,22 @@ describe('findDiffersences', () => {
|
|
|
170
188
|
message: 'Expected to not find matching entry via _excludes',
|
|
171
189
|
}}],
|
|
172
190
|
},
|
|
191
|
+
'_includes and _excludes (object)': {
|
|
192
|
+
actual: {'0-alpha': 1, '1-beta': 2, '3-gamma': 3},
|
|
193
|
+
expected: {
|
|
194
|
+
_includes: [
|
|
195
|
+
['0-alpha', '<2'],
|
|
196
|
+
],
|
|
197
|
+
_excludes: [
|
|
198
|
+
[/[0-9]-alpha/, 1],
|
|
199
|
+
[/[0-9]-beta/, 2],
|
|
200
|
+
],
|
|
201
|
+
},
|
|
202
|
+
diffs: [{path: '', actual: ['1-beta', 2], expected: {
|
|
203
|
+
expectedExclusion: [/[0-9]-beta/, 2],
|
|
204
|
+
message: 'Expected to not find matching entry via _excludes',
|
|
205
|
+
}}],
|
|
206
|
+
},
|
|
173
207
|
};
|
|
174
208
|
|
|
175
209
|
for (const [testName, {actual, expected, diffs}] of Object.entries(testCases)) {
|
|
@@ -105,6 +105,8 @@ function findDifferences(path, actual, expected) {
|
|
|
105
105
|
|
|
106
106
|
/** @type {Difference[]} */
|
|
107
107
|
const diffs = [];
|
|
108
|
+
|
|
109
|
+
/** @type {any[]|undefined} */
|
|
108
110
|
let inclExclCopy;
|
|
109
111
|
|
|
110
112
|
// We only care that all expected's own properties are on actual (and not the other way around).
|
|
@@ -116,15 +118,20 @@ function findDifferences(path, actual, expected) {
|
|
|
116
118
|
const expectedValue = expected[key];
|
|
117
119
|
|
|
118
120
|
if (key === '_includes') {
|
|
119
|
-
|
|
121
|
+
if (Array.isArray(actual)) {
|
|
122
|
+
inclExclCopy = [...actual];
|
|
123
|
+
} else if (typeof actual === 'object') {
|
|
124
|
+
inclExclCopy = Object.entries(actual);
|
|
125
|
+
}
|
|
120
126
|
|
|
121
127
|
if (!Array.isArray(expectedValue)) throw new Error('Array subset must be array');
|
|
122
|
-
if (!
|
|
128
|
+
if (!inclExclCopy) {
|
|
123
129
|
diffs.push({
|
|
124
130
|
path,
|
|
125
|
-
actual: 'Actual value is not an array',
|
|
131
|
+
actual: 'Actual value is not an array or object',
|
|
126
132
|
expected,
|
|
127
133
|
});
|
|
134
|
+
continue;
|
|
128
135
|
}
|
|
129
136
|
|
|
130
137
|
for (const expectedEntry of expectedValue) {
|
|
@@ -148,20 +155,33 @@ function findDifferences(path, actual, expected) {
|
|
|
148
155
|
|
|
149
156
|
if (key === '_excludes') {
|
|
150
157
|
// Re-use state from `_includes` check, if there was one.
|
|
151
|
-
|
|
152
|
-
|
|
158
|
+
if (!inclExclCopy) {
|
|
159
|
+
if (Array.isArray(actual)) {
|
|
160
|
+
// We won't be removing items, so we can just copy the reference.
|
|
161
|
+
inclExclCopy = actual;
|
|
162
|
+
} else if (typeof actual === 'object') {
|
|
163
|
+
inclExclCopy = Object.entries(actual);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
153
166
|
|
|
154
167
|
if (!Array.isArray(expectedValue)) throw new Error('Array subset must be array');
|
|
155
|
-
if (!
|
|
168
|
+
if (!inclExclCopy) {
|
|
169
|
+
diffs.push({
|
|
170
|
+
path,
|
|
171
|
+
actual: 'Actual value is not an array or object',
|
|
172
|
+
expected,
|
|
173
|
+
});
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
156
176
|
|
|
157
177
|
const expectedExclusions = expectedValue;
|
|
158
178
|
for (const expectedExclusion of expectedExclusions) {
|
|
159
|
-
const matchingIndex =
|
|
179
|
+
const matchingIndex = inclExclCopy.findIndex(actualEntry =>
|
|
160
180
|
!findDifferences(keyPath, actualEntry, expectedExclusion));
|
|
161
181
|
if (matchingIndex !== -1) {
|
|
162
182
|
diffs.push({
|
|
163
183
|
path,
|
|
164
|
-
actual:
|
|
184
|
+
actual: inclExclCopy[matchingIndex],
|
|
165
185
|
expected: {
|
|
166
186
|
message: 'Expected to not find matching entry via _excludes',
|
|
167
187
|
expectedExclusion,
|
package/package.json
CHANGED