apify-test-tools 0.9.1-beta.5 → 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.
Files changed (49) hide show
  1. package/.github/workflows/on_pull_request.yaml +1 -1
  2. package/CHANGELOG.md +4 -0
  3. package/bin/utils/config/load-config.ts +14 -132
  4. package/bin/utils/config/parser.ts +88 -0
  5. package/bin/utils/config/structures/base.ts +61 -0
  6. package/bin/utils/config/structures/legacy.ts +20 -0
  7. package/dist/bin/utils/config/load-config.d.ts +2 -33
  8. package/dist/bin/utils/config/load-config.d.ts.map +1 -1
  9. package/dist/bin/utils/config/load-config.js +13 -91
  10. package/dist/bin/utils/config/load-config.js.map +1 -1
  11. package/dist/bin/utils/config/parser.d.ts +19 -0
  12. package/dist/bin/utils/config/parser.d.ts.map +1 -0
  13. package/dist/bin/utils/config/parser.js +72 -0
  14. package/dist/bin/utils/config/parser.js.map +1 -0
  15. package/dist/bin/utils/config/structures/base.d.ts +35 -0
  16. package/dist/bin/utils/config/structures/base.d.ts.map +1 -0
  17. package/dist/bin/utils/config/structures/base.js +40 -0
  18. package/dist/bin/utils/config/structures/base.js.map +1 -0
  19. package/dist/bin/utils/config/structures/legacy.d.ts +6 -0
  20. package/dist/bin/utils/config/structures/legacy.d.ts.map +1 -0
  21. package/dist/bin/utils/config/structures/legacy.js +14 -0
  22. package/dist/bin/utils/config/structures/legacy.js.map +1 -0
  23. package/dist/test/unit/bin/utils/config/load-config.test.d.ts +2 -0
  24. package/dist/test/unit/bin/utils/config/load-config.test.d.ts.map +1 -0
  25. package/dist/test/unit/bin/utils/config/load-config.test.js +138 -0
  26. package/dist/test/unit/bin/utils/config/load-config.test.js.map +1 -0
  27. package/dist/test/unit/bin/utils/config/parser.test.d.ts +2 -0
  28. package/dist/test/unit/bin/utils/config/parser.test.d.ts.map +1 -0
  29. package/dist/test/unit/bin/utils/config/parser.test.js +111 -0
  30. package/dist/test/unit/bin/utils/config/parser.test.js.map +1 -0
  31. package/dist/test/unit/bin/utils/config/structures/base.test.d.ts +2 -0
  32. package/dist/test/unit/bin/utils/config/structures/base.test.d.ts.map +1 -0
  33. package/dist/test/unit/bin/utils/config/structures/base.test.js +74 -0
  34. package/dist/test/unit/bin/utils/config/structures/base.test.js.map +1 -0
  35. package/dist/test/unit/bin/utils/config/structures/legacy.test.d.ts +2 -0
  36. package/dist/test/unit/bin/utils/config/structures/legacy.test.d.ts.map +1 -0
  37. package/dist/test/unit/bin/utils/config/structures/legacy.test.js +63 -0
  38. package/dist/test/unit/bin/utils/config/structures/legacy.test.js.map +1 -0
  39. package/dist/tsconfig.tsbuildinfo +1 -1
  40. package/package.json +1 -1
  41. package/test/unit/bin/utils/config/load-config.test.ts +179 -0
  42. package/test/unit/bin/utils/config/parser.test.ts +137 -0
  43. package/test/unit/bin/utils/config/structures/base.test.ts +83 -0
  44. package/test/unit/bin/utils/config/structures/legacy.test.ts +78 -0
  45. package/dist/test/unit/bin/utils/actor-config.test.d.ts +0 -2
  46. package/dist/test/unit/bin/utils/actor-config.test.d.ts.map +0 -1
  47. package/dist/test/unit/bin/utils/actor-config.test.js +0 -396
  48. package/dist/test/unit/bin/utils/actor-config.test.js.map +0 -1
  49. package/test/unit/bin/utils/actor-config.test.ts +0 -481
@@ -0,0 +1,72 @@
1
+ import z from 'zod';
2
+ import { CONFIG_FILE_STRATEGY } from './structures/base.js';
3
+ import { LEGACY_PARSER } from './structures/legacy.js';
4
+ const CONFIG_FILE_STRATEGIES = {
5
+ [CONFIG_FILE_STRATEGY.LEGACY]: LEGACY_PARSER,
6
+ };
7
+ const ModeSelectionSchema = z.enum(CONFIG_FILE_STRATEGY).default(CONFIG_FILE_STRATEGY.LEGACY);
8
+ function selectStrategy(mode) {
9
+ const parsed = ModeSelectionSchema.safeParse(mode);
10
+ if (!parsed.success) {
11
+ throw new Error(z.prettifyError(parsed.error));
12
+ }
13
+ return CONFIG_FILE_STRATEGIES[parsed.data];
14
+ }
15
+ // Strips a trailing slash so config-declared paths ("actors/shopify/" vs "actors/shopify") compare equal.
16
+ const stripTrailingSlash = (pathValue) => pathValue.replace(/\/+$/, '');
17
+ // The repo root may be written as ".", "./", "/" or ""; everything downstream spells it "".
18
+ const normalizeFolder = (folder) => {
19
+ const stripped = stripTrailingSlash(folder);
20
+ return stripped === '.' ? '' : stripped;
21
+ };
22
+ /**
23
+ * Normalizes the paths the user wrote and checks the cross-entry invariants a per-entry schema
24
+ * cannot: that no two actors claim the same folder once normalized, nor the same actor on the
25
+ * platform. Collects every violation before throwing, so one run reports all of them rather than
26
+ * only the first.
27
+ *
28
+ * @returns the actors it vouched for, with their paths normalized.
29
+ * @throws Error listing every problem found.
30
+ */
31
+ function verifyConfiguration(body) {
32
+ const seenFolders = new Set();
33
+ const seenActorFullNames = new Set();
34
+ const errors = [];
35
+ const normalized = body.map((entry) => ({
36
+ ...entry,
37
+ folder: normalizeFolder(entry.folder),
38
+ overrideActorContext: entry.overrideActorContext?.map(stripTrailingSlash),
39
+ }));
40
+ for (const [index, entry] of normalized.entries()) {
41
+ // TODO: drop folder uniqueness (this requires several changes on other places)
42
+ if (seenFolders.has(entry.folder)) {
43
+ errors.push(`Duplicate folder "${body[index].folder}". Each actor must have a unique folder.`);
44
+ }
45
+ else {
46
+ seenFolders.add(entry.folder);
47
+ }
48
+ if (seenActorFullNames.has(entry.actorFullName)) {
49
+ errors.push(`Duplicate actor "${entry.actorFullName}". Each entry must point at a different actor.`);
50
+ }
51
+ else {
52
+ seenActorFullNames.add(entry.actorFullName);
53
+ }
54
+ }
55
+ if (errors.length > 0) {
56
+ throw new Error(errors.join('\n'));
57
+ }
58
+ return normalized;
59
+ }
60
+ // eslint-disable-next-line no-underscore-dangle
61
+ export const _privates = {
62
+ selectStrategy,
63
+ verifyConfiguration,
64
+ };
65
+ export function parseConfigFile(body) {
66
+ const { mode, ...rest } = body;
67
+ const strategy = selectStrategy(mode);
68
+ const resolved = strategy.parse(rest);
69
+ const validated = verifyConfiguration(resolved);
70
+ return validated;
71
+ }
72
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../../bin/utils/config/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { type ZodType } from 'zod';
2
+ export declare const ACTOR_FULL_NAME_REGEX: RegExp;
3
+ export interface ResolvedActorConfig {
4
+ actorFullName: string;
5
+ folder: string;
6
+ tokenEnvVar: string;
7
+ overrideActorContext?: string[];
8
+ }
9
+ export declare enum CONFIG_FILE_STRATEGY {
10
+ LEGACY = "legacy"
11
+ }
12
+ export type StrategyParser = {
13
+ mode: CONFIG_FILE_STRATEGY;
14
+ parse: (body: Record<string, unknown>) => ResolvedActorConfig[];
15
+ };
16
+ export declare function defineStrategy<T extends Record<string, unknown>, Mode extends CONFIG_FILE_STRATEGY>(mode: Mode, schema: ZodType<T>, resolve: (body: T) => ResolvedActorConfig[]): {
17
+ mode: Mode;
18
+ /**
19
+ *
20
+ * @param body raw config file to be read
21
+ * @returns ResolvedActorConfig[] if the config file is valid, otherwise throws an error with a description of the issues.
22
+ * @throws Error if the config file is invalid.
23
+ * @example
24
+ * ```ts
25
+ * const strategy = defineStrategy(CONFIG_FILE_STRATEGY.LEGACY, schema, resolve);
26
+ * const resolvedActors = strategy.parse(configFileContents);
27
+ * ```
28
+ *
29
+ * This function is used to parse the config file according to the strategy defined by the user.
30
+ * It uses the schema defined in the strategy to validate the config file and resolve it into a list of ResolvedActorConfig.
31
+ * If the config file is invalid, it throws an error with a description of the issues.
32
+ */
33
+ parse: (body: Record<string, unknown>) => ResolvedActorConfig[];
34
+ };
35
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../../../bin/utils/config/structures/base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,KAAK,CAAC;AAQlD,eAAO,MAAM,qBAAqB,QAGjC,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACnC;AAED,oBAAY,oBAAoB;IAC5B,MAAM,WAAW;CACpB;AAED,MAAM,MAAM,cAAc,GAAG;IACzB,IAAI,EAAE,oBAAoB,CAAC;IAC3B,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,mBAAmB,EAAE,CAAC;CACnE,CAAC;AAEF,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,SAAS,oBAAoB,EAE/F,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAClB,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,mBAAmB,EAAE;;IAIvC;;;;;;;;;;;;;;OAcG;kBACW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;EAQ5C"}
@@ -0,0 +1,40 @@
1
+ import { prettifyError } from 'zod';
2
+ import { ACTOR_NAME, USERNAME } from '@apify/consts';
3
+ function stripRegexAnchor(regex) {
4
+ return regex.replace(/^\^/, '').replace(/\$$/, '');
5
+ }
6
+ export const ACTOR_FULL_NAME_REGEX = new RegExp(`^${stripRegexAnchor(USERNAME.REGEX.source)}/${stripRegexAnchor(ACTOR_NAME.REGEX.source)}$`, USERNAME.REGEX.flags + ACTOR_NAME.REGEX.flags);
7
+ export var CONFIG_FILE_STRATEGY;
8
+ (function (CONFIG_FILE_STRATEGY) {
9
+ CONFIG_FILE_STRATEGY["LEGACY"] = "legacy";
10
+ })(CONFIG_FILE_STRATEGY || (CONFIG_FILE_STRATEGY = {}));
11
+ export function defineStrategy(
12
+ // mode is transparent so it can be validated with & { mode: Mode }
13
+ mode, schema, resolve) {
14
+ return {
15
+ mode,
16
+ /**
17
+ *
18
+ * @param body raw config file to be read
19
+ * @returns ResolvedActorConfig[] if the config file is valid, otherwise throws an error with a description of the issues.
20
+ * @throws Error if the config file is invalid.
21
+ * @example
22
+ * ```ts
23
+ * const strategy = defineStrategy(CONFIG_FILE_STRATEGY.LEGACY, schema, resolve);
24
+ * const resolvedActors = strategy.parse(configFileContents);
25
+ * ```
26
+ *
27
+ * This function is used to parse the config file according to the strategy defined by the user.
28
+ * It uses the schema defined in the strategy to validate the config file and resolve it into a list of ResolvedActorConfig.
29
+ * If the config file is invalid, it throws an error with a description of the issues.
30
+ */
31
+ parse: (body) => {
32
+ const parsed = schema.safeParse(body);
33
+ if (parsed.success) {
34
+ return resolve(parsed.data);
35
+ }
36
+ throw new Error(prettifyError(parsed.error));
37
+ },
38
+ };
39
+ }
40
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../../bin/utils/config/structures/base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAgB,MAAM,KAAK,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAErD,SAAS,gBAAgB,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,MAAM,CAC3C,IAAI,gBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,gBAAgB,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAC3F,QAAQ,CAAC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAChD,CAAC;AASF,MAAM,CAAN,IAAY,oBAEX;AAFD,WAAY,oBAAoB;IAC5B,yCAAiB,CAAA;AACrB,CAAC,EAFW,oBAAoB,KAApB,oBAAoB,QAE/B;AAOD,MAAM,UAAU,cAAc;AAC1B,mEAAmE;AACnE,IAAU,EACV,MAAkB,EAClB,OAA2C;IAE3C,OAAO;QACH,IAAI;QACJ;;;;;;;;;;;;;;WAcG;QACH,KAAK,EAAE,CAAC,IAA6B,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAChC,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACjD,CAAC;KACJ,CAAC;AACN,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { CONFIG_FILE_STRATEGY } from './base.js';
2
+ export declare const LEGACY_PARSER: {
3
+ mode: CONFIG_FILE_STRATEGY;
4
+ parse: (body: Record<string, unknown>) => import("./base.js").ResolvedActorConfig[];
5
+ };
6
+ //# sourceMappingURL=legacy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy.d.ts","sourceRoot":"","sources":["../../../../../bin/utils/config/structures/legacy.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,oBAAoB,EAAkB,MAAM,WAAW,CAAC;AAiBxF,eAAO,MAAM,aAAa;;;CAA2F,CAAC"}
@@ -0,0 +1,14 @@
1
+ import z from 'zod';
2
+ import { ACTOR_FULL_NAME_REGEX, CONFIG_FILE_STRATEGY, defineStrategy } from './base.js';
3
+ const schema = z.object({
4
+ actors: z
5
+ .array(z.object({
6
+ folder: z.string(),
7
+ actorFullName: z.string().regex(ACTOR_FULL_NAME_REGEX),
8
+ tokenEnvVar: z.string(),
9
+ overrideActorContext: z.array(z.string()).optional(),
10
+ }))
11
+ .min(1),
12
+ });
13
+ export const LEGACY_PARSER = defineStrategy(CONFIG_FILE_STRATEGY.LEGACY, schema, (body) => body.actors);
14
+ //# sourceMappingURL=legacy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy.js","sourceRoot":"","sources":["../../../../../bin/utils/config/structures/legacy.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAC;AAEpB,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAExF,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC;SACJ,KAAK,CACF,CAAC,CAAC,MAAM,CAAC;QACL,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC;QACtD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;QACvB,oBAAoB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;KACvD,CAAC,CACL;SACA,GAAG,CAAC,CAAC,CAAC;CACd,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,aAAa,GAAG,cAAc,CAAC,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,IAAkB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=load-config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-config.test.d.ts","sourceRoot":"","sources":["../../../../../../test/unit/bin/utils/config/load-config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,138 @@
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, readConfigFile } from '../../../../../bin/utils/config/load-config.js';
6
+ let repoDir;
7
+ let originalCwd;
8
+ beforeEach(async () => {
9
+ originalCwd = process.cwd();
10
+ // `realpath` because macOS hands out a symlinked temp dir, while `process.cwd()` reports the target.
11
+ repoDir = await fs.realpath(await fs.mkdtemp(path.join(os.tmpdir(), 'apify-test-tools-config-')));
12
+ process.chdir(repoDir);
13
+ });
14
+ afterEach(async () => {
15
+ process.chdir(originalCwd);
16
+ await fs.rm(repoDir, { recursive: true, force: true });
17
+ });
18
+ const emptyActorSelection = { actors: [], ignore: [] };
19
+ const validConfig = (actors) => JSON.stringify({ actors });
20
+ const actorJson = (fields = {}) => JSON.stringify(fields);
21
+ const writeFiles = async (files) => Promise.all(Object.entries(files).map(async ([filePath, contents]) => {
22
+ const absPath = path.join(repoDir, filePath);
23
+ await fs.mkdir(path.dirname(absPath), { recursive: true });
24
+ await fs.writeFile(absPath, contents);
25
+ }));
26
+ describe('loadActorConfig', () => {
27
+ const entry = (fields = {}) => ({
28
+ folder: 'actors/shopify',
29
+ actorFullName: 'myteam/shopify',
30
+ tokenEnvVar: 'APIFY_TOKEN',
31
+ ...fields,
32
+ });
33
+ const writeActorJson = async (fields = {}) => writeFiles({ 'actors/shopify/.actor/actor.json': actorJson(fields) });
34
+ it('resolves data coming from actor.json', async () => {
35
+ await writeActorJson({ dockerContextDir: '..' });
36
+ expect(loadActorConfig(entry())).toEqual({
37
+ actorFullName: 'myteam/shopify',
38
+ folder: 'actors/shopify',
39
+ tokenEnvVar: 'APIFY_TOKEN',
40
+ dockerContextDir: 'actors/shopify',
41
+ contextPaths: ['actors/shopify'],
42
+ });
43
+ });
44
+ it('defaults dockerContextDir to the actor folder when actor.json does not set it', async () => {
45
+ await writeActorJson();
46
+ expect(loadActorConfig(entry()).dockerContextDir).toBe('actors/shopify');
47
+ });
48
+ it('resolves dockerContextDir relative to the .actor/ folder, not the actor folder', async () => {
49
+ await writeActorJson({ dockerContextDir: '../../..' });
50
+ expect(loadActorConfig(entry()).dockerContextDir).toBe('');
51
+ });
52
+ it('throws when dockerContextDir resolves outside the repository root', async () => {
53
+ await writeActorJson({ dockerContextDir: '../../../..' });
54
+ expect(() => loadActorConfig(entry())).toThrow(/resolves outside the repository root/);
55
+ });
56
+ it('throws when actor.json is missing', () => {
57
+ expect(() => loadActorConfig(entry())).toThrow('Cannot read');
58
+ });
59
+ it('resolves contextPaths from overrideActorContext', async () => {
60
+ await writeActorJson({ dockerContextDir: '../../..' });
61
+ expect(loadActorConfig(entry({ overrideActorContext: ['actors/shopify', 'packages'] })).contextPaths).toEqual([
62
+ 'actors/shopify',
63
+ 'packages',
64
+ ]);
65
+ });
66
+ it('adds the actor own folder automatically when overrideActorContext does not cover it', async () => {
67
+ await writeActorJson();
68
+ expect(loadActorConfig(entry({ overrideActorContext: ['code', 'shared'] })).contextPaths).toEqual([
69
+ 'code',
70
+ 'shared',
71
+ 'actors/shopify',
72
+ ]);
73
+ });
74
+ it('allows overrideActorContext with disjoint sibling paths that all reach the actor folder via one entry', async () => {
75
+ await writeActorJson();
76
+ expect(loadActorConfig(entry({ overrideActorContext: ['actors/shopify', 'code', 'shared'] })).contextPaths).toEqual(['actors/shopify', 'code', 'shared']);
77
+ });
78
+ it('throws when overrideActorContext entries overlap (one is a prefix of another)', async () => {
79
+ await writeActorJson();
80
+ expect(() => loadActorConfig(entry({ overrideActorContext: ['actors/shopify', 'actors'] }))).toThrow(/overlap/);
81
+ });
82
+ it('throws when overrideActorContext contains the repo root alongside another entry', async () => {
83
+ await writeActorJson();
84
+ expect(() => loadActorConfig(entry({ overrideActorContext: ['', 'actors/shopify'] }))).toThrow(/overlap/);
85
+ });
86
+ });
87
+ describe('readConfigFile', () => {
88
+ // Golden output massaging the whole config reading process
89
+ it("carries the parser's normalization through to ActorConfig[]", async () => {
90
+ await writeFiles({
91
+ [CONFIG_FILE_NAME]: validConfig([
92
+ { folder: '.', actorFullName: 'apify/root', tokenEnvVar: 'APIFY_TOKEN_APIFY' },
93
+ {
94
+ folder: 'actors/shopify/',
95
+ actorFullName: 'myteam/shopify',
96
+ tokenEnvVar: 'APIFY_TOKEN',
97
+ overrideActorContext: ['actors/shopify/', 'packages/'],
98
+ },
99
+ ]),
100
+ '.actor/actor.json': actorJson({}),
101
+ 'actors/shopify/.actor/actor.json': actorJson({}),
102
+ });
103
+ expect(await readConfigFile(emptyActorSelection)).toEqual([
104
+ {
105
+ actorFullName: 'apify/root',
106
+ folder: '',
107
+ tokenEnvVar: 'APIFY_TOKEN_APIFY',
108
+ dockerContextDir: '',
109
+ contextPaths: [''],
110
+ },
111
+ {
112
+ actorFullName: 'myteam/shopify',
113
+ folder: 'actors/shopify',
114
+ tokenEnvVar: 'APIFY_TOKEN',
115
+ dockerContextDir: 'actors/shopify',
116
+ contextPaths: ['actors/shopify', 'packages'],
117
+ },
118
+ ]);
119
+ });
120
+ it('throws when config file is missing', async () => {
121
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('not found');
122
+ });
123
+ it('throws when config file contains invalid JSON', async () => {
124
+ await writeFiles({ [CONFIG_FILE_NAME]: '{bad json' });
125
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('invalid JSON');
126
+ });
127
+ it('throws when the config file is not a JSON object', async () => {
128
+ await writeFiles({ [CONFIG_FILE_NAME]: JSON.stringify([{ folder: 'actors/shopify' }]) });
129
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow('"actors" array');
130
+ });
131
+ // The wording of a schema failure belongs to the strategy; this only checks that the failure
132
+ // reaches the caller rather than being swallowed on the way out of readConfigFile.
133
+ it('surfaces a schema failure from the parser', async () => {
134
+ await writeFiles({ [CONFIG_FILE_NAME]: JSON.stringify({ notActors: [] }) });
135
+ await expect(readConfigFile(emptyActorSelection)).rejects.toThrow(/at actors/);
136
+ });
137
+ });
138
+ //# sourceMappingURL=load-config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-config.test.js","sourceRoot":"","sources":["../../../../../../test/unit/bin/utils/config/load-config.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=parser.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.test.d.ts","sourceRoot":"","sources":["../../../../../../test/unit/bin/utils/config/parser.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,111 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { _privates, parseConfigFile } from '../../../../../bin/utils/config/parser.js';
3
+ import { CONFIG_FILE_STRATEGY } from '../../../../../bin/utils/config/structures/base.js';
4
+ import { LEGACY_PARSER } from '../../../../../bin/utils/config/structures/legacy.js';
5
+ const { selectStrategy, verifyConfiguration } = _privates;
6
+ const actor = (fields = {}) => ({
7
+ folder: 'actors/shopify',
8
+ actorFullName: 'myteam/shopify',
9
+ tokenEnvVar: 'APIFY_TOKEN',
10
+ ...fields,
11
+ });
12
+ describe('selectStrategy', () => {
13
+ it('falls back to the legacy strategy when no mode is declared', () => {
14
+ expect(selectStrategy(undefined)).toBe(LEGACY_PARSER);
15
+ });
16
+ it('honours an explicit mode', () => {
17
+ expect(selectStrategy(CONFIG_FILE_STRATEGY.LEGACY)).toBe(LEGACY_PARSER);
18
+ });
19
+ it('throws on a mode no strategy is registered for', () => {
20
+ expect(() => selectStrategy('some-nonexistent-mode')).toThrow(/Invalid input/);
21
+ });
22
+ });
23
+ describe('verifyConfiguration', () => {
24
+ it('resolves the repo root to "" and gets rid of trailing slashes', () => {
25
+ const result = verifyConfiguration([
26
+ { folder: '.', actorFullName: 'myteam/root', tokenEnvVar: 'APIFY_TOKEN' },
27
+ {
28
+ folder: 'actors/shopify/',
29
+ actorFullName: 'myteam/shopify',
30
+ tokenEnvVar: 'APIFY_TOKEN',
31
+ overrideActorContext: ['packages/'],
32
+ },
33
+ ]);
34
+ expect(result).toEqual([
35
+ { folder: '', actorFullName: 'myteam/root', tokenEnvVar: 'APIFY_TOKEN', overrideActorContext: undefined },
36
+ {
37
+ folder: 'actors/shopify',
38
+ actorFullName: 'myteam/shopify',
39
+ tokenEnvVar: 'APIFY_TOKEN',
40
+ overrideActorContext: ['packages'],
41
+ },
42
+ ]);
43
+ });
44
+ it.each([
45
+ ['"." and ""', '.', ''],
46
+ ['weird roots', '', './//'],
47
+ ['a trailing slash', 'actors/shopify', 'actors/shopify/'],
48
+ ])('rejects folders that collide once normalized: %s', (_name, first, second) => {
49
+ expect(() => verifyConfiguration([
50
+ actor({ folder: first, actorFullName: 'myteam/actor-a' }),
51
+ actor({ folder: second, actorFullName: 'myteam/actor-b' }),
52
+ ])).toThrow(/Duplicate folder/);
53
+ });
54
+ it('quotes a duplicate folder the way it was written, not the way it normalized', () => {
55
+ expect(() => verifyConfiguration([
56
+ actor({ folder: '.', actorFullName: 'myteam/actor-a' }),
57
+ actor({ folder: './', actorFullName: 'myteam/actor-b' }),
58
+ ])).toThrow('Duplicate folder "./"');
59
+ });
60
+ it('rejects two entries pointing at the same actor', () => {
61
+ expect(() => verifyConfiguration([actor({ folder: 'actors/a' }), actor({ folder: 'actors/b' })])).toThrow(/Duplicate actor "myteam\/shopify"/);
62
+ });
63
+ it('treats actorFullName case-sensitively — "myteam/A" is not "myteam/a"', () => {
64
+ expect(() => verifyConfiguration([
65
+ actor({ folder: 'actors/a', actorFullName: 'myteam/abc' }),
66
+ actor({ folder: 'actors/b', actorFullName: 'myteam/ABC' }),
67
+ ])).not.toThrow();
68
+ });
69
+ it('reports every collision at once instead of stopping at the first', () => {
70
+ const message = (() => {
71
+ try {
72
+ verifyConfiguration([
73
+ actor({ folder: 'actors/a', actorFullName: 'myteam/actor-a' }),
74
+ actor({ folder: 'actors/a', actorFullName: 'myteam/actor-b' }),
75
+ actor({ folder: 'actors/c', actorFullName: 'myteam/actor-c' }),
76
+ actor({ folder: 'actors/d', actorFullName: 'myteam/actor-c' }),
77
+ ]);
78
+ return '';
79
+ }
80
+ catch (err) {
81
+ return err.message;
82
+ }
83
+ })();
84
+ expect(message.split('\n')).toEqual([
85
+ 'Duplicate folder "actors/a". Each actor must have a unique folder.',
86
+ 'Duplicate actor "myteam/actor-c". Each entry must point at a different actor.',
87
+ ]);
88
+ });
89
+ it('reports both problems for an entry that duplicates a folder and an actor at once', () => {
90
+ expect(() => verifyConfiguration([actor(), actor()])).toThrow(/Duplicate folder[\s\S]*Duplicate actor/);
91
+ });
92
+ it('accepts an empty configuration', () => {
93
+ expect(verifyConfiguration([])).toEqual([]);
94
+ });
95
+ });
96
+ describe('parseConfigFile', () => {
97
+ it('validates and normalizes a plain object without touching the filesystem', () => {
98
+ expect(parseConfigFile({ actors: [actor({ folder: 'actors/shopify/' })] })).toEqual([
99
+ actor({ folder: 'actors/shopify', overrideActorContext: undefined }),
100
+ ]);
101
+ });
102
+ it('surfaces cross-entry violations from verifyConfiguration', () => {
103
+ expect(() => parseConfigFile({
104
+ actors: [
105
+ actor({ actorFullName: 'myteam/actor-a', folder: 'collide/collide' }),
106
+ actor({ actorFullName: 'myteam/actor-b', folder: 'collide/collide' }),
107
+ ],
108
+ })).toThrow(/Duplicate folder/);
109
+ });
110
+ });
111
+ //# sourceMappingURL=parser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.test.js","sourceRoot":"","sources":["../../../../../../test/unit/bin/utils/config/parser.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=base.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.test.d.ts","sourceRoot":"","sources":["../../../../../../../test/unit/bin/utils/config/structures/base.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,74 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ACTOR_NAME, USERNAME } from '@apify/consts';
3
+ import { ACTOR_FULL_NAME_REGEX } from '../../../../../../bin/utils/config/structures/base.js';
4
+ // ACTOR_FULL_NAME_REGEX is spliced together from two platform constants by stripping their anchors
5
+ // and joining them with a "/". These tests are about the splice, not about re-testing the platform's
6
+ // own rules: an anchor left behind, an anchor stripped too eagerly, or the actor-name alternation
7
+ // losing its parentheses would all produce a regex that still looks plausible and matches the wrong
8
+ // things. The cases below are the ones that tell those failures apart.
9
+ describe('ACTOR_FULL_NAME_REGEX', () => {
10
+ it.each([
11
+ ['apify/web-scraper'],
12
+ ['myteam/shopify'],
13
+ ['my.team/web-scraper'],
14
+ ['my-team/shopify'],
15
+ ['my_team/a1'],
16
+ // ACTOR_NAME's first alternative — a single character — is a legal actor name on its own.
17
+ ['myteam/a'],
18
+ ['myteam/a--b'],
19
+ ])('accepts %s', (fullName) => {
20
+ expect(ACTOR_FULL_NAME_REGEX.test(fullName)).toBe(true);
21
+ });
22
+ it.each([
23
+ ['there is no slash', 'shopify'],
24
+ ['the owner half is empty', '/shopify'],
25
+ ['the actor half is empty', 'myteam/'],
26
+ ['there are two slashes', 'myteam//shopify'],
27
+ ['there is a third segment', 'myteam/shopify/extra'],
28
+ ['the owner holds a space', 'my team/shopify'],
29
+ ['the actor name starts with a hyphen', 'myteam/-shopify'],
30
+ ['the actor name ends with a hyphen', 'myteam/shopify-'],
31
+ ['the actor name holds an underscore', 'myteam/web_scraper'],
32
+ ['the actor name holds a dot', 'myteam/web.scraper'],
33
+ ])('rejects a name where %s', (_name, fullName) => {
34
+ expect(ACTOR_FULL_NAME_REGEX.test(fullName)).toBe(false);
35
+ });
36
+ // Both halves arrive anchored and get de-anchored so they can be joined; the composed regex has to
37
+ // put the anchors back. Without them these all match on a substring.
38
+ it.each([
39
+ ['leading text', 'see myteam/shopify'],
40
+ ['trailing text', 'myteam/shopify here'],
41
+ ['a leading newline', '\nmyteam/shopify'],
42
+ ['a trailing newline', 'myteam/shopify\n'],
43
+ ['surrounding whitespace', ' myteam/shopify '],
44
+ ])('matches the whole string, so it rejects %s', (_name, fullName) => {
45
+ expect(ACTOR_FULL_NAME_REGEX.test(fullName)).toBe(false);
46
+ });
47
+ // ACTOR_NAME's source is an alternation, "(A|B)". It survives the splice only because the platform
48
+ // wrote it parenthesized — lose those parens and the regex becomes "^owner/A|B$", where the "B"
49
+ // branch matches a bare actor name with no owner at all.
50
+ it('keeps the actor-name alternation from swallowing the owner half', () => {
51
+ expect(ACTOR_NAME.REGEX.source).toMatch(/^\^\(.*\)\$$/);
52
+ expect(ACTOR_FULL_NAME_REGEX.test('shopify')).toBe(false);
53
+ expect(ACTOR_FULL_NAME_REGEX.test('a')).toBe(false);
54
+ });
55
+ // The owner half carries a {min,max} quantifier, the one part of either source that a sloppy strip
56
+ // could eat. Bounds come from the constants so this stays honest if the platform moves them.
57
+ it("enforces the platform's username length bounds", () => {
58
+ const owner = (length) => `${'a'.repeat(length)}/shopify`;
59
+ expect(ACTOR_FULL_NAME_REGEX.test(owner(USERNAME.MIN_LENGTH))).toBe(true);
60
+ expect(ACTOR_FULL_NAME_REGEX.test(owner(USERNAME.MIN_LENGTH - 1))).toBe(false);
61
+ expect(ACTOR_FULL_NAME_REGEX.test(owner(USERNAME.MAX_LENGTH))).toBe(true);
62
+ expect(ACTOR_FULL_NAME_REGEX.test(owner(USERNAME.MAX_LENGTH + 1))).toBe(false);
63
+ });
64
+ // `.source` carries the pattern and none of the flags, so the flags have to be re-applied by hand.
65
+ // USERNAME.REGEX is declared /i and the platform does accept "MyTeam" as a username; drop that on
66
+ // the way here and the owner half silently becomes stricter than the thing it was copied from.
67
+ it('accepts either half in any case, the way the platform does', () => {
68
+ expect(USERNAME.REGEX.flags).toContain('i');
69
+ expect(ACTOR_FULL_NAME_REGEX.flags).toContain('i');
70
+ expect(ACTOR_FULL_NAME_REGEX.test('myteam/Shopify')).toBe(true);
71
+ expect(ACTOR_FULL_NAME_REGEX.test('MyTeam/shopify')).toBe(true);
72
+ });
73
+ });
74
+ //# sourceMappingURL=base.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.test.js","sourceRoot":"","sources":["../../../../../../../test/unit/bin/utils/config/structures/base.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=legacy.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy.test.d.ts","sourceRoot":"","sources":["../../../../../../../test/unit/bin/utils/config/structures/legacy.test.ts"],"names":[],"mappings":""}