Skip to content
Open
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
6 changes: 3 additions & 3 deletions test/integration/_fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ const TOKEN_ENV_VAR = 'APIFY_TEST_USER_API_TOKEN';
/** Overrides the API the suite runs against, so it can be pointed at a staging deployment. */
const API_URL_ENV_VAR = 'APIFY_INTEGRATION_TESTS_API_URL';

/** Client authenticated as the primary test user. */
export function makeClient(): ApifyClient {
const token = process.env[TOKEN_ENV_VAR];
/** Client authenticated as the primary test user, or with the given `token` instead. */
export function makeClient(token?: string): ApifyClient {
token ??= process.env[TOKEN_ENV_VAR];
if (!token) {
throw new Error(`${TOKEN_ENV_VAR} environment variable is missing, cannot run tests!`);
}
Expand Down
65 changes: 49 additions & 16 deletions test/integration/run.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,26 +240,59 @@ test('resurrect() restarts a finished run, which then succeeds again', async ()
});

test('metamorph() transforms a started run into another Actor, keeping the run id', async () => {
const run = await client.actor(HELLO_WORLD_ACTOR).start();
const runClient = client.run(run.id);
// Metamorphing the run from outside is not allowed, so we cheat a bit: the Actor stores its own run token in its key-value store,
Comment on lines 242 to +243

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this comment and the one at line 281 say the same thing, and the first line is longer than 120 chars. One comment here is enough, and line 281 can go:

Suggested change
test('metamorph() transforms a started run into another Actor, keeping the run id', async () => {
const run = await client.actor(HELLO_WORLD_ACTOR).start();
const runClient = client.run(run.id);
// Metamorphing the run from outside is not allowed, so we cheat a bit: the Actor stores its own run token in its key-value store,
// Only the run's own token may metamorph it, so the Actor stores its token in its KVS for the test to read.

✍️ Drafted by Claude Code

// and we construct a new client with this token, and test that.
const actor = await client.actors().create({
name: getRandomResourceName('actor'),
versions: [
{
versionNumber: '0.0',
sourceType: ActorSourceType.SourceFiles,
buildTag: 'latest',
sourceFiles: [
{
name: 'Dockerfile',
format: 'TEXT',
content: 'FROM apify/actor-node:22\nCOPY . ./\nCMD ["node", "main.js"]\n',
},
{
name: 'main.js',
format: 'TEXT',
content: `
const { Actor } = require('apify');
Actor.main(async () => {
await Actor.setValue('TOKEN', process.env.APIFY_TOKEN, { contentType: 'text/plain' });
await new Promise((resolve) => setTimeout(resolve, 60000));
});
`,
},
],
},
],
});
const actorClient = client.actor(actor.id);
let runClient: RunClient | undefined;

try {
await waitUntilStarted(runClient);

try {
const metamorphedRun = await runClient.metamorph(HELLO_WORLD_ACTOR, {
message: 'Hello from metamorph!',
});
expect(metamorphedRun.id).toBe(run.id);
await client.build((await actorClient.build('0.0')).id).waitForFinish();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should check the build status, same as in Python


Suggestion: check the build status, as the iterateDatasetItems() test does. A failed build then fails here, and not later in start() with a less clear error.

Suggested change
await client.build((await actorClient.build('0.0')).id).waitForFinish();
const build = await client.build((await actorClient.build('0.0')).id).waitForFinish();
expect(build.status).toBe('SUCCEEDED');

✍️ Drafted by Claude Code

const run = await actorClient.start();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we add some limits to this run?


Suggestion: this run sleeps for 60 s with the default memory, on an account that parallel tests share. Limits like the other custom Actor test in this file would keep it small and stop it if the cleanup fails:

Suggested change
const run = await actorClient.start();
const run = await actorClient.start(undefined, { memory: 256, runTimeoutSecs: 120 });

✍️ Drafted by Claude Code

runClient = client.run(run.id);

// Only the run's own API token may metamorph it, so take it from the Actor's key-value store.
const record = await pollUntilCondition(
async () => client.keyValueStore(run.defaultKeyValueStoreId).getRecord('TOKEN'),
(rec) => rec !== undefined,
{ timeoutSecs: 120, backoffFactor: 2 },
);
const runTokenClient = makeClient(record!.value as string);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

provide a clear failure when the token is missing


Suggestion: pollUntilCondition returns undefined on timeout and does not throw. If the Actor never stores TOKEN, this line fails with "Cannot read properties of undefined". An explicit assertion gives a clear message:

Suggested change
const runTokenClient = makeClient(record!.value as string);
expect(record, 'the Actor did not store its run token').toBeDefined();
const runTokenClient = makeClient(record!.value as string);

✍️ Drafted by Claude Code


await runClient.waitForFinish();
} catch (err) {
// hello-world can finish before the metamorph lands; the API call was still exercised.
rethrowUnlessAlreadyFinished(err);
}
const metamorphedRun = await runTokenClient.run(run.id).metamorph(HELLO_WORLD_ACTOR);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep test coverage of the metamorph input body


Nit: the old test sent an input to metamorph(). Without it, no integration test sends a metamorph input body.

Suggested change
const metamorphedRun = await runTokenClient.run(run.id).metamorph(HELLO_WORLD_ACTOR);
const metamorphedRun = await runTokenClient.run(run.id).metamorph(HELLO_WORLD_ACTOR, { message: 'Hello from metamorph!' });

✍️ Drafted by Claude Code

expect(metamorphedRun.id).toBe(run.id);
} finally {
await runClient.waitForFinish();
await runClient.delete();
await runClient?.abort();
await runClient?.waitForFinish();
await runClient?.delete();
await actorClient.delete();
}
});

Expand Down
Loading