From 4725a836212e7e2dc27eb64140b900131d5ff85a Mon Sep 17 00:00:00 2001 From: Shane Osbourne Date: Sat, 16 Nov 2024 21:08:00 +0000 Subject: [PATCH 1/2] not found v2 --- crates/bsnext_core/src/handler_stack.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/bsnext_core/src/handler_stack.rs b/crates/bsnext_core/src/handler_stack.rs index 9229e0ea..25513537 100644 --- a/crates/bsnext_core/src/handler_stack.rs +++ b/crates/bsnext_core/src/handler_stack.rs @@ -1,9 +1,10 @@ use crate::handlers::proxy::{proxy_handler, ProxyConfig}; +use crate::not_found::not_found_service::{not_found_loader, not_found_srv}; use crate::optional_layers::optional_layers; use crate::raw_loader::serve_raw_one; use crate::serve_dir::try_many_services_dir; use axum::handler::Handler; -use axum::middleware::from_fn_with_state; +use axum::middleware::{from_fn, from_fn_with_state}; use axum::routing::{any, any_service, get_service, MethodRouter}; use axum::{Extension, Router}; use bsnext_input::route::{DirRoute, FallbackRoute, Opts, ProxyRoute, RawRoute, Route, RouteKind}; @@ -219,7 +220,9 @@ pub fn stack_to_router(path: &str, stack: HandlerStack) -> Router { } HandlerStack::Dirs(dirs) => { let service = serve_dir_layer(&dirs, Router::new()); - Router::new().nest_service(path, service) + Router::new() + .nest_service(path, service) + .layer(from_fn(not_found_loader)) } HandlerStack::Proxy { proxy, opts } => { let proxy_config = ProxyConfig { From 7fcbc9e8d1ac4de05d15f2259afe93be5dc6508d Mon Sep 17 00:00:00 2001 From: Shane Osbourne Date: Sat, 16 Nov 2024 21:32:28 +0000 Subject: [PATCH 2/2] added a test for 404 --- examples/basic/empty/.gitignore | 0 examples/basic/fallback.yml | 5 ++ package.json | 3 +- tests/bslive-ui.spec.ts | 32 +++++-- tests/client.spec.ts | 13 ++- tests/delays.spec.ts | 34 +++---- tests/headers.spec.ts | 39 ++++---- tests/inject.spec.ts | 28 +++--- tests/live-reload.spec.ts | 87 +++++++++--------- tests/playground.spec.ts | 22 ++--- tests/react-router.spec.ts | 48 +++++----- tests/sse.spec.ts | 26 +++--- tests/utils.ts | 155 ++++++++++++++++---------------- 13 files changed, 265 insertions(+), 227 deletions(-) create mode 100644 examples/basic/empty/.gitignore create mode 100644 examples/basic/fallback.yml diff --git a/examples/basic/empty/.gitignore b/examples/basic/empty/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/examples/basic/fallback.yml b/examples/basic/fallback.yml new file mode 100644 index 00000000..68f9b920 --- /dev/null +++ b/examples/basic/fallback.yml @@ -0,0 +1,5 @@ +servers: + - name: "fallback" + routes: + - path: / + dir: examples/basic/empty diff --git a/package.json b/package.json index d9d50cf2..3739cc75 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,8 @@ "universal": "napi universal", "version": "napi version", "tsc": "tsc", - "tsc:watch": "tsc --watch" + "tsc:watch": "tsc --watch", + "lint": "deno fmt tests" }, "napi": { "name": "bslive", diff --git a/tests/bslive-ui.spec.ts b/tests/bslive-ui.spec.ts index 320dba8a..7d3f2440 100644 --- a/tests/bslive-ui.spec.ts +++ b/tests/bslive-ui.spec.ts @@ -1,15 +1,29 @@ -import {bstest, test} from './utils'; +import { bstest, test } from "./utils"; +import { expect } from "@playwright/test"; -test.describe('Browsersync bslive 404 UI', { +test.describe("Browsersync bslive 404 UI", { annotation: { type: bstest({ - input: 'examples/basic/headers.yml' - }) - } + input: "examples/basic/headers.yml", + }), + }, }, () => { + test("shows the UI", async ({ page, request, bs }) => { + await page.goto(bs.path("/__bslive")); + await page.locator("bs-header").waitFor({ timeout: 1000 }); + }); +}); - test('shows the UI', async ({page, request, bs}) => { - await page.goto(bs.path('/__bslive')); - await page.locator('bs-header').waitFor({timeout: 1000}); +test.describe("Browsersync bslive 404 fallback", { + annotation: { + type: bstest({ + input: "examples/basic/fallback.yml", + }), + }, +}, () => { + test("shows the UI as fallback on DIR", async ({ page, bs }) => { + const r = await page.goto(bs.path("/")); + await page.locator("bs-header").waitFor({ timeout: 1000 }); + expect(r?.status()).toEqual(404); }); -}) +}); diff --git a/tests/client.spec.ts b/tests/client.spec.ts index 4f830840..763a487c 100644 --- a/tests/client.spec.ts +++ b/tests/client.spec.ts @@ -1,14 +1,13 @@ import {bstest, test} from "./utils"; -import {expect} from "@playwright/test"; -test.describe('examples/basic/client.yml', { +test.describe("examples/basic/client.yml", { annotation: { type: bstest({ - input: 'examples/basic/client.yml' + input: "examples/basic/client.yml", }), - description: '' - } + description: "", + }, }, () => { - test('configures log level', async ({request, bs}) => { + test("configures log level", async ({request, bs}) => { }); -}) +}); diff --git a/tests/delays.spec.ts b/tests/delays.spec.ts index 20adf854..2c77e2ce 100644 --- a/tests/delays.spec.ts +++ b/tests/delays.spec.ts @@ -1,34 +1,34 @@ -import {bstest, test} from "./utils"; -import {expect} from "@playwright/test"; +import { bstest, test } from "./utils"; +import { expect } from "@playwright/test"; -test.describe('examples/basic/delays.yml', { +test.describe("examples/basic/delays.yml", { annotation: { type: bstest({ - input: 'examples/basic/delays.yml' + input: "examples/basic/delays.yml", }), - description: '' - } + description: "", + }, }, () => { - test('first delay item', async ({request, bs}) => { + test("first delay item", async ({ request, bs }) => { const start = Date.now(); - const response = await request.get(bs.path('/')); + const response = await request.get(bs.path("/")); const body = await response.body(); const diff = Date.now() - start; - expect(body.toString()).toBe(`first - 200ms delay`) - expect(diff).toBeGreaterThan(200) - expect(diff).toBeLessThan(300) + expect(body.toString()).toBe(`first - 200ms delay`); + expect(diff).toBeGreaterThan(200); + expect(diff).toBeLessThan(300); }); - test('500ms delay', async ({request, bs}) => { + test("500ms delay", async ({ request, bs }) => { const start = Date.now(); - const response = await request.get(bs.path('/500')); + const response = await request.get(bs.path("/500")); const body = await response.body(); const diff = Date.now() - start; - expect(body.toString()).toBe(`second - 500ms delay`) - expect(diff).toBeGreaterThan(500) - expect(diff).toBeLessThan(600) + expect(body.toString()).toBe(`second - 500ms delay`); + expect(diff).toBeGreaterThan(500); + expect(diff).toBeLessThan(600); }); -}) +}); diff --git a/tests/headers.spec.ts b/tests/headers.spec.ts index 717f351b..43184ff1 100644 --- a/tests/headers.spec.ts +++ b/tests/headers.spec.ts @@ -1,17 +1,17 @@ -import {bstest, test} from "./utils"; -import {expect} from "@playwright/test"; +import { bstest, test } from "./utils"; +import { expect } from "@playwright/test"; -test.describe('examples/basic/headers.yml', { +test.describe("examples/basic/headers.yml", { annotation: { type: bstest({ - input: 'examples/basic/headers.yml' + input: "examples/basic/headers.yml", }), - description: '' - } + description: "", + }, }, () => { - test('first item /', async ({request, bs}) => { + test("first item /", async ({ request, bs }) => { // Send a GET request to the base URL - const response = await request.get(bs.path('/')); + const response = await request.get(bs.path("/")); // Extract headers from the response const headers = response.headers(); @@ -20,20 +20,21 @@ test.describe('examples/basic/headers.yml', { const body = await response.body(); // Assert that the content-type header is 'application/json' - expect(headers['content-type']).toBe('application/json') + expect(headers["content-type"]).toBe("application/json"); // Assert that the body content is '[ 1, 2 ]' - expect(body.toString()).toBe(`[ 1, 2 ]`) + expect(body.toString()).toBe(`[ 1, 2 ]`); }); - test('/other', async ({request, bs}) => { - const response = await request.get(bs.path('/other')); + test("/other", async ({ request, bs }) => { + const response = await request.get(bs.path("/other")); const headers = response.headers(); const expected = { - 'vary': 'origin, access-control-request-method, access-control-request-headers', - 'access-control-allow-origin': 'localhost', - 'access-control-expose-headers': '*', - abc: 'def', - } - expect(headers).toMatchObject(expected) + "vary": + "origin, access-control-request-method, access-control-request-headers", + "access-control-allow-origin": "localhost", + "access-control-expose-headers": "*", + abc: "def", + }; + expect(headers).toMatchObject(expected); }); -}) +}); diff --git a/tests/inject.spec.ts b/tests/inject.spec.ts index 7629e39f..ee970c73 100644 --- a/tests/inject.spec.ts +++ b/tests/inject.spec.ts @@ -1,31 +1,31 @@ -import {bstest, test} from "./utils"; -import {expect} from "@playwright/test"; +import { bstest, test } from "./utils"; +import { expect } from "@playwright/test"; -test.describe('examples/basic/inject.yml', { +test.describe("examples/basic/inject.yml", { annotation: { type: bstest({ - input: 'examples/basic/inject.yml' + input: "examples/basic/inject.yml", }), - description: '' - } + description: "", + }, }, () => { - test('inject bslive:connector', async ({request, bs}) => { - const response = await request.get(bs.path('/'), { + test("inject bslive:connector", async ({ request, bs }) => { + const response = await request.get(bs.path("/"), { headers: { - accept: 'text/html' - } + accept: "text/html", + }, }); const body = await response.body(); expect(body.toString()).toMatchSnapshot(); { - const response = await request.get(bs.path('/form.html'), { + const response = await request.get(bs.path("/form.html"), { headers: { - accept: 'text/html' - } + accept: "text/html", + }, }); const body = await response.body(); expect(body.toString()).toMatchSnapshot(); } }); -}) +}); diff --git a/tests/live-reload.spec.ts b/tests/live-reload.spec.ts index 1fe2c23b..f4b33e54 100644 --- a/tests/live-reload.spec.ts +++ b/tests/live-reload.spec.ts @@ -1,45 +1,48 @@ -import {bstest, installMockHandler, readCalls, test} from "./utils"; -import {expect} from "@playwright/test"; -import {z} from "zod"; -import {clientEventSchema} from "bsnext_client/generated/schema"; -import {ChangeKind} from "bsnext_client/generated/dto"; +import { bstest, installMockHandler, readCalls, test } from "./utils"; +import { expect } from "@playwright/test"; +import { z } from "zod"; +import { clientEventSchema } from "bsnext_client/generated/schema"; +import { ChangeKind } from "bsnext_client/generated/dto"; -test.describe('examples/basic/live-reload.yml', { +test.describe("examples/basic/live-reload.yml", { annotation: { type: bstest({ - input: 'examples/basic/live-reload.yml' + input: "examples/basic/live-reload.yml", }), - description: '' - } + description: "", + }, }, () => { - test('live-reloading css', async ({page, bs}) => { + test("live-reloading css", async ({ page, bs }) => { // Array to store console messages const messages: [type: string, text: string][] = []; // Listen to console messages on the page - page.on('console', (msg) => { + page.on("console", (msg) => { messages.push([msg.type(), msg.text()]); }); // Navigate to the page and wait until network is idle - await page.goto(bs.path('/'), {waitUntil: 'networkidle'}); + await page.goto(bs.path("/"), { waitUntil: "networkidle" }); // Set up the request waiting promise const requestPromise = page.waitForRequest((req) => { const url = new URL(req.url()); - return url.searchParams.has('livereload') && url.pathname === "/styles.css"; - }, {timeout: 2000}); + return url.searchParams.has("livereload") && + url.pathname === "/styles.css"; + }, { timeout: 2000 }); // Trigger the live-reload by touching the CSS file - bs.touch('examples/basic/public/styles.css'); + bs.touch("examples/basic/public/styles.css"); await requestPromise; // Filter the log messages for specific content and assert - const log = messages.filter(([, text]) => text === "[debug] found 1 LINKed stylesheets, 1 @imported stylesheets"); + const log = messages.filter(([, text]) => + text === "[debug] found 1 LINKed stylesheets, 1 @imported stylesheets" + ); expect(log).toHaveLength(1); }); - test('reloads with HTML change', async ({page, bs, request}) => { - await page.goto(bs.path('/'), {waitUntil: 'networkidle'}) + test("reloads with HTML change", async ({ page, bs, request }) => { + await page.goto(bs.path("/"), { waitUntil: "networkidle" }); // Define the change event const change: z.infer = { @@ -48,33 +51,33 @@ test.describe('examples/basic/live-reload.yml', { "kind": "Fs", "payload": { "path": "index.html", - "change_kind": ChangeKind.Changed - } - } + "change_kind": ChangeKind.Changed, + }, + }, }; // Install mock handler and send change event await page.evaluate(installMockHandler); - await request.post(bs.api('events'), {data: change}); + await request.post(bs.api("events"), { data: change }); // Wait for the reloadPage call await page.waitForFunction(() => { - return window.__playwright?.calls?.length === 1 - }) + return window.__playwright?.calls?.length === 1; + }); // Verify the calls - const calls = await page.evaluate(readCalls) + const calls = await page.evaluate(readCalls); expect(calls).toStrictEqual([ [ { - "kind": "reloadPage" - } - ] + "kind": "reloadPage", + }, + ], ]); }); - test('no css reloads with HTML + CSS change', async ({page, bs, request}) => { + test("no css reloads with HTML + CSS change", async ({ page, bs, request }) => { // Navigate to the page and wait until network is idle - await page.goto(bs.path('/'), {waitUntil: 'networkidle'}); + await page.goto(bs.path("/"), { waitUntil: "networkidle" }); // Define the change event const change: z.infer = { @@ -86,23 +89,23 @@ test.describe('examples/basic/live-reload.yml', { "kind": "Fs", "payload": { "path": "reset.css", - "change_kind": ChangeKind.Changed - } + "change_kind": ChangeKind.Changed, + }, }, { "kind": "Fs", "payload": { "path": "index.html", - "change_kind": ChangeKind.Changed - } - } - ] - } + "change_kind": ChangeKind.Changed, + }, + }, + ], + }, }; // Install mock handler and send change event await page.evaluate(installMockHandler); - await request.post(bs.api('events'), {data: change}); + await request.post(bs.api("events"), { data: change }); // Wait for a short period await page.waitForTimeout(500); @@ -112,9 +115,9 @@ test.describe('examples/basic/live-reload.yml', { expect(calls).toStrictEqual([ [ { - "kind": "reloadPage" - } - ] + "kind": "reloadPage", + }, + ], ]); }); -}) +}); diff --git a/tests/playground.spec.ts b/tests/playground.spec.ts index 2c408731..9b50eb2b 100644 --- a/tests/playground.spec.ts +++ b/tests/playground.spec.ts @@ -1,18 +1,18 @@ -import {bstest, test} from './utils'; -import {expect} from "@playwright/test"; +import { bstest, test } from "./utils"; +import { expect } from "@playwright/test"; -test.describe('examples/markdown/playground.md', { +test.describe("examples/markdown/playground.md", { annotation: { type: bstest({ - input: 'examples/markdown/playground.md' + input: "examples/markdown/playground.md", }), - description: '' - } + description: "", + }, }, () => { - test('playground', async ({page, bs}) => { + test("playground", async ({ page, bs }) => { const text: string[] = []; - page.on('console', (msg) => text.push(msg.text())); - await page.goto(bs.path('/'), {waitUntil: 'networkidle'}) - expect(text).toContain('Hello from playground.md') + page.on("console", (msg) => text.push(msg.text())); + await page.goto(bs.path("/"), { waitUntil: "networkidle" }); + expect(text).toContain("Hello from playground.md"); }); -}) \ No newline at end of file +}); diff --git a/tests/react-router.spec.ts b/tests/react-router.spec.ts index 2c08acfa..2413067e 100644 --- a/tests/react-router.spec.ts +++ b/tests/react-router.spec.ts @@ -1,46 +1,54 @@ -import {bstest, test} from './utils'; -import {expect} from "@playwright/test"; +import { bstest, test } from "./utils"; +import { expect } from "@playwright/test"; -test.describe('examples/react-router/bslive.yaml', { +test.describe("examples/react-router/bslive.yaml", { annotation: { type: bstest({ - input: 'examples/react-router/bslive.yaml' + input: "examples/react-router/bslive.yaml", }), - description: '' - } + description: "", + }, }, () => { - test('support client-side routing', async ({page, bs}) => { - await page.goto(bs.path('/'), {waitUntil: 'networkidle'}) - await expect(page.locator('#root')).toContainText('API response from /abc[1,2,3]'); + test("support client-side routing", async ({ page, bs }) => { + await page.goto(bs.path("/"), { waitUntil: "networkidle" }); + await expect(page.locator("#root")).toContainText( + "API response from /abc[1,2,3]", + ); }); - test('supports compressed responses', async ({page, bs}) => { + test("supports compressed responses", async ({ page, bs }) => { // Navigate to the page and wait until the network becomes idle - const load = page.goto(bs.named('react-router-with-compression', '/'), {waitUntil: 'networkidle'}); + const load = page.goto(bs.named("react-router-with-compression", "/"), { + waitUntil: "networkidle", + }); // Set up the request waiting promise const requestPromise = page.waitForResponse((req) => { const url = new URL(req.url()); - return url.pathname.includes('assets/index') && url.pathname.endsWith('.js'); - }, {timeout: 2000}); + return url.pathname.includes("assets/index") && + url.pathname.endsWith(".js"); + }, { timeout: 2000 }); // Wait for both navigation and request to complete const [_, jsfile] = await Promise.all([load, requestPromise]); // Assert that the content-encoding header is 'zstd' - expect(jsfile?.headers()['content-encoding']).toBe('zstd'); + expect(jsfile?.headers()["content-encoding"]).toBe("zstd"); }); - test('does not compress by default', async ({page, bs}) => { - const load = page.goto(bs.named('react-router', '/'), {waitUntil: 'networkidle'}) + test("does not compress by default", async ({ page, bs }) => { + const load = page.goto(bs.named("react-router", "/"), { + waitUntil: "networkidle", + }); const requestPromise = page.waitForResponse((req) => { const url = new URL(req.url()); - return url.pathname.includes('assets/index') && url.pathname.endsWith('.js'); - }, {timeout: 2000}); + return url.pathname.includes("assets/index") && + url.pathname.endsWith(".js"); + }, { timeout: 2000 }); // Wait for both navigation and request to complete const [_, jsfile] = await Promise.all([load, requestPromise]); // Assert that the content-encoding header is undefined by default - expect(jsfile?.headers()['content-encoding']).toBeUndefined(); + expect(jsfile?.headers()["content-encoding"]).toBeUndefined(); }); -}) \ No newline at end of file +}); diff --git a/tests/sse.spec.ts b/tests/sse.spec.ts index 0c704df6..36a90c2b 100644 --- a/tests/sse.spec.ts +++ b/tests/sse.spec.ts @@ -1,18 +1,20 @@ -import {bstest, test} from './utils'; -import {expect} from "@playwright/test"; +import { bstest, test } from "./utils"; +import { expect } from "@playwright/test"; -test.describe('examples/openai/bslive.yml', { +test.describe("examples/openai/bslive.yml", { annotation: { type: bstest({ - input: 'examples/openai/bslive.yml' + input: "examples/openai/bslive.yml", }), - description: '' - } + description: "", + }, }, () => { - test('server sent events', async ({page, bs}) => { - await page.goto(bs.path('/'), {waitUntil: 'networkidle'}) - await expect(page.locator('#output')).toContainText('"" "Thsis" " is"', {timeout: 10000}); - const html = await page.innerHTML('#output'); - expect(html).toMatchSnapshot() + test("server sent events", async ({ page, bs }) => { + await page.goto(bs.path("/"), { waitUntil: "networkidle" }); + await expect(page.locator("#output")).toContainText('"" "Thsis" " is"', { + timeout: 10000, + }); + const html = await page.innerHTML("#output"); + expect(html).toMatchSnapshot(); }); -}) \ No newline at end of file +}); diff --git a/tests/utils.ts b/tests/utils.ts index 9cc5f7c1..1d995628 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,22 +1,22 @@ -import {test as base} from '@playwright/test'; -import {execSync, fork} from "node:child_process"; -import {join, sep} from 'node:path'; +import { test as base } from "@playwright/test"; +import { execSync, fork } from "node:child_process"; +import { join, sep } from "node:path"; import * as z from "zod"; import { externalEventsSchema, getServersMessageResponseSchema, internalEventsDTOSchema, } from "../crates/bsnext_client/generated/schema.mjs"; -import {existsSync} from "node:fs"; +import { existsSync } from "node:fs"; const either = z.union([internalEventsDTOSchema, externalEventsSchema]); declare global { interface Window { __playwright?: { - calls?: any[], - record?: (...args: any[]) => void - } + calls?: any[]; + record?: (...args: any[]) => void; + }; } } @@ -25,14 +25,14 @@ const messageSchema = z.discriminatedUnion("kind", [ kind: z.literal("ready"), urls: z.object({ local: z.string(), - ui: z.string() + ui: z.string(), }), - cwd: z.string() - }) + cwd: z.string(), + }), ]); type Msg = z.infer; const inputSchema = z.object({ - input: z.string() + input: z.string(), }); export function bstest(input: z.infer) { @@ -49,20 +49,20 @@ export const test = base.extend<{ bs: { url: string; cwd: string; - data: TServersResp, - servers: { url: string }[], + data: TServersResp; + servers: { url: string }[]; child: any; path: (path: string) => string; named: (name: string, path: string) => string; stdout: string[]; touch: (path: string) => void; - api: (kind: 'events') => string + api: (kind: "events") => string; // next: (args: NextArgs) => Promise; }; }>({ bs: async ({}, use, testInfo) => { const ann = inputSchema.parse(JSON.parse(testInfo.annotations[0].type)); - const test_dir = ['tests']; + const test_dir = ["tests"]; const cwd = process.cwd(); const base = join(cwd, ...test_dir); const file = join(base, "..", "bin.js"); @@ -70,99 +70,104 @@ export const test = base.extend<{ const exampleInput = join(cwd, ann.input); if (!existsSync(exampleInput)) { - throw new Error('example input not found') + throw new Error("example input not found"); } const child = fork(file, [ - '-i', ann.input, - '-f', 'json', - + "-i", + ann.input, + "-f", + "json", // uncomment these 2 lines to debug trace data in a bslive.log file // tip: ensure you only run 1 test at a time // '-l', 'trace', // '--write-log' ], { cwd, - stdio: "pipe" + stdio: "pipe", }); const lines: string[] = []; - const servers_changed_msg: Promise = new Promise((res, rej) => { - const handler = (chunk: Buffer) => { - for (let line of chunk.toString().split('\n')) { - if (line.trim() === "") continue; - lines.push(line); - console.log("--", line); - const json = JSON.parse(line); - const parsed = either.safeParse(json); - if (parsed.error) { - // console.log(parsed.error.message) - // rej(parsed.error) - } else { - if (parsed.data.kind === "ServersChanged") { - res(parsed.data.payload as TServersResp) - child.stdout?.off("data", handler); + const servers_changed_msg: Promise = new Promise( + (res, rej) => { + const handler = (chunk: Buffer) => { + for (let line of chunk.toString().split("\n")) { + if (line.trim() === "") continue; + lines.push(line); + console.log("--", line); + const json = JSON.parse(line); + const parsed = either.safeParse(json); + if (parsed.error) { + // console.log(parsed.error.message) + // rej(parsed.error) + } else { + if (parsed.data.kind === "ServersChanged") { + res(parsed.data.payload as TServersResp); + child.stdout?.off("data", handler); + } } } - } - } - child.stdout?.on("data", handler); - }); - child.stderr?.on("data", d => console.error(d.toString())); + }; + child.stdout?.on("data", handler); + }, + ); + child.stderr?.on("data", (d) => console.error(d.toString())); const closed = new Promise((res, rej) => { - child.on('disconnect', (...args) => { - console.log('did disconnect', ...args) - }) - child.on('close', (err, signal) => { + child.on("disconnect", (...args) => { + console.log("did disconnect", ...args); + }); + child.on("close", (err, signal) => { if (err) { if (err !== 0) { - console.log('did close with error code', err) + console.log("did close with error code", err); console.log(lines); - return rej(err) + return rej(err); } } - console.log('did close cleanly', {signal}) - res(signal) - }) - child.on('exit', (err, signal) => { - console.log('did exit', {err, signal}) - }) - child.on('error', (err) => { - console.error('did error', err) - }) - }) + console.log("did close cleanly", { signal }); + res(signal); + }); + child.on("exit", (err, signal) => { + console.log("did exit", { err, signal }); + }); + child.on("error", (err) => { + console.error("did error", err); + }); + }); const data = await servers_changed_msg; - const servers = data.servers.map(s => { - return {url: 'http://' + s.socket_addr, identity: s.identity} + const servers = data.servers.map((s) => { + return { url: "http://" + s.socket_addr, identity: s.identity }; }); await use({ - url: 'msg.urls.local', - cwd: 'msg.cwd', + url: "msg.urls.local", + cwd: "msg.cwd", child, data, servers, path(path: string) { const url = new URL(path, servers[0].url); - return url.toString() + return url.toString(); }, named(server_name: string, path: string) { - const server = servers.find(x => { + const server = servers.find((x) => { if (x.identity.kind === "Named") { - return x.identity.payload.name === server_name + return x.identity.payload.name === server_name; } - return false + return false; }); - if (!server) throw new Error('server not found with name: ' + server_name); + if (!server) { + throw new Error("server not found with name: " + server_name); + } const url = new URL(path, server.url); - return url.toString() + return url.toString(); }, - api(kind: 'events') { + api(kind: "events") { switch (kind) { case "events": - return this.path('/__bs_api/events') + return this.path("/__bs_api/events"); } - throw new Error("unreachable") + throw new Error("unreachable"); }, stdout, touch: (path: string) => { @@ -173,8 +178,8 @@ export const test = base.extend<{ child.kill("SIGTERM"); await closed; - } -}) + }, +}); function touchFile(filePath: string) { execSync(`touch ${filePath}`); @@ -184,11 +189,11 @@ export function installMockHandler() { window.__playwright = { calls: [], record: (...args) => { - window.__playwright?.calls?.push(args) - } - } + window.__playwright?.calls?.push(args); + }, + }; } export function readCalls() { - return window.__playwright?.calls + return window.__playwright?.calls; }