| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- const fs = require("node:fs");
- const path = require("node:path");
- const { test, expect } = require("@playwright/test");
- const speedtestSource = fs.readFileSync(
- path.join(__dirname, "..", "..", "speedtest.js"),
- "utf8"
- );
- async function installSpeedtest(page) {
- await page.goto("about:blank");
- await page.evaluate(() => {
- window.__workers = [];
- window.Worker = class FakeWorker {
- constructor(url) {
- this.url = url;
- this.messages = [];
- this.terminated = false;
- this.terminateCount = 0;
- window.__workers.push(this);
- }
- postMessage(message) {
- this.messages.push(message);
- }
- terminate() {
- this.terminated = true;
- this.terminateCount++;
- }
- emit(data) {
- this.onmessage(new MessageEvent("message", { data: JSON.stringify(data) }));
- }
- };
- });
- await page.addScriptTag({ content: speedtestSource });
- }
- function terminalState(testState) {
- return { testState: testState };
- }
- test.describe("Speedtest worker lifecycle", () => {
- test.beforeEach(async ({ page }) => {
- await installSpeedtest(page);
- });
- test("terminates a worker after normal completion", async ({ page }) => {
- const result = await page.evaluate((data) => {
- const speedtest = new Speedtest();
- speedtest.start();
- const worker = window.__workers[0];
- worker.emit(data);
- return {
- state: speedtest.getState(),
- worker: speedtest.worker,
- updater: speedtest.updater,
- terminated: worker.terminated,
- terminateCount: worker.terminateCount
- };
- }, terminalState(4));
- expect(result).toEqual({
- state: 4,
- worker: null,
- updater: null,
- terminated: true,
- terminateCount: 1
- });
- });
- test("can start again after normal completion", async ({ page }) => {
- const result = await page.evaluate((data) => {
- const speedtest = new Speedtest();
- speedtest.start();
- const first = window.__workers[0];
- first.emit(data);
- speedtest.start();
- const second = window.__workers[1];
- return {
- state: speedtest.getState(),
- firstTerminated: first.terminated,
- secondTerminated: second.terminated,
- activeWorkerIsSecond: speedtest.worker === second
- };
- }, terminalState(4));
- expect(result).toEqual({
- state: 3,
- firstTerminated: true,
- secondTerminated: false,
- activeWorkerIsSecond: true
- });
- });
- test("can start again after an abort response", async ({ page }) => {
- const result = await page.evaluate((data) => {
- const speedtest = new Speedtest();
- speedtest.start();
- const first = window.__workers[0];
- speedtest.abort();
- first.emit(data);
- speedtest.start();
- const second = window.__workers[1];
- return {
- state: speedtest.getState(),
- firstTerminated: first.terminated,
- secondTerminated: second.terminated,
- activeWorkerIsSecond: speedtest.worker === second
- };
- }, terminalState(5));
- expect(result).toEqual({
- state: 3,
- firstTerminated: true,
- secondTerminated: false,
- activeWorkerIsSecond: true
- });
- });
- test("does not terminate a worker started synchronously by onend", async ({ page }) => {
- const result = await page.evaluate((data) => {
- const speedtest = new Speedtest();
- let endCalls = 0;
- speedtest.onend = () => {
- endCalls++;
- speedtest.start();
- };
- speedtest.start();
- const first = window.__workers[0];
- first.emit(data);
- const second = window.__workers[1];
- return {
- endCalls: endCalls,
- state: speedtest.getState(),
- firstTerminated: first.terminated,
- secondTerminated: second.terminated,
- activeWorkerIsSecond: speedtest.worker === second
- };
- }, terminalState(4));
- expect(result).toEqual({
- endCalls: 1,
- state: 3,
- firstTerminated: true,
- secondTerminated: false,
- activeWorkerIsSecond: true
- });
- });
- test("forces a single aborted completion when a worker does not respond", async ({ page }) => {
- await page.evaluate(() => {
- window.__speedtest = new Speedtest();
- window.__endCalls = 0;
- window.__speedtest.onend = (aborted) => {
- if (aborted) window.__endCalls++;
- };
- window.__speedtest.start();
- window.__speedtest.abort();
- });
- await expect
- .poll(() =>
- page.evaluate(() => ({
- state: window.__speedtest.getState(),
- worker: window.__speedtest.worker,
- updater: window.__speedtest.updater,
- terminated: window.__workers[0].terminated,
- endCalls: window.__endCalls
- }))
- )
- .toEqual({
- state: 4,
- worker: null,
- updater: null,
- terminated: true,
- endCalls: 1
- });
- await page.waitForTimeout(1100);
- expect(await page.evaluate(() => window.__endCalls)).toBe(1);
- });
- test("ignores delayed events and an old abort timeout after a new run starts", async ({ page }) => {
- await page.evaluate((data) => {
- window.__speedtest = new Speedtest();
- window.__endCalls = 0;
- window.__updates = 0;
- window.__speedtest.onupdate = () => window.__updates++;
- window.__speedtest.onend = () => {
- window.__endCalls++;
- window.__speedtest.start();
- };
- window.__speedtest.start();
- window.__first = window.__workers[0];
- window.__speedtest.abort();
- window.__first.emit(data);
- window.__second = window.__workers[1];
- }, terminalState(5));
- await page.waitForTimeout(1100);
- const result = await page.evaluate((data) => {
- window.__first.emit(data);
- return {
- endCalls: window.__endCalls,
- updates: window.__updates,
- state: window.__speedtest.getState(),
- firstTerminated: window.__first.terminated,
- secondTerminated: window.__second.terminated,
- activeWorkerIsSecond: window.__speedtest.worker === window.__second
- };
- }, terminalState(5));
- expect(result).toEqual({
- endCalls: 1,
- updates: 1,
- state: 3,
- firstTerminated: true,
- secondTerminated: false,
- activeWorkerIsSecond: true
- });
- });
- });
|