Skip to content
Merged
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
31 changes: 31 additions & 0 deletions test/e2e/commands/actor/calculate-memory.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { runCli } from '../../__helpers__/run-cli.js';
import { createTestActor, removeTestActor, type TestActor } from '../../__helpers__/test-actor.js';

describe('[e2e] actor calculate-memory', () => {
let actor: TestActor;

beforeAll(async () => {
actor = await createTestActor();
});

afterAll(async () => {
if (actor) await removeTestActor(actor);
});

it('calculates memory with --default-memory-mbytes flag', async () => {
const result = await runCli('apify', ['actor', 'calculate-memory', '--default-memory-mbytes', '256'], {
cwd: actor.dir,
});
expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
expect(result.stdout).toContain('Calculated memory');
expect(result.stdout).toContain('256');
});

it('errors when no memory expression is found', async () => {
const result = await runCli('apify', ['actor', 'calculate-memory'], {
cwd: actor.dir,
});
expect(result.exitCode).not.toBe(0);
expect(result.stderr).toContain('No memory-calculation expression found');
});
});
34 changes: 34 additions & 0 deletions test/e2e/commands/actor/get-value.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { runCli } from '../../__helpers__/run-cli.js';
import { createTestActor, removeTestActor, type TestActor } from '../../__helpers__/test-actor.js';

describe('[e2e] actor get-value', () => {
let actor: TestActor;

beforeAll(async () => {
actor = await createTestActor();

// Run the actor once so storage is initialized
const runResult = await runCli('apify', ['run'], { cwd: actor.dir });
if (runResult.exitCode !== 0) {
throw new Error(`Test actor failed to run:\n${runResult.stderr}`);
}
});

afterAll(async () => {
if (actor) await removeTestActor(actor);
});

it('gets the value back from the default key-value store', async () => {
// First make sure the value is set
await runCli('apify', ['actor', 'set-value', 'MY_KEY', '{"hello":"world"}'], {
cwd: actor.dir,
});

const result = await runCli('apify', ['actor', 'get-value', 'MY_KEY'], {
cwd: actor.dir,
});
expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
expect(result.stdout).toContain('hello');
expect(result.stdout).toContain('world');
});
});
38 changes: 38 additions & 0 deletions test/e2e/commands/actor/push-data.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { mkdir, readdir } from 'node:fs/promises';
import path from 'node:path';

import { runCli } from '../../__helpers__/run-cli.js';
import { createTestActor, removeTestActor, type TestActor } from '../../__helpers__/test-actor.js';

describe('[e2e] actor push-data', () => {
let actor: TestActor;

beforeAll(async () => {
actor = await createTestActor();

// Run the actor once so storage is initialized
const runResult = await runCli('apify', ['run'], { cwd: actor.dir });
if (runResult.exitCode !== 0) {
throw new Error(`Test actor failed to run:\n${runResult.stderr}`);
}

// Ensure the default dataset directory exists for push-data tests
await mkdir(path.join(actor.dir, 'storage', 'datasets', 'default'), { recursive: true });
});

afterAll(async () => {
if (actor) await removeTestActor(actor);
});

it('pushes data to the default dataset', async () => {
const result = await runCli('apify', ['actor', 'push-data', '{"item":"test"}'], {
cwd: actor.dir,
});
expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);

// Verify a file exists in the dataset directory
const datasetDir = path.join(actor.dir, 'storage', 'datasets', 'default');
const files = await readdir(datasetDir);
expect(files.length).toBeGreaterThan(0);
});
});
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { writeFile } from 'node:fs/promises';
import path from 'node:path';

import { runCli } from './__helpers__/run-cli.js';
import { runCli } from '../../__helpers__/run-cli.js';
import {
cleanRunResults,
createTestActor,
getRunResults,
removeTestActor,
type TestActor,
} from './__helpers__/test-actor.js';
} from '../../__helpers__/test-actor.js';

describe('[e2e] actor run input', () => {
let actor: TestActor;
Expand Down
27 changes: 27 additions & 0 deletions test/e2e/commands/actor/set-value.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { runCli } from '../../__helpers__/run-cli.js';
import { createTestActor, removeTestActor, type TestActor } from '../../__helpers__/test-actor.js';

describe('[e2e] actor set-value', () => {
let actor: TestActor;

beforeAll(async () => {
actor = await createTestActor();

// Run the actor once so storage is initialized
const runResult = await runCli('apify', ['run'], { cwd: actor.dir });
if (runResult.exitCode !== 0) {
throw new Error(`Test actor failed to run:\n${runResult.stderr}`);
}
});

afterAll(async () => {
if (actor) await removeTestActor(actor);
});

it('sets a value in the default key-value store', async () => {
const result = await runCli('apify', ['actor', 'set-value', 'MY_KEY', '{"hello":"world"}'], {
cwd: actor.dir,
});
expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { randomBytes } from 'node:crypto';

import { ApifyClient } from 'apify-client';

import { getApifyClientOptions } from '../../src/lib/utils.js';
import { runCli } from './__helpers__/run-cli.js';
import { createTestActor, removeTestActor, type TestActor } from './__helpers__/test-actor.js';
import { getApifyClientOptions } from '../../../../src/lib/utils.js';
import { runCli } from '../../__helpers__/run-cli.js';
import { createTestActor, removeTestActor, type TestActor } from '../../__helpers__/test-actor.js';

describe('[e2e][api] builds namespace', () => {
let actor: TestActor;
Expand Down
74 changes: 74 additions & 0 deletions test/e2e/commands/create.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { randomBytes } from 'node:crypto';
import { access, mkdir, rm } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

import { runCli } from '../__helpers__/run-cli.js';

const TestTmpRoot = fileURLToPath(new URL('../../../tmp/', import.meta.url));

describe('[e2e] apify create', () => {
let tmpDir: string;
const createdDirs: string[] = [];

beforeAll(async () => {
const dirName = `e2e-create-${randomBytes(6).toString('hex')}`;
tmpDir = path.join(TestTmpRoot, dirName);
await mkdir(tmpDir, { recursive: true });
});

afterAll(async () => {
for (const dir of createdDirs) {
await rm(dir, { recursive: true, force: true });
}
await rm(tmpDir, { recursive: true, force: true });
});

it('creates an actor project with --template project_empty --skip-dependency-install', async () => {
const actorName = `test-actor-${randomBytes(4).toString('hex')}`;
const actorDir = path.join(tmpDir, actorName);
createdDirs.push(actorDir);

const result = await runCli(
'apify',
['create', actorName, '--template', 'project_empty', '--skip-dependency-install'],
{
cwd: tmpDir,
},
);

expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
expect(result.stderr).toContain('created successfully');

// Verify directory structure
await expect(access(actorDir)).resolves.toBeUndefined();
await expect(access(path.join(actorDir, '.actor', 'actor.json'))).resolves.toBeUndefined();
await expect(access(path.join(actorDir, 'src'))).resolves.toBeUndefined();
});

it('fails when creating in a directory that already exists with content', async () => {
const actorName = `test-actor-${randomBytes(4).toString('hex')}`;
const actorDir = path.join(tmpDir, actorName);
createdDirs.push(actorDir);

// First create succeeds
const first = await runCli(
'apify',
['create', actorName, '--template', 'project_empty', '--skip-dependency-install'],
{
cwd: tmpDir,
},
);
expect(first.exitCode, `stderr: ${first.stderr}`).toBe(0);

// Second create in same dir should fail
const second = await runCli(
'apify',
['create', actorName, '--template', 'project_empty', '--skip-dependency-install'],
{
cwd: tmpDir,
},
);
expect(second.exitCode).not.toBe(0);
});
});
2 changes: 1 addition & 1 deletion test/e2e/help.test.ts → test/e2e/commands/help.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { runCli } from './__helpers__/run-cli.js';
import { runCli } from '../__helpers__/run-cli.js';

describe.concurrent('[e2e] help command', () => {
it('apify help prints the full help message', async () => {
Expand Down
32 changes: 32 additions & 0 deletions test/e2e/commands/init.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { randomBytes } from 'node:crypto';
import { access, mkdir, rm } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

import { runCli } from '../__helpers__/run-cli.js';

const TestTmpRoot = fileURLToPath(new URL('../../../tmp/', import.meta.url));

describe('[e2e] apify init', () => {
let tmpDir: string;

beforeAll(async () => {
const dirName = `e2e-init-${randomBytes(6).toString('hex')}`;
tmpDir = path.join(TestTmpRoot, dirName);
await mkdir(tmpDir, { recursive: true });
});

afterAll(async () => {
await rm(tmpDir, { recursive: true, force: true });
});

it('initializes an actor project in an empty directory with --yes', async () => {
const result = await runCli('apify', ['init', 'my-test-actor', '--yes'], { cwd: tmpDir });

expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
expect(result.stderr).toContain('The Actor has been initialized in the current directory.');

// Verify .actor/actor.json exists
await expect(access(path.join(tmpDir, '.actor', 'actor.json'))).resolves.toBeUndefined();
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { runCli } from './__helpers__/run-cli.js';
import { corruptActorJson, createTestActor, removeTestActor, type TestActor } from './__helpers__/test-actor.js';
import { runCli } from '../__helpers__/run-cli.js';
import { corruptActorJson, createTestActor, removeTestActor, type TestActor } from '../__helpers__/test-actor.js';

describe('[e2e] invalid actor.json', () => {
let actor: TestActor;
Expand Down
14 changes: 14 additions & 0 deletions test/e2e/commands/logout.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { randomBytes } from 'node:crypto';

import { runCli } from '../__helpers__/run-cli.js';

describe('[e2e] apify logout', () => {
const authEnv = { __APIFY_INTERNAL_TEST_AUTH_PATH__: `e2e-logout-${randomBytes(6).toString('hex')}` };

it('logs out successfully even when not logged in', async () => {
const result = await runCli('apify', ['logout'], { env: authEnv });

expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
expect(result.stderr).toContain('You are logged out from your Apify account');
});
});
45 changes: 45 additions & 0 deletions test/e2e/commands/secrets/lifecycle.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { randomBytes } from 'node:crypto';

import { runCli } from '../../__helpers__/run-cli.js';

describe('[e2e] apify secrets add/ls/rm', () => {
const authEnv = { __APIFY_INTERNAL_TEST_AUTH_PATH__: `e2e-secrets-${randomBytes(6).toString('hex')}` };

it('full lifecycle: add, ls, rm', async () => {
const secretName = `MY_SECRET_${randomBytes(4).toString('hex')}`;

// Add a secret
const addResult = await runCli('apify', ['secrets', 'add', secretName, 'my-value'], { env: authEnv });
expect(addResult.exitCode, `stderr: ${addResult.stderr}`).toBe(0);

// List secrets — should contain the secret name
const lsResult = await runCli('apify', ['secrets', 'ls'], { env: authEnv });
expect(lsResult.exitCode, `stderr: ${lsResult.stderr}`).toBe(0);
expect(lsResult.stdout).toContain(secretName);

// Remove the secret
const rmResult = await runCli('apify', ['secrets', 'rm', secretName], { env: authEnv });
expect(rmResult.exitCode, `stderr: ${rmResult.stderr}`).toBe(0);

// List again — should NOT contain the secret name
const lsAfterRm = await runCli('apify', ['secrets', 'ls'], { env: authEnv });
expect(lsAfterRm.exitCode, `stderr: ${lsAfterRm.stderr}`).toBe(0);
expect(lsAfterRm.stdout).not.toContain(secretName);
});

it('fails when adding a secret that already exists', async () => {
const secretName = `DUP_SECRET_${randomBytes(4).toString('hex')}`;

// Add first time
const addResult = await runCli('apify', ['secrets', 'add', secretName, 'value1'], { env: authEnv });
expect(addResult.exitCode, `stderr: ${addResult.stderr}`).toBe(0);

// Add same secret again — should fail
const dupResult = await runCli('apify', ['secrets', 'add', secretName, 'value2'], { env: authEnv });
expect(dupResult.exitCode).not.toBe(0);
expect(dupResult.stderr).toContain('already exists');

// Cleanup
await runCli('apify', ['secrets', 'rm', secretName], { env: authEnv });
});
});
21 changes: 21 additions & 0 deletions test/e2e/commands/telemetry/enable-disable.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { randomBytes } from 'node:crypto';

import { runCli } from '../../__helpers__/run-cli.js';

describe('[e2e] apify telemetry enable/disable', () => {
const authEnv = { __APIFY_INTERNAL_TEST_AUTH_PATH__: `e2e-telemetry-${randomBytes(6).toString('hex')}` };

it('disables telemetry', async () => {
const result = await runCli('apify', ['telemetry', 'disable'], { env: authEnv });
expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
// Output goes to stderr and contains either "Telemetry disabled" or "already disabled"
expect(result.stderr).toMatch(/Telemetry disabled|already disabled/i);
});

it('enables telemetry', async () => {
const result = await runCli('apify', ['telemetry', 'enable'], { env: authEnv });
expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
// Output goes to stderr and contains either "Telemetry enabled" or "already enabled"
expect(result.stderr).toMatch(/Telemetry enabled|already enabled/i);
});
});
Loading