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
- inclExclCopy = [...actual];
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 (!Array.isArray(actual)) {
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
- /** @type {any[]} */
152
- const arrToCheckAgainst = inclExclCopy || actual;
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 (!Array.isArray(actual)) continue;
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 = arrToCheckAgainst.findIndex(actualEntry =>
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: arrToCheckAgainst[matchingIndex],
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lighthouse",
3
3
  "type": "module",
4
- "version": "9.5.0-dev.20220808",
4
+ "version": "9.5.0-dev.20220809",
5
5
  "description": "Automated auditing, performance metrics, and best practices for the web.",
6
6
  "main": "./core/index.js",
7
7
  "bin": {