Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/commands/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,9 @@ export class RunCommand extends ApifyCommand<typeof RunCommand> {
}

/**
* 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.json and no override is provided, it validates in-memory
* without modifying the file (returns null so the finally block is a no-op).
* @param inputOverride Optional input received through command flags
*/
private async validateAndStoreInput(inputOverride?: { input: Record<string, unknown>; source: string }) {
Expand Down Expand Up @@ -546,15 +548,8 @@ export class RunCommand extends ApifyCommand<typeof RunCommand> {
);
}

// Step 4: store the input
await mkdir(dirname(inputFilePath), { recursive: true });
await writeFile(inputFilePath, JSON.stringify(fullInput, null, 2));

return {
existingInput,
inputFilePath,
writtenAt: Date.now(),
};
// Don't write to the file — leave the user's INPUT.json untouched
return null;
}

return null;
Expand Down
11 changes: 7 additions & 4 deletions test/local/commands/crawlee/run.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' });
Expand Down
8 changes: 6 additions & 2 deletions test/local/commands/run.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
Loading