From 73387968e72941ce72909e36d3ccdf015fc46107 Mon Sep 17 00:00:00 2001 From: Shane Osbourne Date: Sun, 8 Sep 2024 21:27:28 +0100 Subject: [PATCH 1/5] adding baseline tests --- crates/bsnext_client/inject/dist/index.js | 15 ++++++- crates/bsnext_client/inject/src/index.ts | 23 ++++++++++- .../bsnext_core/src/server/router/pub_api.rs | 1 + tests/examples.spec.ts | 41 +++++++++++++++++++ ...ads-with-HTML-change-1-chromium-darwin.txt | 18 ++++++++ tests/utils.ts | 15 ++++++- 6 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-reloads-with-HTML-change-1-chromium-darwin.txt diff --git a/crates/bsnext_client/inject/dist/index.js b/crates/bsnext_client/inject/dist/index.js index 4e2b9ce..f2e5dfc 100644 --- a/crates/bsnext_client/inject/dist/index.js +++ b/crates/bsnext_client/inject/dist/index.js @@ -6568,14 +6568,25 @@ function changedPath(change) { } case "Fs": { let path = change.payload.path; - r.reload(path, { + const opts = { liveCSS: true, liveImg: true, reloadMissingCSS: true, originalPath: "", overrideURL: "", serverURL: `` - }); + }; + if (window.__playwright?.record) { + window.__playwright?.record({ + kind: "reload", + args: { + path, + opts + } + }); + } else { + r.reload(path, opts); + } } } } diff --git a/crates/bsnext_client/inject/src/index.ts b/crates/bsnext_client/inject/src/index.ts index a24a4c9..27d2303 100644 --- a/crates/bsnext_client/inject/src/index.ts +++ b/crates/bsnext_client/inject/src/index.ts @@ -44,14 +44,24 @@ function changedPath(change: ChangeDTO) { } case "Fs": { let path = change.payload.path; - r.reload(path, { + const opts = { liveCSS: true, liveImg: true, reloadMissingCSS: true, originalPath: '', overrideURL: '', serverURL: ``, - }) + } + if (window.__playwright?.record) { + window.__playwright?.record({ + kind: 'reload', + args: { + path, opts + } + }) + } else { + r.reload(path, opts) + } } } } @@ -70,3 +80,12 @@ consoleSubject.subscribe(evt => { } }) +// todo: share this with tests +declare global { + interface Window { + __playwright?: { + calls?: any[], + record?: (...args: any[]) => void + } + } +} \ No newline at end of file diff --git a/crates/bsnext_core/src/server/router/pub_api.rs b/crates/bsnext_core/src/server/router/pub_api.rs index b983ca3..b62d7a6 100644 --- a/crates/bsnext_core/src/server/router/pub_api.rs +++ b/crates/bsnext_core/src/server/router/pub_api.rs @@ -47,6 +47,7 @@ async fn post_events( State(app): State>, Json(payload): Json, ) -> impl IntoResponse { + tracing::trace!("Got post event: {:?}", payload); match &app.evt_receiver { None => unreachable!("should be unreachable?"), Some(recv) => { diff --git a/tests/examples.spec.ts b/tests/examples.spec.ts index 29932b8..9620f2b 100644 --- a/tests/examples.spec.ts +++ b/tests/examples.spec.ts @@ -109,6 +109,38 @@ test.describe('examples/basic/live-reload.yml', { bs.touch('examples/basic/public/styles.css') await requestPromise; }); + test('reloads with HTML change', async ({page, bs, request}) => { + page.on('console', (evt) => { + console.log("PAGE LOG: ", evt.type(), evt.text()) + }) + await page.goto(bs.path('/'), {waitUntil: 'networkidle'}) + const change = { + "kind": "Change", + "payload": { + "kind": "Fs", + "payload": { + "path": "index.html", + "change_kind": "Changed" + } + } + }; + await page.evaluate(() => { + window.__playwright = { + calls: [], + record: (...args) => { + window.__playwright?.calls?.push(args) + } + } + }); + await request.post(bs.api('events'), {data: change}); + await page.waitForFunction(() => { + return window.__playwright?.calls?.length === 1 + }) + const calls = await page.evaluate(() => { + return window.__playwright?.calls + }) + expect(JSON.stringify(calls, null, 2)).toMatchSnapshot(); + }); }) test.describe('examples/react-router/bslive.yaml', { @@ -144,3 +176,12 @@ test.describe('examples/react-router/bslive.yaml', { expect(jsfile?.headers()['content-encoding']).toBeUndefined() }); }) + +declare global { + interface Window { + __playwright?: { + calls?: any[], + record?: (...args: any[]) => void + } + } +} diff --git a/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-reloads-with-HTML-change-1-chromium-darwin.txt b/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-reloads-with-HTML-change-1-chromium-darwin.txt new file mode 100644 index 0000000..45a98e7 --- /dev/null +++ b/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-reloads-with-HTML-change-1-chromium-darwin.txt @@ -0,0 +1,18 @@ +[ + [ + { + "kind": "reload", + "args": { + "path": "index.html", + "opts": { + "liveCSS": true, + "liveImg": true, + "reloadMissingCSS": true, + "originalPath": "", + "overrideURL": "", + "serverURL": "" + } + } + } + ] +] \ No newline at end of file diff --git a/tests/utils.ts b/tests/utils.ts index 4fde22a..4cd83bd 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -47,6 +47,7 @@ export const test = base.extend<{ named: (name: string, path: string) => string; stdout: string[]; touch: (path: string) => void; + api: (kind: 'events') => string // next: (args: NextArgs) => Promise; }; }>({ @@ -65,7 +66,12 @@ export const test = base.extend<{ const child = fork(file, [ '-i', ann.input, - '-f', 'json' + '-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" @@ -142,6 +148,13 @@ export const test = base.extend<{ const url = new URL(path, server.url); return url.toString() }, + api(kind: 'events') { + switch (kind) { + case "events": + return this.path('/__bs_api/events') + } + throw new Error("unreachable") + }, stdout, touch: (path: string) => { touchFile(join(cwd, path)); From 38baa18846bb9c65299cced8a6a6e4606e52c138 Mon Sep 17 00:00:00 2001 From: Shane Osbourne Date: Sun, 8 Sep 2024 21:42:31 +0100 Subject: [PATCH 2/5] added a failing test case --- tests/examples.spec.ts | 50 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/tests/examples.spec.ts b/tests/examples.spec.ts index 9620f2b..84f8872 100644 --- a/tests/examples.spec.ts +++ b/tests/examples.spec.ts @@ -1,5 +1,8 @@ import {bstest, test} from './utils'; import {expect} from "@playwright/test"; +import {ChangeKind} from 'bsnext_client/generated/dto'; +import {clientEventSchema} from "bsnext_client/generated/schema"; +import {z} from "zod"; test.describe('examples/basic/headers.yml', { annotation: { @@ -114,13 +117,13 @@ test.describe('examples/basic/live-reload.yml', { console.log("PAGE LOG: ", evt.type(), evt.text()) }) await page.goto(bs.path('/'), {waitUntil: 'networkidle'}) - const change = { + const change: z.infer = { "kind": "Change", "payload": { "kind": "Fs", "payload": { "path": "index.html", - "change_kind": "Changed" + "change_kind": ChangeKind.Changed } } }; @@ -141,6 +144,49 @@ test.describe('examples/basic/live-reload.yml', { }) expect(JSON.stringify(calls, null, 2)).toMatchSnapshot(); }); + test.only('no css reloads with HTML + CSS change', async ({page, bs, request}) => { + page.on('console', (evt) => { + console.log("PAGE LOG: ", evt.type(), evt.text()) + }) + await page.goto(bs.path('/'), {waitUntil: 'networkidle'}) + + const change: z.infer = { + "kind": "Change", + "payload": { + "kind": "FsMany", + "payload": [ + { + "kind": "Fs", + "payload": { + "path": "reset.css", + "change_kind": ChangeKind.Changed + } + }, + { + "kind": "Fs", + "payload": { + "path": "index.html", + "change_kind": ChangeKind.Changed + } + } + ] + } + }; + await page.evaluate(() => { + window.__playwright = { + calls: [], + record: (...args) => { + window.__playwright?.calls?.push(args) + } + } + }); + await request.post(bs.api('events'), {data: change}); + await page.waitForTimeout(500); + const calls = await page.evaluate(() => { + return window.__playwright?.calls + }) + expect(calls).toHaveLength(1); + }); }) test.describe('examples/react-router/bslive.yaml', { From 2bb486facc7c14f42dee5c95cf81af02aad231a6 Mon Sep 17 00:00:00 2001 From: Shane Osbourne Date: Tue, 10 Sep 2024 21:56:29 +0100 Subject: [PATCH 3/5] added primitive checks on incoming lists of files --- crates/bsnext_client/inject/dist/index.js | 30 ++++++++++++++-- crates/bsnext_client/inject/package.json | 3 +- crates/bsnext_client/inject/src/index.ts | 36 +++++++++++++++++-- tests/examples.spec.ts | 28 ++++++++------- ...with-HTML-CSS-change-1-chromium-darwin.txt | 7 ++++ 5 files changed, 86 insertions(+), 18 deletions(-) create mode 100644 tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-no-css-reloads-with-HTML-CSS-change-1-chromium-darwin.txt diff --git a/crates/bsnext_client/inject/dist/index.js b/crates/bsnext_client/inject/dist/index.js index f2e5dfc..d96290f 100644 --- a/crates/bsnext_client/inject/dist/index.js +++ b/crates/bsnext_client/inject/dist/index.js @@ -101,7 +101,7 @@ var require_reloader = __commonJS({ var DEFAULT_OPTIONS = { stylesheetReloadTimeout: 15e3 }; - var IMAGES_REGEX = /\.(jpe?g|png|gif|svg)$/i; + var IMAGES_REGEX2 = /\.(jpe?g|png|gif|svg)$/i; var Reloader2 = class { constructor(window2, console2, Timer2) { this.window = window2; @@ -135,7 +135,7 @@ var require_reloader = __commonJS({ return; } } - if (options.liveImg && path.match(IMAGES_REGEX)) { + if (options.liveImg && path.match(IMAGES_REGEX2)) { this.reloadImages(path); return; } @@ -155,7 +155,7 @@ var require_reloader = __commonJS({ } } if (pluginId === "img") { - if (options.liveImg && path.match(IMAGES_REGEX)) { + if (options.liveImg && path.match(IMAGES_REGEX2)) { this.reloadImages(path); return true; } @@ -6558,9 +6558,33 @@ socket.pipe(retry({ delay: 5e3 })).subscribe((m) => { } } }); +var IMAGES_REGEX = /\.(jpe?g|png|gif|svg)$/i; function changedPath(change) { switch (change.kind) { case "FsMany": { + const hasNoneInjectable = change.payload.some((changeDTO) => { + switch (changeDTO.kind) { + case "Fs": + if (changeDTO.payload.path.match(/\.css(?:\.map)?$/i)) { + return false; + } + if (changeDTO.payload.path.match(IMAGES_REGEX)) { + return false; + } + return true; + case "FsMany": + throw new Error("unreachable"); + } + }); + if (hasNoneInjectable) { + if (window.__playwright?.record) { + return window.__playwright?.record({ + kind: "reloadPage" + }); + } else { + return r.reloadPage(); + } + } for (let changeDTO of change.payload) { changedPath(changeDTO); } diff --git a/crates/bsnext_client/inject/package.json b/crates/bsnext_client/inject/package.json index dd1a773..cb279c4 100644 --- a/crates/bsnext_client/inject/package.json +++ b/crates/bsnext_client/inject/package.json @@ -4,7 +4,8 @@ "description": "", "main": "index.js", "scripts": { - "build:client": "esbuild src/index.ts --bundle --outdir=dist --format=esm" + "build:client": "esbuild src/index.ts --bundle --outdir=dist --format=esm", + "build:client:debug": "npm run build:client -- --sourcemap=inline" }, "keywords": [], "author": "", diff --git a/crates/bsnext_client/inject/src/index.ts b/crates/bsnext_client/inject/src/index.ts index 27d2303..0ef7df6 100644 --- a/crates/bsnext_client/inject/src/index.ts +++ b/crates/bsnext_client/inject/src/index.ts @@ -1,5 +1,5 @@ // @ts-ignore -import {Reloader} from "livereload-js/src/reloader.js"; +import {Reloader,} from "livereload-js/src/reloader.js"; // @ts-ignore import {Timer} from "livereload-js/src/timer.js"; @@ -33,10 +33,42 @@ socket } }) +// todo: the checks are lifted directly from live reload, we should not use them, but are a good starting point +const IMAGES_REGEX = /\.(jpe?g|png|gif|svg)$/i; + function changedPath(change: ChangeDTO) { switch (change.kind) { case "FsMany": { - // todo(alpha): if this collection of events contains anything that will cause a refresh, just do it immediately + + const hasNoneInjectable = change.payload.some(changeDTO => { + switch (changeDTO.kind) { + case "Fs": + if (changeDTO.payload.path.match(/\.css(?:\.map)?$/i)) { + return false + } + if (changeDTO.payload.path.match(IMAGES_REGEX)) { + return false + } + + // if we get here, we're not going to live inject anything + return true + case "FsMany": + throw new Error("unreachable") + } + }); + + // if any path will cause a reload anyway, don't both hot-reloading anything. + if (hasNoneInjectable) { + if (window.__playwright?.record) { + return window.__playwright?.record({ + kind: 'reloadPage', + }) + } else { + return r.reloadPage() + } + } + + // if we get here, every path given was injectable, so try to inject them all for (let changeDTO of change.payload) { changedPath(changeDTO); } diff --git a/tests/examples.spec.ts b/tests/examples.spec.ts index 84f8872..13ed6f0 100644 --- a/tests/examples.spec.ts +++ b/tests/examples.spec.ts @@ -172,20 +172,11 @@ test.describe('examples/basic/live-reload.yml', { ] } }; - await page.evaluate(() => { - window.__playwright = { - calls: [], - record: (...args) => { - window.__playwright?.calls?.push(args) - } - } - }); + await page.evaluate(installMockHandler); await request.post(bs.api('events'), {data: change}); await page.waitForTimeout(500); - const calls = await page.evaluate(() => { - return window.__playwright?.calls - }) - expect(calls).toHaveLength(1); + const calls = await page.evaluate(readCalls) + expect(JSON.stringify(calls, null, 2)).toMatchSnapshot() }); }) @@ -231,3 +222,16 @@ declare global { } } } + +function installMockHandler() { + window.__playwright = { + calls: [], + record: (...args) => { + window.__playwright?.calls?.push(args) + } + } +} + +function readCalls() { + return window.__playwright?.calls +} diff --git a/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-no-css-reloads-with-HTML-CSS-change-1-chromium-darwin.txt b/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-no-css-reloads-with-HTML-CSS-change-1-chromium-darwin.txt new file mode 100644 index 0000000..df5cce7 --- /dev/null +++ b/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-no-css-reloads-with-HTML-CSS-change-1-chromium-darwin.txt @@ -0,0 +1,7 @@ +[ + [ + { + "kind": "reloadPage" + } + ] +] \ No newline at end of file From d2d607cd86c150f7cbc7920e0dcbe78080419a5c Mon Sep 17 00:00:00 2001 From: Shane Osbourne Date: Tue, 10 Sep 2024 22:08:32 +0100 Subject: [PATCH 4/5] updated tests --- tests/examples.spec.ts | 15 +++------------ ...ds-with-HTML-CSS-change-1-chromium-darwin.txt | 16 ++++++++++++++++ ...eloads-with-HTML-change-1-chromium-darwin.txt | 13 +------------ 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/tests/examples.spec.ts b/tests/examples.spec.ts index 13ed6f0..0fb6974 100644 --- a/tests/examples.spec.ts +++ b/tests/examples.spec.ts @@ -127,24 +127,15 @@ test.describe('examples/basic/live-reload.yml', { } } }; - await page.evaluate(() => { - window.__playwright = { - calls: [], - record: (...args) => { - window.__playwright?.calls?.push(args) - } - } - }); + await page.evaluate(installMockHandler); await request.post(bs.api('events'), {data: change}); await page.waitForFunction(() => { return window.__playwright?.calls?.length === 1 }) - const calls = await page.evaluate(() => { - return window.__playwright?.calls - }) + const calls = await page.evaluate(readCalls) expect(JSON.stringify(calls, null, 2)).toMatchSnapshot(); }); - test.only('no css reloads with HTML + CSS change', async ({page, bs, request}) => { + test('no css reloads with HTML + CSS change', async ({page, bs, request}) => { page.on('console', (evt) => { console.log("PAGE LOG: ", evt.type(), evt.text()) }) diff --git a/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-no-css-reloads-with-HTML-CSS-change-1-chromium-darwin.txt b/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-no-css-reloads-with-HTML-CSS-change-1-chromium-darwin.txt index df5cce7..ea7d7e6 100644 --- a/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-no-css-reloads-with-HTML-CSS-change-1-chromium-darwin.txt +++ b/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-no-css-reloads-with-HTML-CSS-change-1-chromium-darwin.txt @@ -3,5 +3,21 @@ { "kind": "reloadPage" } + ], + [ + { + "kind": "reload", + "args": { + "path": "/Users/shaneosbourne/WebstormProjects/bslive/examples/basic/public/styles.css", + "opts": { + "liveCSS": true, + "liveImg": true, + "reloadMissingCSS": true, + "originalPath": "", + "overrideURL": "", + "serverURL": "" + } + } + } ] ] \ No newline at end of file diff --git a/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-reloads-with-HTML-change-1-chromium-darwin.txt b/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-reloads-with-HTML-change-1-chromium-darwin.txt index 45a98e7..df5cce7 100644 --- a/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-reloads-with-HTML-change-1-chromium-darwin.txt +++ b/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-reloads-with-HTML-change-1-chromium-darwin.txt @@ -1,18 +1,7 @@ [ [ { - "kind": "reload", - "args": { - "path": "index.html", - "opts": { - "liveCSS": true, - "liveImg": true, - "reloadMissingCSS": true, - "originalPath": "", - "overrideURL": "", - "serverURL": "" - } - } + "kind": "reloadPage" } ] ] \ No newline at end of file From 56ac3332460308633b90b113741b935eb552c06e Mon Sep 17 00:00:00 2001 From: Shane Osbourne Date: Tue, 10 Sep 2024 22:18:39 +0100 Subject: [PATCH 5/5] tests --- playwright.config.ts | 3 ++- tests/examples.spec.ts | 16 +++++++++++-- ...with-HTML-CSS-change-1-chromium-darwin.txt | 23 ------------------- ...ads-with-HTML-change-1-chromium-darwin.txt | 7 ------ 4 files changed, 16 insertions(+), 33 deletions(-) delete mode 100644 tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-no-css-reloads-with-HTML-CSS-change-1-chromium-darwin.txt delete mode 100644 tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-reloads-with-HTML-change-1-chromium-darwin.txt diff --git a/playwright.config.ts b/playwright.config.ts index fe8b51c..c79360c 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -19,7 +19,8 @@ export default defineConfig({ /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, + // workers: process.env.CI ? 1 : undefined, + workers: 1, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: 'html', /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ diff --git a/tests/examples.spec.ts b/tests/examples.spec.ts index 0fb6974..c7cbbe3 100644 --- a/tests/examples.spec.ts +++ b/tests/examples.spec.ts @@ -133,7 +133,13 @@ test.describe('examples/basic/live-reload.yml', { return window.__playwright?.calls?.length === 1 }) const calls = await page.evaluate(readCalls) - expect(JSON.stringify(calls, null, 2)).toMatchSnapshot(); + expect(calls).toStrictEqual([ + [ + { + "kind": "reloadPage" + } + ] + ]); }); test('no css reloads with HTML + CSS change', async ({page, bs, request}) => { page.on('console', (evt) => { @@ -167,7 +173,13 @@ test.describe('examples/basic/live-reload.yml', { await request.post(bs.api('events'), {data: change}); await page.waitForTimeout(500); const calls = await page.evaluate(readCalls) - expect(JSON.stringify(calls, null, 2)).toMatchSnapshot() + expect(calls).toStrictEqual([ + [ + { + "kind": "reloadPage" + } + ] + ]) }); }) diff --git a/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-no-css-reloads-with-HTML-CSS-change-1-chromium-darwin.txt b/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-no-css-reloads-with-HTML-CSS-change-1-chromium-darwin.txt deleted file mode 100644 index ea7d7e6..0000000 --- a/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-no-css-reloads-with-HTML-CSS-change-1-chromium-darwin.txt +++ /dev/null @@ -1,23 +0,0 @@ -[ - [ - { - "kind": "reloadPage" - } - ], - [ - { - "kind": "reload", - "args": { - "path": "/Users/shaneosbourne/WebstormProjects/bslive/examples/basic/public/styles.css", - "opts": { - "liveCSS": true, - "liveImg": true, - "reloadMissingCSS": true, - "originalPath": "", - "overrideURL": "", - "serverURL": "" - } - } - } - ] -] \ No newline at end of file diff --git a/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-reloads-with-HTML-change-1-chromium-darwin.txt b/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-reloads-with-HTML-change-1-chromium-darwin.txt deleted file mode 100644 index df5cce7..0000000 --- a/tests/examples.spec.ts-snapshots/examples-basic-live-reload-yml-reloads-with-HTML-change-1-chromium-darwin.txt +++ /dev/null @@ -1,7 +0,0 @@ -[ - [ - { - "kind": "reloadPage" - } - ] -] \ No newline at end of file