Skip to content

Commit 98555b0

Browse files
committed
refactor(dev-server-hmr): migrate tests from mocha/chai/hanbi to node:test
Replace mocha globals, chai assertions, and hanbi stubs with node:test, node:assert/strict, and node:test mock API across 2 test files + utils.ts. - `import { stubMethod, restore } from 'hanbi'` -> `mock` from `node:test` - `stubMethod(obj, 'send')` -> `mock.method(obj, 'send')` - `restoreStubs()` -> `mock.restoreAll()` - `stub.firstCall!.args[0]` -> `stub.mock.calls[0].arguments[0]` - `stub.callCount` -> `stub.mock.callCount()` - `stub.getCall(n)!.args[0]` -> `stub.mock.calls[n].arguments[0]` - `import type { Context } from 'koa'` (type-only in utils.ts) - `import type { Browser, HTTPResponse, Page } from 'puppeteer'` (type-only) - `launch as launchPuppeteer` -> `import puppeteer` + `puppeteer.launch()` - `../src/*.js` -> `../dist/*.js`, `./utils.js` -> `./utils.ts` - `__dirname` -> `import.meta.dirname` - Add `--experimental-strip-types` for CI compat Assisted-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 597fb32 commit 98555b0

4 files changed

Lines changed: 92 additions & 82 deletions

File tree

packages/dev-server-hmr/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
"build": "tsc",
2929
"start:lit-html": "wds --config demo/lit-html/server.config.mjs",
3030
"start:vanilla": "wds --config demo/vanilla/server.config.mjs",
31-
"test:node": "mocha \"test/**/*.test.ts\" --require ts-node/register --reporter dot",
32-
"test:watch": "mocha \"test/**/*.test.ts\" --require ts-node/register --watch --watch-files src,test"
31+
"test:node": "node --experimental-strip-types --test --test-force-exit test/**/*.test.ts",
32+
"test:watch": "node --experimental-strip-types --test --test-force-exit --watch test/**/*.test.ts"
3333
},
3434
"files": [
3535
"*.d.ts",

packages/dev-server-hmr/test/HmrPlugin.test.ts

Lines changed: 65 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
import { expect } from 'chai';
2-
import { stubMethod, restore as restoreStubs } from 'hanbi';
1+
import { describe, it, afterEach, mock } from 'node:test';
2+
import assert from 'node:assert/strict';
33
import { createTestServer, fetchText, expectIncludes } from '@web/dev-server-core/test-helpers';
44
import { posix as pathUtil } from 'path';
55

6-
import { hmrPlugin } from '../src/index.js';
7-
import { NAME_HMR_CLIENT_IMPORT } from '../src/HmrPlugin.js';
8-
import { mockFile, mockFiles } from './utils.js';
6+
import { hmrPlugin } from '../dist/index.js';
7+
import { NAME_HMR_CLIENT_IMPORT } from '../dist/HmrPlugin.js';
8+
import { mockFile, mockFiles } from './utils.ts';
99

1010
describe('HmrPlugin', () => {
1111
afterEach(async () => {
12-
restoreStubs();
12+
mock.restoreAll();
1313
});
1414

1515
it('should emit update for tracked files', async () => {
1616
const { server, host } = await createTestServer({
17-
rootDir: __dirname,
17+
rootDir: import.meta.dirname,
1818
plugins: [
1919
mockFile(
2020
'/foo.js',
@@ -26,12 +26,13 @@ describe('HmrPlugin', () => {
2626
],
2727
});
2828
const { fileWatcher, webSockets } = server;
29-
const stub = stubMethod(webSockets!, 'send');
29+
const stub = mock.method(webSockets!, 'send');
3030
try {
3131
await fetch(`${host}/foo.js`);
32-
fileWatcher.emit('change', pathUtil.join(__dirname, '/foo.js'));
32+
fileWatcher.emit('change', pathUtil.join(import.meta.dirname, '/foo.js'));
3333

34-
expect(stub.firstCall!.args[0]).to.equal(
34+
assert.equal(
35+
stub.mock.calls[0].arguments[0],
3536
JSON.stringify({
3637
type: 'hmr:update',
3738
url: '/foo.js',
@@ -44,7 +45,7 @@ describe('HmrPlugin', () => {
4445

4546
it('should bubble updates for changed dependencies', async () => {
4647
const { server, host } = await createTestServer({
47-
rootDir: __dirname,
48+
rootDir: import.meta.dirname,
4849
plugins: [
4950
mockFile(
5051
'/foo.js',
@@ -55,13 +56,14 @@ describe('HmrPlugin', () => {
5556
],
5657
});
5758
const { fileWatcher, webSockets } = server;
58-
const stub = stubMethod(webSockets!, 'send');
59+
const stub = mock.method(webSockets!, 'send');
5960
try {
6061
await fetch(`${host}/foo.js`);
6162
await fetch(`${host}/bar.js`);
62-
fileWatcher.emit('change', pathUtil.join(__dirname, '/bar.js'));
63+
fileWatcher.emit('change', pathUtil.join(import.meta.dirname, '/bar.js'));
6364

64-
expect(stub.firstCall!.args[0]).to.equal(
65+
assert.equal(
66+
stub.mock.calls[0].arguments[0],
6567
JSON.stringify({
6668
type: 'hmr:update',
6769
url: '/foo.js',
@@ -74,22 +76,23 @@ describe('HmrPlugin', () => {
7476

7577
it('should not reload if dependent handles change', async () => {
7678
const { server, host } = await createTestServer({
77-
rootDir: __dirname,
79+
rootDir: import.meta.dirname,
7880
plugins: [
7981
mockFile('/foo.js', `import '/bar.js'; import.meta.hot.accept();`),
8082
mockFile('/bar.js', `export const s = 808;`),
8183
hmrPlugin(),
8284
],
8385
});
8486
const { fileWatcher, webSockets } = server;
85-
const stub = stubMethod(webSockets!, 'send');
87+
const stub = mock.method(webSockets!, 'send');
8688
try {
8789
await fetch(`${host}/foo.js`);
8890
await fetch(`${host}/bar.js`);
89-
fileWatcher.emit('change', pathUtil.join(__dirname, '/bar.js'));
91+
fileWatcher.emit('change', pathUtil.join(import.meta.dirname, '/bar.js'));
9092

91-
expect(stub.callCount).to.equal(1);
92-
expect(stub.firstCall!.args[0]).to.equal(
93+
assert.equal(stub.mock.callCount(), 1);
94+
assert.equal(
95+
stub.mock.calls[0].arguments[0],
9396
JSON.stringify({
9497
type: 'hmr:update',
9598
url: '/foo.js',
@@ -102,22 +105,23 @@ describe('HmrPlugin', () => {
102105

103106
it('should reload if dependents do not handle change', async () => {
104107
const { server, host } = await createTestServer({
105-
rootDir: __dirname,
108+
rootDir: import.meta.dirname,
106109
plugins: [
107110
mockFile('/foo.js', `import '/bar.js';`),
108111
mockFile('/bar.js', `export const s = 808;`),
109112
hmrPlugin(),
110113
],
111114
});
112115
const { fileWatcher, webSockets } = server;
113-
const stub = stubMethod(webSockets!, 'send');
116+
const stub = mock.method(webSockets!, 'send');
114117
try {
115118
await fetch(`${host}/foo.js`);
116119
await fetch(`${host}/bar.js`);
117-
fileWatcher.emit('change', pathUtil.join(__dirname, '/bar.js'));
120+
fileWatcher.emit('change', pathUtil.join(import.meta.dirname, '/bar.js'));
118121

119-
expect(stub.callCount).to.equal(1);
120-
expect(stub.firstCall!.args[0]).to.equal(
122+
assert.equal(stub.mock.callCount(), 1);
123+
assert.equal(
124+
stub.mock.calls[0].arguments[0],
121125
JSON.stringify({
122126
type: 'hmr:reload',
123127
}),
@@ -129,7 +133,7 @@ describe('HmrPlugin', () => {
129133

130134
it('handles dependencies referenced relatively', async () => {
131135
const { server, host } = await createTestServer({
132-
rootDir: __dirname,
136+
rootDir: import.meta.dirname,
133137
plugins: [
134138
mockFile(
135139
'/root/foo.js',
@@ -140,13 +144,14 @@ describe('HmrPlugin', () => {
140144
],
141145
});
142146
const { fileWatcher, webSockets } = server;
143-
const stub = stubMethod(webSockets!, 'send');
147+
const stub = mock.method(webSockets!, 'send');
144148
try {
145149
await fetch(`${host}/root/foo.js`);
146150
await fetch(`${host}/root/bar.js`);
147-
fileWatcher.emit('change', pathUtil.join(__dirname, '/root/bar.js'));
151+
fileWatcher.emit('change', pathUtil.join(import.meta.dirname, '/root/bar.js'));
148152

149-
expect(stub.firstCall!.args[0]).to.equal(
153+
assert.equal(
154+
stub.mock.calls[0].arguments[0],
150155
JSON.stringify({
151156
type: 'hmr:update',
152157
url: '/root/foo.js',
@@ -159,7 +164,7 @@ describe('HmrPlugin', () => {
159164

160165
it('should bubble updates for changed dynamic import dependencies', async () => {
161166
const { server, host } = await createTestServer({
162-
rootDir: __dirname,
167+
rootDir: import.meta.dirname,
163168
plugins: [
164169
mockFile(
165170
'/foo.js',
@@ -170,13 +175,14 @@ describe('HmrPlugin', () => {
170175
],
171176
});
172177
const { fileWatcher, webSockets } = server;
173-
const stub = stubMethod(webSockets!, 'send');
178+
const stub = mock.method(webSockets!, 'send');
174179
try {
175180
await fetch(`${host}/foo.js`);
176181
await fetch(`${host}/bar.js`);
177-
fileWatcher.emit('change', pathUtil.join(__dirname, '/bar.js'));
182+
fileWatcher.emit('change', pathUtil.join(import.meta.dirname, '/bar.js'));
178183

179-
expect(stub.firstCall!.args[0]).to.equal(
184+
assert.equal(
185+
stub.mock.calls[0].arguments[0],
180186
JSON.stringify({
181187
type: 'hmr:update',
182188
url: '/foo.js',
@@ -189,7 +195,7 @@ describe('HmrPlugin', () => {
189195

190196
it('imports changed dependencies with a unique URL', async () => {
191197
const { server, host } = await createTestServer({
192-
rootDir: __dirname,
198+
rootDir: import.meta.dirname,
193199
plugins: [
194200
mockFiles({
195201
'/a.js': "import '/b.js'; import '/c.js'; import.meta.hot.accept();",
@@ -204,11 +210,11 @@ describe('HmrPlugin', () => {
204210
await fetchText(`${host}/a.js`);
205211
await fetchText(`${host}/b.js`);
206212
await fetchText(`${host}/c.js`);
207-
fileWatcher.emit('change', pathUtil.join(__dirname, '/b.js'));
213+
fileWatcher.emit('change', pathUtil.join(import.meta.dirname, '/b.js'));
208214

209215
const updatedA = await fetchText(`${host}/a.js?m=1234567890123`);
210216
await fetchText(`${host}/b.js?m=1234567890123`);
211-
expect(/import '\/b\.js\?m=\d{13}';/.test(updatedA)).to.equal(true);
217+
assert.match(updatedA, /import '\/b\.js\?m=\d{13}';/);
212218
expectIncludes(updatedA, "import '/c.js';");
213219
} finally {
214220
await server.stop();
@@ -217,7 +223,7 @@ describe('HmrPlugin', () => {
217223

218224
it('imports deeply changed dependencies with a unique URL', async () => {
219225
const { server, host } = await createTestServer({
220-
rootDir: __dirname,
226+
rootDir: import.meta.dirname,
221227
plugins: [
222228
mockFiles({
223229
'/a.js': "import '/b.js'; import.meta.hot.accept();",
@@ -232,21 +238,21 @@ describe('HmrPlugin', () => {
232238
await fetchText(`${host}/a.js`);
233239
await fetchText(`${host}/b.js`);
234240
await fetchText(`${host}/c.js`);
235-
fileWatcher.emit('change', pathUtil.join(__dirname, '/c.js'));
241+
fileWatcher.emit('change', pathUtil.join(import.meta.dirname, '/c.js'));
236242

237243
const updatedA = await fetchText(`${host}/a.js?m=1234567890123`);
238244
const updatedB = await fetchText(`${host}/b.js?m=1234567890123`);
239245
await fetchText(`${host}/c.js?m=1234567890123`);
240-
expect(/import '\/b\.js\?m=\d{13}';/.test(updatedA)).to.equal(true);
241-
expect(/import '\/c\.js\?m=\d{13}';/.test(updatedB)).to.equal(true);
246+
assert.match(updatedA, /import '\/b\.js\?m=\d{13}';/);
247+
assert.match(updatedB, /import '\/c\.js\?m=\d{13}';/);
242248
} finally {
243249
await server.stop();
244250
}
245251
});
246252

247253
it('multiple dependents will import deep dependency changes with a unique URL', async () => {
248254
const { server, host } = await createTestServer({
249-
rootDir: __dirname,
255+
rootDir: import.meta.dirname,
250256
plugins: [
251257
mockFiles({
252258
'/a1.js': "import '/b.js'; import.meta.hot.accept(); // a1",
@@ -264,22 +270,22 @@ describe('HmrPlugin', () => {
264270
await fetchText(`${host}/a2.js`);
265271
await fetchText(`${host}/b.js`);
266272
await fetchText(`${host}/c.js`);
267-
fileWatcher.emit('change', pathUtil.join(__dirname, '/c.js'));
273+
fileWatcher.emit('change', pathUtil.join(import.meta.dirname, '/c.js'));
268274

269275
const updatedA1 = await fetchText(`${host}/a1.js?m=1234567890123`);
270276
const updatedA2 = await fetchText(`${host}/a2.js?m=1234567890123`);
271277
await fetchText(`${host}/b.js?m=1234567890123`);
272278
await fetchText(`${host}/c.js?m=1234567890123`);
273-
expect(/import '\/b\.js\?m=\d{13}';/.test(updatedA1)).to.equal(true);
274-
expect(/import '\/b\.js\?m=\d{13}';/.test(updatedA2)).to.equal(true);
279+
assert.match(updatedA1, /import '\/b\.js\?m=\d{13}';/);
280+
assert.match(updatedA2, /import '\/b\.js\?m=\d{13}';/);
275281
} finally {
276282
await server.stop();
277283
}
278284
});
279285

280286
it('does not get confused by dynamic imports with non string literals', async () => {
281287
const { server, host } = await createTestServer({
282-
rootDir: __dirname,
288+
rootDir: import.meta.dirname,
283289
plugins: [
284290
mockFile(
285291
'/foo.js',
@@ -290,13 +296,14 @@ describe('HmrPlugin', () => {
290296
],
291297
});
292298
const { fileWatcher, webSockets } = server;
293-
const stub = stubMethod(webSockets!, 'send');
299+
const stub = mock.method(webSockets!, 'send');
294300
try {
295301
await fetch(`${host}/foo.js`);
296302
await fetch(`${host}/bar.js`);
297-
fileWatcher.emit('change', pathUtil.join(__dirname, '/bar.js'));
303+
fileWatcher.emit('change', pathUtil.join(import.meta.dirname, '/bar.js'));
298304

299-
expect(stub.firstCall!.args[0]).to.equal(
305+
assert.equal(
306+
stub.mock.calls[0].arguments[0],
300307
JSON.stringify({
301308
type: 'hmr:update',
302309
url: '/foo.js',
@@ -309,7 +316,7 @@ describe('HmrPlugin', () => {
309316

310317
it('should emit reload for tracked files', async () => {
311318
const { server, host } = await createTestServer({
312-
rootDir: __dirname,
319+
rootDir: import.meta.dirname,
313320
plugins: [
314321
mockFile(
315322
'/foo.js',
@@ -321,12 +328,13 @@ describe('HmrPlugin', () => {
321328
],
322329
});
323330
const { fileWatcher, webSockets } = server;
324-
const stub = stubMethod(webSockets!, 'send');
331+
const stub = mock.method(webSockets!, 'send');
325332
try {
326333
await fetch(`${host}/foo.js`);
327-
fileWatcher.emit('change', pathUtil.join(__dirname, '/foo.js'));
334+
fileWatcher.emit('change', pathUtil.join(import.meta.dirname, '/foo.js'));
328335

329-
expect(stub.firstCall!.args[0]).to.equal(
336+
assert.equal(
337+
stub.mock.calls[0].arguments[0],
330338
JSON.stringify({
331339
type: 'hmr:reload',
332340
}),
@@ -338,22 +346,22 @@ describe('HmrPlugin', () => {
338346

339347
it('serves a hmr client', async () => {
340348
const { server, host } = await createTestServer({
341-
rootDir: __dirname,
349+
rootDir: import.meta.dirname,
342350
plugins: [hmrPlugin()],
343351
});
344352

345353
try {
346354
const response = await fetch(`${host}${NAME_HMR_CLIENT_IMPORT}`);
347355
const body = await response.text();
348-
expect(body.includes('class HotModule')).to.equal(true);
356+
assert.ok(body.includes('class HotModule'));
349357
} finally {
350358
await server.stop();
351359
}
352360
});
353361

354362
it('transforms hmr-capable js files', async () => {
355363
const { server, host } = await createTestServer({
356-
rootDir: __dirname,
364+
rootDir: import.meta.dirname,
357365
plugins: [
358366
mockFile(
359367
'/foo.js',
@@ -369,23 +377,23 @@ describe('HmrPlugin', () => {
369377
const response = await fetch(`${host}/foo.js`);
370378
const body = await response.text();
371379

372-
expect(body.includes('__WDS_HMR__')).to.equal(true);
380+
assert.ok(body.includes('__WDS_HMR__'));
373381
} finally {
374382
await server.stop();
375383
}
376384
});
377385

378386
it('does not transform non-hmr js files', async () => {
379387
const { server, host } = await createTestServer({
380-
rootDir: __dirname,
388+
rootDir: import.meta.dirname,
381389
plugins: [mockFile('/foo.js', `export const foo = 5;`), hmrPlugin()],
382390
});
383391

384392
try {
385393
const response = await fetch(`${host}/foo.js`);
386394
const body = await response.text();
387395

388-
expect(body.includes('__WDS_HMR__')).to.equal(false);
396+
assert.ok(!body.includes('__WDS_HMR__'));
389397
} finally {
390398
await server.stop();
391399
}

0 commit comments

Comments
 (0)