apify-test-tools 0.9.1-beta.4 → 0.9.1-beta.6
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/on_pull_request.yaml +1 -1
- package/.prettierignore +3 -0
- package/.vscode/settings.json +2 -1
- package/CHANGELOG.md +4 -0
- package/bin/main.ts +2 -1
- package/bin/types.ts +0 -11
- package/bin/utils/config/load-config.ts +133 -0
- package/bin/utils/config/parser.ts +88 -0
- package/bin/utils/config/structures/base.ts +61 -0
- package/bin/utils/config/structures/legacy.ts +20 -0
- package/bin/utils/json-file.ts +55 -0
- package/bin/utils.ts +0 -138
- package/dist/bin/main.d.ts.map +1 -1
- package/dist/bin/main.js +2 -1
- package/dist/bin/main.js.map +1 -1
- package/dist/bin/types.d.ts +0 -9
- package/dist/bin/types.d.ts.map +1 -1
- package/dist/bin/utils/config/load-config.d.ts +13 -0
- package/dist/bin/utils/config/load-config.d.ts.map +1 -0
- package/dist/bin/utils/config/load-config.js +99 -0
- package/dist/bin/utils/config/load-config.js.map +1 -0
- package/dist/bin/utils/config/parser.d.ts +19 -0
- package/dist/bin/utils/config/parser.d.ts.map +1 -0
- package/dist/bin/utils/config/parser.js +72 -0
- package/dist/bin/utils/config/parser.js.map +1 -0
- package/dist/bin/utils/config/structures/base.d.ts +35 -0
- package/dist/bin/utils/config/structures/base.d.ts.map +1 -0
- package/dist/bin/utils/config/structures/base.js +40 -0
- package/dist/bin/utils/config/structures/base.js.map +1 -0
- package/dist/bin/utils/config/structures/legacy.d.ts +6 -0
- package/dist/bin/utils/config/structures/legacy.d.ts.map +1 -0
- package/dist/bin/utils/config/structures/legacy.js +14 -0
- package/dist/bin/utils/config/structures/legacy.js.map +1 -0
- package/dist/bin/utils/json-file.d.ts +20 -0
- package/dist/bin/utils/json-file.d.ts.map +1 -0
- package/dist/bin/utils/json-file.js +42 -0
- package/dist/bin/utils/json-file.js.map +1 -0
- package/dist/bin/utils.d.ts +0 -6
- package/dist/bin/utils.d.ts.map +1 -1
- package/dist/bin/utils.js +0 -98
- package/dist/bin/utils.js.map +1 -1
- package/dist/test/unit/bin/utils/config/load-config.test.d.ts +2 -0
- package/dist/test/unit/bin/utils/config/load-config.test.d.ts.map +1 -0
- package/dist/test/unit/bin/utils/config/load-config.test.js +138 -0
- package/dist/test/unit/bin/utils/config/load-config.test.js.map +1 -0
- package/dist/test/unit/bin/utils/config/parser.test.d.ts +2 -0
- package/dist/test/unit/bin/utils/config/parser.test.d.ts.map +1 -0
- package/dist/test/unit/bin/utils/config/parser.test.js +111 -0
- package/dist/test/unit/bin/utils/config/parser.test.js.map +1 -0
- package/dist/test/unit/bin/utils/config/structures/base.test.d.ts +2 -0
- package/dist/test/unit/bin/utils/config/structures/base.test.d.ts.map +1 -0
- package/dist/test/unit/bin/utils/config/structures/base.test.js +74 -0
- package/dist/test/unit/bin/utils/config/structures/base.test.js.map +1 -0
- package/dist/test/unit/bin/utils/config/structures/legacy.test.d.ts +2 -0
- package/dist/test/unit/bin/utils/config/structures/legacy.test.d.ts.map +1 -0
- package/dist/test/unit/bin/utils/config/structures/legacy.test.js +63 -0
- package/dist/test/unit/bin/utils/config/structures/legacy.test.js.map +1 -0
- package/dist/test/unit/bin/utils/files.test.d.ts +2 -0
- package/dist/test/unit/bin/utils/files.test.d.ts.map +1 -0
- package/dist/test/unit/bin/utils/files.test.js +117 -0
- package/dist/test/unit/bin/utils/files.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/test/fixtures/bin/utils/files/array.json +1 -0
- package/test/fixtures/bin/utils/files/comments.jsonc +4 -0
- package/test/fixtures/bin/utils/files/directory.json/.gitkeep +0 -0
- package/test/fixtures/bin/utils/files/empty-object.json +1 -0
- package/test/fixtures/bin/utils/files/empty.json +0 -0
- package/test/fixtures/bin/utils/files/malformed.json +1 -0
- package/test/fixtures/bin/utils/files/nested.json +6 -0
- package/test/fixtures/bin/utils/files/no-json-extension.actorrc +1 -0
- package/test/fixtures/bin/utils/files/null.json +1 -0
- package/test/fixtures/bin/utils/files/number.json +1 -0
- package/test/fixtures/bin/utils/files/unreadable.json +1 -0
- package/test/tsconfig.json +4 -2
- package/test/unit/bin/utils/config/load-config.test.ts +179 -0
- package/test/unit/bin/utils/config/parser.test.ts +137 -0
- package/test/unit/bin/utils/config/structures/base.test.ts +83 -0
- package/test/unit/bin/utils/config/structures/legacy.test.ts +78 -0
- package/test/unit/bin/utils/files.test.ts +158 -0
- package/dist/test/unit/bin/utils.test.d.ts +0 -2
- package/dist/test/unit/bin/utils.test.d.ts.map +0 -1
- package/dist/test/unit/bin/utils.test.js +0 -321
- package/dist/test/unit/bin/utils.test.js.map +0 -1
- package/test/unit/bin/utils.test.ts +0 -381
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { safeReadJsonObjectFile } from '../../../../bin/utils/json-file.js';
|
|
8
|
+
|
|
9
|
+
// These tests read real fixture files rather than mocking `node:fs`: the whole point of
|
|
10
|
+
// `safeReadJsonObjectFile` is how it reacts to real stat/readFile outcomes (missing path, directory,
|
|
11
|
+
// symlink, unreadable file), so mocking those away would only assert the mock back to itself.
|
|
12
|
+
const FIXTURE_DIR = fileURLToPath(new URL('../../../fixtures/bin/utils/files/', import.meta.url));
|
|
13
|
+
|
|
14
|
+
const fixture = (name: string) => path.join(FIXTURE_DIR, name);
|
|
15
|
+
|
|
16
|
+
const NESTED_FIXTURE = {
|
|
17
|
+
storages: { datasets: { default: { title: 'Default' } } },
|
|
18
|
+
overrideActorContext: ['../shared', '.'],
|
|
19
|
+
changelog: null,
|
|
20
|
+
nested: [{ deep: [1, 2, { deeper: true }] }],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
describe('safeReadJsonObjectFile', () => {
|
|
24
|
+
describe('valid JSON objects', () => {
|
|
25
|
+
it('returns the parsed contents, preserving nested objects, arrays and null values', () => {
|
|
26
|
+
const result = safeReadJsonObjectFile(fixture('nested.json'));
|
|
27
|
+
|
|
28
|
+
expect(result).toStrictEqual({ success: true, contents: NESTED_FIXTURE });
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('accepts an empty JSON object', () => {
|
|
32
|
+
const result = safeReadJsonObjectFile(fixture('empty-object.json'));
|
|
33
|
+
|
|
34
|
+
expect(result).toStrictEqual({ success: true, contents: {} });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('reads files that are not named *.json', () => {
|
|
38
|
+
const result = safeReadJsonObjectFile(fixture('no-json-extension.actorrc'));
|
|
39
|
+
|
|
40
|
+
expect(result).toStrictEqual({ success: true, contents: { a: 1 } });
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('filesystem-level handling', () => {
|
|
45
|
+
it('fails when the path does not exist', () => {
|
|
46
|
+
const filePath = fixture('does-not-exist.json');
|
|
47
|
+
|
|
48
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
49
|
+
|
|
50
|
+
expect(result).toMatchObject({
|
|
51
|
+
success: false,
|
|
52
|
+
reason: 'unreadable',
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// The fixture is named `directory.json` on purpose — the check is `stat().isFile()`, not the extension.
|
|
57
|
+
it('fails when the path is a directory', () => {
|
|
58
|
+
const filePath = fixture('directory.json');
|
|
59
|
+
|
|
60
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
61
|
+
|
|
62
|
+
expect(result).toMatchObject({
|
|
63
|
+
success: false,
|
|
64
|
+
reason: 'not-a-file',
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Regression guard: `lstat` would report the link itself as "not a file" and reject it, even
|
|
69
|
+
// though `readFile` follows symlinks and would have read the target without complaint.
|
|
70
|
+
it('follows a symlink to its target file', () => {
|
|
71
|
+
const result = safeReadJsonObjectFile(fixture('symlink-to-valid.json'));
|
|
72
|
+
|
|
73
|
+
expect(result).toStrictEqual({ success: true, contents: NESTED_FIXTURE });
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Git only tracks the executable bit, so this is the one case whose fixture cannot carry its own
|
|
77
|
+
// mode — `unreadable.json` is committed readable and stripped of permissions just for this test.
|
|
78
|
+
describe('unreadable file', () => {
|
|
79
|
+
const filePath = fixture('unreadable.json');
|
|
80
|
+
|
|
81
|
+
afterEach(async () => fs.chmod(filePath, 0o644));
|
|
82
|
+
|
|
83
|
+
it.runIf(process.getuid?.() !== 0)('fails when the file exists but cannot be read', async () => {
|
|
84
|
+
await fs.chmod(filePath, 0o000);
|
|
85
|
+
|
|
86
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
87
|
+
|
|
88
|
+
expect(result).toMatchObject({
|
|
89
|
+
success: false,
|
|
90
|
+
reason: 'unreadable',
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('JSON that is not an object', () => {
|
|
97
|
+
it('rejects a JSON array', () => {
|
|
98
|
+
const filePath = fixture('array.json');
|
|
99
|
+
|
|
100
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
101
|
+
|
|
102
|
+
expect(result).toMatchObject({
|
|
103
|
+
success: false,
|
|
104
|
+
reason: 'not-an-object',
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('rejects JSON null', () => {
|
|
109
|
+
const filePath = fixture('null.json');
|
|
110
|
+
|
|
111
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
112
|
+
|
|
113
|
+
expect(result).toMatchObject({
|
|
114
|
+
success: false,
|
|
115
|
+
reason: 'not-an-object',
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('rejects a JSON primitive', () => {
|
|
120
|
+
const filePath = fixture('number.json');
|
|
121
|
+
|
|
122
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
123
|
+
|
|
124
|
+
expect(result).toMatchObject({
|
|
125
|
+
success: false,
|
|
126
|
+
reason: 'not-an-object',
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('unparseable files', () => {
|
|
132
|
+
it('fails on malformed JSON', () => {
|
|
133
|
+
const filePath = fixture('malformed.json');
|
|
134
|
+
|
|
135
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
136
|
+
|
|
137
|
+
expect(result).toMatchObject({ success: false, reason: 'invalid-json' });
|
|
138
|
+
expect((result as { failure: Error }).failure.message).toContain(`Failed to parse ${filePath}`);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('fails on an empty file', () => {
|
|
142
|
+
const filePath = fixture('empty.json');
|
|
143
|
+
|
|
144
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
145
|
+
|
|
146
|
+
expect(result).toMatchObject({ success: false, reason: 'invalid-json' });
|
|
147
|
+
expect((result as { failure: Error }).failure.message).toContain(`Failed to parse ${filePath}`);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it.fails('reads jsonc', () => {
|
|
151
|
+
const filePath = fixture('comments.jsonc');
|
|
152
|
+
|
|
153
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
154
|
+
|
|
155
|
+
expect(result).toMatchObject({ success: true, contents: { a: 3 } });
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../../../test/unit/bin/utils.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { CONFIG_FILE_NAME, readConfigFile } from '../../../bin/utils.js';
|
|
3
|
-
const { fsMock } = vi.hoisted(() => ({
|
|
4
|
-
fsMock: {
|
|
5
|
-
readFile: vi.fn(),
|
|
6
|
-
},
|
|
7
|
-
}));
|
|
8
|
-
vi.mock('node:fs/promises', () => ({ default: fsMock }));
|
|
9
|
-
afterEach(() => vi.restoreAllMocks());
|
|
10
|
-
const emptyActorSelection = { actors: [], ignore: [] };
|
|
11
|
-
const validConfig = (actors) => JSON.stringify({ actors });
|
|
12
|
-
const actorJson = (fields = {}) => JSON.stringify(fields);
|
|
13
|
-
const expectFileRead = (filePath) => {
|
|
14
|
-
expect(fsMock.readFile).toHaveBeenCalledWith(filePath, expect.anything());
|
|
15
|
-
};
|
|
16
|
-
const mockFiles = (files) => {
|
|
17
|
-
fsMock.readFile.mockImplementation(async (filePath) => {
|
|
18
|
-
if (filePath in files)
|
|
19
|
-
return Promise.resolve(files[filePath]);
|
|
20
|
-
return Promise.reject(new Error(`ENOENT: ${filePath}`));
|
|
21
|
-
});
|
|
22
|
-
};
|
|
23
|
-
describe('readConfigFile', () => {
|
|
24
|
-
it('returns correct ActorConfig[] for a valid config', async () => {
|
|
25
|
-
mockFiles({
|
|
26
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
27
|
-
{
|
|
28
|
-
folder: 'actors/shopify',
|
|
29
|
-
actorFullName: 'myteam/shopify-scraper',
|
|
30
|
-
tokenEnvVar: 'APIFY_TOKEN_MYTEAM',
|
|
31
|
-
},
|
|
32
|
-
]),
|
|
33
|
-
'actors/shopify/.actor/actor.json': actorJson({ dockerContextDir: '../../..' }),
|
|
34
|
-
});
|
|
35
|
-
const result = await readConfigFile(emptyActorSelection);
|
|
36
|
-
expectFileRead('actors/shopify/.actor/actor.json');
|
|
37
|
-
expect(result).toEqual([
|
|
38
|
-
{
|
|
39
|
-
actorFullName: 'myteam/shopify-scraper',
|
|
40
|
-
folder: 'actors/shopify',
|
|
41
|
-
tokenEnvVar: 'APIFY_TOKEN_MYTEAM',
|
|
42
|
-
dockerContextDir: '',
|
|
43
|
-
contextPaths: [''],
|
|
44
|
-
},
|
|
45
|
-
]);
|
|
46
|
-
});
|
|
47
|
-
it('normalizes folder "." to ""', async () => {
|
|
48
|
-
mockFiles({
|
|
49
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
50
|
-
{ folder: '.', actorFullName: 'apify/my-actor', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
51
|
-
]),
|
|
52
|
-
'.actor/actor.json': actorJson({}),
|
|
53
|
-
});
|
|
54
|
-
const result = await readConfigFile(emptyActorSelection);
|
|
55
|
-
expect(result[0].folder).toBe('');
|
|
56
|
-
expectFileRead('.actor/actor.json');
|
|
57
|
-
});
|
|
58
|
-
it('defaults dockerContextDir to actor folder when absent from actor.json', async () => {
|
|
59
|
-
mockFiles({
|
|
60
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
61
|
-
{ folder: 'actors/web-scraper', actorFullName: 'apify/web-scraper', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
62
|
-
]),
|
|
63
|
-
'actors/web-scraper/.actor/actor.json': actorJson({}),
|
|
64
|
-
});
|
|
65
|
-
const result = await readConfigFile(emptyActorSelection);
|
|
66
|
-
expect(result[0].dockerContextDir).toBe('actors/web-scraper');
|
|
67
|
-
expect(result[0].contextPaths).toEqual(['actors/web-scraper']);
|
|
68
|
-
});
|
|
69
|
-
it('resolves dockerContextDir relative to .actor/ folder', async () => {
|
|
70
|
-
mockFiles({
|
|
71
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
72
|
-
{ folder: 'actors/shopify', actorFullName: 'myteam/shopify', tokenEnvVar: 'APIFY_TOKEN' },
|
|
73
|
-
]),
|
|
74
|
-
'actors/shopify/.actor/actor.json': actorJson({ dockerContextDir: '../../..' }),
|
|
75
|
-
});
|
|
76
|
-
const result = await readConfigFile(emptyActorSelection);
|
|
77
|
-
expect(result[0].dockerContextDir).toBe('');
|
|
78
|
-
});
|
|
79
|
-
it('resolves contextPaths from overrideActorContext', async () => {
|
|
80
|
-
mockFiles({
|
|
81
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
82
|
-
{
|
|
83
|
-
folder: 'actors/shopify',
|
|
84
|
-
actorFullName: 'myteam/shopify',
|
|
85
|
-
tokenEnvVar: 'APIFY_TOKEN',
|
|
86
|
-
overrideActorContext: ['actors/shopify', 'packages'],
|
|
87
|
-
},
|
|
88
|
-
]),
|
|
89
|
-
'actors/shopify/.actor/actor.json': actorJson({ dockerContextDir: '../../..' }),
|
|
90
|
-
});
|
|
91
|
-
const result = await readConfigFile(emptyActorSelection);
|
|
92
|
-
expect(result[0].contextPaths).toEqual(['actors/shopify', 'packages']);
|
|
93
|
-
});
|
|
94
|
-
it('handles multiple actors', async () => {
|
|
95
|
-
mockFiles({
|
|
96
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
97
|
-
{ folder: 'actors/web-scraper', actorFullName: 'apify/web-scraper', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
98
|
-
{
|
|
99
|
-
folder: 'actors/email-sender',
|
|
100
|
-
actorFullName: 'other-team/email-sender',
|
|
101
|
-
tokenEnvVar: 'APIFY_TOKEN_OTHER_TEAM',
|
|
102
|
-
},
|
|
103
|
-
]),
|
|
104
|
-
'actors/web-scraper/.actor/actor.json': actorJson({}),
|
|
105
|
-
'actors/email-sender/.actor/actor.json': actorJson({}),
|
|
106
|
-
});
|
|
107
|
-
const result = await readConfigFile(emptyActorSelection);
|
|
108
|
-
expect(result).toHaveLength(2);
|
|
109
|
-
expect(result[0].actorFullName).toBe('apify/web-scraper');
|
|
110
|
-
expect(result[1].actorFullName).toBe('other-team/email-sender');
|
|
111
|
-
});
|
|
112
|
-
it('throws when config file is missing', async () => {
|
|
113
|
-
fsMock.readFile.mockRejectedValue(new Error('ENOENT'));
|
|
114
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('not found');
|
|
115
|
-
});
|
|
116
|
-
it('throws when config file contains invalid JSON', async () => {
|
|
117
|
-
fsMock.readFile.mockResolvedValue('{bad json');
|
|
118
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('invalid JSON');
|
|
119
|
-
});
|
|
120
|
-
it('throws when actors array is missing', async () => {
|
|
121
|
-
fsMock.readFile.mockResolvedValue(JSON.stringify({ notActors: [] }));
|
|
122
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('"actors" array');
|
|
123
|
-
});
|
|
124
|
-
it('throws on duplicate folders', async () => {
|
|
125
|
-
mockFiles({
|
|
126
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
127
|
-
{ folder: 'actors/shopify', actorFullName: 'apify/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
128
|
-
{ folder: 'actors/shopify', actorFullName: 'other/shopify', tokenEnvVar: 'APIFY_TOKEN_OTHER' },
|
|
129
|
-
]),
|
|
130
|
-
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
131
|
-
});
|
|
132
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Duplicate folder');
|
|
133
|
-
});
|
|
134
|
-
it('throws on duplicate folders after normalization ("." and "")', async () => {
|
|
135
|
-
mockFiles({
|
|
136
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
137
|
-
{ folder: '.', actorFullName: 'apify/actor-a', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
138
|
-
{ folder: '', actorFullName: 'other/actor-b', tokenEnvVar: 'APIFY_TOKEN_OTHER' },
|
|
139
|
-
]),
|
|
140
|
-
'.actor/actor.json': actorJson({}),
|
|
141
|
-
});
|
|
142
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Duplicate folder');
|
|
143
|
-
});
|
|
144
|
-
it('throws when actor.json is missing', async () => {
|
|
145
|
-
mockFiles({
|
|
146
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
147
|
-
{ folder: 'actors/shopify', actorFullName: 'apify/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
148
|
-
]),
|
|
149
|
-
});
|
|
150
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Cannot read');
|
|
151
|
-
});
|
|
152
|
-
it('throws when folder is missing', async () => {
|
|
153
|
-
mockFiles({
|
|
154
|
-
[CONFIG_FILE_NAME]: validConfig([{ actorFullName: 'apify/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' }]),
|
|
155
|
-
});
|
|
156
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/Invalid "folder"/);
|
|
157
|
-
});
|
|
158
|
-
it('throws when folder is not a string', async () => {
|
|
159
|
-
mockFiles({
|
|
160
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
161
|
-
{ folder: 123, actorFullName: 'apify/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
162
|
-
]),
|
|
163
|
-
});
|
|
164
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/Invalid "folder"/);
|
|
165
|
-
});
|
|
166
|
-
it('throws when actorFullName is missing', async () => {
|
|
167
|
-
mockFiles({
|
|
168
|
-
[CONFIG_FILE_NAME]: validConfig([{ folder: 'actors/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' }]),
|
|
169
|
-
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
170
|
-
});
|
|
171
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "actorFullName"');
|
|
172
|
-
});
|
|
173
|
-
it('throws when actorFullName has no slash', async () => {
|
|
174
|
-
mockFiles({
|
|
175
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
176
|
-
{ folder: 'actors/shopify', actorFullName: 'shopify-scraper', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
177
|
-
]),
|
|
178
|
-
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
179
|
-
});
|
|
180
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "actorFullName"');
|
|
181
|
-
});
|
|
182
|
-
it('throws when actorFullName has empty parts', async () => {
|
|
183
|
-
mockFiles({
|
|
184
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
185
|
-
{ folder: 'actors/shopify', actorFullName: '/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
186
|
-
]),
|
|
187
|
-
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
188
|
-
});
|
|
189
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "actorFullName"');
|
|
190
|
-
});
|
|
191
|
-
it('throws when overrideActorContext is not an array', async () => {
|
|
192
|
-
mockFiles({
|
|
193
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
194
|
-
{
|
|
195
|
-
folder: 'actors/shopify',
|
|
196
|
-
actorFullName: 'myteam/shopify',
|
|
197
|
-
tokenEnvVar: 'APIFY_TOKEN',
|
|
198
|
-
overrideActorContext: 'packages',
|
|
199
|
-
},
|
|
200
|
-
]),
|
|
201
|
-
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
202
|
-
});
|
|
203
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "overrideActorContext"');
|
|
204
|
-
});
|
|
205
|
-
it('throws when overrideActorContext contains non-strings', async () => {
|
|
206
|
-
mockFiles({
|
|
207
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
208
|
-
{
|
|
209
|
-
folder: 'actors/shopify',
|
|
210
|
-
actorFullName: 'myteam/shopify',
|
|
211
|
-
tokenEnvVar: 'APIFY_TOKEN',
|
|
212
|
-
overrideActorContext: [123],
|
|
213
|
-
},
|
|
214
|
-
]),
|
|
215
|
-
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
216
|
-
});
|
|
217
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "overrideActorContext"');
|
|
218
|
-
});
|
|
219
|
-
it('throws when overrideActorContext entries overlap (one is a prefix of another)', async () => {
|
|
220
|
-
mockFiles({
|
|
221
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
222
|
-
{
|
|
223
|
-
folder: 'actors/shopify',
|
|
224
|
-
actorFullName: 'myteam/shopify',
|
|
225
|
-
tokenEnvVar: 'APIFY_TOKEN',
|
|
226
|
-
overrideActorContext: ['actors/shopify', 'actors'],
|
|
227
|
-
},
|
|
228
|
-
]),
|
|
229
|
-
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
230
|
-
});
|
|
231
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/overlap/);
|
|
232
|
-
});
|
|
233
|
-
it('throws when overrideActorContext contains the repo root alongside another entry', async () => {
|
|
234
|
-
mockFiles({
|
|
235
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
236
|
-
{
|
|
237
|
-
folder: 'actors/shopify',
|
|
238
|
-
actorFullName: 'myteam/shopify',
|
|
239
|
-
tokenEnvVar: 'APIFY_TOKEN',
|
|
240
|
-
overrideActorContext: ['', 'actors/shopify'],
|
|
241
|
-
},
|
|
242
|
-
]),
|
|
243
|
-
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
244
|
-
});
|
|
245
|
-
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/overlap/);
|
|
246
|
-
});
|
|
247
|
-
it('adds the actor own folder automatically when overrideActorContext does not cover it', async () => {
|
|
248
|
-
mockFiles({
|
|
249
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
250
|
-
{
|
|
251
|
-
folder: 'actors/shopify',
|
|
252
|
-
actorFullName: 'myteam/shopify',
|
|
253
|
-
tokenEnvVar: 'APIFY_TOKEN',
|
|
254
|
-
overrideActorContext: ['code', 'shared'],
|
|
255
|
-
},
|
|
256
|
-
]),
|
|
257
|
-
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
258
|
-
});
|
|
259
|
-
const result = await readConfigFile(emptyActorSelection);
|
|
260
|
-
expect(result[0].contextPaths).toEqual(['code', 'shared', 'actors/shopify']);
|
|
261
|
-
});
|
|
262
|
-
it('strips trailing slashes from folder and overrideActorContext entries', async () => {
|
|
263
|
-
mockFiles({
|
|
264
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
265
|
-
{
|
|
266
|
-
folder: 'actors/shopify/',
|
|
267
|
-
actorFullName: 'myteam/shopify',
|
|
268
|
-
tokenEnvVar: 'APIFY_TOKEN',
|
|
269
|
-
overrideActorContext: ['actors/shopify/', 'packages/'],
|
|
270
|
-
},
|
|
271
|
-
]),
|
|
272
|
-
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
273
|
-
});
|
|
274
|
-
const result = await readConfigFile(emptyActorSelection);
|
|
275
|
-
expect(result[0].folder).toBe('actors/shopify');
|
|
276
|
-
expect(result[0].contextPaths).toEqual(['actors/shopify', 'packages']);
|
|
277
|
-
});
|
|
278
|
-
it('allows overrideActorContext with disjoint sibling paths that all reach the actor folder via one entry', async () => {
|
|
279
|
-
mockFiles({
|
|
280
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
281
|
-
{
|
|
282
|
-
folder: 'actors/shopify',
|
|
283
|
-
actorFullName: 'myteam/shopify',
|
|
284
|
-
tokenEnvVar: 'APIFY_TOKEN',
|
|
285
|
-
overrideActorContext: ['actors/shopify', 'code', 'shared'],
|
|
286
|
-
},
|
|
287
|
-
]),
|
|
288
|
-
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
289
|
-
});
|
|
290
|
-
const result = await readConfigFile(emptyActorSelection);
|
|
291
|
-
expect(result[0].contextPaths).toEqual(['actors/shopify', 'code', 'shared']);
|
|
292
|
-
});
|
|
293
|
-
describe('actor selection', () => {
|
|
294
|
-
const twoActors = () => mockFiles({
|
|
295
|
-
[CONFIG_FILE_NAME]: validConfig([
|
|
296
|
-
{ folder: 'actors/a', actorFullName: 'team/a', tokenEnvVar: 'TOKEN' },
|
|
297
|
-
{ folder: 'actors/b', actorFullName: 'team/b', tokenEnvVar: 'TOKEN' },
|
|
298
|
-
]),
|
|
299
|
-
'actors/a/.actor/actor.json': actorJson({}),
|
|
300
|
-
'actors/b/.actor/actor.json': actorJson({}),
|
|
301
|
-
});
|
|
302
|
-
const fullNames = (result) => result.map((c) => c.actorFullName);
|
|
303
|
-
it('returns all actors when the selection is empty', async () => {
|
|
304
|
-
twoActors();
|
|
305
|
-
expect(fullNames(await readConfigFile(emptyActorSelection))).toEqual(['team/a', 'team/b']);
|
|
306
|
-
});
|
|
307
|
-
it('keeps only the selected actors', async () => {
|
|
308
|
-
twoActors();
|
|
309
|
-
expect(fullNames(await readConfigFile({ actors: ['team/a'], ignore: [] }))).toEqual(['team/a']);
|
|
310
|
-
});
|
|
311
|
-
it('drops ignored actors', async () => {
|
|
312
|
-
twoActors();
|
|
313
|
-
expect(fullNames(await readConfigFile({ actors: [], ignore: ['team/a'] }))).toEqual(['team/b']);
|
|
314
|
-
});
|
|
315
|
-
it('throws on an unknown actor name', async () => {
|
|
316
|
-
twoActors();
|
|
317
|
-
await expect(readConfigFile({ actors: ['team/nope'], ignore: [] })).rejects.toThrow('do not exist: team/nope');
|
|
318
|
-
});
|
|
319
|
-
});
|
|
320
|
-
});
|
|
321
|
-
//# sourceMappingURL=utils.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../../../test/unit/bin/utils.test.ts"],"names":[],"mappings":"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"}
|