Files
ark-stronghold-protocol/test/e2e/client-wait.test.js
T

87 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// test/e2e/client.mjs waitForFunctionLong (Node, no browser): a long wait of the real-server browser suites polls in
// slices shorter than the CDP protocol timeout. A plain page.waitForFunction runs its whole poll inside one
// Runtime.callFunctionOn, which the 90 s protocol timeout cut off: watch-bonds.e2e's "own battle over" wait (240 s) failed
// with a bare "Waiting failed" whenever the own battle at 1× lasted longer than 90 s (0.1.4 release candidate).
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync, readdirSync } from 'node:fs';
import path from 'node:path';
import { ROOT, PROTOCOL_TIMEOUT_MS, waitForFunctionLong } from './client.mjs';
const timeoutError = (ms) => Object.assign(new Error(`Waiting failed: ${ms}ms exceeded`), { name: 'TimeoutError' });
/** A page whose predicate turns true after `trueAfter` ms; each waitForFunction slice behaves like puppeteer's. */
function fakePage(trueAfter) {
const t0 = Date.now();
const calls = [];
return {
calls,
waitForFunction(fn, opts, ...args) {
calls.push({ fn, opts, args });
const left = t0 + trueAfter - Date.now();
return new Promise((resolve, reject) => {
if (left <= opts.timeout) setTimeout(() => resolve({ handle: 'ok', args }), Math.max(0, left));
else setTimeout(() => reject(timeoutError(opts.timeout)), opts.timeout);
});
},
};
}
test('a wait longer than one slice keeps polling the same predicate until it holds', async () => {
const page = fakePage(95);
const fn = () => true;
const got = await waitForFunctionLong(page, fn, { timeout: 1000, polling: 200, slice: 30 }, 'a', 2);
assert.deepEqual(got, { handle: 'ok', args: ['a', 2] });
assert.ok(page.calls.length >= 4, `sliced (${page.calls.length} calls)`);
for (const c of page.calls) {
assert.equal(c.fn, fn);
assert.deepEqual(c.args, ['a', 2]);
assert.equal(c.opts.polling, 200);
assert.ok(c.opts.timeout > 0 && c.opts.timeout <= 30, `slice ${c.opts.timeout}`);
}
});
test('the overall timeout still ends the wait with a TimeoutError naming it; the last slice is the remainder', async () => {
const page = fakePage(10_000);
const t0 = Date.now();
await assert.rejects(waitForFunctionLong(page, () => false, { timeout: 70, slice: 30 }), (e) => e.name === 'TimeoutError' && /70ms exceeded/.test(e.message));
assert.ok(Date.now() - t0 >= 65, 'not before the deadline');
assert.ok(page.calls.at(-1).opts.timeout <= 30);
assert.ok(page.calls.reduce((n, c) => n + c.opts.timeout, 0) <= 75, 'the slices add up to the timeout');
});
test('any other failure is not retried (a page error, a detached frame, the protocol timeout itself)', async () => {
for (const err of [new Error('Waiting failed'), Object.assign(new Error('boom'), { name: 'ProtocolError' })]) {
let n = 0;
const page = { waitForFunction: () => { n++; return Promise.reject(err); } };
await assert.rejects(waitForFunctionLong(page, () => true, { timeout: 1000, slice: 30 }), (e) => e === err);
assert.equal(n, 1);
}
});
test('the default slice stays well under the protocol timeout every Client launches with', async () => {
const page = fakePage(0);
await waitForFunctionLong(page, () => true, { timeout: 240000 });
assert.ok(page.calls[0].opts.timeout < PROTOCOL_TIMEOUT_MS / 2, `slice ${page.calls[0].opts.timeout}`);
const client = readFileSync(path.join(ROOT, 'test/e2e/client.mjs'), 'utf8');
assert.match(client, /protocolTimeout: PROTOCOL_TIMEOUT_MS \}/, 'Client.open launches with the exported constant');
});
test('no Client suite has a plain page.waitForFunction as long as the protocol timeout (use waitForFunctionLong)', () => {
const files = [];
for (const dir of ['test/ui', 'test/e2e']) {
for (const f of readdirSync(path.join(ROOT, dir))) if (/\.(m?js)$/.test(f)) files.push(path.join(dir, f));
}
const long = [];
for (const f of files) {
const src = readFileSync(path.join(ROOT, f), 'utf8');
if (!/from '\.\.\/e2e\/client\.mjs'|from '\.\/client\.mjs'/.test(src)) continue;
for (let i = src.indexOf('.waitForFunction('); i >= 0; i = src.indexOf('.waitForFunction(', i + 1)) {
const next = src.indexOf('.waitForFunction(', i + 1);
const m = src.slice(i, next < 0 ? undefined : next).match(/\{ timeout: ([0-9_]+)/);
if (m && Number(m[1].replace(/_/g, '')) >= PROTOCOL_TIMEOUT_MS) long.push(`${f}:${src.slice(0, i).split('\n').length} (${m[1]} ms)`);
}
}
assert.deepEqual(long, []);
});