test(activity): wait for the job view's settled detail read, not a fixed delay

The 200-row cap test now starts counting detail reads once one read has
returned the full listing and none is in flight. The job view re-reads after
an in-flight read only when the summary still lists more than that read
returned, so no redundant read is left due after opening.
This commit is contained in:
Vito Sansevero
2026-10-21 17:34:02 -07:00
parent 66b3d078db
commit e2c1cc8fc9
2 changed files with 22 additions and 4 deletions
+16 -3
View File
@@ -611,6 +611,19 @@ test('job view renders 200-row cap note', async ({ page, request }) => {
await step(request, job.id, { processed: 260, bulk: { group: 'added', count: 250 }, records: [
...Array.from({ length: 10 }, (_, index) => ({ group: 'no_metadata', path: `misc/plain_${index}.png`, detail: 'No prompt metadata in the file' })),
] });
// Every detail read of this job: in flight, and whether one has returned the full listing.
const detailUrl = `/prompt_manager/jobs/${job.id}`;
const isDetail = item => new URL(item.url()).pathname === detailUrl;
const detailReads = { inFlight: 0, full: false };
page.on('request', item => { if (isDetail(item)) detailReads.inFlight += 1; });
page.on('requestfailed', item => { if (isDetail(item)) detailReads.inFlight -= 1; });
page.on('response', async response => {
if (!isDetail(response)) return;
const body = await response.json().catch(() => null);
const outcomes = body?.job?.outcomes ?? {};
if (outcomes.added?.length === 200 && outcomes.no_metadata?.length === 10) detailReads.full = true;
detailReads.inFlight -= 1;
});
await openJob(page, job.id);
await expect(tiles(page).first().locator('dd')).toHaveText('250');
await expect(fileRows(page)).toHaveCount(200);
@@ -626,9 +639,9 @@ test('job view renders 200-row cap note', async ({ page, request }) => {
// Review M12: with the list capped and the log closed, more files only update the counters; the detail is read
// again only when the log opens with new lines.
// A read still due from opening the view (at most one per DETAIL_INTERVAL_MS, 1 s) lands first; Firefox is slow
// enough that it otherwise fell inside the window below.
await page.waitForTimeout(1200);
// The reads from opening the view have settled: one returned the full listing and none is in flight. The view
// re-reads only while what the summary lists differs from the last read, so no further read is due.
await expect.poll(() => detailReads.full && detailReads.inFlight === 0).toBe(true);
const reads = [];
page.on('request', item => { if (new URL(item.url()).pathname === `/prompt_manager/jobs/${job.id}`) reads.push(Date.now()); });
await step(request, job.id, { processed: 300, bulk: { group: 'added', count: 40 } });
+6 -1
View File
@@ -329,7 +329,12 @@ export function mountActivityJobView(main, { store, scope, api, jobId }) {
reading = false;
}
render();
if (readAgain) { readAgain = false; scheduleRead(); }
// Read once more only if the summary moved past what this read returned (review: no redundant re-read).
if (readAgain) {
readAgain = false;
const job = store.find(jobId);
if (job && job.state !== 'lost' && detailChanged(job)) scheduleRead();
}
}
/**