|
1 | 1 | import fs from "node:fs"; |
2 | 2 | import os from "node:os"; |
3 | 3 | import path from "node:path"; |
4 | | -import { describe, it } from "node:test"; |
| 4 | +import { afterEach, beforeEach, describe, it } from "node:test"; |
| 5 | +import { fileURLToPath } from "node:url"; |
5 | 6 | import { expect } from "expect"; |
6 | 7 | import { spyOn } from "jest-mock"; |
7 | 8 | import webpack from "webpack"; |
8 | 9 | import WebSocket from "ws"; |
9 | 10 | import Server from "../../lib/Server.js"; |
10 | 11 | import config from "../fixtures/client-config/webpack.config.js"; |
11 | 12 | import multiCompilerConfig from "../fixtures/multi-compiler-two-configurations/webpack.config.js"; |
| 13 | +import reloadConfig from "../fixtures/reload-config/webpack.config.js"; |
12 | 14 | import compile from "../helpers/compile.js"; |
13 | 15 | import runBrowser from "../helpers/run-browser.js"; |
14 | 16 | import portsMap from "../ports-map.js"; |
15 | 17 |
|
| 18 | +const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
| 19 | + |
16 | 20 | const port = portsMap["api-plugin"]; |
17 | 21 | const [portA, portB] = portsMap["api-plugin-multi"]; |
18 | 22 |
|
| 23 | +const cssFilePath = path.resolve( |
| 24 | + __dirname, |
| 25 | + "../fixtures/reload-config/main.css", |
| 26 | +); |
| 27 | + |
19 | 28 | describe("API (plugin)", () => { |
20 | 29 | it("should work with plugin API", async (t) => { |
21 | 30 | const compiler = webpack(config); |
@@ -485,4 +494,83 @@ describe("API (plugin)", () => { |
485 | 494 | } |
486 | 495 | }); |
487 | 496 | }); |
| 497 | + |
| 498 | + describe("hot module replacement", () => { |
| 499 | + beforeEach(() => { |
| 500 | + fs.writeFileSync( |
| 501 | + cssFilePath, |
| 502 | + "body { background-color: rgb(0, 0, 255); }", |
| 503 | + ); |
| 504 | + }); |
| 505 | + |
| 506 | + afterEach(() => { |
| 507 | + fs.unlinkSync(cssFilePath); |
| 508 | + }); |
| 509 | + |
| 510 | + it("should apply hot module replacement updates", async () => { |
| 511 | + const server = new Server({ port, hot: true }); |
| 512 | + const compiler = webpack({ |
| 513 | + ...reloadConfig, |
| 514 | + plugins: [...reloadConfig.plugins, server], |
| 515 | + }); |
| 516 | + |
| 517 | + await compile(compiler, port); |
| 518 | + |
| 519 | + const { page, browser } = await runBrowser(); |
| 520 | + |
| 521 | + try { |
| 522 | + const pageErrors = []; |
| 523 | + let doneHotUpdate = false; |
| 524 | + |
| 525 | + page |
| 526 | + .on("pageerror", (error) => { |
| 527 | + pageErrors.push(error); |
| 528 | + }) |
| 529 | + .on("request", (request) => { |
| 530 | + if (/\.hot-update\.json$/.test(request.url())) { |
| 531 | + doneHotUpdate = true; |
| 532 | + } |
| 533 | + }); |
| 534 | + |
| 535 | + await page.goto(`http://127.0.0.1:${port}/`, { |
| 536 | + waitUntil: "networkidle0", |
| 537 | + }); |
| 538 | + |
| 539 | + const backgroundColorBefore = await page.evaluate( |
| 540 | + () => getComputedStyle(document.body)["background-color"], |
| 541 | + ); |
| 542 | + |
| 543 | + expect(backgroundColorBefore).toBe("rgb(0, 0, 255)"); |
| 544 | + |
| 545 | + fs.writeFileSync( |
| 546 | + cssFilePath, |
| 547 | + "body { background-color: rgb(255, 0, 0); }", |
| 548 | + ); |
| 549 | + |
| 550 | + // The change must arrive through HMR (a `.hot-update.json` fetch), |
| 551 | + // not a full page reload. |
| 552 | + await page.waitForFunction( |
| 553 | + () => |
| 554 | + getComputedStyle(document.body)["background-color"] === |
| 555 | + "rgb(255, 0, 0)", |
| 556 | + ); |
| 557 | + |
| 558 | + expect(doneHotUpdate).toBe(true); |
| 559 | + expect(pageErrors).toEqual([]); |
| 560 | + |
| 561 | + // The hot-update delta is served from webpack-dev-middleware's in-memory |
| 562 | + // file system, never the real disk. |
| 563 | + expect(compiler.outputFileSystem).not.toBe(fs); |
| 564 | + const outputFiles = compiler.outputFileSystem.readdirSync("/"); |
| 565 | + expect( |
| 566 | + outputFiles.some((file) => /\.hot-update\.json$/.test(file)), |
| 567 | + ).toBe(true); |
| 568 | + } finally { |
| 569 | + await browser.close(); |
| 570 | + await new Promise((resolve) => { |
| 571 | + compiler.close(resolve); |
| 572 | + }); |
| 573 | + } |
| 574 | + }); |
| 575 | + }); |
488 | 576 | }); |
0 commit comments