apify-test-tools 0.9.0-beta.1 → 0.9.0

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/bin/actor-filtering.ts +21 -0
  3. package/bin/git.ts +5 -1
  4. package/bin/main.ts +65 -61
  5. package/bin/slack.ts +4 -4
  6. package/bin/types.ts +2 -0
  7. package/bin/utils.ts +3 -2
  8. package/dist/bin/actor-filtering.d.ts +13 -0
  9. package/dist/bin/actor-filtering.d.ts.map +1 -0
  10. package/dist/bin/actor-filtering.js +19 -0
  11. package/dist/bin/actor-filtering.js.map +1 -0
  12. package/dist/bin/git.d.ts +1 -1
  13. package/dist/bin/git.d.ts.map +1 -1
  14. package/dist/bin/git.js +1 -1
  15. package/dist/bin/git.js.map +1 -1
  16. package/dist/bin/main.d.ts +20 -1
  17. package/dist/bin/main.d.ts.map +1 -1
  18. package/dist/bin/main.js +56 -37
  19. package/dist/bin/main.js.map +1 -1
  20. package/dist/bin/slack.js +4 -4
  21. package/dist/bin/slack.js.map +1 -1
  22. package/dist/bin/types.d.ts +2 -0
  23. package/dist/bin/types.d.ts.map +1 -1
  24. package/dist/bin/utils.d.ts +4 -1
  25. package/dist/bin/utils.d.ts.map +1 -1
  26. package/dist/bin/utils.js +3 -2
  27. package/dist/bin/utils.js.map +1 -1
  28. package/dist/lib/consts.d.ts +6 -0
  29. package/dist/lib/consts.d.ts.map +1 -1
  30. package/dist/lib/consts.js +6 -0
  31. package/dist/lib/consts.js.map +1 -1
  32. package/dist/lib/lib.js +3 -3
  33. package/dist/lib/lib.js.map +1 -1
  34. package/dist/test/unit/bin/actor-filtering.test.d.ts +2 -0
  35. package/dist/test/unit/bin/actor-filtering.test.d.ts.map +1 -0
  36. package/dist/test/unit/bin/actor-filtering.test.js +41 -0
  37. package/dist/test/unit/bin/actor-filtering.test.js.map +1 -0
  38. package/dist/test/unit/bin/utils.test.js +52 -24
  39. package/dist/test/unit/bin/utils.test.js.map +1 -1
  40. package/dist/tsconfig.tsbuildinfo +1 -1
  41. package/lib/consts.ts +7 -0
  42. package/lib/lib.ts +3 -3
  43. package/package.json +62 -62
  44. package/test/unit/bin/actor-filtering.test.ts +52 -0
  45. package/test/unit/bin/utils.test.ts +62 -24
package/lib/consts.ts CHANGED
@@ -16,3 +16,10 @@ export const TO_FINISH_WITH_OPTIONS: ToFinishWithOptionsWithDefaults = {
16
16
  * Both the test runs and the vitest test specs should finish in this time - 1 hour
17
17
  */
18
18
  export const DEFAULT_TEST_RUN_DURATION_MS = 60 * 60 * 1000; // 1 hour
19
+
20
+ /**
21
+ * Delay before checking the dataset and statistics after a run finishes to resolve eventual consistency.
22
+ * - This value should ensure that the dataset and statistics are fully updated before any assertions are made.
23
+ * - Super rarely the platform is still not synced even after 10s, so 20s should be sufficient practically always.
24
+ */
25
+ export const DATASET_SYNC_DELAY_MS = 20 * 1000; // 20 seconds
package/lib/lib.ts CHANGED
@@ -3,7 +3,7 @@ import { ApifyClient } from 'apify-client';
3
3
  import type { SuiteFactory, TestContext, TestFunction } from 'vitest';
4
4
  import { describe as vitestDescribe, ExpectStatic, test as vitestTest } from 'vitest';
5
5
 
6
- import { DEFAULT_TEST_RUN_DURATION_MS } from './consts.js';
6
+ import { DATASET_SYNC_DELAY_MS, DEFAULT_TEST_RUN_DURATION_MS } from './consts.js';
7
7
  import { extendExpect } from './extend-expect.js';
8
8
  import { RunTestResult } from './run-test-result.js';
9
9
  import type { ActorBuild, ActorTestOptions, RunOptions } from './types.js';
@@ -286,8 +286,8 @@ const createStartRunFn = <T>(actorId: string, testContext: TestContext) => {
286
286
  actorId: actorConfig?.actorFullName ?? actorId,
287
287
  };
288
288
 
289
- // waiting for datasetItemCount and chargedEventCounts to sync
290
- await sleep(10_000);
289
+ // waiting for dataset and statistics to sync, the Apify platform is only eventually consistent.
290
+ await sleep(DATASET_SYNC_DELAY_MS);
291
291
 
292
292
  return new RunTestResult(apifyClient, run);
293
293
  };
package/package.json CHANGED
@@ -1,64 +1,64 @@
1
1
  {
2
- "name": "apify-test-tools",
3
- "version": "0.9.0-beta.1",
4
- "type": "module",
5
- "description": "TBD",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/apify/apify-test-tools.git"
9
- },
10
- "engines": {
11
- "node": ">=18.0.0"
12
- },
13
- "bin": {
14
- "apify-test-tools": "dist/bin/main.js"
15
- },
16
- "types": "./dist/index.d.ts",
17
- "main": "./dist/lib/lib.js",
18
- "dependencies": {
19
- "@apify/consts": "^2.43.0",
20
- "@slack/web-api": "^7.9.2",
21
- "apify-client": "^2.22.2",
22
- "ignore": "^7.0.5",
23
- "yargs": "^18.0.0"
24
- },
25
- "devDependencies": {
26
- "@apify/eslint-config": "^1.0.0",
27
- "@apify/tsconfig": "^0.1.1",
28
- "@types/node": "^24.0.0",
29
- "@types/yargs": "^17.0.33",
30
- "eslint": "^9.29.0",
31
- "eslint-config-prettier": "^10.1.5",
32
- "globals": "^17.0.0",
33
- "husky": "^9.0.11",
34
- "knip": "^5.65.0",
35
- "lint-staged": "^15.2.2",
36
- "prettier": "^3.5.3",
37
- "tsx": "^4.20.3",
38
- "typescript": "^5.9.3",
39
- "typescript-eslint": "^8.34.1",
40
- "vitest": "^3.2.4"
41
- },
42
- "peerDependencies": {
43
- "vitest": ">=3.2.4"
44
- },
45
- "scripts": {
46
- "start": "npm run dist/bin/main.js",
47
- "start:dev": "GITHUB_WORKSPACE=local-clone tsx bin/main.ts",
48
- "build": "tsc && chmod +x ./dist/bin/main.js",
49
- "lint": "eslint",
50
- "lint:fix": "eslint --fix",
51
- "format": "prettier --write .",
52
- "format:check": "prettier --check .",
53
- "type-check": "tsc --noEmit",
54
- "test": "vitest run",
55
- "check-unused": "npx knip",
56
- "prepare": "husky .husky || true"
57
- },
58
- "lint-staged": {
59
- "*.js": "eslint",
60
- "*.ts": "eslint"
61
- },
62
- "author": "oklinov",
63
- "license": "ISC"
2
+ "name": "apify-test-tools",
3
+ "version": "0.9.0",
4
+ "type": "module",
5
+ "description": "TBD",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/apify/apify-test-tools.git"
9
+ },
10
+ "engines": {
11
+ "node": ">=18.0.0"
12
+ },
13
+ "bin": {
14
+ "apify-test-tools": "dist/bin/main.js"
15
+ },
16
+ "types": "./dist/index.d.ts",
17
+ "main": "./dist/lib/lib.js",
18
+ "dependencies": {
19
+ "@apify/consts": "^2.43.0",
20
+ "@slack/web-api": "^7.9.2",
21
+ "apify-client": "^2.22.2",
22
+ "ignore": "^7.0.5",
23
+ "yargs": "^18.0.0"
24
+ },
25
+ "devDependencies": {
26
+ "@apify/eslint-config": "^1.0.0",
27
+ "@apify/tsconfig": "^0.1.1",
28
+ "@types/node": "^24.0.0",
29
+ "@types/yargs": "^17.0.33",
30
+ "eslint": "^9.29.0",
31
+ "eslint-config-prettier": "^10.1.5",
32
+ "globals": "^17.0.0",
33
+ "husky": "^9.0.11",
34
+ "knip": "^5.65.0",
35
+ "lint-staged": "^15.2.2",
36
+ "prettier": "^3.5.3",
37
+ "tsx": "^4.20.3",
38
+ "typescript": "^5.9.3",
39
+ "typescript-eslint": "^8.34.1",
40
+ "vitest": "^3.2.4"
41
+ },
42
+ "peerDependencies": {
43
+ "vitest": ">=3.2.4"
44
+ },
45
+ "scripts": {
46
+ "start": "npm run dist/bin/main.js",
47
+ "start:dev": "GITHUB_WORKSPACE=local-clone tsx bin/main.ts",
48
+ "build": "tsc && chmod +x ./dist/bin/main.js",
49
+ "lint": "eslint",
50
+ "lint:fix": "eslint --fix",
51
+ "format": "prettier --write .",
52
+ "format:check": "prettier --check .",
53
+ "type-check": "tsc --noEmit",
54
+ "test": "vitest run",
55
+ "check-unused": "npx knip",
56
+ "prepare": "husky .husky || true"
57
+ },
58
+ "lint-staged": {
59
+ "*.js": "eslint",
60
+ "*.ts": "eslint"
61
+ },
62
+ "author": "oklinov",
63
+ "license": "ISC"
64
64
  }
@@ -0,0 +1,52 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { selectActors } from '../../../bin/actor-filtering.js';
4
+ import type { ActorConfig } from '../../../bin/types.js';
5
+
6
+ const actor = (actorFullName: string): ActorConfig => ({
7
+ actorFullName,
8
+ folder: actorFullName.split('/')[1],
9
+ tokenEnvVar: 'TOKEN',
10
+ dockerContextDir: '.',
11
+ contextPaths: [],
12
+ });
13
+
14
+ const configs = [actor('owner/a'), actor('owner/b'), actor('owner/c')];
15
+ const names = (result: ActorConfig[]) => result.map((c) => c.actorFullName);
16
+
17
+ describe('selectActors', () => {
18
+ it('returns all actors when neither filter is set', () => {
19
+ expect(names(selectActors({ actors: [], ignore: [] }, configs))).toStrictEqual([
20
+ 'owner/a',
21
+ 'owner/b',
22
+ 'owner/c',
23
+ ]);
24
+ });
25
+
26
+ it('keeps only the actors listed in --actors', () => {
27
+ expect(names(selectActors({ actors: ['owner/a', 'owner/c'], ignore: [] }, configs))).toStrictEqual([
28
+ 'owner/a',
29
+ 'owner/c',
30
+ ]);
31
+ });
32
+
33
+ it('drops the actors listed in --ignore', () => {
34
+ expect(names(selectActors({ actors: [], ignore: ['owner/b'] }, configs))).toStrictEqual(['owner/a', 'owner/c']);
35
+ });
36
+
37
+ it('applies --actors first, then removes --ignore from that subset', () => {
38
+ expect(names(selectActors({ actors: ['owner/a', 'owner/b'], ignore: ['owner/b'] }, configs))).toStrictEqual([
39
+ 'owner/a',
40
+ ]);
41
+ });
42
+
43
+ it('can select down to nothing when --actors and --ignore overlap fully', () => {
44
+ expect(selectActors({ actors: ['owner/a'], ignore: ['owner/a'] }, configs)).toStrictEqual([]);
45
+ });
46
+
47
+ it('throws listing every unknown name across both filters', () => {
48
+ expect(() => selectActors({ actors: ['owner/x'], ignore: ['owner/y'] }, configs)).toThrow(
49
+ 'The following actors from the filter config do not exist: owner/x, owner/y',
50
+ );
51
+ });
52
+ });
@@ -12,6 +12,8 @@ vi.mock('node:fs/promises', () => ({ default: fsMock }));
12
12
 
13
13
  afterEach(() => vi.restoreAllMocks());
14
14
 
15
+ const emptyActorSelection = { actors: [], ignore: [] };
16
+
15
17
  const validConfig = (actors: object[]) => JSON.stringify({ actors });
16
18
  const actorJson = (fields: Record<string, unknown> = {}) => JSON.stringify(fields);
17
19
 
@@ -39,7 +41,7 @@ describe('readConfigFile', () => {
39
41
  'actors/shopify/.actor/actor.json': actorJson({ dockerContextDir: '../../..' }),
40
42
  });
41
43
 
42
- const result = await readConfigFile();
44
+ const result = await readConfigFile(emptyActorSelection);
43
45
  expectFileRead('actors/shopify/.actor/actor.json');
44
46
  expect(result).toEqual([
45
47
  {
@@ -60,7 +62,7 @@ describe('readConfigFile', () => {
60
62
  '.actor/actor.json': actorJson({}),
61
63
  });
62
64
 
63
- const result = await readConfigFile();
65
+ const result = await readConfigFile(emptyActorSelection);
64
66
  expect(result[0].folder).toBe('');
65
67
  expectFileRead('.actor/actor.json');
66
68
  });
@@ -73,7 +75,7 @@ describe('readConfigFile', () => {
73
75
  'actors/web-scraper/.actor/actor.json': actorJson({}),
74
76
  });
75
77
 
76
- const result = await readConfigFile();
78
+ const result = await readConfigFile(emptyActorSelection);
77
79
  expect(result[0].dockerContextDir).toBe('actors/web-scraper');
78
80
  expect(result[0].contextPaths).toEqual(['actors/web-scraper']);
79
81
  });
@@ -86,7 +88,7 @@ describe('readConfigFile', () => {
86
88
  'actors/shopify/.actor/actor.json': actorJson({ dockerContextDir: '../../..' }),
87
89
  });
88
90
 
89
- const result = await readConfigFile();
91
+ const result = await readConfigFile(emptyActorSelection);
90
92
  expect(result[0].dockerContextDir).toBe('');
91
93
  });
92
94
 
@@ -103,7 +105,7 @@ describe('readConfigFile', () => {
103
105
  'actors/shopify/.actor/actor.json': actorJson({ dockerContextDir: '../../..' }),
104
106
  });
105
107
 
106
- const result = await readConfigFile();
108
+ const result = await readConfigFile(emptyActorSelection);
107
109
  expect(result[0].contextPaths).toEqual(['actors/shopify', 'packages']);
108
110
  });
109
111
 
@@ -121,7 +123,7 @@ describe('readConfigFile', () => {
121
123
  'actors/email-sender/.actor/actor.json': actorJson({}),
122
124
  });
123
125
 
124
- const result = await readConfigFile();
126
+ const result = await readConfigFile(emptyActorSelection);
125
127
  expect(result).toHaveLength(2);
126
128
  expect(result[0].actorFullName).toBe('apify/web-scraper');
127
129
  expect(result[1].actorFullName).toBe('other-team/email-sender');
@@ -129,17 +131,17 @@ describe('readConfigFile', () => {
129
131
 
130
132
  it('throws when config file is missing', async () => {
131
133
  fsMock.readFile.mockRejectedValue(new Error('ENOENT'));
132
- await expect(readConfigFile()).rejects.toThrow('not found');
134
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('not found');
133
135
  });
134
136
 
135
137
  it('throws when config file contains invalid JSON', async () => {
136
138
  fsMock.readFile.mockResolvedValue('{bad json');
137
- await expect(readConfigFile()).rejects.toThrow('invalid JSON');
139
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('invalid JSON');
138
140
  });
139
141
 
140
142
  it('throws when actors array is missing', async () => {
141
143
  fsMock.readFile.mockResolvedValue(JSON.stringify({ notActors: [] }));
142
- await expect(readConfigFile()).rejects.toThrow('"actors" array');
144
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('"actors" array');
143
145
  });
144
146
 
145
147
  it('throws on duplicate folders', async () => {
@@ -151,7 +153,7 @@ describe('readConfigFile', () => {
151
153
  'actors/shopify/.actor/actor.json': actorJson({}),
152
154
  });
153
155
 
154
- await expect(readConfigFile()).rejects.toThrow('Duplicate folder');
156
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Duplicate folder');
155
157
  });
156
158
 
157
159
  it('throws on duplicate folders after normalization ("." and "")', async () => {
@@ -163,7 +165,7 @@ describe('readConfigFile', () => {
163
165
  '.actor/actor.json': actorJson({}),
164
166
  });
165
167
 
166
- await expect(readConfigFile()).rejects.toThrow('Duplicate folder');
168
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Duplicate folder');
167
169
  });
168
170
 
169
171
  it('throws when actor.json is missing', async () => {
@@ -173,7 +175,7 @@ describe('readConfigFile', () => {
173
175
  ]),
174
176
  });
175
177
 
176
- await expect(readConfigFile()).rejects.toThrow('Cannot read');
178
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Cannot read');
177
179
  });
178
180
 
179
181
  it('throws when folder is missing', async () => {
@@ -181,7 +183,7 @@ describe('readConfigFile', () => {
181
183
  [CONFIG_FILE_NAME]: validConfig([{ actorFullName: 'apify/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' }]),
182
184
  });
183
185
 
184
- await expect(readConfigFile()).rejects.toThrow(/Invalid "folder"/);
186
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/Invalid "folder"/);
185
187
  });
186
188
 
187
189
  it('throws when folder is not a string', async () => {
@@ -191,7 +193,7 @@ describe('readConfigFile', () => {
191
193
  ]),
192
194
  });
193
195
 
194
- await expect(readConfigFile()).rejects.toThrow(/Invalid "folder"/);
196
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/Invalid "folder"/);
195
197
  });
196
198
 
197
199
  it('throws when actorFullName is missing', async () => {
@@ -200,7 +202,7 @@ describe('readConfigFile', () => {
200
202
  'actors/shopify/.actor/actor.json': actorJson({}),
201
203
  });
202
204
 
203
- await expect(readConfigFile()).rejects.toThrow('Invalid "actorFullName"');
205
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "actorFullName"');
204
206
  });
205
207
 
206
208
  it('throws when actorFullName has no slash', async () => {
@@ -211,7 +213,7 @@ describe('readConfigFile', () => {
211
213
  'actors/shopify/.actor/actor.json': actorJson({}),
212
214
  });
213
215
 
214
- await expect(readConfigFile()).rejects.toThrow('Invalid "actorFullName"');
216
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "actorFullName"');
215
217
  });
216
218
 
217
219
  it('throws when actorFullName has empty parts', async () => {
@@ -222,7 +224,7 @@ describe('readConfigFile', () => {
222
224
  'actors/shopify/.actor/actor.json': actorJson({}),
223
225
  });
224
226
 
225
- await expect(readConfigFile()).rejects.toThrow('Invalid "actorFullName"');
227
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "actorFullName"');
226
228
  });
227
229
 
228
230
  it('throws when overrideActorContext is not an array', async () => {
@@ -238,7 +240,7 @@ describe('readConfigFile', () => {
238
240
  'actors/shopify/.actor/actor.json': actorJson({}),
239
241
  });
240
242
 
241
- await expect(readConfigFile()).rejects.toThrow('Invalid "overrideActorContext"');
243
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "overrideActorContext"');
242
244
  });
243
245
 
244
246
  it('throws when overrideActorContext contains non-strings', async () => {
@@ -254,7 +256,7 @@ describe('readConfigFile', () => {
254
256
  'actors/shopify/.actor/actor.json': actorJson({}),
255
257
  });
256
258
 
257
- await expect(readConfigFile()).rejects.toThrow('Invalid "overrideActorContext"');
259
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "overrideActorContext"');
258
260
  });
259
261
 
260
262
  it('throws when overrideActorContext entries overlap (one is a prefix of another)', async () => {
@@ -270,7 +272,7 @@ describe('readConfigFile', () => {
270
272
  'actors/shopify/.actor/actor.json': actorJson({}),
271
273
  });
272
274
 
273
- await expect(readConfigFile()).rejects.toThrow(/overlap/);
275
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/overlap/);
274
276
  });
275
277
 
276
278
  it('throws when overrideActorContext contains the repo root alongside another entry', async () => {
@@ -286,7 +288,7 @@ describe('readConfigFile', () => {
286
288
  'actors/shopify/.actor/actor.json': actorJson({}),
287
289
  });
288
290
 
289
- await expect(readConfigFile()).rejects.toThrow(/overlap/);
291
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/overlap/);
290
292
  });
291
293
 
292
294
  it('adds the actor own folder automatically when overrideActorContext does not cover it', async () => {
@@ -302,7 +304,7 @@ describe('readConfigFile', () => {
302
304
  'actors/shopify/.actor/actor.json': actorJson({}),
303
305
  });
304
306
 
305
- const result = await readConfigFile();
307
+ const result = await readConfigFile(emptyActorSelection);
306
308
  expect(result[0].contextPaths).toEqual(['code', 'shared', 'actors/shopify']);
307
309
  });
308
310
 
@@ -319,7 +321,7 @@ describe('readConfigFile', () => {
319
321
  'actors/shopify/.actor/actor.json': actorJson({}),
320
322
  });
321
323
 
322
- const result = await readConfigFile();
324
+ const result = await readConfigFile(emptyActorSelection);
323
325
  expect(result[0].folder).toBe('actors/shopify');
324
326
  expect(result[0].contextPaths).toEqual(['actors/shopify', 'packages']);
325
327
  });
@@ -337,7 +339,43 @@ describe('readConfigFile', () => {
337
339
  'actors/shopify/.actor/actor.json': actorJson({}),
338
340
  });
339
341
 
340
- const result = await readConfigFile();
342
+ const result = await readConfigFile(emptyActorSelection);
341
343
  expect(result[0].contextPaths).toEqual(['actors/shopify', 'code', 'shared']);
342
344
  });
345
+
346
+ describe('actor selection', () => {
347
+ const twoActors = () =>
348
+ mockFiles({
349
+ [CONFIG_FILE_NAME]: validConfig([
350
+ { folder: 'actors/a', actorFullName: 'team/a', tokenEnvVar: 'TOKEN' },
351
+ { folder: 'actors/b', actorFullName: 'team/b', tokenEnvVar: 'TOKEN' },
352
+ ]),
353
+ 'actors/a/.actor/actor.json': actorJson({}),
354
+ 'actors/b/.actor/actor.json': actorJson({}),
355
+ });
356
+
357
+ const fullNames = (result: { actorFullName: string }[]) => result.map((c) => c.actorFullName);
358
+
359
+ it('returns all actors when the selection is empty', async () => {
360
+ twoActors();
361
+ expect(fullNames(await readConfigFile(emptyActorSelection))).toEqual(['team/a', 'team/b']);
362
+ });
363
+
364
+ it('keeps only the selected actors', async () => {
365
+ twoActors();
366
+ expect(fullNames(await readConfigFile({ actors: ['team/a'], ignore: [] }))).toEqual(['team/a']);
367
+ });
368
+
369
+ it('drops ignored actors', async () => {
370
+ twoActors();
371
+ expect(fullNames(await readConfigFile({ actors: [], ignore: ['team/a'] }))).toEqual(['team/b']);
372
+ });
373
+
374
+ it('throws on an unknown actor name', async () => {
375
+ twoActors();
376
+ await expect(readConfigFile({ actors: ['team/nope'], ignore: [] })).rejects.toThrow(
377
+ 'do not exist: team/nope',
378
+ );
379
+ });
380
+ });
343
381
  });