diff --git a/src/commands/run.ts b/src/commands/run.ts index 917f9593f..0f0999831 100644 --- a/src/commands/run.ts +++ b/src/commands/run.ts @@ -7,7 +7,7 @@ import type { ExecaError } from 'execa'; import mime from 'mime'; import { minVersion } from 'semver'; -import { APIFY_ENV_VARS } from '@apify/consts'; +import { ACTOR_ENV_VARS, APIFY_ENV_VARS } from '@apify/consts'; import { validateInputSchema, validateInputUsingValidator } from '@apify/input_schema'; import { ApifyCommand, StdinMode } from '../lib/command-framework/apify-command.js'; @@ -26,6 +26,7 @@ import { useActorConfig } from '../lib/hooks/useActorConfig.js'; import { ProjectLanguage, useCwdProject } from '../lib/hooks/useCwdProject.js'; import { useModuleVersion } from '../lib/hooks/useModuleVersion.js'; import { getAjvValidator, getDefaultsFromInputSchema, readInputSchema } from '../lib/input_schema.js'; +import { CRAWLEE_INPUT_KEY_ENV, resolveInputKey, TEMP_INPUT_KEY_PREFIX } from '../lib/input-key.js'; import { error, info, warning } from '../lib/outputs.js'; import { replaceSecretsValue } from '../lib/secrets.js'; import { @@ -42,6 +43,19 @@ import { purgeDefaultQueue, } from '../lib/utils.js'; +interface TempInputResult { + tempInputKey: string; + tempInputFilePath: string; +} + +interface OverwrittenInputResult { + existingInput: ReturnType; + inputFilePath: string; + writtenAt: number; +} + +type ValidateAndStoreInputResult = TempInputResult | OverwrittenInputResult; + enum RunType { DirectFile = 0, Module = 1, @@ -124,6 +138,7 @@ export class RunCommand extends ApifyCommand { const { config: localConfig } = localConfigResult.unwrap(); const actualStoragePath = getLocalStorageDir(); + const resolvedInputKey = resolveInputKey(); const projectRuntimeResult = await useCwdProject({ cwd }); @@ -233,13 +248,17 @@ export class RunCommand extends ApifyCommand { CRAWLEE_PURGE_ON_START = '1'; if (crawleeVersion.isNone()) { - await Promise.all([purgeDefaultQueue(), purgeDefaultKeyValueStore(), purgeDefaultDataset()]); + await Promise.all([ + purgeDefaultQueue(), + purgeDefaultKeyValueStore(resolvedInputKey), + purgeDefaultDataset(), + ]); info({ message: 'All default local stores were purged.' }); } } if (!this.flags.purge) { - const isStorageEmpty = await checkIfStorageIsEmpty(); + const isStorageEmpty = await checkIfStorageIsEmpty(resolvedInputKey); if (!isStorageEmpty && !this.flags.resurrect) { warning({ @@ -258,13 +277,35 @@ export class RunCommand extends ApifyCommand { return; } - const storedInputResults = await this.validateAndStoreInput(inputOverride); + const storedInputResults = await this.validateAndStoreInput(inputOverride, resolvedInputKey); + + // When a temp input file was created, disable crawlee's purge so it doesn't + // delete the temp file (its name doesn't match the input key regex that purge skips). + // Also determine the effective input key for env vars (temp key overrides resolved key). + let effectiveInputKey = resolvedInputKey; + if (storedInputResults && 'tempInputKey' in storedInputResults) { + if (this.flags.purge && crawleeVersion.isSome()) { + // Crawlee would have purged on start, but we need to disable that to protect + // the temp file. Purge from CLI side instead, preserving both input files. + await Promise.all([ + purgeDefaultQueue(), + purgeDefaultKeyValueStore(resolvedInputKey, storedInputResults.tempInputKey), + purgeDefaultDataset(), + ]); + } + CRAWLEE_PURGE_ON_START = '0'; + effectiveInputKey = storedInputResults.tempInputKey; + } - // Attach env vars from local config files + // Attach env vars from local config files. + // Set all three input key env vars so both Node.js and Python SDKs pick up the resolved key. const localEnvVars: Record = { [APIFY_ENV_VARS.LOCAL_STORAGE_DIR]: actualStoragePath, CRAWLEE_STORAGE_DIR: actualStoragePath, CRAWLEE_PURGE_ON_START, + [ACTOR_ENV_VARS.INPUT_KEY]: effectiveInputKey, + [APIFY_ENV_VARS.INPUT_KEY]: effectiveInputKey, + [CRAWLEE_INPUT_KEY_ENV]: effectiveInputKey, }; if (proxy && proxy.password) localEnvVars[APIFY_ENV_VARS.PROXY_PASSWORD] = proxy.password; @@ -279,8 +320,8 @@ export class RunCommand extends ApifyCommand { Object.assign(localEnvVars, updatedEnv); } - // NOTE: User can overwrite env vars - const env = Object.assign(localEnvVars, process.env); + // localEnvVars must take priority so the CLI can redirect the SDK to temp input files + const env = { ...process.env, ...localEnvVars }; if (!userId) { warning({ @@ -393,7 +434,10 @@ export class RunCommand extends ApifyCommand { } } finally { if (storedInputResults) { - if (storedInputResults.existingInput) { + if ('tempInputKey' in storedInputResults) { + // Temp input file: just delete it, user's INPUT.json was never touched + await deleteFile(storedInputResults.tempInputFilePath); + } else if (storedInputResults.existingInput) { // Check if the input file was modified since we modified it. If it was, we abort the re-overwrite and warn the user const stats = await stat(storedInputResults.inputFilePath); @@ -420,10 +464,17 @@ export class RunCommand extends ApifyCommand { } /** - * Ensures the input that the actor will be ran with locally matches the input schema (and prefills default values if missing) + * Validates the input against the input schema and writes to disk only when necessary. + * When the user already has an input file and no override is provided, it writes the + * merged defaults to a separate temp file so the user's file is never touched. + * The caller redirects the SDK to the temp file via the ACTOR_INPUT_KEY env var. * @param inputOverride Optional input received through command flags + * @param resolvedInputKey The input key resolved from env vars (default "INPUT") */ - private async validateAndStoreInput(inputOverride?: { input: Record; source: string }) { + private async validateAndStoreInput( + inputOverride?: { input: Record; source: string }, + resolvedInputKey = 'INPUT', + ): Promise { const { inputSchema } = await readInputSchema({ cwd: process.cwd() }); if (!inputSchema) { @@ -432,22 +483,18 @@ export class RunCommand extends ApifyCommand { } // We cannot validate input schema if it is not found -> default to no validation and overriding if flags are given - const existingInput = getLocalInput(process.cwd()); + // Write the override to a temp file so the user's input file is never touched. + const defaultStorePath = join(process.cwd(), getLocalKeyValueStorePath()); + await mkdir(defaultStorePath, { recursive: true }); - // Prepare the file path for where we'll temporarily store the validated input - const inputFilePath = join( - process.cwd(), - getLocalKeyValueStorePath(), - existingInput?.fileName ?? 'INPUT.json', - ); + const tempInputKey = `${TEMP_INPUT_KEY_PREFIX}${resolvedInputKey}`; + const tempInputFilePath = join(defaultStorePath, `${tempInputKey}.json`); - await mkdir(dirname(inputFilePath), { recursive: true }); - await writeFile(inputFilePath, JSON.stringify(inputOverride.input, null, 2)); + await writeFile(tempInputFilePath, JSON.stringify(inputOverride.input, null, 2)); return { - existingInput, - inputFilePath, - writtenAt: Date.now(), + tempInputKey, + tempInputFilePath, }; } @@ -458,11 +505,15 @@ export class RunCommand extends ApifyCommand { const defaults = getDefaultsFromInputSchema(inputSchema); const compiledInputSchema = getAjvValidator(inputSchema, validator); - // Step 2: try to fetch the existing INPUT from the local storage - const existingInput = getLocalInput(process.cwd()); + // Step 2: try to fetch the existing input from the local storage + const existingInput = getLocalInput(process.cwd(), resolvedInputKey); // Prepare the file path for where we'll temporarily store the validated input - const inputFilePath = join(process.cwd(), getLocalKeyValueStorePath(), existingInput?.fileName ?? 'INPUT.json'); + const inputFilePath = join( + process.cwd(), + getLocalKeyValueStorePath(), + existingInput?.fileName ?? `${resolvedInputKey}.json`, + ); let errorHeader: string; @@ -501,13 +552,16 @@ export class RunCommand extends ApifyCommand { ); } + // Write to a temp file so the user's input file is never touched. + const tempInputKey = `${TEMP_INPUT_KEY_PREFIX}${resolvedInputKey}`; + const tempInputFilePath = join(dirname(inputFilePath), `${tempInputKey}.json`); + await mkdir(dirname(inputFilePath), { recursive: true }); - await writeFile(inputFilePath, JSON.stringify(fullInputOverride, null, 2)); + await writeFile(tempInputFilePath, JSON.stringify(fullInputOverride, null, 2)); return { - existingInput, - inputFilePath, - writtenAt: Date.now(), + tempInputKey, + tempInputFilePath, }; } @@ -546,14 +600,16 @@ export class RunCommand extends ApifyCommand { ); } - // Step 4: store the input - await mkdir(dirname(inputFilePath), { recursive: true }); - await writeFile(inputFilePath, JSON.stringify(fullInput, null, 2)); + // Write merged input to a temp file so the user's INPUT.json is never touched. + // The SDK is redirected to this file via the ACTOR_INPUT_KEY env var. + const tempInputKey = `${TEMP_INPUT_KEY_PREFIX}${resolvedInputKey}`; + const tempInputFilePath = join(dirname(inputFilePath), `${tempInputKey}.json`); + + await writeFile(tempInputFilePath, JSON.stringify(fullInput, null, 2)); return { - existingInput, - inputFilePath, - writtenAt: Date.now(), + tempInputKey, + tempInputFilePath, }; } diff --git a/src/lib/consts.ts b/src/lib/consts.ts index e0869435c..5d1f8c3da 100644 --- a/src/lib/consts.ts +++ b/src/lib/consts.ts @@ -3,7 +3,7 @@ import { homedir } from 'node:os'; import { join } from 'node:path'; -import { KEY_VALUE_STORE_KEYS, META_ORIGINS } from '@apify/consts'; +import { META_ORIGINS } from '@apify/consts'; import pkg from '../../package.json' with { type: 'json' }; @@ -49,8 +49,6 @@ export const LOCAL_CONFIG_NAME = 'actor.json'; export const LOCAL_CONFIG_PATH = join(ACTOR_SPECIFICATION_FOLDER, LOCAL_CONFIG_NAME); -export const INPUT_FILE_REG_EXP = new RegExp(`(^${KEY_VALUE_STORE_KEYS.INPUT}(?:\\.[^.]+)?$)`); - export const SUPPORTED_NODEJS_VERSION = pkg.engines.node; export const APIFY_CLIENT_DEFAULT_HEADERS = { 'X-Apify-Request-Origin': META_ORIGINS.CLI }; diff --git a/src/lib/input-key.ts b/src/lib/input-key.ts new file mode 100644 index 000000000..d01f52123 --- /dev/null +++ b/src/lib/input-key.ts @@ -0,0 +1,28 @@ +import escapeStringRegexp from 'escape-string-regexp'; + +import { ACTOR_ENV_VARS, APIFY_ENV_VARS } from '@apify/consts'; + +export const CRAWLEE_INPUT_KEY_ENV = 'CRAWLEE_INPUT_KEY'; + +export const TEMP_INPUT_KEY_PREFIX = '__CLI_'; + +/** + * Resolves the input key from environment variables in priority order: + * ACTOR_INPUT_KEY > APIFY_INPUT_KEY > CRAWLEE_INPUT_KEY > "INPUT" + */ +export function resolveInputKey(): string { + return ( + process.env[ACTOR_ENV_VARS.INPUT_KEY] || + process.env[APIFY_ENV_VARS.INPUT_KEY] || + process.env[CRAWLEE_INPUT_KEY_ENV] || + 'INPUT' + ); +} + +/** + * Creates a RegExp that matches the given key with an optional file extension. + * e.g. inputFileRegExp('INPUT') matches 'INPUT', 'INPUT.json', 'INPUT.bin' + */ +export function inputFileRegExp(key: string): RegExp { + return new RegExp(`(^${escapeStringRegexp(key)}(?:\\.[^.]+)?$)`); +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 432b1126a..7455b6a42 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -41,12 +41,12 @@ import { CommandExitCodes, DEFAULT_LOCAL_STORAGE_DIR, GLOBAL_CONFIGS_FOLDER, - INPUT_FILE_REG_EXP, LOCAL_CONFIG_PATH, MINIMUM_SUPPORTED_PYTHON_VERSION, SUPPORTED_NODEJS_VERSION, } from './consts.js'; import { deleteFile, ensureFolderExistsSync, rimrafPromised } from './files.js'; +import { inputFileRegExp, TEMP_INPUT_KEY_PREFIX } from './input-key.js'; import type { AuthJSON } from './types.js'; import { cliDebugPrint } from './utils/cliDebugPrint.js'; @@ -504,7 +504,7 @@ export const createActZip = async (zipName: string, pathsToZip: string[], cwd: s /** * Get Actor input from local store */ -export const getLocalInput = (cwd: string) => { +export const getLocalInput = (cwd: string, inputKey?: string) => { const defaultLocalStorePath = getLocalKeyValueStorePath(); const folderExists = existsSync(join(cwd, defaultLocalStorePath)); @@ -512,7 +512,7 @@ export const getLocalInput = (cwd: string) => { if (!folderExists) return; const files = readdirSync(join(cwd, defaultLocalStorePath)); - const inputName = files.find((file) => !!file.match(INPUT_FILE_REG_EXP)); + const inputName = files.find((file) => !!file.match(inputFileRegExp(inputKey ?? 'INPUT'))); // No input file if (!inputName) return; @@ -536,16 +536,17 @@ export const purgeDefaultDataset = async () => { } }; -export const purgeDefaultKeyValueStore = async () => { +export const purgeDefaultKeyValueStore = async (...inputKeys: string[]) => { const defaultKeyValueStorePath = getLocalKeyValueStorePath(); if (!existsSync(getLocalStorageDir()) || !existsSync(defaultKeyValueStorePath)) { return; } const filesToDelete = readdirSync(defaultKeyValueStorePath); + const preserveRegExps = (inputKeys.length > 0 ? inputKeys : ['INPUT']).map(inputFileRegExp); const deletePromises: Promise[] = []; filesToDelete.forEach((file) => { - if (!file.match(INPUT_FILE_REG_EXP)) { + if (!preserveRegExps.some((re) => re.test(file))) { deletePromises.push(deleteFile(join(defaultKeyValueStorePath, file))); } }); @@ -626,13 +627,12 @@ export const getNpmCmd = (): string => { /** * Returns true if apify storage is empty (expect INPUT.*) */ -export const checkIfStorageIsEmpty = async () => { +export const checkIfStorageIsEmpty = async (inputKey?: string) => { + const key = inputKey || KEY_VALUE_STORE_KEYS.INPUT; const filesWithoutInput = await glob([ `${getLocalStorageDir()}/**`, - // Omit INPUT.* file - `!${getLocalKeyValueStorePath()}/${KEY_VALUE_STORE_KEYS.INPUT}.*`, - // Omit INPUT_CLI-* files - `!${getLocalKeyValueStorePath()}/${KEY_VALUE_STORE_KEYS.INPUT}_CLI-*`, + `!${getLocalKeyValueStorePath()}/${key}.*`, + `!${getLocalKeyValueStorePath()}/${TEMP_INPUT_KEY_PREFIX}${key}.*`, ]); return filesWithoutInput.length === 0; diff --git a/test/local/commands/crawlee/run.test.ts b/test/local/commands/crawlee/run.test.ts index 6d06d891b..69174d587 100644 --- a/test/local/commands/crawlee/run.test.ts +++ b/test/local/commands/crawlee/run.test.ts @@ -68,22 +68,25 @@ describe('apify run', () => { expect(lastErrorMessage()).toMatch(/Field awesome is required/i); }); - it('prefills input with defaults', async () => { + it('validates input without modifying file', async () => { await writeFile(inputPath, originalInput); await testRunCommand(RunCommand, {}); const output = JSON.parse(await readFile(outputPath, 'utf8')); expect(output).toStrictEqual({ awesome: true, help: 'this_maze_is_not_meant_for_you' }); + + const inputAfterRun = await readFile(inputPath, 'utf8'); + expect(inputAfterRun).toBe(originalInput); }); - it('should restore the original input file after run', async () => { + it('does not modify input file during run', async () => { await writeFile(inputPath, originalInputWithExtraField); await testRunCommand(RunCommand, {}); - const input = JSON.parse(await readFile(inputPath, 'utf8')); - expect(input).toStrictEqual({ awesome: true, extra: 'field' }); + const inputAfterRun = await readFile(inputPath, 'utf8'); + expect(inputAfterRun).toBe(originalInputWithExtraField); const output = JSON.parse(await readFile(outputPath, 'utf8')); expect(output).toStrictEqual({ awesome: true, help: 'this_maze_is_not_meant_for_you', extra: 'field' }); diff --git a/test/local/commands/run.test.ts b/test/local/commands/run.test.ts index dbbf6fc9b..bc4e26323 100644 --- a/test/local/commands/run.test.ts +++ b/test/local/commands/run.test.ts @@ -1,7 +1,7 @@ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import { dirname } from 'node:path/win32'; -import { APIFY_ENV_VARS } from '@apify/consts'; +import { ACTOR_ENV_VARS, APIFY_ENV_VARS } from '@apify/consts'; import { testRunCommand } from '../../../src/lib/command-framework/apify-command.js'; import { AUTH_FILE_PATH, EMPTY_LOCAL_CONFIG, LOCAL_CONFIG_PATH } from '../../../src/lib/consts.js'; @@ -333,14 +333,18 @@ writeFileSync(String.raw\`${joinPath('result.txt')}\`, 'hello world'); expect(lastErrorMessage()).toMatch(/Field help must be string/i); }); - it('automatically inserts missing defaulted fields', async () => { - writeFileSync(inputPath, '{"awesome": true}', { flag: 'w' }); + it('does not inject defaults into existing input file', async () => { + const originalContent = '{"awesome": true}'; + writeFileSync(inputPath, originalContent, { flag: 'w' }); copyFileSync(defaultsInputSchemaPath, inputSchemaPath); await testRunCommand(RunCommand, {}); const output = JSON.parse(readFileSync(outputPath, 'utf8')); expect(output).toStrictEqual({ awesome: true, help: 'this_maze_is_not_meant_for_you' }); + + const inputAfterRun = readFileSync(inputPath, 'utf8'); + expect(inputAfterRun).toBe(originalContent); }); it('does not insert missing prefilled fields', async () => { @@ -352,5 +356,27 @@ writeFileSync(String.raw\`${joinPath('result.txt')}\`, 'hello world'); const output = JSON.parse(readFileSync(outputPath, 'utf8')); expect(output).toStrictEqual({ awesome: true }); }); + + it('respects ACTOR_INPUT_KEY env var for custom input file', async () => { + const customInputPath = joinPath(getLocalKeyValueStorePath(), 'MY_INPUT.json'); + const originalContent = '{"awesome": true}'; + + writeFileSync(customInputPath, originalContent, { flag: 'w' }); + copyFileSync(defaultsInputSchemaPath, inputSchemaPath); + + process.env[ACTOR_ENV_VARS.INPUT_KEY] = 'MY_INPUT'; + + try { + await testRunCommand(RunCommand, {}); + + const output = JSON.parse(readFileSync(outputPath, 'utf8')); + expect(output).toStrictEqual({ awesome: true, help: 'this_maze_is_not_meant_for_you' }); + + const inputAfterRun = readFileSync(customInputPath, 'utf8'); + expect(inputAfterRun).toBe(originalContent); + } finally { + delete process.env[ACTOR_ENV_VARS.INPUT_KEY]; + } + }); }); }); diff --git a/test/local/lib/consts.test.ts b/test/local/lib/consts.test.ts index 4402fe991..9b62054b7 100644 --- a/test/local/lib/consts.test.ts +++ b/test/local/lib/consts.test.ts @@ -1,7 +1,7 @@ -import { INPUT_FILE_REG_EXP } from '../../../src/lib/consts.js'; +import { inputFileRegExp } from '../../../src/lib/input-key.js'; describe('Consts', () => { - describe('INPUT_FILE_REG_EXP', () => { + describe('inputFileRegExp', () => { const testValues = [ { text: 'INPUT.json', @@ -27,7 +27,7 @@ describe('Consts', () => { testValues.forEach((value) => { it(`should match ${value.text}`, () => { - expect(!!value.text.match(INPUT_FILE_REG_EXP)).toEqual(value.match); + expect(!!value.text.match(inputFileRegExp('INPUT'))).toEqual(value.match); }); }); }); diff --git a/test/local/lib/input-key.test.ts b/test/local/lib/input-key.test.ts new file mode 100644 index 000000000..62e66f66b --- /dev/null +++ b/test/local/lib/input-key.test.ts @@ -0,0 +1,83 @@ +import { ACTOR_ENV_VARS, APIFY_ENV_VARS } from '@apify/consts'; + +import { CRAWLEE_INPUT_KEY_ENV, inputFileRegExp, resolveInputKey } from '../../../src/lib/input-key.js'; + +describe('resolveInputKey', () => { + const envVars = [ACTOR_ENV_VARS.INPUT_KEY, APIFY_ENV_VARS.INPUT_KEY, CRAWLEE_INPUT_KEY_ENV] as const; + + afterEach(() => { + for (const key of envVars) { + delete process.env[key]; + } + }); + + it('returns "INPUT" when no env vars are set', () => { + expect(resolveInputKey()).toBe('INPUT'); + }); + + it('returns ACTOR_INPUT_KEY when set', () => { + process.env[ACTOR_ENV_VARS.INPUT_KEY] = 'FROM_ACTOR'; + expect(resolveInputKey()).toBe('FROM_ACTOR'); + }); + + it('returns APIFY_INPUT_KEY when ACTOR_INPUT_KEY is not set', () => { + process.env[APIFY_ENV_VARS.INPUT_KEY] = 'FROM_APIFY'; + expect(resolveInputKey()).toBe('FROM_APIFY'); + }); + + it('returns CRAWLEE_INPUT_KEY when neither ACTOR nor APIFY is set', () => { + process.env[CRAWLEE_INPUT_KEY_ENV] = 'FROM_CRAWLEE'; + expect(resolveInputKey()).toBe('FROM_CRAWLEE'); + }); + + it('ACTOR_INPUT_KEY takes priority over APIFY and CRAWLEE', () => { + process.env[ACTOR_ENV_VARS.INPUT_KEY] = 'A'; + process.env[APIFY_ENV_VARS.INPUT_KEY] = 'B'; + process.env[CRAWLEE_INPUT_KEY_ENV] = 'C'; + expect(resolveInputKey()).toBe('A'); + }); + + it('APIFY_INPUT_KEY takes priority over CRAWLEE', () => { + process.env[APIFY_ENV_VARS.INPUT_KEY] = 'B'; + process.env[CRAWLEE_INPUT_KEY_ENV] = 'C'; + expect(resolveInputKey()).toBe('B'); + }); +}); + +describe('inputFileRegExp', () => { + it('matches key without extension', () => { + expect(inputFileRegExp('INPUT').test('INPUT')).toBe(true); + }); + + it('matches key with .json extension', () => { + expect(inputFileRegExp('INPUT').test('INPUT.json')).toBe(true); + }); + + it('matches key with .bin extension', () => { + expect(inputFileRegExp('INPUT').test('INPUT.bin')).toBe(true); + }); + + it('does not match partial name', () => { + expect(inputFileRegExp('INPUT').test('INPUT_BACKUP')).toBe(false); + }); + + it('does not match prefixed name', () => { + expect(inputFileRegExp('INPUT').test('MY_INPUT')).toBe(false); + }); + + it('works with custom key', () => { + const re = inputFileRegExp('CUSTOM_INPUT'); + expect(re.test('CUSTOM_INPUT')).toBe(true); + expect(re.test('CUSTOM_INPUT.json')).toBe(true); + expect(re.test('INPUT')).toBe(false); + expect(re.test('INPUT.json')).toBe(false); + }); + + it('escapes regex special characters in key', () => { + const re = inputFileRegExp('INPUT.v2'); + expect(re.test('INPUT.v2')).toBe(true); + expect(re.test('INPUT.v2.json')).toBe(true); + // The dot in "INPUT.v2" should be literal, not match any char + expect(re.test('INPUTxv2')).toBe(false); + }); +}); diff --git a/test/local/lib/utils.test.ts b/test/local/lib/utils.test.ts index ab43f9d7b..0c72bab53 100644 --- a/test/local/lib/utils.test.ts +++ b/test/local/lib/utils.test.ts @@ -1,9 +1,9 @@ import { existsSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; -import { INPUT_FILE_REG_EXP } from '../../../src/lib/consts.js'; import { execWithLog } from '../../../src/lib/exec.js'; import { ensureFolderExistsSync } from '../../../src/lib/files.js'; +import { inputFileRegExp } from '../../../src/lib/input-key.js'; import { createActZip, getActorLocalFilePaths } from '../../../src/lib/utils.js'; import { useTempPath } from '../../__setup__/hooks/useTempPath.js'; import { withRetries } from '../../__setup__/hooks/withRetries.js'; @@ -93,13 +93,13 @@ describe('Utils', () => { validFiles.forEach((file) => { it(`should match ${file}`, () => { - expect(!!file.match(INPUT_FILE_REG_EXP)).toBeTruthy(); + expect(!!file.match(inputFileRegExp('INPUT'))).toBeTruthy(); }); }); invalidFiles.forEach((file) => { it(`should not match ${file}`, () => { - expect(!!file.match(INPUT_FILE_REG_EXP)).toBeFalsy(); + expect(!!file.match(inputFileRegExp('INPUT'))).toBeFalsy(); }); }); });