Skip to content

Commit

Permalink
Merge pull request #25 from BrowserSync/bslive-20-reload-events
Browse files Browse the repository at this point in the history
adding baseline tests
  • Loading branch information
shakyShane authored Sep 10, 2024
2 parents fa88c9d + 56ac333 commit 3a9aa76
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 12 deletions.
45 changes: 40 additions & 5 deletions crates/bsnext_client/inject/dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -6558,24 +6558,59 @@ 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);
}
break;
}
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);
}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion crates/bsnext_client/inject/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "",
Expand Down
59 changes: 55 additions & 4 deletions crates/bsnext_client/inject/src/index.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -33,25 +33,67 @@ 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);
}
break
}
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)
}
}
}
}
Expand All @@ -70,3 +112,12 @@ consoleSubject.subscribe(evt => {
}
})

// todo: share this with tests
declare global {
interface Window {
__playwright?: {
calls?: any[],
record?: (...args: any[]) => void
}
}
}
1 change: 1 addition & 0 deletions crates/bsnext_core/src/server/router/pub_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ async fn post_events(
State(app): State<Arc<ServerState>>,
Json(payload): Json<ClientEvent>,
) -> impl IntoResponse {
tracing::trace!("Got post event: {:?}", payload);
match &app.evt_receiver {
None => unreachable!("should be unreachable?"),
Some(recv) => {
Expand Down
3 changes: 2 additions & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
94 changes: 94 additions & 0 deletions tests/examples.spec.ts
Original file line number Diff line number Diff line change
@@ -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: {
Expand Down Expand Up @@ -109,6 +112,75 @@ 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: z.infer<typeof clientEventSchema> = {
"kind": "Change",
"payload": {
"kind": "Fs",
"payload": {
"path": "index.html",
"change_kind": ChangeKind.Changed
}
}
};
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(readCalls)
expect(calls).toStrictEqual([
[
{
"kind": "reloadPage"
}
]
]);
});
test('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<typeof clientEventSchema> = {
"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(installMockHandler);
await request.post(bs.api('events'), {data: change});
await page.waitForTimeout(500);
const calls = await page.evaluate(readCalls)
expect(calls).toStrictEqual([
[
{
"kind": "reloadPage"
}
]
])
});
})

test.describe('examples/react-router/bslive.yaml', {
Expand Down Expand Up @@ -144,3 +216,25 @@ test.describe('examples/react-router/bslive.yaml', {
expect(jsfile?.headers()['content-encoding']).toBeUndefined()
});
})

declare global {
interface Window {
__playwright?: {
calls?: any[],
record?: (...args: any[]) => void
}
}
}

function installMockHandler() {
window.__playwright = {
calls: [],
record: (...args) => {
window.__playwright?.calls?.push(args)
}
}
}

function readCalls() {
return window.__playwright?.calls
}
15 changes: 14 additions & 1 deletion tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string[]>;
};
}>({
Expand All @@ -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"
Expand Down Expand Up @@ -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));
Expand Down

0 comments on commit 3a9aa76

Please sign in to comment.