apify-test-tools 0.10.1 → 0.10.2-beta.1
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.
- package/.github/workflows/public_pr-build-test.yaml +3 -26
- package/.github/workflows-package-version +1 -1
- package/CHANGELOG.md +10 -0
- package/README.md +5 -2
- package/bin/diff-changes.ts +24 -3
- package/bin/main.ts +15 -2
- package/bin/types.ts +1 -0
- package/dist/bin/diff-changes.d.ts +2 -1
- package/dist/bin/diff-changes.d.ts.map +1 -1
- package/dist/bin/diff-changes.js +16 -5
- package/dist/bin/diff-changes.js.map +1 -1
- package/dist/bin/main.js +14 -2
- package/dist/bin/main.js.map +1 -1
- package/dist/bin/types.d.ts +1 -0
- package/dist/bin/types.d.ts.map +1 -1
- package/dist/lib/extend-expect.js +2 -2
- package/dist/lib/extend-expect.js.map +1 -1
- package/dist/test/unit/bin/diff-changes.test.js +91 -0
- package/dist/test/unit/bin/diff-changes.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/lib/extend-expect.ts +2 -2
- package/package.json +67 -65
- package/test/unit/bin/diff-changes.test.ts +106 -0
package/lib/extend-expect.ts
CHANGED
|
@@ -53,7 +53,7 @@ export const extendExpect = (expect: ExpectStatic): ExpectStatic => {
|
|
|
53
53
|
};
|
|
54
54
|
},
|
|
55
55
|
toBeNonEmptyObject: (actual) => {
|
|
56
|
-
const isObject = typeof actual === 'object' && !Array.isArray(actual);
|
|
56
|
+
const isObject = typeof actual === 'object' && !Array.isArray(actual) && actual !== null;
|
|
57
57
|
const isNonEmpty = Object.entries(actual).length > 0;
|
|
58
58
|
const pass = isObject && isNonEmpty;
|
|
59
59
|
return {
|
|
@@ -62,7 +62,7 @@ export const extendExpect = (expect: ExpectStatic): ExpectStatic => {
|
|
|
62
62
|
};
|
|
63
63
|
},
|
|
64
64
|
toBeObject: (actual) => {
|
|
65
|
-
const pass = typeof actual === 'object' && !Array.isArray(actual);
|
|
65
|
+
const pass = typeof actual === 'object' && !Array.isArray(actual) && actual !== null;
|
|
66
66
|
return {
|
|
67
67
|
pass,
|
|
68
68
|
message: () => `Expected "${actual}" to be an object`,
|
package/package.json
CHANGED
|
@@ -1,67 +1,69 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"
|
|
66
|
-
|
|
2
|
+
"name": "apify-test-tools",
|
|
3
|
+
"version": "0.10.2-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": "^3.0.1",
|
|
20
|
+
"@slack/web-api": "^8.2.0",
|
|
21
|
+
"adm-zip": "^0.6.1",
|
|
22
|
+
"apify-client": "^2.25.0",
|
|
23
|
+
"ignore": "^7.0.5",
|
|
24
|
+
"picomatch": "^4.0.7",
|
|
25
|
+
"yargs": "^18.0.0",
|
|
26
|
+
"zod": "^4.6.5"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@apify/eslint-config": "^1.0.0",
|
|
30
|
+
"@apify/tsconfig": "^0.1.1",
|
|
31
|
+
"@types/adm-zip": "^0.5.8",
|
|
32
|
+
"@types/node": "^24.0.0",
|
|
33
|
+
"@types/picomatch": "^4.0.3",
|
|
34
|
+
"@types/yargs": "^17.0.33",
|
|
35
|
+
"eslint": "^9.29.0",
|
|
36
|
+
"eslint-config-prettier": "^10.1.5",
|
|
37
|
+
"globals": "^17.0.0",
|
|
38
|
+
"husky": "^9.0.11",
|
|
39
|
+
"knip": "^5.65.0",
|
|
40
|
+
"lint-staged": "^15.2.2",
|
|
41
|
+
"prettier": "^3.5.3",
|
|
42
|
+
"tsx": "^4.20.3",
|
|
43
|
+
"typescript": "^5.9.3",
|
|
44
|
+
"typescript-eslint": "^8.34.1",
|
|
45
|
+
"vitest": "^3.2.4"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"vitest": ">=3.2.4"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"start": "npm run dist/bin/main.js",
|
|
52
|
+
"start:dev": "cd local-clone && tsx ../bin/main.ts",
|
|
53
|
+
"build": "tsc && chmod +x ./dist/bin/main.js",
|
|
54
|
+
"lint": "eslint",
|
|
55
|
+
"lint:fix": "eslint --fix",
|
|
56
|
+
"format": "prettier --write .",
|
|
57
|
+
"format:check": "prettier --check .",
|
|
58
|
+
"type-check": "tsc --noEmit",
|
|
59
|
+
"test": "vitest run",
|
|
60
|
+
"check-unused": "npx knip",
|
|
61
|
+
"prepare": "husky .husky || true"
|
|
62
|
+
},
|
|
63
|
+
"lint-staged": {
|
|
64
|
+
"*.js": "eslint",
|
|
65
|
+
"*.ts": "eslint"
|
|
66
|
+
},
|
|
67
|
+
"author": "oklinov",
|
|
68
|
+
"license": "ISC"
|
|
67
69
|
}
|
|
@@ -63,6 +63,7 @@ const commits = [{ sha: 'Commit1', author: '', date: '', message: '' }];
|
|
|
63
63
|
|
|
64
64
|
describe('getChangedActors', () => {
|
|
65
65
|
beforeEach(() => {
|
|
66
|
+
vi.restoreAllMocks();
|
|
66
67
|
vi.spyOn(DiffJsonSchema, 'isCosmeticOnlyJsonSchemaChange').mockResolvedValue(false);
|
|
67
68
|
});
|
|
68
69
|
|
|
@@ -393,6 +394,72 @@ describe('getChangedActors', () => {
|
|
|
393
394
|
expect(result).toEqual([miniActor]);
|
|
394
395
|
});
|
|
395
396
|
|
|
397
|
+
it('test file listed in .dockerignore triggers a build when it matches the test files glob', async () => {
|
|
398
|
+
vi.spyOn(Dockerignore, 'loadDockerIgnore').mockReturnValue((filePath) => filePath.startsWith('test/'));
|
|
399
|
+
const result = await getChangedActors({
|
|
400
|
+
filepathsChanged: ['test/platform/daily/foo.test.ts'],
|
|
401
|
+
actorConfigs: [miniActor],
|
|
402
|
+
commits,
|
|
403
|
+
testFilesGlob: 'test/platform/**',
|
|
404
|
+
});
|
|
405
|
+
expect(result).toEqual([miniActor]);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('test file listed in .dockerignore stays ignored without a test files glob', async () => {
|
|
409
|
+
vi.spyOn(Dockerignore, 'loadDockerIgnore').mockReturnValue((filePath) => filePath.startsWith('test/'));
|
|
410
|
+
const result = await getChangedActors({
|
|
411
|
+
filepathsChanged: ['test/platform/daily/foo.test.ts'],
|
|
412
|
+
actorConfigs: [miniActor],
|
|
413
|
+
commits,
|
|
414
|
+
});
|
|
415
|
+
expect(result).toEqual([]);
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it('test files glob matches case-insensitively and does not bypass .dockerignore for other files', async () => {
|
|
419
|
+
vi.spyOn(Dockerignore, 'loadDockerIgnore').mockReturnValue(() => true);
|
|
420
|
+
const result = await getChangedActors({
|
|
421
|
+
filepathsChanged: ['Test/Platform/Foo.test.ts'],
|
|
422
|
+
actorConfigs: [miniActor],
|
|
423
|
+
commits,
|
|
424
|
+
testFilesGlob: 'test/platform/**',
|
|
425
|
+
});
|
|
426
|
+
expect(result).toEqual([miniActor]);
|
|
427
|
+
expect(
|
|
428
|
+
await getChangedActors({
|
|
429
|
+
filepathsChanged: ['actors/foo_bar/node_modules/foo.js'],
|
|
430
|
+
actorConfigs: [miniActor],
|
|
431
|
+
commits,
|
|
432
|
+
testFilesGlob: 'test/platform/**',
|
|
433
|
+
}),
|
|
434
|
+
).toEqual([]);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it('test file outside an actor context still does not trigger it', async () => {
|
|
438
|
+
vi.spyOn(Dockerignore, 'loadDockerIgnore').mockReturnValue(() => true);
|
|
439
|
+
const result = await getChangedActors({
|
|
440
|
+
filepathsChanged: ['test/platform/daily/foo.test.ts'],
|
|
441
|
+
actorConfigs: [standaloneActor],
|
|
442
|
+
commits,
|
|
443
|
+
testFilesGlob: 'test/platform/**',
|
|
444
|
+
});
|
|
445
|
+
expect(result).toEqual([]);
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
it('test file listed in .dockerignore triggers an actor whose overrideActorContext includes it', async () => {
|
|
449
|
+
vi.spyOn(Dockerignore, 'loadDockerIgnore').mockReturnValue(() => true);
|
|
450
|
+
const actorWithTests = {
|
|
451
|
+
...standaloneActor,
|
|
452
|
+
contextPaths: [...standaloneActor.contextPaths, new RelativeDir('test')],
|
|
453
|
+
};
|
|
454
|
+
const result = await getChangedActors({
|
|
455
|
+
filepathsChanged: ['test/platform/standalone.test.ts'],
|
|
456
|
+
actorConfigs: [actorWithTests],
|
|
457
|
+
commits,
|
|
458
|
+
testFilesGlob: 'test/platform/**',
|
|
459
|
+
});
|
|
460
|
+
expect(result).toEqual([actorWithTests]);
|
|
461
|
+
});
|
|
462
|
+
|
|
396
463
|
it('JSON file in context but outside actor folder is functional (not checked for cosmetic)', async () => {
|
|
397
464
|
const result = await getChangedActors({
|
|
398
465
|
filepathsChanged: ['lib/config.json'],
|
|
@@ -473,6 +540,7 @@ describe('getChangedActors logging', () => {
|
|
|
473
540
|
beforeEach(() => {
|
|
474
541
|
vi.spyOn(DiffJsonSchema, 'isCosmeticOnlyJsonSchemaChange').mockResolvedValue(false);
|
|
475
542
|
vi.spyOn(logger, 'info').mockImplementation(() => undefined);
|
|
543
|
+
vi.spyOn(logger, 'warn').mockImplementation(() => undefined);
|
|
476
544
|
});
|
|
477
545
|
|
|
478
546
|
it('logs a single "specific" group for a single actor with one functional file', async () => {
|
|
@@ -525,6 +593,44 @@ describe('getChangedActors logging', () => {
|
|
|
525
593
|
]);
|
|
526
594
|
});
|
|
527
595
|
|
|
596
|
+
const outsideContextWarning = (testFile: string) =>
|
|
597
|
+
`[DIFF]: Test file ${testFile} is outside every Actor's context, so changing only it builds and tests nothing. ` +
|
|
598
|
+
'Add its folder to "overrideActorContext" of the Actors it tests.';
|
|
599
|
+
|
|
600
|
+
it('warns about a changed test file outside every Actor context', async () => {
|
|
601
|
+
await getChangedActors({
|
|
602
|
+
filepathsChanged: ['test/platform/standalone.test.ts'],
|
|
603
|
+
actorConfigs: [standaloneActor],
|
|
604
|
+
commits,
|
|
605
|
+
testFilesGlob: 'test/platform/**',
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
expect(logger.warn).toHaveBeenCalledWith(outsideContextWarning('test/platform/standalone.test.ts'));
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
it('still warns when the same push also rebuilds an Actor', async () => {
|
|
612
|
+
const result = await getChangedActors({
|
|
613
|
+
filepathsChanged: ['test/platform/standalone.test.ts', 'standalone-actors/standalone/src/main.ts'],
|
|
614
|
+
actorConfigs: [standaloneActor],
|
|
615
|
+
commits,
|
|
616
|
+
testFilesGlob: 'test/platform/**',
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
expect(result).toEqual([standaloneActor]);
|
|
620
|
+
expect(logger.warn).toHaveBeenCalledWith(outsideContextWarning('test/platform/standalone.test.ts'));
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
it('does not warn about test files inside an Actor context, even cosmetic ones', async () => {
|
|
624
|
+
await getChangedActors({
|
|
625
|
+
filepathsChanged: ['test/platform/foo.test.ts', 'test/platform/README.md', 'test/platform/CHANGELOG.md'],
|
|
626
|
+
actorConfigs: [miniActor],
|
|
627
|
+
commits,
|
|
628
|
+
testFilesGlob: 'test/platform/**',
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
expect(logger.warn).not.toHaveBeenCalled();
|
|
632
|
+
});
|
|
633
|
+
|
|
528
634
|
it('logs no group lines when zero actors changed', async () => {
|
|
529
635
|
await getChangedActors({
|
|
530
636
|
filepathsChanged: ['.gitignore', '.prettierrc'],
|