Skip to content

Commit 6b080ac

Browse files
authored
Update test.rerun.spec.ts
1 parent bdec093 commit 6b080ac

1 file changed

Lines changed: 132 additions & 67 deletions

File tree

src/commands/test.rerun.spec.ts

Lines changed: 132 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -4823,77 +4823,142 @@ describe('rerun --wait — dashboardUrl on terminal output', () => {
48234823
// ---------------------------------------------------------------------------
48244824
// Batch --all --wait fan-out: RequestTimeoutError must not leave stdout empty
48254825
// ---------------------------------------------------------------------------
4826-
describe('[finding-5] batch rerun --wait: RequestTimeoutError during fan-out poll writes JSON stdout + exit 7', () => {
4827-
it('stdout contains accepted[] with runIds when member polls throw RequestTimeoutError', async () => {
4828-
const creds = makeCreds();
4829-
const batchResp: BatchRerunResponse = {
4830-
accepted: [
4831-
{ testId: 'test_1', runId: 'run_b1', enqueuedAt: '2026-06-03T10:00:00.000Z' },
4832-
{ testId: 'test_2', runId: 'run_b2', enqueuedAt: '2026-06-03T10:00:00.000Z' }
4833-
],
4834-
deferred: [],
4835-
conflicts: [],
4836-
closure: { byProject: [] }
4837-
};
4838-
const fetchImpl = makeFetch((url) => {
4839-
if (url.includes('/tests/batch/rerun')) return { status: 202, body: batchResp };
4840-
if (url.includes('/runs/')) throw new RequestTimeoutError(120000, 'req_timeout_batch');
4841-
return errorBody('NOT_FOUND');
4842-
});
4843-
const stdoutLines: string[] = [];
4844-
const err = await runTestRerun(
4845-
{
4846-
testIds: ['test_1', 'test_2'],
4847-
all: false,
4848-
wait: true,
4849-
timeoutSeconds: 60,
4850-
autoHeal: false,
4851-
autoHealExplicit: false,
4852-
skipDependencies: false,
4853-
maxConcurrency: 1,
4854-
profile: 'default',
4855-
output: 'json',
4856-
debug: false
4826+
describe(
4827+
'[finding-5] batch rerun --wait: RequestTimeoutError during fan-out poll writes JSON stdout + exit 7',
4828+
() => {
4829+
it(
4830+
'stdout contains accepted[] with runIds when member polls throw RequestTimeoutError',
4831+
async () => {
4832+
const creds = makeCreds();
4833+
const batchResp: BatchRerunResponse = {
4834+
accepted: [
4835+
{ testId: 'test_1', runId: 'run_b1', enqueuedAt: '2026-06-03T10:00:00.000Z' },
4836+
{ testId: 'test_2', runId: 'run_b2', enqueuedAt: '2026-06-03T10:00:00.000Z' },
4837+
],
4838+
deferred: [],
4839+
conflicts: [],
4840+
closure: { byProject: [] },
4841+
};
4842+
4843+
const fetchImpl = makeFetch((url) => {
4844+
if (url.includes('/tests/batch/rerun')) {
4845+
return { status: 202, body: batchResp };
4846+
}
4847+
if (url.includes('/runs/')) {
4848+
throw new RequestTimeoutError(120000, 'req_timeout_batch_rerun');
4849+
}
4850+
return errorBody('NOT_FOUND');
4851+
});
4852+
4853+
const stdoutLines: string[] = [];
4854+
const err = await runTestRerun(
4855+
{
4856+
testIds: ['test_1', 'test_2'],
4857+
all: false,
4858+
wait: true,
4859+
timeoutSeconds: 60,
4860+
autoHeal: false,
4861+
autoHealExplicit: false,
4862+
skipDependencies: false,
4863+
maxConcurrency: 1,
4864+
profile: 'default',
4865+
output: 'json',
4866+
debug: false,
4867+
},
4868+
{
4869+
...creds,
4870+
sleep: instantSleep,
4871+
fetchImpl: fetchImpl as unknown as FetchImpl,
4872+
stdout: (line) => stdoutLines.push(line),
4873+
stderr: () => undefined,
4874+
},
4875+
).catch((e) => e);
4876+
4877+
expect(err).toMatchObject({ exitCode: 7 });
4878+
const parsed = JSON.parse(stdoutLines.join('\n')) as {
4879+
accepted: Array<{ testId: string; runId: string; status: string }>;
4880+
};
4881+
expect(parsed.accepted).toHaveLength(2);
4882+
expect(parsed.accepted.map((r) => r.runId).sort()).toEqual(['run_b1', 'run_b2']);
4883+
expect(parsed.accepted.every((r) => r.status === 'timeout')).toBe(true);
48574884
},
4858-
{ ...creds, sleep: instantSleep, fetchImpl: fetchImpl as unknown as FetchImpl, stdout: (l) => stdoutLines.push(l), stderr: () => undefined }
4859-
).catch((e) => e);
4860-
expect(err).toMatchObject({ exitCode: 7 });
4861-
});
4862-
});
4885+
);
4886+
},
4887+
);
48634888

48644889
// ---------------------------------------------------------------------------
48654890
// TimeoutError on single FE rerun --wait: partial stdout + exit 7
48664891
// ---------------------------------------------------------------------------
48674892
describe('[finding-4] single FE rerun --wait: TimeoutError writes partial JSON to stdout', () => {
4868-
it('exit 7 AND stdout contains {runId, status:"running"} when --timeout polling deadline is exceeded', async () => {
4869-
const creds = makeCreds();
4870-
const rerunResp = { runId: 'run_fe_01', status: 'accepted' };
4871-
const fetchImpl: FetchImpl = async (input) => {
4872-
const url = typeof input === 'string' ? input : (input as Request).url;
4873-
if (url.includes('/runs/rerun')) return new Response(JSON.stringify(rerunResp), { status: 202 });
4874-
if (url.includes('/runs/')) return new Response(JSON.stringify({ runId: rerunResp.runId, status: 'running', finishedAt: null }), { status: 200 });
4875-
return new Response(JSON.stringify({ error: { code: 'NOT_FOUND' } }), { status: 404 });
4876-
};
4877-
const stdoutLines: string[] = [];
4878-
const err = await runTestRerun(
4879-
{
4880-
testIds: ['test_fe_01'],
4881-
all: false,
4882-
wait: true,
4883-
timeoutSeconds: 0,
4884-
autoHeal: false,
4885-
autoHealExplicit: false,
4886-
skipDependencies: false,
4887-
maxConcurrency: 10,
4888-
output: 'json',
4889-
profile: 'default',
4890-
debug: false
4891-
},
4892-
{ ...creds, sleep: instantSleep, fetchImpl: fetchImpl as unknown as FetchImpl, stdout: (l) => stdoutLines.push(l), stderr: () => undefined }
4893-
).catch((e) => e);
4894-
expect(err).toMatchObject({ exitCode: 7 });
4895-
const parsed = JSON.parse(stdoutLines.join('\n')) as { runId: string; status: string };
4896-
expect(parsed.runId).toBe(rerunResp.runId);
4897-
expect(parsed.status).toBe('running');
4898-
});
4893+
it(
4894+
'exit 7 AND stdout contains {runId, status:"running"} when --timeout polling deadline is exceeded',
4895+
async () => {
4896+
const creds = makeCreds();
4897+
const rerunResp = makeFeRerunResp();
4898+
4899+
let fetchCallCount = 0;
4900+
const fetchImpl: typeof globalThis.fetch = async (input, _init) => {
4901+
const url =
4902+
typeof input === 'string'
4903+
? input
4904+
: input instanceof URL
4905+
? input.toString()
4906+
: (input as { url: string }).url;
4907+
fetchCallCount++;
4908+
if (url.includes('/tests/test_fe_01/runs/rerun')) {
4909+
return new Response(JSON.stringify(rerunResp), {
4910+
status: 202,
4911+
headers: { 'content-type': 'application/json' },
4912+
});
4913+
}
4914+
if (url.includes('/runs/')) {
4915+
const runningRun: RunResponse = {
4916+
...makeTerminalRun(rerunResp.runId, 'passed'),
4917+
status: 'running',
4918+
finishedAt: null,
4919+
};
4920+
return new Response(JSON.stringify(runningRun), {
4921+
status: 200,
4922+
headers: { 'content-type': 'application/json' },
4923+
});
4924+
}
4925+
return new Response(JSON.stringify({ error: { code: 'NOT_FOUND' } }), { status: 404 });
4926+
};
4927+
4928+
const stdoutLines: string[] = [];
4929+
4930+
const err = await runTestRerun(
4931+
{
4932+
testIds: ['test_fe_01'],
4933+
all: false,
4934+
wait: true,
4935+
timeoutSeconds: 0,
4936+
autoHeal: false,
4937+
autoHealExplicit: false,
4938+
skipDependencies: false,
4939+
maxConcurrency: 10,
4940+
output: 'json',
4941+
profile: 'default',
4942+
dryRun: false,
4943+
debug: false,
4944+
verbose: false,
4945+
},
4946+
{
4947+
...creds,
4948+
sleep: instantSleep,
4949+
fetchImpl: fetchImpl as unknown as FetchImpl,
4950+
stdout: (line) => stdoutLines.push(line),
4951+
stderr: () => undefined,
4952+
},
4953+
).catch((e) => e);
4954+
4955+
expect(err).toMatchObject({ exitCode: 7 });
4956+
expect(stdoutLines.length).toBeGreaterThan(0);
4957+
const parsed = JSON.parse(stdoutLines.join('\n')) as { runId: string; status: string };
4958+
expect(parsed.runId).toBe(rerunResp.runId);
4959+
expect(parsed.status).toBe('running');
4960+
4961+
void fetchCallCount;
4962+
},
4963+
);
48994964
});

0 commit comments

Comments
 (0)