apify-test-tools 0.9.1-beta.3 → 0.9.1-beta.5
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/.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 +251 -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 +44 -0
- package/dist/bin/utils/config/load-config.d.ts.map +1 -0
- package/dist/bin/utils/config/load-config.js +177 -0
- package/dist/bin/utils/config/load-config.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/lib/consts.d.ts +1 -0
- package/dist/lib/consts.d.ts.map +1 -1
- package/dist/lib/consts.js +3 -0
- package/dist/lib/consts.js.map +1 -1
- package/dist/lib/lib.d.ts +4 -0
- package/dist/lib/lib.d.ts.map +1 -1
- package/dist/lib/lib.js +12 -16
- package/dist/lib/lib.js.map +1 -1
- package/dist/lib/types.d.ts +11 -3
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/test/unit/bin/utils/actor-config.test.d.ts +2 -0
- package/dist/test/unit/bin/utils/actor-config.test.d.ts.map +1 -0
- package/dist/test/unit/bin/{utils.test.js → utils/actor-config.test.js} +126 -51
- package/dist/test/unit/bin/utils/actor-config.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/test/unit/lib.test.d.ts +2 -0
- package/dist/test/unit/lib.test.d.ts.map +1 -0
- package/dist/test/unit/lib.test.js +37 -0
- package/dist/test/unit/lib.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/lib/consts.ts +4 -0
- package/lib/lib.ts +20 -18
- package/lib/types.ts +11 -3
- 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.test.ts → utils/actor-config.test.ts} +152 -52
- package/test/unit/bin/utils/files.test.ts +158 -0
- package/test/unit/lib.test.ts +53 -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.map +0 -1
package/dist/lib/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAErD,MAAM,MAAM,UAAU,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI;IACxB,KAAK,EAAE,IAAI,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actor-config.test.d.ts","sourceRoot":"","sources":["../../../../../test/unit/bin/utils/actor-config.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,28 +1,76 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { CONFIG_FILE_NAME, loadActorConfig, parseConfigFile, readConfigFile, resolveRawConfig, } from '../../../../bin/utils/config/load-config.js';
|
|
6
|
+
// `readConfigFile` resolves every path against the process's working directory, so these tests give it
|
|
7
|
+
// a real one: a throwaway repo in a temp dir. Reading actual files rather than a mocked
|
|
8
|
+
// `node:fs/promises` is what makes the path handling (the ".actor/" hop, a dockerContextDir escaping
|
|
9
|
+
// the repo root) worth asserting on — against a mock those assertions only describe the mock.
|
|
10
|
+
let repoDir;
|
|
11
|
+
let originalCwd;
|
|
12
|
+
beforeEach(async () => {
|
|
13
|
+
originalCwd = process.cwd();
|
|
14
|
+
// `realpath` because macOS hands out a symlinked temp dir, while `process.cwd()` reports the target.
|
|
15
|
+
repoDir = await fs.realpath(await fs.mkdtemp(path.join(os.tmpdir(), 'apify-test-tools-config-')));
|
|
16
|
+
process.chdir(repoDir);
|
|
17
|
+
});
|
|
18
|
+
afterEach(async () => {
|
|
19
|
+
process.chdir(originalCwd);
|
|
20
|
+
await fs.rm(repoDir, { recursive: true, force: true });
|
|
21
|
+
});
|
|
10
22
|
const emptyActorSelection = { actors: [], ignore: [] };
|
|
11
23
|
const validConfig = (actors) => JSON.stringify({ actors });
|
|
12
24
|
const actorJson = (fields = {}) => JSON.stringify(fields);
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
25
|
+
const writeFiles = async (files) => Promise.all(Object.entries(files).map(async ([filePath, contents]) => {
|
|
26
|
+
const absPath = path.join(repoDir, filePath);
|
|
27
|
+
await fs.mkdir(path.dirname(absPath), { recursive: true });
|
|
28
|
+
await fs.writeFile(absPath, contents);
|
|
29
|
+
}));
|
|
30
|
+
// Stages 2-4 are callable on their own, which is the point: a differently shaped config file only
|
|
31
|
+
// has to reach `resolveRawConfig`'s output to work with everything downstream.
|
|
32
|
+
describe('the parse/resolve/load seam', () => {
|
|
33
|
+
it('parseConfigFile validates the file shape without touching the filesystem', () => {
|
|
34
|
+
const entry = { folder: 'actors/shopify', actorFullName: 'myteam/shopify', tokenEnvVar: 'APIFY_TOKEN' };
|
|
35
|
+
expect(parseConfigFile({ actors: [entry] })).toEqual({ actors: [entry] });
|
|
36
|
+
expect(() => parseConfigFile({ actors: [{ ...entry, folder: 123 }] })).toThrow(/Invalid "folder"/);
|
|
37
|
+
});
|
|
38
|
+
it('resolveRawConfig is where the repo root becomes "" and trailing slashes go', () => {
|
|
39
|
+
const result = resolveRawConfig({
|
|
40
|
+
actors: [
|
|
41
|
+
{ folder: '.', actorFullName: 'myteam/root', tokenEnvVar: 'APIFY_TOKEN' },
|
|
42
|
+
{
|
|
43
|
+
folder: 'actors/shopify/',
|
|
44
|
+
actorFullName: 'myteam/shopify',
|
|
45
|
+
tokenEnvVar: 'APIFY_TOKEN',
|
|
46
|
+
overrideActorContext: ['packages/'],
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
expect(result).toEqual([
|
|
51
|
+
{ folder: '', actorFullName: 'myteam/root', tokenEnvVar: 'APIFY_TOKEN', overrideActorContext: undefined },
|
|
52
|
+
{
|
|
53
|
+
folder: 'actors/shopify',
|
|
54
|
+
actorFullName: 'myteam/shopify',
|
|
55
|
+
tokenEnvVar: 'APIFY_TOKEN',
|
|
56
|
+
overrideActorContext: ['packages'],
|
|
57
|
+
},
|
|
58
|
+
]);
|
|
59
|
+
});
|
|
60
|
+
it('loadActorConfig resolves data coming from actor.json', async () => {
|
|
61
|
+
await writeFiles({ 'actors/shopify/.actor/actor.json': actorJson({ dockerContextDir: '..' }) });
|
|
62
|
+
expect(loadActorConfig({ folder: 'actors/shopify', actorFullName: 'myteam/shopify', tokenEnvVar: 'APIFY_TOKEN' })).toEqual({
|
|
63
|
+
actorFullName: 'myteam/shopify',
|
|
64
|
+
folder: 'actors/shopify',
|
|
65
|
+
tokenEnvVar: 'APIFY_TOKEN',
|
|
66
|
+
dockerContextDir: 'actors/shopify',
|
|
67
|
+
contextPaths: ['actors/shopify'],
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
23
71
|
describe('readConfigFile', () => {
|
|
24
72
|
it('returns correct ActorConfig[] for a valid config', async () => {
|
|
25
|
-
|
|
73
|
+
await writeFiles({
|
|
26
74
|
[CONFIG_FILE_NAME]: validConfig([
|
|
27
75
|
{
|
|
28
76
|
folder: 'actors/shopify',
|
|
@@ -33,7 +81,6 @@ describe('readConfigFile', () => {
|
|
|
33
81
|
'actors/shopify/.actor/actor.json': actorJson({ dockerContextDir: '../../..' }),
|
|
34
82
|
});
|
|
35
83
|
const result = await readConfigFile(emptyActorSelection);
|
|
36
|
-
expectFileRead('actors/shopify/.actor/actor.json');
|
|
37
84
|
expect(result).toEqual([
|
|
38
85
|
{
|
|
39
86
|
actorFullName: 'myteam/shopify-scraper',
|
|
@@ -45,7 +92,7 @@ describe('readConfigFile', () => {
|
|
|
45
92
|
]);
|
|
46
93
|
});
|
|
47
94
|
it('normalizes folder "." to ""', async () => {
|
|
48
|
-
|
|
95
|
+
await writeFiles({
|
|
49
96
|
[CONFIG_FILE_NAME]: validConfig([
|
|
50
97
|
{ folder: '.', actorFullName: 'apify/my-actor', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
51
98
|
]),
|
|
@@ -53,10 +100,9 @@ describe('readConfigFile', () => {
|
|
|
53
100
|
});
|
|
54
101
|
const result = await readConfigFile(emptyActorSelection);
|
|
55
102
|
expect(result[0].folder).toBe('');
|
|
56
|
-
expectFileRead('.actor/actor.json');
|
|
57
103
|
});
|
|
58
104
|
it('defaults dockerContextDir to actor folder when absent from actor.json', async () => {
|
|
59
|
-
|
|
105
|
+
await writeFiles({
|
|
60
106
|
[CONFIG_FILE_NAME]: validConfig([
|
|
61
107
|
{ folder: 'actors/web-scraper', actorFullName: 'apify/web-scraper', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
62
108
|
]),
|
|
@@ -67,7 +113,7 @@ describe('readConfigFile', () => {
|
|
|
67
113
|
expect(result[0].contextPaths).toEqual(['actors/web-scraper']);
|
|
68
114
|
});
|
|
69
115
|
it('resolves dockerContextDir relative to .actor/ folder', async () => {
|
|
70
|
-
|
|
116
|
+
await writeFiles({
|
|
71
117
|
[CONFIG_FILE_NAME]: validConfig([
|
|
72
118
|
{ folder: 'actors/shopify', actorFullName: 'myteam/shopify', tokenEnvVar: 'APIFY_TOKEN' },
|
|
73
119
|
]),
|
|
@@ -76,8 +122,17 @@ describe('readConfigFile', () => {
|
|
|
76
122
|
const result = await readConfigFile(emptyActorSelection);
|
|
77
123
|
expect(result[0].dockerContextDir).toBe('');
|
|
78
124
|
});
|
|
125
|
+
it('throws when dockerContextDir resolves outside the repository root', async () => {
|
|
126
|
+
await writeFiles({
|
|
127
|
+
[CONFIG_FILE_NAME]: validConfig([
|
|
128
|
+
{ folder: 'actors/shopify', actorFullName: 'myteam/shopify', tokenEnvVar: 'APIFY_TOKEN' },
|
|
129
|
+
]),
|
|
130
|
+
'actors/shopify/.actor/actor.json': actorJson({ dockerContextDir: '../../../..' }),
|
|
131
|
+
});
|
|
132
|
+
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/resolves outside the repository root/);
|
|
133
|
+
});
|
|
79
134
|
it('resolves contextPaths from overrideActorContext', async () => {
|
|
80
|
-
|
|
135
|
+
await writeFiles({
|
|
81
136
|
[CONFIG_FILE_NAME]: validConfig([
|
|
82
137
|
{
|
|
83
138
|
folder: 'actors/shopify',
|
|
@@ -92,7 +147,7 @@ describe('readConfigFile', () => {
|
|
|
92
147
|
expect(result[0].contextPaths).toEqual(['actors/shopify', 'packages']);
|
|
93
148
|
});
|
|
94
149
|
it('handles multiple actors', async () => {
|
|
95
|
-
|
|
150
|
+
await writeFiles({
|
|
96
151
|
[CONFIG_FILE_NAME]: validConfig([
|
|
97
152
|
{ folder: 'actors/web-scraper', actorFullName: 'apify/web-scraper', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
98
153
|
{
|
|
@@ -110,19 +165,22 @@ describe('readConfigFile', () => {
|
|
|
110
165
|
expect(result[1].actorFullName).toBe('other-team/email-sender');
|
|
111
166
|
});
|
|
112
167
|
it('throws when config file is missing', async () => {
|
|
113
|
-
fsMock.readFile.mockRejectedValue(new Error('ENOENT'));
|
|
114
168
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('not found');
|
|
115
169
|
});
|
|
116
170
|
it('throws when config file contains invalid JSON', async () => {
|
|
117
|
-
|
|
171
|
+
await writeFiles({ [CONFIG_FILE_NAME]: '{bad json' });
|
|
118
172
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('invalid JSON');
|
|
119
173
|
});
|
|
120
174
|
it('throws when actors array is missing', async () => {
|
|
121
|
-
|
|
175
|
+
await writeFiles({ [CONFIG_FILE_NAME]: JSON.stringify({ notActors: [] }) });
|
|
176
|
+
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('"actors" array');
|
|
177
|
+
});
|
|
178
|
+
it('throws when the config file is not a JSON object', async () => {
|
|
179
|
+
await writeFiles({ [CONFIG_FILE_NAME]: JSON.stringify([{ folder: 'actors/shopify' }]) });
|
|
122
180
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('"actors" array');
|
|
123
181
|
});
|
|
124
182
|
it('throws on duplicate folders', async () => {
|
|
125
|
-
|
|
183
|
+
await writeFiles({
|
|
126
184
|
[CONFIG_FILE_NAME]: validConfig([
|
|
127
185
|
{ folder: 'actors/shopify', actorFullName: 'apify/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
128
186
|
{ folder: 'actors/shopify', actorFullName: 'other/shopify', tokenEnvVar: 'APIFY_TOKEN_OTHER' },
|
|
@@ -132,7 +190,7 @@ describe('readConfigFile', () => {
|
|
|
132
190
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Duplicate folder');
|
|
133
191
|
});
|
|
134
192
|
it('throws on duplicate folders after normalization ("." and "")', async () => {
|
|
135
|
-
|
|
193
|
+
await writeFiles({
|
|
136
194
|
[CONFIG_FILE_NAME]: validConfig([
|
|
137
195
|
{ folder: '.', actorFullName: 'apify/actor-a', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
138
196
|
{ folder: '', actorFullName: 'other/actor-b', tokenEnvVar: 'APIFY_TOKEN_OTHER' },
|
|
@@ -142,7 +200,7 @@ describe('readConfigFile', () => {
|
|
|
142
200
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Duplicate folder');
|
|
143
201
|
});
|
|
144
202
|
it('throws when actor.json is missing', async () => {
|
|
145
|
-
|
|
203
|
+
await writeFiles({
|
|
146
204
|
[CONFIG_FILE_NAME]: validConfig([
|
|
147
205
|
{ folder: 'actors/shopify', actorFullName: 'apify/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
148
206
|
]),
|
|
@@ -150,13 +208,13 @@ describe('readConfigFile', () => {
|
|
|
150
208
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Cannot read');
|
|
151
209
|
});
|
|
152
210
|
it('throws when folder is missing', async () => {
|
|
153
|
-
|
|
211
|
+
await writeFiles({
|
|
154
212
|
[CONFIG_FILE_NAME]: validConfig([{ actorFullName: 'apify/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' }]),
|
|
155
213
|
});
|
|
156
214
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/Invalid "folder"/);
|
|
157
215
|
});
|
|
158
216
|
it('throws when folder is not a string', async () => {
|
|
159
|
-
|
|
217
|
+
await writeFiles({
|
|
160
218
|
[CONFIG_FILE_NAME]: validConfig([
|
|
161
219
|
{ folder: 123, actorFullName: 'apify/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
162
220
|
]),
|
|
@@ -164,14 +222,14 @@ describe('readConfigFile', () => {
|
|
|
164
222
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/Invalid "folder"/);
|
|
165
223
|
});
|
|
166
224
|
it('throws when actorFullName is missing', async () => {
|
|
167
|
-
|
|
225
|
+
await writeFiles({
|
|
168
226
|
[CONFIG_FILE_NAME]: validConfig([{ folder: 'actors/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' }]),
|
|
169
227
|
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
170
228
|
});
|
|
171
229
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "actorFullName"');
|
|
172
230
|
});
|
|
173
231
|
it('throws when actorFullName has no slash', async () => {
|
|
174
|
-
|
|
232
|
+
await writeFiles({
|
|
175
233
|
[CONFIG_FILE_NAME]: validConfig([
|
|
176
234
|
{ folder: 'actors/shopify', actorFullName: 'shopify-scraper', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
177
235
|
]),
|
|
@@ -180,7 +238,7 @@ describe('readConfigFile', () => {
|
|
|
180
238
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "actorFullName"');
|
|
181
239
|
});
|
|
182
240
|
it('throws when actorFullName has empty parts', async () => {
|
|
183
|
-
|
|
241
|
+
await writeFiles({
|
|
184
242
|
[CONFIG_FILE_NAME]: validConfig([
|
|
185
243
|
{ folder: 'actors/shopify', actorFullName: '/shopify', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
|
|
186
244
|
]),
|
|
@@ -188,8 +246,25 @@ describe('readConfigFile', () => {
|
|
|
188
246
|
});
|
|
189
247
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "actorFullName"');
|
|
190
248
|
});
|
|
249
|
+
it('throws when tokenEnvVar is missing', async () => {
|
|
250
|
+
await writeFiles({
|
|
251
|
+
[CONFIG_FILE_NAME]: validConfig([{ folder: 'actors/shopify', actorFullName: 'apify/shopify' }]),
|
|
252
|
+
'actors/shopify/.actor/actor.json': actorJson({}),
|
|
253
|
+
});
|
|
254
|
+
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "tokenEnvVar"');
|
|
255
|
+
});
|
|
256
|
+
it('reports every invalid field at once instead of only the first', async () => {
|
|
257
|
+
await writeFiles({
|
|
258
|
+
[CONFIG_FILE_NAME]: validConfig([{ folder: 123, actorFullName: 'shopify', overrideActorContext: 'nope' }]),
|
|
259
|
+
});
|
|
260
|
+
const promise = readConfigFile(emptyActorSelection);
|
|
261
|
+
await expect(promise).rejects.toThrow(/Invalid "folder"/);
|
|
262
|
+
await expect(promise).rejects.toThrow(/Invalid "actorFullName"/);
|
|
263
|
+
await expect(promise).rejects.toThrow(/Invalid "tokenEnvVar"/);
|
|
264
|
+
await expect(promise).rejects.toThrow(/Invalid "overrideActorContext"/);
|
|
265
|
+
});
|
|
191
266
|
it('throws when overrideActorContext is not an array', async () => {
|
|
192
|
-
|
|
267
|
+
await writeFiles({
|
|
193
268
|
[CONFIG_FILE_NAME]: validConfig([
|
|
194
269
|
{
|
|
195
270
|
folder: 'actors/shopify',
|
|
@@ -203,7 +278,7 @@ describe('readConfigFile', () => {
|
|
|
203
278
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "overrideActorContext"');
|
|
204
279
|
});
|
|
205
280
|
it('throws when overrideActorContext contains non-strings', async () => {
|
|
206
|
-
|
|
281
|
+
await writeFiles({
|
|
207
282
|
[CONFIG_FILE_NAME]: validConfig([
|
|
208
283
|
{
|
|
209
284
|
folder: 'actors/shopify',
|
|
@@ -217,7 +292,7 @@ describe('readConfigFile', () => {
|
|
|
217
292
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('Invalid "overrideActorContext"');
|
|
218
293
|
});
|
|
219
294
|
it('throws when overrideActorContext entries overlap (one is a prefix of another)', async () => {
|
|
220
|
-
|
|
295
|
+
await writeFiles({
|
|
221
296
|
[CONFIG_FILE_NAME]: validConfig([
|
|
222
297
|
{
|
|
223
298
|
folder: 'actors/shopify',
|
|
@@ -231,7 +306,7 @@ describe('readConfigFile', () => {
|
|
|
231
306
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/overlap/);
|
|
232
307
|
});
|
|
233
308
|
it('throws when overrideActorContext contains the repo root alongside another entry', async () => {
|
|
234
|
-
|
|
309
|
+
await writeFiles({
|
|
235
310
|
[CONFIG_FILE_NAME]: validConfig([
|
|
236
311
|
{
|
|
237
312
|
folder: 'actors/shopify',
|
|
@@ -245,7 +320,7 @@ describe('readConfigFile', () => {
|
|
|
245
320
|
await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/overlap/);
|
|
246
321
|
});
|
|
247
322
|
it('adds the actor own folder automatically when overrideActorContext does not cover it', async () => {
|
|
248
|
-
|
|
323
|
+
await writeFiles({
|
|
249
324
|
[CONFIG_FILE_NAME]: validConfig([
|
|
250
325
|
{
|
|
251
326
|
folder: 'actors/shopify',
|
|
@@ -260,7 +335,7 @@ describe('readConfigFile', () => {
|
|
|
260
335
|
expect(result[0].contextPaths).toEqual(['code', 'shared', 'actors/shopify']);
|
|
261
336
|
});
|
|
262
337
|
it('strips trailing slashes from folder and overrideActorContext entries', async () => {
|
|
263
|
-
|
|
338
|
+
await writeFiles({
|
|
264
339
|
[CONFIG_FILE_NAME]: validConfig([
|
|
265
340
|
{
|
|
266
341
|
folder: 'actors/shopify/',
|
|
@@ -276,7 +351,7 @@ describe('readConfigFile', () => {
|
|
|
276
351
|
expect(result[0].contextPaths).toEqual(['actors/shopify', 'packages']);
|
|
277
352
|
});
|
|
278
353
|
it('allows overrideActorContext with disjoint sibling paths that all reach the actor folder via one entry', async () => {
|
|
279
|
-
|
|
354
|
+
await writeFiles({
|
|
280
355
|
[CONFIG_FILE_NAME]: validConfig([
|
|
281
356
|
{
|
|
282
357
|
folder: 'actors/shopify',
|
|
@@ -291,7 +366,7 @@ describe('readConfigFile', () => {
|
|
|
291
366
|
expect(result[0].contextPaths).toEqual(['actors/shopify', 'code', 'shared']);
|
|
292
367
|
});
|
|
293
368
|
describe('actor selection', () => {
|
|
294
|
-
const twoActors = () =>
|
|
369
|
+
const twoActors = async () => writeFiles({
|
|
295
370
|
[CONFIG_FILE_NAME]: validConfig([
|
|
296
371
|
{ folder: 'actors/a', actorFullName: 'team/a', tokenEnvVar: 'TOKEN' },
|
|
297
372
|
{ folder: 'actors/b', actorFullName: 'team/b', tokenEnvVar: 'TOKEN' },
|
|
@@ -301,21 +376,21 @@ describe('readConfigFile', () => {
|
|
|
301
376
|
});
|
|
302
377
|
const fullNames = (result) => result.map((c) => c.actorFullName);
|
|
303
378
|
it('returns all actors when the selection is empty', async () => {
|
|
304
|
-
twoActors();
|
|
379
|
+
await twoActors();
|
|
305
380
|
expect(fullNames(await readConfigFile(emptyActorSelection))).toEqual(['team/a', 'team/b']);
|
|
306
381
|
});
|
|
307
382
|
it('keeps only the selected actors', async () => {
|
|
308
|
-
twoActors();
|
|
383
|
+
await twoActors();
|
|
309
384
|
expect(fullNames(await readConfigFile({ actors: ['team/a'], ignore: [] }))).toEqual(['team/a']);
|
|
310
385
|
});
|
|
311
386
|
it('drops ignored actors', async () => {
|
|
312
|
-
twoActors();
|
|
387
|
+
await twoActors();
|
|
313
388
|
expect(fullNames(await readConfigFile({ actors: [], ignore: ['team/a'] }))).toEqual(['team/b']);
|
|
314
389
|
});
|
|
315
390
|
it('throws on an unknown actor name', async () => {
|
|
316
|
-
twoActors();
|
|
391
|
+
await twoActors();
|
|
317
392
|
await expect(readConfigFile({ actors: ['team/nope'], ignore: [] })).rejects.toThrow('do not exist: team/nope');
|
|
318
393
|
});
|
|
319
394
|
});
|
|
320
395
|
});
|
|
321
|
-
//# sourceMappingURL=
|
|
396
|
+
//# sourceMappingURL=actor-config.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actor-config.test.js","sourceRoot":"","sources":["../../../../../test/unit/bin/utils/actor-config.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAErE,OAAO,EACH,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,cAAc,EACd,gBAAgB,GACnB,MAAM,6CAA6C,CAAC;AAErD,uGAAuG;AACvG,wFAAwF;AACxF,qGAAqG;AACrG,8FAA8F;AAC9F,IAAI,OAAe,CAAC;AACpB,IAAI,WAAmB,CAAC;AAExB,UAAU,CAAC,KAAK,IAAI,EAAE;IAClB,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC5B,qGAAqG;IACrG,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,0BAA0B,CAAC,CAAC,CAAC,CAAC;IAClG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,KAAK,IAAI,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC3B,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3D,CAAC,CAAC,CAAC;AAEH,MAAM,mBAAmB,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAEvD,MAAM,WAAW,GAAG,CAAC,MAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;AACrE,MAAM,SAAS,GAAG,CAAC,SAAkC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAEnF,MAAM,UAAU,GAAG,KAAK,EAAE,KAA6B,EAAE,EAAE,CACvD,OAAO,CAAC,GAAG,CACP,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7C,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC,CAAC,CACL,CAAC;AAEN,kGAAkG;AAClG,+EAA+E;AAC/E,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;IACzC,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAChF,MAAM,KAAK,GAAG,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC;QAExG,MAAM,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC1E,MAAM,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACvG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QAClF,MAAM,MAAM,GAAG,gBAAgB,CAAC;YAC5B,MAAM,EAAE;gBACJ,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE;gBACzE;oBACI,MAAM,EAAE,iBAAiB;oBACzB,aAAa,EAAE,gBAAgB;oBAC/B,WAAW,EAAE,aAAa;oBAC1B,oBAAoB,EAAE,CAAC,WAAW,CAAC;iBACtC;aACJ;SACJ,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACnB,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,oBAAoB,EAAE,SAAS,EAAE;YACzG;gBACI,MAAM,EAAE,gBAAgB;gBACxB,aAAa,EAAE,gBAAgB;gBAC/B,WAAW,EAAE,aAAa;gBAC1B,oBAAoB,EAAE,CAAC,UAAU,CAAC;aACrC;SACJ,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,UAAU,CAAC,EAAE,kCAAkC,EAAE,SAAS,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QAEhG,MAAM,CACF,eAAe,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC,CAC7G,CAAC,OAAO,CAAC;YACN,aAAa,EAAE,gBAAgB;YAC/B,MAAM,EAAE,gBAAgB;YACxB,WAAW,EAAE,aAAa;YAC1B,gBAAgB,EAAE,gBAAgB;YAClC,YAAY,EAAE,CAAC,gBAAgB,CAAC;SACnC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B;oBACI,MAAM,EAAE,gBAAgB;oBACxB,aAAa,EAAE,wBAAwB;oBACvC,WAAW,EAAE,oBAAoB;iBACpC;aACJ,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC;SAClF,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACnB;gBACI,aAAa,EAAE,wBAAwB;gBACvC,MAAM,EAAE,gBAAgB;gBACxB,WAAW,EAAE,oBAAoB;gBACjC,gBAAgB,EAAE,EAAE;gBACpB,YAAY,EAAE,CAAC,EAAE,CAAC;aACrB;SACJ,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,mBAAmB,EAAE;aACrF,CAAC;YACF,mBAAmB,EAAE,SAAS,CAAC,EAAE,CAAC;SACrC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B,EAAE,MAAM,EAAE,oBAAoB,EAAE,aAAa,EAAE,mBAAmB,EAAE,WAAW,EAAE,mBAAmB,EAAE;aACzG,CAAC;YACF,sCAAsC,EAAE,SAAS,CAAC,EAAE,CAAC;SACxD,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,aAAa,EAAE;aAC5F,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC;SAClF,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,aAAa,EAAE;aAC5F,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,gBAAgB,EAAE,aAAa,EAAE,CAAC;SACrF,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC;IAC9G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B;oBACI,MAAM,EAAE,gBAAgB;oBACxB,aAAa,EAAE,gBAAgB;oBAC/B,WAAW,EAAE,aAAa;oBAC1B,oBAAoB,EAAE,CAAC,gBAAgB,EAAE,UAAU,CAAC;iBACvD;aACJ,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC;SAClF,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;QACrC,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B,EAAE,MAAM,EAAE,oBAAoB,EAAE,aAAa,EAAE,mBAAmB,EAAE,WAAW,EAAE,mBAAmB,EAAE;gBACtG;oBACI,MAAM,EAAE,qBAAqB;oBAC7B,aAAa,EAAE,yBAAyB;oBACxC,WAAW,EAAE,wBAAwB;iBACxC;aACJ,CAAC;YACF,sCAAsC,EAAE,SAAS,CAAC,EAAE,CAAC;YACrD,uCAAuC,EAAE,SAAS,CAAC,EAAE,CAAC;SACzD,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAC1D,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,UAAU,CAAC,EAAE,CAAC,gBAAgB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;QACtD,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,UAAU,CAAC,EAAE,CAAC,gBAAgB,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QAC5E,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,UAAU,CAAC,EAAE,CAAC,gBAAgB,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QACzF,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,mBAAmB,EAAE;gBAC9F,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,mBAAmB,EAAE;aACjG,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC1E,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,mBAAmB,EAAE;gBACjF,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,mBAAmB,EAAE;aACnF,CAAC;YACF,mBAAmB,EAAE,SAAS,CAAC,EAAE,CAAC;SACrC,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,mBAAmB,EAAE;aACjG,CAAC;SACL,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC,CAAC;SAC1G,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,mBAAmB,EAAE;aACpF,CAAC;SACL,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAC,CAAC;YACjG,kCAAkC,EAAE,SAAS,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACjG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,mBAAmB,EAAE;aACnG,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACjG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,mBAAmB,EAAE;aAC5F,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACjG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,CAAC,CAAC;YAC/F,kCAAkC,EAAE,SAAS,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC/F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,EAAE,CAAC,CAAC;SAC7G,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACpD,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAC1D,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;QACjE,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;QAC/D,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B;oBACI,MAAM,EAAE,gBAAgB;oBACxB,aAAa,EAAE,gBAAgB;oBAC/B,WAAW,EAAE,aAAa;oBAC1B,oBAAoB,EAAE,UAAU;iBACnC;aACJ,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;IACxG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B;oBACI,MAAM,EAAE,gBAAgB;oBACxB,aAAa,EAAE,gBAAgB;oBAC/B,WAAW,EAAE,aAAa;oBAC1B,oBAAoB,EAAE,CAAC,GAAG,CAAC;iBAC9B;aACJ,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;IACxG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,KAAK,IAAI,EAAE;QAC3F,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B;oBACI,MAAM,EAAE,gBAAgB;oBACxB,aAAa,EAAE,gBAAgB;oBAC/B,WAAW,EAAE,aAAa;oBAC1B,oBAAoB,EAAE,CAAC,gBAAgB,EAAE,QAAQ,CAAC;iBACrD;aACJ,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iFAAiF,EAAE,KAAK,IAAI,EAAE;QAC7F,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B;oBACI,MAAM,EAAE,gBAAgB;oBACxB,aAAa,EAAE,gBAAgB;oBAC/B,WAAW,EAAE,aAAa;oBAC1B,oBAAoB,EAAE,CAAC,EAAE,EAAE,gBAAgB,CAAC;iBAC/C;aACJ,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qFAAqF,EAAE,KAAK,IAAI,EAAE;QACjG,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B;oBACI,MAAM,EAAE,gBAAgB;oBACxB,aAAa,EAAE,gBAAgB;oBAC/B,WAAW,EAAE,aAAa;oBAC1B,oBAAoB,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;iBAC3C;aACJ,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;QAClF,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B;oBACI,MAAM,EAAE,iBAAiB;oBACzB,aAAa,EAAE,gBAAgB;oBAC/B,WAAW,EAAE,aAAa;oBAC1B,oBAAoB,EAAE,CAAC,iBAAiB,EAAE,WAAW,CAAC;iBACzD;aACJ,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uGAAuG,EAAE,KAAK,IAAI,EAAE;QACnH,MAAM,UAAU,CAAC;YACb,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B;oBACI,MAAM,EAAE,gBAAgB;oBACxB,aAAa,EAAE,gBAAgB;oBAC/B,WAAW,EAAE,aAAa;oBAC1B,oBAAoB,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,QAAQ,CAAC;iBAC7D;aACJ,CAAC;YACF,kCAAkC,EAAE,SAAS,CAAC,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,gBAAgB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC7B,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE,CACzB,UAAU,CAAC;YACP,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC;gBAC5B,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE;gBACrE,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE;aACxE,CAAC;YACF,4BAA4B,EAAE,SAAS,CAAC,EAAE,CAAC;YAC3C,4BAA4B,EAAE,SAAS,CAAC,EAAE,CAAC;SAC9C,CAAC,CAAC;QAEP,MAAM,SAAS,GAAG,CAAC,MAAmC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QAE9F,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;YAC5D,MAAM,SAAS,EAAE,CAAC;YAClB,MAAM,CAAC,SAAS,CAAC,MAAM,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC/F,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAC5C,MAAM,SAAS,EAAE,CAAC;YAClB,MAAM,CAAC,SAAS,CAAC,MAAM,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QACpG,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;YAClC,MAAM,SAAS,EAAE,CAAC;YAClB,MAAM,CAAC,SAAS,CAAC,MAAM,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QACpG,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC7C,MAAM,SAAS,EAAE,CAAC;YAClB,MAAM,MAAM,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC/E,yBAAyB,CAC5B,CAAC;QACN,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.test.d.ts","sourceRoot":"","sources":["../../../../../test/unit/bin/utils/files.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { safeReadJsonObjectFile } from '../../../../bin/utils/json-file.js';
|
|
6
|
+
// These tests read real fixture files rather than mocking `node:fs`: the whole point of
|
|
7
|
+
// `safeReadJsonObjectFile` is how it reacts to real stat/readFile outcomes (missing path, directory,
|
|
8
|
+
// symlink, unreadable file), so mocking those away would only assert the mock back to itself.
|
|
9
|
+
const FIXTURE_DIR = fileURLToPath(new URL('../../../fixtures/bin/utils/files/', import.meta.url));
|
|
10
|
+
const fixture = (name) => path.join(FIXTURE_DIR, name);
|
|
11
|
+
const NESTED_FIXTURE = {
|
|
12
|
+
storages: { datasets: { default: { title: 'Default' } } },
|
|
13
|
+
overrideActorContext: ['../shared', '.'],
|
|
14
|
+
changelog: null,
|
|
15
|
+
nested: [{ deep: [1, 2, { deeper: true }] }],
|
|
16
|
+
};
|
|
17
|
+
describe('safeReadJsonObjectFile', () => {
|
|
18
|
+
describe('valid JSON objects', () => {
|
|
19
|
+
it('returns the parsed contents, preserving nested objects, arrays and null values', () => {
|
|
20
|
+
const result = safeReadJsonObjectFile(fixture('nested.json'));
|
|
21
|
+
expect(result).toStrictEqual({ success: true, contents: NESTED_FIXTURE });
|
|
22
|
+
});
|
|
23
|
+
it('accepts an empty JSON object', () => {
|
|
24
|
+
const result = safeReadJsonObjectFile(fixture('empty-object.json'));
|
|
25
|
+
expect(result).toStrictEqual({ success: true, contents: {} });
|
|
26
|
+
});
|
|
27
|
+
it('reads files that are not named *.json', () => {
|
|
28
|
+
const result = safeReadJsonObjectFile(fixture('no-json-extension.actorrc'));
|
|
29
|
+
expect(result).toStrictEqual({ success: true, contents: { a: 1 } });
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe('filesystem-level handling', () => {
|
|
33
|
+
it('fails when the path does not exist', () => {
|
|
34
|
+
const filePath = fixture('does-not-exist.json');
|
|
35
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
36
|
+
expect(result).toMatchObject({
|
|
37
|
+
success: false,
|
|
38
|
+
reason: 'unreadable',
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
// The fixture is named `directory.json` on purpose — the check is `stat().isFile()`, not the extension.
|
|
42
|
+
it('fails when the path is a directory', () => {
|
|
43
|
+
const filePath = fixture('directory.json');
|
|
44
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
45
|
+
expect(result).toMatchObject({
|
|
46
|
+
success: false,
|
|
47
|
+
reason: 'not-a-file',
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
// Regression guard: `lstat` would report the link itself as "not a file" and reject it, even
|
|
51
|
+
// though `readFile` follows symlinks and would have read the target without complaint.
|
|
52
|
+
it('follows a symlink to its target file', () => {
|
|
53
|
+
const result = safeReadJsonObjectFile(fixture('symlink-to-valid.json'));
|
|
54
|
+
expect(result).toStrictEqual({ success: true, contents: NESTED_FIXTURE });
|
|
55
|
+
});
|
|
56
|
+
// Git only tracks the executable bit, so this is the one case whose fixture cannot carry its own
|
|
57
|
+
// mode — `unreadable.json` is committed readable and stripped of permissions just for this test.
|
|
58
|
+
describe('unreadable file', () => {
|
|
59
|
+
const filePath = fixture('unreadable.json');
|
|
60
|
+
afterEach(async () => fs.chmod(filePath, 0o644));
|
|
61
|
+
it.runIf(process.getuid?.() !== 0)('fails when the file exists but cannot be read', async () => {
|
|
62
|
+
await fs.chmod(filePath, 0o000);
|
|
63
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
64
|
+
expect(result).toMatchObject({
|
|
65
|
+
success: false,
|
|
66
|
+
reason: 'unreadable',
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('JSON that is not an object', () => {
|
|
72
|
+
it('rejects a JSON array', () => {
|
|
73
|
+
const filePath = fixture('array.json');
|
|
74
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
75
|
+
expect(result).toMatchObject({
|
|
76
|
+
success: false,
|
|
77
|
+
reason: 'not-an-object',
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
it('rejects JSON null', () => {
|
|
81
|
+
const filePath = fixture('null.json');
|
|
82
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
83
|
+
expect(result).toMatchObject({
|
|
84
|
+
success: false,
|
|
85
|
+
reason: 'not-an-object',
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
it('rejects a JSON primitive', () => {
|
|
89
|
+
const filePath = fixture('number.json');
|
|
90
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
91
|
+
expect(result).toMatchObject({
|
|
92
|
+
success: false,
|
|
93
|
+
reason: 'not-an-object',
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe('unparseable files', () => {
|
|
98
|
+
it('fails on malformed JSON', () => {
|
|
99
|
+
const filePath = fixture('malformed.json');
|
|
100
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
101
|
+
expect(result).toMatchObject({ success: false, reason: 'invalid-json' });
|
|
102
|
+
expect(result.failure.message).toContain(`Failed to parse ${filePath}`);
|
|
103
|
+
});
|
|
104
|
+
it('fails on an empty file', () => {
|
|
105
|
+
const filePath = fixture('empty.json');
|
|
106
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
107
|
+
expect(result).toMatchObject({ success: false, reason: 'invalid-json' });
|
|
108
|
+
expect(result.failure.message).toContain(`Failed to parse ${filePath}`);
|
|
109
|
+
});
|
|
110
|
+
it.fails('reads jsonc', () => {
|
|
111
|
+
const filePath = fixture('comments.jsonc');
|
|
112
|
+
const result = safeReadJsonObjectFile(filePath);
|
|
113
|
+
expect(result).toMatchObject({ success: true, contents: { a: 3 } });
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=files.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.test.js","sourceRoot":"","sources":["../../../../../test/unit/bin/utils/files.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lib.test.d.ts","sourceRoot":"","sources":["../../../test/unit/lib.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ApifyClient } from 'apify-client';
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { DEFAULT_TEST_ACTOR_TIMEOUT_SECS } from '../../lib/consts.js';
|
|
4
|
+
import { _private } from '../../lib/lib.js';
|
|
5
|
+
import * as UtilsModule from '../../lib/utils.js';
|
|
6
|
+
const { createStartRunFn } = _private;
|
|
7
|
+
describe('createStartRunFn()', () => {
|
|
8
|
+
const actorCallMock = vi.fn(async () => Promise.resolve({ id: 'fake-run-id' }));
|
|
9
|
+
const testContext = { task: {}, annotate: vi.fn() };
|
|
10
|
+
vi.spyOn(UtilsModule, 'sleep').mockResolvedValue(undefined);
|
|
11
|
+
beforeEach(vi.clearAllMocks);
|
|
12
|
+
it('should apply default timeout to actor runs', async () => {
|
|
13
|
+
// Arrange
|
|
14
|
+
vi.spyOn(ApifyClient.prototype, 'actor').mockReturnValue({
|
|
15
|
+
call: actorCallMock,
|
|
16
|
+
get: vi.fn(async () => ({ defaultRunOptions: {} })),
|
|
17
|
+
});
|
|
18
|
+
// Act
|
|
19
|
+
await createStartRunFn('123', testContext)({ input: {} });
|
|
20
|
+
// Assert
|
|
21
|
+
expect(actorCallMock).toHaveBeenCalledTimes(1);
|
|
22
|
+
expect(actorCallMock).toHaveBeenCalledWith({}, { build: undefined, log: null, timeout: DEFAULT_TEST_ACTOR_TIMEOUT_SECS });
|
|
23
|
+
});
|
|
24
|
+
it('should respect the default actor run timeout if less', async () => {
|
|
25
|
+
// Arrange
|
|
26
|
+
vi.spyOn(ApifyClient.prototype, 'actor').mockReturnValue({
|
|
27
|
+
call: actorCallMock,
|
|
28
|
+
get: vi.fn(async () => ({ defaultRunOptions: { timeoutSecs: 60 } })),
|
|
29
|
+
});
|
|
30
|
+
// Act
|
|
31
|
+
await createStartRunFn('123', testContext)({ input: {} });
|
|
32
|
+
// Assert
|
|
33
|
+
expect(actorCallMock).toHaveBeenCalledTimes(1);
|
|
34
|
+
expect(actorCallMock).toHaveBeenCalledWith({}, { build: undefined, log: null, timeout: 60 });
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=lib.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lib.test.js","sourceRoot":"","sources":["../../../test/unit/lib.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9D,OAAO,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,WAAW,MAAM,oBAAoB,CAAC;AAElD,MAAM,EAAE,gBAAgB,EAAE,GAAG,QAAQ,CAAC;AAEtC,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAChC,MAAM,aAAa,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,aAAa,EAAc,CAAC,CAAC,CAAC;IAC5F,MAAM,WAAW,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE,EAA6B,EAAiB,CAAC;IAE9F,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAE5D,UAAU,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAE7B,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QACxD,UAAU;QAEV,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,eAAe,CAAC;YACrD,IAAI,EAAE,aAAoC;YAC1C,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,iBAAiB,EAAE,EAAE,EAAE,CAAU,CAAuB;SACtE,CAAC,CAAC;QAElB,MAAM;QACN,MAAM,gBAAgB,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAE1D,SAAS;QACT,MAAM,CAAC,aAAa,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,aAAa,CAAC,CAAC,oBAAoB,CACtC,EAAE,EACF,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAC5E,CAAC;IACN,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QAClE,UAAU;QACV,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,eAAe,CAAC;YACrD,IAAI,EAAE,aAAoC;YAC1C,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,iBAAiB,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,CAAU,CAAuB;SACvF,CAAC,CAAC;QAElB,MAAM;QACN,MAAM,gBAAgB,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAE1D,SAAS;QACT,MAAM,CAAC,aAAa,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,aAAa,CAAC,CAAC,oBAAoB,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IACjG,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|