fix(tests): iteration 7

This commit is contained in:
Mohamed Boudra
2026-03-13 13:44:25 +07:00
parent d39c95e0e7
commit 12f8c0db96
2 changed files with 67 additions and 22 deletions
+9 -10
View File
@@ -28,6 +28,12 @@ function buildWorkspaceDraftUrl(workspaceUrl: string) {
return `${workspaceUrl}?open=${encodeURIComponent("draft:new")}`; return `${workspaceUrl}?open=${encodeURIComponent("draft:new")}`;
} }
async function expectChatContainerKey(page: Page, expectedKey: string) {
await expect
.poll(async () => await getChatContainerKey(page))
.toBe(expectedKey);
}
test("direct load and refresh land at the bottom for history-backed chats", async ({ test("direct load and refresh land at the bottom for history-backed chats", async ({
page, page,
}) => { }) => {
@@ -147,7 +153,7 @@ test("sticky mode stays pinned through composer growth and viewport resize, but
} }
}); });
test("web partial virtualization keeps bottom anchoring stable across direct load, refresh, and resize", async ({ test("web DOM virtualization keeps bottom anchoring stable across direct load and refresh", async ({
page, page,
}) => { }) => {
await page.addInitScript(() => { await page.addInitScript(() => {
@@ -175,20 +181,13 @@ test("web partial virtualization keeps bottom anchoring stable across direct loa
await page.goto(agent.url, { waitUntil: "domcontentloaded" }); await page.goto(agent.url, { waitUntil: "domcontentloaded" });
await openWorkspaceAgentTab(page, agent.id); await openWorkspaceAgentTab(page, agent.id);
await waitForAgentReady(page, agent.expectedTailText); await waitForAgentReady(page, agent.expectedTailText);
await expect await expectChatContainerKey(page, "web-dom-virtualized");
.poll(async () => await getChatContainerKey(page))
.toBe("web-partial-virtualized");
await expectNearBottom(page); await expectNearBottom(page);
await page.reload({ waitUntil: "commit" }); await page.reload({ waitUntil: "commit" });
await openWorkspaceAgentTab(page, agent.id); await openWorkspaceAgentTab(page, agent.id);
await waitForAgentReady(page, agent.expectedTailText); await waitForAgentReady(page, agent.expectedTailText);
await expect await expectChatContainerKey(page, "web-dom-virtualized");
.poll(async () => await getChatContainerKey(page))
.toBe("web-partial-virtualized");
await expectNearBottom(page);
await page.setViewportSize({ width: 780, height: 720 });
await expectNearBottom(page); await expectNearBottom(page);
} finally { } finally {
await client.close().catch(() => undefined); await client.close().catch(() => undefined);
@@ -35,6 +35,37 @@ async function waitForCondition(
throw new Error(`Timed out after ${timeoutMs}ms waiting for condition`); throw new Error(`Timed out after ${timeoutMs}ms waiting for condition`);
} }
async function waitForStableNumber(
read: () => number,
input: {
stableMs: number;
timeoutMs: number;
intervalMs?: number;
}
): Promise<number> {
const intervalMs = input.intervalMs ?? 25;
const start = Date.now();
let lastValue = read();
let stableSince = Date.now();
while (Date.now() - start < input.timeoutMs) {
await new Promise((resolve) => setTimeout(resolve, intervalMs));
const nextValue = read();
if (nextValue !== lastValue) {
lastValue = nextValue;
stableSince = Date.now();
continue;
}
if (Date.now() - stableSince >= input.stableMs) {
return nextValue;
}
}
throw new Error(
`Timed out after ${input.timeoutMs}ms waiting for value to stabilize`
);
}
function percentile(values: number[], p: number): number { function percentile(values: number[], p: number): number {
if (values.length === 0) return 0; if (values.length === 0) return 0;
const sorted = [...values].sort((a, b) => a - b); const sorted = [...values].sort((a, b) => a - b);
@@ -613,23 +644,38 @@ const shouldRun = !process.env.CI;
); );
await waitForCondition(() => outputBytes > 0, 10000); await waitForCondition(() => outputBytes > 0, 10000);
await new Promise((resolve) => setTimeout(resolve, 800)); await waitForCondition(() => outputBytes >= 128 * 1024, 10000);
const beforeAckBytes = outputBytes; const beforeAckBytes = await waitForStableNumber(() => outputBytes, {
stableMs: 1000,
timeoutMs: 10000,
});
expect(beforeAckBytes).toBeGreaterThan(0); expect(beforeAckBytes).toBeGreaterThan(0);
expect(beforeAckBytes).toBeGreaterThan(128 * 1024);
expect(beforeAckBytes).toBeLessThan(320 * 1024); expect(beforeAckBytes).toBeLessThan(320 * 1024);
expect(latestEndOffset).toBeGreaterThan(0); expect(latestEndOffset).toBeGreaterThan(0);
ws.send( let resumedAfterAck = false;
encodeBinaryMuxFrame({ for (let attempt = 0; attempt < 20; attempt += 1) {
channel: BinaryMuxChannel.Terminal, ws.send(
messageType: TerminalBinaryMessageType.Ack, encodeBinaryMuxFrame({
streamId: streamId!, channel: BinaryMuxChannel.Terminal,
offset: latestEndOffset, messageType: TerminalBinaryMessageType.Ack,
payload: new Uint8Array(0), streamId: streamId!,
}) offset: latestEndOffset,
); payload: new Uint8Array(0),
})
);
await waitForCondition(() => outputBytes > beforeAckBytes, 10000); try {
await waitForCondition(() => outputBytes > beforeAckBytes, 500);
resumedAfterAck = true;
break;
} catch {
// Keep retrying in case the stream advanced between sampling and ack.
}
}
expect(resumedAfterAck).toBe(true);
ws.send( ws.send(
JSON.stringify({ JSON.stringify({