apify-test-tools 0.10.1-beta.6 → 0.10.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +1 -3
  2. package/bin/build-from-local.ts +19 -27
  3. package/bin/build.ts +1 -1
  4. package/bin/diff-changes.ts +26 -35
  5. package/bin/dockerignore.ts +24 -17
  6. package/bin/types.ts +7 -3
  7. package/bin/utils/config/actor-json.ts +49 -8
  8. package/bin/utils/config/load-config.ts +4 -24
  9. package/bin/utils/path/repo-relative.ts +27 -4
  10. package/dist/bin/build-from-local.d.ts +3 -2
  11. package/dist/bin/build-from-local.d.ts.map +1 -1
  12. package/dist/bin/build-from-local.js +16 -23
  13. package/dist/bin/build-from-local.js.map +1 -1
  14. package/dist/bin/build.js +1 -1
  15. package/dist/bin/build.js.map +1 -1
  16. package/dist/bin/diff-changes.d.ts.map +1 -1
  17. package/dist/bin/diff-changes.js +26 -29
  18. package/dist/bin/diff-changes.js.map +1 -1
  19. package/dist/bin/dockerignore.d.ts +11 -10
  20. package/dist/bin/dockerignore.d.ts.map +1 -1
  21. package/dist/bin/dockerignore.js +24 -15
  22. package/dist/bin/dockerignore.js.map +1 -1
  23. package/dist/bin/types.d.ts +6 -3
  24. package/dist/bin/types.d.ts.map +1 -1
  25. package/dist/bin/utils/config/actor-json.d.ts.map +1 -1
  26. package/dist/bin/utils/config/actor-json.js +35 -4
  27. package/dist/bin/utils/config/actor-json.js.map +1 -1
  28. package/dist/bin/utils/config/load-config.d.ts +1 -11
  29. package/dist/bin/utils/config/load-config.d.ts.map +1 -1
  30. package/dist/bin/utils/config/load-config.js +1 -10
  31. package/dist/bin/utils/config/load-config.js.map +1 -1
  32. package/dist/bin/utils/path/repo-relative.d.ts +4 -0
  33. package/dist/bin/utils/path/repo-relative.d.ts.map +1 -1
  34. package/dist/bin/utils/path/repo-relative.js +24 -5
  35. package/dist/bin/utils/path/repo-relative.js.map +1 -1
  36. package/dist/test/unit/bin/actor-filtering.test.js +8 -2
  37. package/dist/test/unit/bin/actor-filtering.test.js.map +1 -1
  38. package/dist/test/unit/bin/build-from-local.test.js +53 -5
  39. package/dist/test/unit/bin/build-from-local.test.js.map +1 -1
  40. package/dist/test/unit/bin/diff-changes.test.js +98 -132
  41. package/dist/test/unit/bin/diff-changes.test.js.map +1 -1
  42. package/dist/test/unit/bin/dockerignore.test.js +27 -24
  43. package/dist/test/unit/bin/dockerignore.test.js.map +1 -1
  44. package/dist/test/unit/bin/utils/config/load-config.test.js +40 -4
  45. package/dist/test/unit/bin/utils/config/load-config.test.js.map +1 -1
  46. package/dist/test/unit/bin/utils/path/repo-relative.test.js +5 -0
  47. package/dist/test/unit/bin/utils/path/repo-relative.test.js.map +1 -1
  48. package/dist/test/unit/should-built-and-test.test.js +55 -116
  49. package/dist/test/unit/should-built-and-test.test.js.map +1 -1
  50. package/dist/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +65 -65
  52. package/test/unit/bin/actor-filtering.test.ts +8 -2
  53. package/test/unit/bin/build-from-local.test.ts +54 -8
  54. package/test/unit/bin/diff-changes.test.ts +133 -133
  55. package/test/unit/bin/dockerignore.test.ts +28 -28
  56. package/test/unit/bin/utils/config/load-config.test.ts +54 -4
  57. package/test/unit/bin/utils/path/repo-relative.test.ts +6 -0
  58. package/test/unit/should-built-and-test.test.ts +98 -121
@@ -3,6 +3,7 @@ import path from 'node:path';
3
3
  import { afterEach, describe, expect, it, vi } from 'vitest';
4
4
 
5
5
  import { buildDockerIgnoreMatcher, loadDockerIgnore } from '../../../bin/dockerignore.js';
6
+ import { RelativeDir, RelativeFile } from '../../../bin/utils/path/repo-relative.js';
6
7
 
7
8
  const { fsMock } = vi.hoisted(() => ({
8
9
  fsMock: {
@@ -19,69 +20,72 @@ describe('loadDockerIgnore', () => {
19
20
  fsMock.readFileSync.mockImplementation(() => {
20
21
  throw new Error('ENOENT');
21
22
  });
22
- const matcher = loadDockerIgnore('actors/my-actor');
23
+ const matcher = loadDockerIgnore(new RelativeDir('actors/my-actor'));
23
24
  expect(matcher('actors/my-actor/src/main.ts')).toBe(false);
24
25
  expect(matcher('actors/my-actor/node_modules/foo.js')).toBe(false);
25
26
  });
26
27
 
27
28
  it('matches files listed in .dockerignore', () => {
28
29
  fsMock.readFileSync.mockReturnValue('node_modules\n*.log\n');
29
- const matcher = loadDockerIgnore('');
30
+ const matcher = loadDockerIgnore(new RelativeDir(''));
30
31
  expect(matcher('node_modules/foo/bar.js')).toBe(true);
31
32
  expect(matcher('debug.log')).toBe(true);
32
33
  });
33
34
 
34
35
  it('does not match files not in .dockerignore', () => {
35
36
  fsMock.readFileSync.mockReturnValue('node_modules\n');
36
- const matcher = loadDockerIgnore('');
37
+ const matcher = loadDockerIgnore(new RelativeDir(''));
37
38
  expect(matcher('src/main.ts')).toBe(false);
38
39
  });
39
40
 
40
41
  it.each(['dist', 'dist/'])('handles directory pattern "%s"', (pattern) => {
41
42
  fsMock.readFileSync.mockReturnValue(`${pattern}\n`);
42
- const matcher = loadDockerIgnore('');
43
+ const matcher = loadDockerIgnore(new RelativeDir(''));
43
44
  expect(matcher('dist/bundle.js')).toBe(true);
44
45
  expect(matcher('src/dist-utils.ts')).toBe(false);
45
46
  });
46
47
 
47
48
  it('handles negation patterns', () => {
48
49
  fsMock.readFileSync.mockReturnValue('*.log\n!important.log\n');
49
- const matcher = loadDockerIgnore('');
50
+ const matcher = loadDockerIgnore(new RelativeDir(''));
50
51
  expect(matcher('debug.log')).toBe(true);
51
52
  expect(matcher('important.log')).toBe(false);
52
53
  });
53
54
 
54
55
  it('strips dockerContextDir prefix before matching', () => {
55
56
  fsMock.readFileSync.mockReturnValue('node_modules\n');
56
- const matcher = loadDockerIgnore('actors/shopify');
57
+ const matcher = loadDockerIgnore(new RelativeDir('actors/shopify'));
57
58
  expect(matcher('actors/shopify/node_modules/foo.js')).toBe(true);
58
59
  expect(matcher('actors/shopify/src/main.ts')).toBe(false);
59
60
  });
60
61
 
61
62
  it('returns false for files outside dockerContextDir', () => {
62
63
  fsMock.readFileSync.mockReturnValue('*\n');
63
- const matcher = loadDockerIgnore('actors/shopify');
64
+ const matcher = loadDockerIgnore(new RelativeDir('actors/shopify'));
64
65
  expect(matcher('other-actor/src/main.ts')).toBe(false);
65
66
  });
66
67
 
67
- it('reads .dockerignore from the resolved, absolute dockerContextDir root', () => {
68
+ it('treats dockerContextDir paths as case-sensitive', () => {
69
+ fsMock.readFileSync.mockReturnValue('*\n');
70
+ const matcher = loadDockerIgnore(new RelativeDir('actors/shopify'));
71
+ expect(matcher('Actors/shopify/src/main.ts')).toBe(false);
72
+ });
73
+
74
+ it('reads .dockerignore from the resolved dockerContextDir root', () => {
68
75
  fsMock.readFileSync.mockReturnValue('');
69
- loadDockerIgnore('actors/shopify');
70
- expect(fsMock.readFileSync).toHaveBeenCalledWith(
71
- path.join(path.resolve('actors/shopify'), '.dockerignore'),
72
- 'utf-8',
73
- );
76
+ loadDockerIgnore(new RelativeDir('actors/shopify'));
77
+ expect(fsMock.readFileSync).toHaveBeenCalledWith(path.join('actors/shopify', '.dockerignore'), 'utf-8');
74
78
  });
75
79
 
76
80
  it('reads .dockerignore from the resolved repo root when dockerContextDir is empty', () => {
77
81
  fsMock.readFileSync.mockReturnValue('');
78
- loadDockerIgnore('');
79
- expect(fsMock.readFileSync).toHaveBeenCalledWith(path.join(path.resolve(''), '.dockerignore'), 'utf-8');
82
+ loadDockerIgnore(new RelativeDir(''));
83
+ expect(fsMock.readFileSync).toHaveBeenCalledWith(path.join('.', '.dockerignore'), 'utf-8');
80
84
  });
81
85
 
82
86
  it('handles comments and blank lines', () => {
83
87
  fsMock.readFileSync.mockReturnValue('# this is a comment\n\nnode_modules\n');
84
- const matcher = loadDockerIgnore('');
88
+ const matcher = loadDockerIgnore(new RelativeDir(''));
85
89
  expect(matcher('node_modules/foo.js')).toBe(true);
86
90
  expect(matcher('src/main.ts')).toBe(false);
87
91
  });
@@ -90,7 +94,8 @@ describe('loadDockerIgnore', () => {
90
94
  // The common real-world .dockerignore style: every pattern prefixed with "./",
91
95
  // including a negation re-including one of the otherwise-matched files.
92
96
  fsMock.readFileSync.mockReturnValue('./node_modules\n./*.log\n!./keep.log\n');
93
- const matcher = loadDockerIgnore('');
97
+ const matcher = loadDockerIgnore(new RelativeDir(''));
98
+ // expect(new RelativeDir('').path).toBe('maemresmtioear');
94
99
  expect(matcher('node_modules/foo.js')).toBe(true);
95
100
  expect(matcher('debug.log')).toBe(true);
96
101
  expect(matcher('keep.log')).toBe(false);
@@ -99,25 +104,20 @@ describe('loadDockerIgnore', () => {
99
104
  });
100
105
 
101
106
  describe('buildDockerIgnoreMatcher', () => {
102
- it('treats paths as already relative to absoluteRootDir when hoistFrom is left at its default', () => {
107
+ it('Matcher correctly resolves paths relative to the .dockerignore file', () => {
108
+ const rootDir = new RelativeDir('repo/actors/shopify');
103
109
  fsMock.readFileSync.mockReturnValue('test/\n*.log\n');
104
- const matcher = buildDockerIgnoreMatcher('/repo/actors/shopify');
105
- expect(matcher('test/fixture.json')).toBe(true);
106
- expect(matcher('debug.log')).toBe(true);
110
+ const matcher = buildDockerIgnoreMatcher(rootDir.joinFile('.dockerignore'));
111
+ expect(matcher(`${rootDir.path}/test/fixture.json`)).toBe(true);
112
+ expect(matcher(`${rootDir.path}/debug.log`)).toBe(true);
107
113
  expect(matcher('main.js')).toBe(false);
108
114
  });
109
115
 
110
- it('reads .dockerignore from the given absoluteRootDir', () => {
111
- fsMock.readFileSync.mockReturnValue('');
112
- buildDockerIgnoreMatcher('/repo/actors/shopify');
113
- expect(fsMock.readFileSync).toHaveBeenCalledWith('/repo/actors/shopify/.dockerignore', 'utf-8');
114
- });
115
-
116
116
  it('returns no-op matcher when .dockerignore is absent', () => {
117
117
  fsMock.readFileSync.mockImplementation(() => {
118
118
  throw new Error('ENOENT');
119
119
  });
120
- const matcher = buildDockerIgnoreMatcher('/repo/actors/shopify');
120
+ const matcher = buildDockerIgnoreMatcher(new RelativeFile('repo/actors/shopify/.dockerignore'));
121
121
  expect(matcher('main.js')).toBe(false);
122
122
  });
123
123
  });
@@ -69,6 +69,44 @@ describe('loadActorConfig', () => {
69
69
  expect(loadActorConfig(entry()).dockerContextDir.path).toBe('actors/shopify');
70
70
  });
71
71
 
72
+ it.each([
73
+ ['dockerfile', 'Dockerfile'],
74
+ ['readme', 'README.md'],
75
+ ['changelog', 'CHANGELOG.md'],
76
+ ] as const)('follows Apify default locations for %s', async (field, filename) => {
77
+ await writeActorJson();
78
+
79
+ expect(loadActorConfig(entry()).actorJson[field]).toBeUndefined();
80
+
81
+ await writeFiles({ [`actors/shopify/${filename}`]: '' });
82
+ expect(loadActorConfig(entry()).actorJson[field]?.path).toBe(`actors/shopify/${filename}`);
83
+
84
+ await writeFiles({ [`actors/shopify/.actor/${filename}`]: '' });
85
+ expect(loadActorConfig(entry()).actorJson[field]?.path).toBe(`actors/shopify/.actor/${filename}`);
86
+
87
+ await writeActorJson({ [field]: '../custom-file' });
88
+ expect(loadActorConfig(entry()).actorJson[field]?.path).toBe('actors/shopify/custom-file');
89
+ });
90
+
91
+ it.each([
92
+ ['dockerfile', 'Dockerfile'],
93
+ ['readme', 'rEaDmE.md'],
94
+ ['changelog', 'CHANGELOG.md'],
95
+ ] as const)(
96
+ 'matches default %s filenames case insensitively and returns the actual path',
97
+ async (field, filename) => {
98
+ await writeActorJson();
99
+ await writeFiles({
100
+ [`actors/shopify/.actor/${filename.toLowerCase()}`]: '',
101
+ [`actors/shopify/${filename}`]: '',
102
+ });
103
+
104
+ expect(loadActorConfig(entry()).actorJson[field]?.path).toBe(
105
+ `actors/shopify/.actor/${filename.toLowerCase()}`,
106
+ );
107
+ },
108
+ );
109
+
72
110
  it('resolves path fields from actor.json while allowing inline schemas', async () => {
73
111
  await writeActorJson({
74
112
  readme: '../README.md',
@@ -176,13 +214,22 @@ describe('readConfigFile', () => {
176
214
  'actors/shopify/.actor/actor.json': actorJson({}),
177
215
  });
178
216
 
179
- expect(await readConfigFile(emptyActorSelection)).toEqual([
217
+ const actors = await readConfigFile(emptyActorSelection);
218
+ expect(
219
+ actors.map(({ actorFullName, folder, tokenEnvVar, dockerContextDir, contextPaths }) => ({
220
+ actorFullName,
221
+ folder: folder.path,
222
+ tokenEnvVar,
223
+ dockerContextDir: dockerContextDir.path,
224
+ contextPaths: contextPaths.map((contextPath) => contextPath.path),
225
+ })),
226
+ ).toEqual([
180
227
  {
181
228
  actorFullName: 'apify/root',
182
- folder: '',
229
+ folder: '.',
183
230
  tokenEnvVar: 'APIFY_TOKEN_APIFY',
184
- dockerContextDir: '',
185
- contextPaths: [''],
231
+ dockerContextDir: '.',
232
+ contextPaths: ['.'],
186
233
  },
187
234
  {
188
235
  actorFullName: 'myteam/shopify',
@@ -192,6 +239,9 @@ describe('readConfigFile', () => {
192
239
  contextPaths: ['actors/shopify', 'packages'],
193
240
  },
194
241
  ]);
242
+ expect(actors.every((actor) => actor.folder instanceof ExistingDir)).toBe(true);
243
+ expect(actors.every((actor) => actor.dockerContextDir instanceof RelativeDir)).toBe(true);
244
+ expect(actors.every((actor) => actor.actorJson.file instanceof ExistingFile)).toBe(true);
195
245
  });
196
246
 
197
247
  it('throws when config file is missing', async () => {
@@ -34,6 +34,12 @@ describe('ExistingDir', () => {
34
34
  });
35
35
 
36
36
  describe('ExistingFile', () => {
37
+ it('checks whether a relative file exists before asserting it', () => {
38
+ expect(file('package.json').exists()).toBe(true);
39
+ expect(file('missing.txt').exists()).toBe(false);
40
+ expect(file('bin').exists()).toBe(false);
41
+ });
42
+
37
43
  it('validates files through initialize', () => {
38
44
  expect(ExistingFile.initialize(file('package.json')).path).toBe('package.json');
39
45
  expect(() => ExistingFile.initialize(file('package.json/missing'))).toThrow();
@@ -1,34 +1,65 @@
1
- import type { MockInstance } from 'vitest';
2
- import { beforeEach, describe, expect, test, vi } from 'vitest';
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+
5
+ import { afterAll, describe, expect, test } from 'vitest';
3
6
 
4
7
  import { getChangedActors } from '../../bin/diff-changes.js';
5
- import * as DiffJsonSchema from '../../bin/diff-json-schema.js';
6
8
  import type { ActorConfig, Commit } from '../../bin/types.js';
9
+ import { ExistingDir, ExistingFile, RelativeDir, RelativeFile } from '../../bin/utils/path/repo-relative.js';
10
+
11
+ const originalCwd = process.cwd();
12
+ const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'apify-should-build-'));
13
+ process.chdir(fixtureRoot);
14
+
15
+ afterAll(() => {
16
+ process.chdir(originalCwd);
17
+ fs.rmSync(fixtureRoot, { recursive: true, force: true });
18
+ });
19
+
20
+ const actorConfig = (
21
+ actorFullName: string,
22
+ folder: string,
23
+ tokenEnvVar: string,
24
+ dockerContextDir = '.',
25
+ ): ActorConfig => {
26
+ const actorJsonPath = path.posix.join(folder, '.actor/actor.json');
27
+ fs.mkdirSync(path.posix.dirname(actorJsonPath), { recursive: true });
28
+ fs.writeFileSync(actorJsonPath, '{}');
29
+ const contextPath = new RelativeDir(dockerContextDir);
30
+ return {
31
+ actorFullName,
32
+ folder: new ExistingDir(folder),
33
+ tokenEnvVar,
34
+ actorJson: {
35
+ file: new ExistingFile(actorJsonPath),
36
+ dockerContextDir: contextPath,
37
+ changelog: new RelativeFile('CHANGELOG.md'),
38
+ },
39
+ dockerContextDir: contextPath,
40
+ contextPaths: [contextPath],
41
+ };
42
+ };
7
43
 
8
44
  describe('Should build and test parser', () => {
9
45
  // From https://github.com/apify-store/testing-repo-for-github-actions
10
46
  const ACTOR_CONFIGS: ActorConfig[] = [
11
- {
12
- actorFullName: 'lukaskrivka/testing-github-integration-1',
13
- folder: 'actors/lukaskrivka_testing-github-integration-1',
14
- tokenEnvVar: 'APIFY_TOKEN_LUKASKRIVKA',
15
- dockerContextDir: '',
16
- contextPaths: [''],
17
- },
18
- {
19
- actorFullName: 'lukaskrivka/testing-github-integration-2',
20
- folder: 'actors/lukaskrivka_testing-github-integration-2',
21
- tokenEnvVar: 'APIFY_TOKEN_LUKASKRIVKA',
22
- dockerContextDir: '',
23
- contextPaths: [''],
24
- },
25
- {
26
- actorFullName: 'lukaskrivka/test-standalone',
27
- folder: 'standalone-actors/lukaskrivka_test-standalone',
28
- tokenEnvVar: 'APIFY_TOKEN_LUKASKRIVKA',
29
- dockerContextDir: 'standalone-actors/lukaskrivka_test-standalone',
30
- contextPaths: ['standalone-actors/lukaskrivka_test-standalone'],
31
- },
47
+ actorConfig(
48
+ 'lukaskrivka/testing-github-integration-1',
49
+ 'actors/lukaskrivka_testing-github-integration-1',
50
+ 'APIFY_TOKEN_LUKASKRIVKA',
51
+ ),
52
+ actorConfig(
53
+ 'lukaskrivka/testing-github-integration-2',
54
+ 'actors/lukaskrivka_testing-github-integration-2',
55
+ 'APIFY_TOKEN_LUKASKRIVKA',
56
+ ),
57
+ actorConfig(
58
+ 'lukaskrivka/test-standalone',
59
+ 'standalone-actors/lukaskrivka_test-standalone',
60
+ 'APIFY_TOKEN_LUKASKRIVKA',
61
+ 'standalone-actors/lukaskrivka_test-standalone',
62
+ ),
32
63
  ];
33
64
 
34
65
  const commits: Commit[] = [
@@ -36,15 +67,6 @@ describe('Should build and test parser', () => {
36
67
  { sha: 'Commit3', author: '', date: '', message: '' },
37
68
  ];
38
69
 
39
- let isCosmeticOnlyJsonSchemaSpy: MockInstance;
40
-
41
- beforeEach(() => {
42
- // Default: JSON changes are functional (triggers build/test)
43
- isCosmeticOnlyJsonSchemaSpy = vi
44
- .spyOn(DiffJsonSchema, 'isCosmeticOnlyJsonSchemaChange')
45
- .mockResolvedValue(false);
46
- });
47
-
48
70
  test('Ignores dev-only readme', async () => {
49
71
  const FILES = ['README.md', 'code/README.md', 'shared/README.md'];
50
72
 
@@ -59,7 +81,7 @@ describe('Should build and test parser', () => {
59
81
  });
60
82
 
61
83
  test('Ignores other ignored files and folders', async () => {
62
- const FILES = ['.vscode/', '.gitignore', '.husky/', '.eslintrc', '.editorconfig'];
84
+ const FILES = ['.vscode/settings.json', '.gitignore', '.husky/pre-commit', '.eslintrc', '.editorconfig'];
63
85
 
64
86
  const actorsChanged = await getChangedActors({
65
87
  actorConfigs: ACTOR_CONFIGS,
@@ -84,8 +106,8 @@ describe('Should build and test parser', () => {
84
106
  expect(actorsChanged).toEqual(ACTOR_CONFIGS.slice(0, 2));
85
107
  });
86
108
 
87
- test('Root-level changelog is cosmetic for every actor, only on latest', async () => {
88
- const FILES = ['shared/CHANGELOG.md', 'CHANGELOG.md'];
109
+ test('Configured changelog is cosmetic for every actor, only on latest', async () => {
110
+ const FILES = ['CHANGELOG.md'];
89
111
 
90
112
  const actorsChangedNotLatest = await getChangedActors({
91
113
  actorConfigs: ACTOR_CONFIGS,
@@ -104,7 +126,7 @@ describe('Should build and test parser', () => {
104
126
  expect(actorsChangedLatest).toEqual(ACTOR_CONFIGS);
105
127
  });
106
128
 
107
- test('A changelog nested inside one actor own folder is excluded for sibling actors, only triggers that actor', async () => {
129
+ test('A changelog nested inside one actor own folder is excluded for sibling actors', async () => {
108
130
  const FILES = ['actors/lukaskrivka_testing-github-integration-1/CHANGELOG.md'];
109
131
 
110
132
  const actorsChanged = await getChangedActors({
@@ -135,7 +157,6 @@ describe('Should build and test parser', () => {
135
157
  'actors/lukaskrivka_testing-github-integration-1/.actor/actor.json',
136
158
  'standalone-actors/lukaskrivka_test-standalone/Dockerfile',
137
159
  ];
138
- // Default mock returns false = functional change
139
160
 
140
161
  const actorsChanged = await getChangedActors({
141
162
  actorConfigs: ACTOR_CONFIGS,
@@ -166,7 +187,6 @@ describe('Should build and test parser', () => {
166
187
  'code/src/main.ts',
167
188
  'standalone-actors/lukaskrivka_test-standalone/Dockerfile',
168
189
  ];
169
- // Default mock returns false = functional change for the JSON file
170
190
 
171
191
  const actorsChanged = await getChangedActors({
172
192
  actorConfigs: ACTOR_CONFIGS,
@@ -180,8 +200,8 @@ describe('Should build and test parser', () => {
180
200
 
181
201
  test('Specific Actor non-functional configs updated', async () => {
182
202
  const FILES = [
183
- 'actors/lukaskrivka_testing-github-integration-2/.actor/README.md',
184
- 'standalone-actors/lukaskrivka_test-standalone/CHANGELOG.md',
203
+ 'actors/lukaskrivka_testing-github-integration-2/README.md',
204
+ 'standalone-actors/lukaskrivka_test-standalone/README.md',
185
205
  ];
186
206
 
187
207
  const actorsChanged = await getChangedActors({
@@ -194,9 +214,8 @@ describe('Should build and test parser', () => {
194
214
  expect(actorsChanged).toEqual([]);
195
215
  });
196
216
 
197
- test('JSON file with cosmetic-only changes in PR context (isLatest=false) skips tests', async () => {
217
+ test('Actor JSON changes in PR context trigger tests', async () => {
198
218
  const FILES = ['actors/lukaskrivka_testing-github-integration-1/.actor/actor.json'];
199
- isCosmeticOnlyJsonSchemaSpy.mockResolvedValue(true);
200
219
 
201
220
  const actorsChanged = await getChangedActors({
202
221
  actorConfigs: ACTOR_CONFIGS,
@@ -205,12 +224,11 @@ describe('Should build and test parser', () => {
205
224
  commits,
206
225
  });
207
226
 
208
- expect(actorsChanged).toEqual([]);
227
+ expect(actorsChanged).toEqual([ACTOR_CONFIGS[0]]);
209
228
  });
210
229
 
211
- test('JSON file with cosmetic-only changes in latest context still triggers build', async () => {
230
+ test('Actor JSON changes in latest context trigger builds', async () => {
212
231
  const FILES = ['actors/lukaskrivka_testing-github-integration-1/.actor/actor.json'];
213
- isCosmeticOnlyJsonSchemaSpy.mockResolvedValue(true);
214
232
 
215
233
  const actorsChanged = await getChangedActors({
216
234
  actorConfigs: ACTOR_CONFIGS,
@@ -224,7 +242,6 @@ describe('Should build and test parser', () => {
224
242
 
225
243
  test('JSON file with functional changes triggers tests', async () => {
226
244
  const FILES = ['actors/lukaskrivka_testing-github-integration-1/.actor/actor.json'];
227
- // Default mock returns false = functional change
228
245
 
229
246
  const actorsChanged = await getChangedActors({
230
247
  actorConfigs: ACTOR_CONFIGS,
@@ -236,15 +253,11 @@ describe('Should build and test parser', () => {
236
253
  expect(actorsChanged).toEqual([ACTOR_CONFIGS[0]]);
237
254
  });
238
255
 
239
- test('Mix: one actor has cosmetic-only JSON change, another has functional JSON change', async () => {
256
+ test('JSON changes in two actor folders trigger both actors', async () => {
240
257
  const FILES = [
241
258
  'actors/lukaskrivka_testing-github-integration-1/.actor/actor.json',
242
259
  'actors/lukaskrivka_testing-github-integration-2/.actor/input_schema.json',
243
260
  ];
244
- // Actor 1 JSON is cosmetic-only, actor 2 JSON is functional
245
- isCosmeticOnlyJsonSchemaSpy.mockImplementation(
246
- async (_commits, filepath: string) => !filepath.includes('input_schema.json'),
247
- );
248
261
 
249
262
  const actorsChanged = await getChangedActors({
250
263
  actorConfigs: ACTOR_CONFIGS,
@@ -253,13 +266,11 @@ describe('Should build and test parser', () => {
253
266
  commits,
254
267
  });
255
268
 
256
- // Only the second actor (functional change) should be built and tested
257
- expect(actorsChanged).toEqual([ACTOR_CONFIGS[1]]);
269
+ expect(actorsChanged).toEqual(ACTOR_CONFIGS.slice(0, 2));
258
270
  });
259
271
 
260
- test('Narrow-context actor with cosmetic-only JSON change in PR context skips tests', async () => {
272
+ test('Narrow-context actor JSON change in PR context triggers tests', async () => {
261
273
  const FILES = ['standalone-actors/lukaskrivka_test-standalone/.actor/actor.json'];
262
- isCosmeticOnlyJsonSchemaSpy.mockResolvedValue(true);
263
274
 
264
275
  const actorsChanged = await getChangedActors({
265
276
  actorConfigs: ACTOR_CONFIGS,
@@ -268,7 +279,7 @@ describe('Should build and test parser', () => {
268
279
  commits,
269
280
  });
270
281
 
271
- expect(actorsChanged).toEqual([]);
282
+ expect(actorsChanged).toEqual([ACTOR_CONFIGS[2]]);
272
283
  });
273
284
 
274
285
  test('Google Maps real user-case that had undefined', async () => {
@@ -288,70 +299,36 @@ describe('Should build and test parser', () => {
288
299
  ];
289
300
 
290
301
  const ACTOR_CONFIGS_GOOGLE_MAPS: ActorConfig[] = [
291
- {
292
- // Edge case of capitals in actor name :)
293
- actorFullName: 'compass/Google-Maps-Reviews-Scraper',
294
- folder: 'actors/compass_Google-Maps-Reviews-Scraper',
295
- tokenEnvVar: 'APIFY_TOKEN_COMPASS',
296
- dockerContextDir: '',
297
- contextPaths: [''],
298
- },
299
- {
300
- actorFullName: 'compass/crawler-google-places',
301
- folder: 'actors/compass_crawler-google-places',
302
- tokenEnvVar: 'APIFY_TOKEN_COMPASS',
303
- dockerContextDir: '',
304
- contextPaths: [''],
305
- },
306
- {
307
- actorFullName: 'compass/easy-google-maps',
308
- folder: 'actors/compass_easy-google-maps',
309
- tokenEnvVar: 'APIFY_TOKEN_COMPASS',
310
- dockerContextDir: '',
311
- contextPaths: [''],
312
- },
313
- {
314
- actorFullName: 'compass/google-maps-extractor',
315
- folder: 'actors/compass_google-maps-extractor',
316
- tokenEnvVar: 'APIFY_TOKEN_COMPASS',
317
- dockerContextDir: '',
318
- contextPaths: [''],
319
- },
320
- {
321
- actorFullName: 'compass/google-places-api',
322
- folder: 'actors/compass_google-places-api',
323
- tokenEnvVar: 'APIFY_TOKEN_COMPASS',
324
- dockerContextDir: '',
325
- contextPaths: [''],
326
- },
327
- {
328
- actorFullName: 'lukaskrivka/google-maps-with-contact-details',
329
- folder: 'actors/lukaskrivka_google-maps-with-contact-details',
330
- tokenEnvVar: 'APIFY_TOKEN_LUKASKRIVKA',
331
- dockerContextDir: '',
332
- contextPaths: [''],
333
- },
334
- {
335
- actorFullName: 'natasha.lekh/gas-prices-scraper',
336
- folder: 'actors/natasha.lekh_gas-prices-scraper',
337
- tokenEnvVar: 'APIFY_TOKEN_NATASHA_LEKH',
338
- dockerContextDir: '',
339
- contextPaths: [''],
340
- },
341
- {
342
- actorFullName: 'natasha.lekh/vegan-places-finder',
343
- folder: 'actors/natasha.lekh_vegan-places-finder',
344
- tokenEnvVar: 'APIFY_TOKEN_NATASHA_LEKH',
345
- dockerContextDir: '',
346
- contextPaths: [''],
347
- },
348
- {
349
- actorFullName: 'lukaskrivka/google-maps-scraper-orchestrator',
350
- folder: 'standalone-actors/lukaskrivka_google-maps-scraper-orchestrator',
351
- tokenEnvVar: 'APIFY_TOKEN_LUKASKRIVKA',
352
- dockerContextDir: 'standalone-actors/lukaskrivka_google-maps-scraper-orchestrator',
353
- contextPaths: ['standalone-actors/lukaskrivka_google-maps-scraper-orchestrator'],
354
- },
302
+ actorConfig(
303
+ 'compass/Google-Maps-Reviews-Scraper',
304
+ 'actors/compass_Google-Maps-Reviews-Scraper',
305
+ 'APIFY_TOKEN_COMPASS',
306
+ ),
307
+ actorConfig('compass/crawler-google-places', 'actors/compass_crawler-google-places', 'APIFY_TOKEN_COMPASS'),
308
+ actorConfig('compass/easy-google-maps', 'actors/compass_easy-google-maps', 'APIFY_TOKEN_COMPASS'),
309
+ actorConfig('compass/google-maps-extractor', 'actors/compass_google-maps-extractor', 'APIFY_TOKEN_COMPASS'),
310
+ actorConfig('compass/google-places-api', 'actors/compass_google-places-api', 'APIFY_TOKEN_COMPASS'),
311
+ actorConfig(
312
+ 'lukaskrivka/google-maps-with-contact-details',
313
+ 'actors/lukaskrivka_google-maps-with-contact-details',
314
+ 'APIFY_TOKEN_LUKASKRIVKA',
315
+ ),
316
+ actorConfig(
317
+ 'natasha.lekh/gas-prices-scraper',
318
+ 'actors/natasha.lekh_gas-prices-scraper',
319
+ 'APIFY_TOKEN_NATASHA_LEKH',
320
+ ),
321
+ actorConfig(
322
+ 'natasha.lekh/vegan-places-finder',
323
+ 'actors/natasha.lekh_vegan-places-finder',
324
+ 'APIFY_TOKEN_NATASHA_LEKH',
325
+ ),
326
+ actorConfig(
327
+ 'lukaskrivka/google-maps-scraper-orchestrator',
328
+ 'standalone-actors/lukaskrivka_google-maps-scraper-orchestrator',
329
+ 'APIFY_TOKEN_LUKASKRIVKA',
330
+ 'standalone-actors/lukaskrivka_google-maps-scraper-orchestrator',
331
+ ),
355
332
  ];
356
333
 
357
334
  const actorsChanged = await getChangedActors({