Skip to content

Commit 3a9aa76

Browse files
authored
Merge pull request #25 from BrowserSync/bslive-20-reload-events
adding baseline tests
2 parents fa88c9d + 56ac333 commit 3a9aa76

File tree

7 files changed

+208
-12
lines changed

7 files changed

+208
-12
lines changed

crates/bsnext_client/inject/dist/index.js

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ var require_reloader = __commonJS({
101101
var DEFAULT_OPTIONS = {
102102
stylesheetReloadTimeout: 15e3
103103
};
104-
var IMAGES_REGEX = /\.(jpe?g|png|gif|svg)$/i;
104+
var IMAGES_REGEX2 = /\.(jpe?g|png|gif|svg)$/i;
105105
var Reloader2 = class {
106106
constructor(window2, console2, Timer2) {
107107
this.window = window2;
@@ -135,7 +135,7 @@ var require_reloader = __commonJS({
135135
return;
136136
}
137137
}
138-
if (options.liveImg && path.match(IMAGES_REGEX)) {
138+
if (options.liveImg && path.match(IMAGES_REGEX2)) {
139139
this.reloadImages(path);
140140
return;
141141
}
@@ -155,7 +155,7 @@ var require_reloader = __commonJS({
155155
}
156156
}
157157
if (pluginId === "img") {
158-
if (options.liveImg && path.match(IMAGES_REGEX)) {
158+
if (options.liveImg && path.match(IMAGES_REGEX2)) {
159159
this.reloadImages(path);
160160
return true;
161161
}
@@ -6558,24 +6558,59 @@ socket.pipe(retry({ delay: 5e3 })).subscribe((m) => {
65586558
}
65596559
}
65606560
});
6561+
var IMAGES_REGEX = /\.(jpe?g|png|gif|svg)$/i;
65616562
function changedPath(change) {
65626563
switch (change.kind) {
65636564
case "FsMany": {
6565+
const hasNoneInjectable = change.payload.some((changeDTO) => {
6566+
switch (changeDTO.kind) {
6567+
case "Fs":
6568+
if (changeDTO.payload.path.match(/\.css(?:\.map)?$/i)) {
6569+
return false;
6570+
}
6571+
if (changeDTO.payload.path.match(IMAGES_REGEX)) {
6572+
return false;
6573+
}
6574+
return true;
6575+
case "FsMany":
6576+
throw new Error("unreachable");
6577+
}
6578+
});
6579+
if (hasNoneInjectable) {
6580+
if (window.__playwright?.record) {
6581+
return window.__playwright?.record({
6582+
kind: "reloadPage"
6583+
});
6584+
} else {
6585+
return r.reloadPage();
6586+
}
6587+
}
65646588
for (let changeDTO of change.payload) {
65656589
changedPath(changeDTO);
65666590
}
65676591
break;
65686592
}
65696593
case "Fs": {
65706594
let path = change.payload.path;
6571-
r.reload(path, {
6595+
const opts = {
65726596
liveCSS: true,
65736597
liveImg: true,
65746598
reloadMissingCSS: true,
65756599
originalPath: "",
65766600
overrideURL: "",
65776601
serverURL: ``
6578-
});
6602+
};
6603+
if (window.__playwright?.record) {
6604+
window.__playwright?.record({
6605+
kind: "reload",
6606+
args: {
6607+
path,
6608+
opts
6609+
}
6610+
});
6611+
} else {
6612+
r.reload(path, opts);
6613+
}
65796614
}
65806615
}
65816616
}

crates/bsnext_client/inject/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"description": "",
55
"main": "index.js",
66
"scripts": {
7-
"build:client": "esbuild src/index.ts --bundle --outdir=dist --format=esm"
7+
"build:client": "esbuild src/index.ts --bundle --outdir=dist --format=esm",
8+
"build:client:debug": "npm run build:client -- --sourcemap=inline"
89
},
910
"keywords": [],
1011
"author": "",

crates/bsnext_client/inject/src/index.ts

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// @ts-ignore
2-
import {Reloader} from "livereload-js/src/reloader.js";
2+
import {Reloader,} from "livereload-js/src/reloader.js";
33
// @ts-ignore
44
import {Timer} from "livereload-js/src/timer.js";
55

@@ -33,25 +33,67 @@ socket
3333
}
3434
})
3535

36+
// todo: the checks are lifted directly from live reload, we should not use them, but are a good starting point
37+
const IMAGES_REGEX = /\.(jpe?g|png|gif|svg)$/i;
38+
3639
function changedPath(change: ChangeDTO) {
3740
switch (change.kind) {
3841
case "FsMany": {
39-
// todo(alpha): if this collection of events contains anything that will cause a refresh, just do it immediately
42+
43+
const hasNoneInjectable = change.payload.some(changeDTO => {
44+
switch (changeDTO.kind) {
45+
case "Fs":
46+
if (changeDTO.payload.path.match(/\.css(?:\.map)?$/i)) {
47+
return false
48+
}
49+
if (changeDTO.payload.path.match(IMAGES_REGEX)) {
50+
return false
51+
}
52+
53+
// if we get here, we're not going to live inject anything
54+
return true
55+
case "FsMany":
56+
throw new Error("unreachable")
57+
}
58+
});
59+
60+
// if any path will cause a reload anyway, don't both hot-reloading anything.
61+
if (hasNoneInjectable) {
62+
if (window.__playwright?.record) {
63+
return window.__playwright?.record({
64+
kind: 'reloadPage',
65+
})
66+
} else {
67+
return r.reloadPage()
68+
}
69+
}
70+
71+
// if we get here, every path given was injectable, so try to inject them all
4072
for (let changeDTO of change.payload) {
4173
changedPath(changeDTO);
4274
}
4375
break
4476
}
4577
case "Fs": {
4678
let path = change.payload.path;
47-
r.reload(path, {
79+
const opts = {
4880
liveCSS: true,
4981
liveImg: true,
5082
reloadMissingCSS: true,
5183
originalPath: '',
5284
overrideURL: '',
5385
serverURL: ``,
54-
})
86+
}
87+
if (window.__playwright?.record) {
88+
window.__playwright?.record({
89+
kind: 'reload',
90+
args: {
91+
path, opts
92+
}
93+
})
94+
} else {
95+
r.reload(path, opts)
96+
}
5597
}
5698
}
5799
}
@@ -70,3 +112,12 @@ consoleSubject.subscribe(evt => {
70112
}
71113
})
72114

115+
// todo: share this with tests
116+
declare global {
117+
interface Window {
118+
__playwright?: {
119+
calls?: any[],
120+
record?: (...args: any[]) => void
121+
}
122+
}
123+
}

crates/bsnext_core/src/server/router/pub_api.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ async fn post_events(
4747
State(app): State<Arc<ServerState>>,
4848
Json(payload): Json<ClientEvent>,
4949
) -> impl IntoResponse {
50+
tracing::trace!("Got post event: {:?}", payload);
5051
match &app.evt_receiver {
5152
None => unreachable!("should be unreachable?"),
5253
Some(recv) => {

playwright.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ export default defineConfig({
1919
/* Retry on CI only */
2020
retries: process.env.CI ? 2 : 0,
2121
/* Opt out of parallel tests on CI. */
22-
workers: process.env.CI ? 1 : undefined,
22+
// workers: process.env.CI ? 1 : undefined,
23+
workers: 1,
2324
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
2425
reporter: 'html',
2526
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */

tests/examples.spec.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import {bstest, test} from './utils';
22
import {expect} from "@playwright/test";
3+
import {ChangeKind} from 'bsnext_client/generated/dto';
4+
import {clientEventSchema} from "bsnext_client/generated/schema";
5+
import {z} from "zod";
36

47
test.describe('examples/basic/headers.yml', {
58
annotation: {
@@ -109,6 +112,75 @@ test.describe('examples/basic/live-reload.yml', {
109112
bs.touch('examples/basic/public/styles.css')
110113
await requestPromise;
111114
});
115+
test('reloads with HTML change', async ({page, bs, request}) => {
116+
page.on('console', (evt) => {
117+
console.log("PAGE LOG: ", evt.type(), evt.text())
118+
})
119+
await page.goto(bs.path('/'), {waitUntil: 'networkidle'})
120+
const change: z.infer<typeof clientEventSchema> = {
121+
"kind": "Change",
122+
"payload": {
123+
"kind": "Fs",
124+
"payload": {
125+
"path": "index.html",
126+
"change_kind": ChangeKind.Changed
127+
}
128+
}
129+
};
130+
await page.evaluate(installMockHandler);
131+
await request.post(bs.api('events'), {data: change});
132+
await page.waitForFunction(() => {
133+
return window.__playwright?.calls?.length === 1
134+
})
135+
const calls = await page.evaluate(readCalls)
136+
expect(calls).toStrictEqual([
137+
[
138+
{
139+
"kind": "reloadPage"
140+
}
141+
]
142+
]);
143+
});
144+
test('no css reloads with HTML + CSS change', async ({page, bs, request}) => {
145+
page.on('console', (evt) => {
146+
console.log("PAGE LOG: ", evt.type(), evt.text())
147+
})
148+
await page.goto(bs.path('/'), {waitUntil: 'networkidle'})
149+
150+
const change: z.infer<typeof clientEventSchema> = {
151+
"kind": "Change",
152+
"payload": {
153+
"kind": "FsMany",
154+
"payload": [
155+
{
156+
"kind": "Fs",
157+
"payload": {
158+
"path": "reset.css",
159+
"change_kind": ChangeKind.Changed
160+
}
161+
},
162+
{
163+
"kind": "Fs",
164+
"payload": {
165+
"path": "index.html",
166+
"change_kind": ChangeKind.Changed
167+
}
168+
}
169+
]
170+
}
171+
};
172+
await page.evaluate(installMockHandler);
173+
await request.post(bs.api('events'), {data: change});
174+
await page.waitForTimeout(500);
175+
const calls = await page.evaluate(readCalls)
176+
expect(calls).toStrictEqual([
177+
[
178+
{
179+
"kind": "reloadPage"
180+
}
181+
]
182+
])
183+
});
112184
})
113185

114186
test.describe('examples/react-router/bslive.yaml', {
@@ -144,3 +216,25 @@ test.describe('examples/react-router/bslive.yaml', {
144216
expect(jsfile?.headers()['content-encoding']).toBeUndefined()
145217
});
146218
})
219+
220+
declare global {
221+
interface Window {
222+
__playwright?: {
223+
calls?: any[],
224+
record?: (...args: any[]) => void
225+
}
226+
}
227+
}
228+
229+
function installMockHandler() {
230+
window.__playwright = {
231+
calls: [],
232+
record: (...args) => {
233+
window.__playwright?.calls?.push(args)
234+
}
235+
}
236+
}
237+
238+
function readCalls() {
239+
return window.__playwright?.calls
240+
}

tests/utils.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export const test = base.extend<{
4747
named: (name: string, path: string) => string;
4848
stdout: string[];
4949
touch: (path: string) => void;
50+
api: (kind: 'events') => string
5051
// next: (args: NextArgs) => Promise<string[]>;
5152
};
5253
}>({
@@ -65,7 +66,12 @@ export const test = base.extend<{
6566

6667
const child = fork(file, [
6768
'-i', ann.input,
68-
'-f', 'json'
69+
'-f', 'json',
70+
71+
// uncomment these 2 lines to debug trace data in a bslive.log file
72+
// tip: ensure you only run 1 test at a time
73+
// '-l', 'trace',
74+
// '--write-log'
6975
], {
7076
cwd,
7177
stdio: "pipe"
@@ -142,6 +148,13 @@ export const test = base.extend<{
142148
const url = new URL(path, server.url);
143149
return url.toString()
144150
},
151+
api(kind: 'events') {
152+
switch (kind) {
153+
case "events":
154+
return this.path('/__bs_api/events')
155+
}
156+
throw new Error("unreachable")
157+
},
145158
stdout,
146159
touch: (path: string) => {
147160
touchFile(join(cwd, path));

0 commit comments

Comments
 (0)