From 78866b276d6ed6e354b1bff81f066e73bab12cfa Mon Sep 17 00:00:00 2001 From: neverland Date: Sat, 14 Mar 2026 22:01:49 +0800 Subject: [PATCH 1/3] refactor(test): remove jest-specific setup file --- rstest.config.mjs | 2 +- setupTest.js | 79 --- test/helpers/listenAndCompile.js | 8 +- test/middleware.test.js | 587 +++++++++++------------ test/utils/ready.test.js | 10 +- test/utils/setupHooks.test.js | 40 +- test/utils/setupOutputFileSystem.test.js | 2 +- test/utils/setupWriteToDisk.test.js | 20 +- 8 files changed, 314 insertions(+), 434 deletions(-) delete mode 100644 setupTest.js diff --git a/rstest.config.mjs b/rstest.config.mjs index 3501e9a..1560363 100644 --- a/rstest.config.mjs +++ b/rstest.config.mjs @@ -3,8 +3,8 @@ import { defineConfig } from "@rstest/core"; export default defineConfig({ testEnvironment: "node", globals: true, + testTimeout: 20000, include: ["test/**/*.test.js"], exclude: ["**/node_modules/**", "**/dist/**", "**/__snapshots__/**"], - setupFiles: ["./setupTest.js"], globalSetup: ["./scripts/globalSetup.mjs"], }); diff --git a/setupTest.js b/setupTest.js deleted file mode 100644 index 41d5245..0000000 --- a/setupTest.js +++ /dev/null @@ -1,79 +0,0 @@ -rstest.setConfig({ - testTimeout: 20000, -}); - -globalThis.jest = rstest; - -function wrapDoneStyleTest(testFn) { - return (name, fn, timeout) => { - if (typeof fn !== "function" || fn.length === 0) { - return testFn(name, fn, timeout); - } - - return testFn( - name, - () => - new Promise((resolve, reject) => { - let settled = false; - - const done = (error) => { - if (settled) { - return; - } - - settled = true; - - if (error) { - reject(error); - - return; - } - - resolve(); - }; - - try { - fn(done); - } catch (error) { - done(error); - } - }), - timeout, - ); - }; -} - -function patchTestApi(name) { - const testFn = globalThis[name]; - - if (typeof testFn !== "function") { - return; - } - - const wrapped = wrapDoneStyleTest(testFn); - - if (typeof testFn.only === "function") { - wrapped.only = wrapDoneStyleTest(testFn.only); - } - - if (typeof testFn.skip === "function") { - wrapped.skip = testFn.skip.bind(testFn); - } - - if (typeof testFn.concurrent === "function") { - wrapped.concurrent = wrapDoneStyleTest(testFn.concurrent); - } - - if (typeof testFn.todo === "function") { - wrapped.todo = testFn.todo.bind(testFn); - } - - if (typeof testFn.each === "function") { - wrapped.each = testFn.each.bind(testFn); - } - - globalThis[name] = wrapped; -} - -patchTestApi("it"); -patchTestApi("test"); diff --git a/test/helpers/listenAndCompile.js b/test/helpers/listenAndCompile.js index abb1e5a..3b20b02 100644 --- a/test/helpers/listenAndCompile.js +++ b/test/helpers/listenAndCompile.js @@ -1,17 +1,17 @@ -export default (app, compiler, done) => { +export default (app, compiler, callback) => { let complete = 0; - // wait until the app is listening and the done hook is called + // wait until the app is listening and the compiler done hook is called const progress = () => { complete += 1; if (complete === 2) { - done(); + callback(); } }; const listen = app.listen((error) => { if (error) { // if there is an error, don't wait for the compilation to finish - return done(error); + return callback(error); } return progress(); diff --git a/test/middleware.test.js b/test/middleware.test.js index c3def60..7df9d98 100644 --- a/test/middleware.test.js +++ b/test/middleware.test.js @@ -32,7 +32,7 @@ import getCompiler from "./helpers/getCompiler"; import getCompilerHooks from "./helpers/getCompilerHooks"; // Suppress unnecessary stats output -jest.spyOn(globalThis.console, "log").mockImplementation(); +rs.spyOn(globalThis.console, "log").mockImplementation(); async function startServer(name, app) { return new Promise((resolve, reject) => { @@ -200,6 +200,18 @@ function getAssetFilename(instance, extension) { return assetName; } +function waitUntilValid(instance) { + return new Promise((resolve) => { + instance.waitUntilValid(resolve); + }); +} + +function waitForCompilerDone(compiler, name = "wdm-test") { + return new Promise((resolve) => { + compiler.hooks.done.tap(name, resolve); + }); +} + async function closeServer(server) { // hapi if (typeof server.stop === "function") { @@ -360,22 +372,21 @@ describe.each([ await close(server, instance); }); - it("should work", (done) => { - const doneSpy = jest.spyOn( + it("should work", async () => { + const doneSpy = rs.spyOn( getCompilerHooks(compiler).done[0], "fn", ); - instance.waitUntilValid(() => { + try { + await waitUntilValid(instance); instance.close(); expect(compiler.running).toBe(false); expect(doneSpy).toHaveBeenCalledTimes(1); - + } finally { doneSpy.mockRestore(); - - done(); - }); + } }); }); @@ -396,22 +407,21 @@ describe.each([ await close(server, instance); }); - it("should work", (done) => { - const doneSpy = jest.spyOn( + it("should work", async () => { + const doneSpy = rs.spyOn( getCompilerHooks(compiler).done[0], "fn", ); - instance.waitUntilValid(() => { + try { + await waitUntilValid(instance); instance.close(); expect(compiler.running).toBe(false); expect(doneSpy).toHaveBeenCalledTimes(1); - + } finally { doneSpy.mockRestore(); - - done(); - }); + } }); }); }); @@ -431,79 +441,69 @@ describe.each([ await close(server, instance); }); - it("should work without callback", (done) => { - const doneSpy = jest.spyOn(getCompilerHooks(compiler).done[0], "fn"); + it("should work without callback", async () => { + const doneSpy = rs.spyOn(getCompilerHooks(compiler).done[0], "fn"); instance.waitUntilValid(); - const intervalId = setInterval(() => { - if (instance.context.state) { + try { + await rs.waitFor(() => { expect(compiler.running).toBe(true); expect(instance.context.state).toBe(true); expect(doneSpy).toHaveBeenCalledTimes(1); expect(doneSpy.mock.calls[0][0]).toBeInstanceOf(Stats); - - doneSpy.mockRestore(); - - clearInterval(intervalId); - - done(); - } - }); + }); + } finally { + doneSpy.mockRestore(); + } }); - it("should work with callback", (done) => { - const doneSpy = jest.spyOn(getCompilerHooks(compiler).done[0], "fn"); + it("should work with callback", async () => { + const doneSpy = rs.spyOn(getCompilerHooks(compiler).done[0], "fn"); let callbackCounter = 0; instance.waitUntilValid(() => { callbackCounter += 1; }); - const intervalId = setInterval(() => { - if (instance.context.state) { + try { + await rs.waitFor(() => { expect(compiler.running).toBe(true); expect(instance.context.state).toBe(true); expect(callbackCounter).toBe(1); expect(doneSpy).toHaveBeenCalledTimes(1); - - doneSpy.mockRestore(); - - clearInterval(intervalId); - - done(); - } - }); + }); + } finally { + doneSpy.mockRestore(); + } }); - it("should run callback immediately when state already valid", (done) => { - const doneSpy = jest.spyOn(getCompilerHooks(compiler).done[0], "fn"); + it("should run callback immediately when state already valid", async () => { + const doneSpy = rs.spyOn(getCompilerHooks(compiler).done[0], "fn"); let callbackCounter = 0; let validToCheck = false; - instance.waitUntilValid(() => { - callbackCounter += 1; + try { + await new Promise((resolve) => { + instance.waitUntilValid(() => { + callbackCounter += 1; - instance.waitUntilValid(() => { - validToCheck = true; - callbackCounter += 1; + instance.waitUntilValid(() => { + validToCheck = true; + callbackCounter += 1; + resolve(); + }); + }); }); - }); - - const intervalId = setInterval(() => { - if (instance.context.state && validToCheck) { - expect(compiler.running).toBe(true); - expect(instance.context.state).toBe(true); - expect(callbackCounter).toBe(2); - expect(doneSpy).toHaveBeenCalledTimes(1); - doneSpy.mockRestore(); - - clearInterval(intervalId); - - done(); - } - }); + expect(compiler.running).toBe(true); + expect(instance.context.state).toBe(true); + expect(validToCheck).toBe(true); + expect(callbackCounter).toBe(2); + expect(doneSpy).toHaveBeenCalledTimes(1); + } finally { + doneSpy.mockRestore(); + } }); }); @@ -522,48 +522,40 @@ describe.each([ await close(server, instance); }); - it("should work without callback", (done) => { - const doneSpy = jest.spyOn(getCompilerHooks(compiler).done[0], "fn"); + it("should work without callback", async () => { + const doneSpy = rs.spyOn(getCompilerHooks(compiler).done[0], "fn"); instance.invalidate(); - const intervalId = setInterval(() => { - if (instance.context.state) { + try { + await rs.waitFor(() => { expect(compiler.running).toBe(true); expect(instance.context.state).toBe(true); expect(doneSpy).toHaveBeenCalledTimes(1); - - doneSpy.mockRestore(); - - clearInterval(intervalId); - - done(); - } - }); + }); + } finally { + doneSpy.mockRestore(); + } }); - it("should work with callback", (done) => { - const doneSpy = jest.spyOn(getCompilerHooks(compiler).done[0], "fn"); + it("should work with callback", async () => { + const doneSpy = rs.spyOn(getCompilerHooks(compiler).done[0], "fn"); let callbackCounter = 0; instance.invalidate(() => { callbackCounter += 1; }); - const intervalId = setInterval(() => { - if (instance.context.state) { + try { + await rs.waitFor(() => { expect(compiler.running).toBe(true); expect(instance.context.state).toBe(true); expect(callbackCounter).toBe(1); expect(doneSpy).toHaveBeenCalledTimes(1); - - doneSpy.mockRestore(); - - clearInterval(intervalId); - - done(); - } - }); + }); + } finally { + doneSpy.mockRestore(); + } }); }); @@ -583,29 +575,27 @@ describe.each([ await close(server, instance); }); - it("should work", (done) => { - instance.waitUntilValid(() => { - expect(instance.getFilenameFromUrl("/bundle.js")).toBe( - path.join(webpackConfig.output.path, "/bundle.js"), - ); - expect(instance.getFilenameFromUrl("/")).toBe( - path.join(webpackConfig.output.path, "/index.html"), - ); - expect(instance.getFilenameFromUrl("/index.html")).toBe( - path.join(webpackConfig.output.path, "/index.html"), - ); - expect(instance.getFilenameFromUrl("/svg.svg")).toBe( - path.join(webpackConfig.output.path, "/svg.svg"), - ); - expect( - instance.getFilenameFromUrl("/unknown.unknown"), - ).toBeUndefined(); - expect( - instance.getFilenameFromUrl("/unknown/unknown.unknown"), - ).toBeUndefined(); - - done(); - }); + it("should work", async () => { + await waitUntilValid(instance); + + expect(instance.getFilenameFromUrl("/bundle.js")).toBe( + path.join(webpackConfig.output.path, "/bundle.js"), + ); + expect(instance.getFilenameFromUrl("/")).toBe( + path.join(webpackConfig.output.path, "/index.html"), + ); + expect(instance.getFilenameFromUrl("/index.html")).toBe( + path.join(webpackConfig.output.path, "/index.html"), + ); + expect(instance.getFilenameFromUrl("/svg.svg")).toBe( + path.join(webpackConfig.output.path, "/svg.svg"), + ); + expect( + instance.getFilenameFromUrl("/unknown.unknown"), + ).toBeUndefined(); + expect( + instance.getFilenameFromUrl("/unknown/unknown.unknown"), + ).toBeUndefined(); }); }); @@ -627,28 +617,26 @@ describe.each([ await close(server, instance); }); - it("should work", (done) => { - instance.waitUntilValid(() => { - expect(instance.getFilenameFromUrl("/bundle.js")).toBe( - path.join(webpackConfig.output.path, "/bundle.js"), - ); + it("should work", async () => { + await waitUntilValid(instance); - expect(instance.getFilenameFromUrl("/")).toBeUndefined(); - expect(instance.getFilenameFromUrl("/index.html")).toBe( - path.join(webpackConfig.output.path, "/index.html"), - ); - expect(instance.getFilenameFromUrl("/svg.svg")).toBe( - path.join(webpackConfig.output.path, "/svg.svg"), - ); - expect( - instance.getFilenameFromUrl("/unknown.unknown"), - ).toBeUndefined(); - expect( - instance.getFilenameFromUrl("/unknown/unknown.unknown"), - ).toBeUndefined(); - - done(); - }); + expect(instance.getFilenameFromUrl("/bundle.js")).toBe( + path.join(webpackConfig.output.path, "/bundle.js"), + ); + + expect(instance.getFilenameFromUrl("/")).toBeUndefined(); + expect(instance.getFilenameFromUrl("/index.html")).toBe( + path.join(webpackConfig.output.path, "/index.html"), + ); + expect(instance.getFilenameFromUrl("/svg.svg")).toBe( + path.join(webpackConfig.output.path, "/svg.svg"), + ); + expect( + instance.getFilenameFromUrl("/unknown.unknown"), + ).toBeUndefined(); + expect( + instance.getFilenameFromUrl("/unknown/unknown.unknown"), + ).toBeUndefined(); }); }); @@ -667,35 +655,29 @@ describe.each([ await close(server, instance); }); - it("should work", (done) => { - instance.waitUntilValid(() => { - expect( - instance.getFilenameFromUrl("/public/path/bundle.js"), - ).toBe( - path.join(webpackPublicPathConfig.output.path, "/bundle.js"), - ); - expect(instance.getFilenameFromUrl("/public/path/")).toBe( - path.join(webpackPublicPathConfig.output.path, "/index.html"), - ); - expect( - instance.getFilenameFromUrl("/public/path/index.html"), - ).toBe( - path.join(webpackPublicPathConfig.output.path, "/index.html"), - ); - expect(instance.getFilenameFromUrl("/public/path/svg.svg")).toBe( - path.join(webpackPublicPathConfig.output.path, "/svg.svg"), - ); + it("should work", async () => { + await waitUntilValid(instance); - expect(instance.getFilenameFromUrl("/")).toBeUndefined(); - expect( - instance.getFilenameFromUrl("/unknown.unknown"), - ).toBeUndefined(); - expect( - instance.getFilenameFromUrl("/unknown/unknown.unknown"), - ).toBeUndefined(); + expect(instance.getFilenameFromUrl("/public/path/bundle.js")).toBe( + path.join(webpackPublicPathConfig.output.path, "/bundle.js"), + ); + expect(instance.getFilenameFromUrl("/public/path/")).toBe( + path.join(webpackPublicPathConfig.output.path, "/index.html"), + ); + expect(instance.getFilenameFromUrl("/public/path/index.html")).toBe( + path.join(webpackPublicPathConfig.output.path, "/index.html"), + ); + expect(instance.getFilenameFromUrl("/public/path/svg.svg")).toBe( + path.join(webpackPublicPathConfig.output.path, "/svg.svg"), + ); - done(); - }); + expect(instance.getFilenameFromUrl("/")).toBeUndefined(); + expect( + instance.getFilenameFromUrl("/unknown.unknown"), + ).toBeUndefined(); + expect( + instance.getFilenameFromUrl("/unknown/unknown.unknown"), + ).toBeUndefined(); }); }); @@ -714,55 +696,45 @@ describe.each([ await close(server, instance); }); - it("should work", (done) => { - instance.waitUntilValid(() => { - expect(instance.getFilenameFromUrl("/static-one/bundle.js")).toBe( - path.join(webpackMultiConfig[0].output.path, "/bundle.js"), - ); - expect(instance.getFilenameFromUrl("/static-one/")).toBe( - path.join(webpackMultiConfig[0].output.path, "/index.html"), - ); - expect( - instance.getFilenameFromUrl("/static-one/index.html"), - ).toBe( - path.join(webpackMultiConfig[0].output.path, "/index.html"), - ); - expect(instance.getFilenameFromUrl("/static-one/svg.svg")).toBe( - path.join(webpackMultiConfig[0].output.path, "/svg.svg"), - ); - expect( - instance.getFilenameFromUrl("/static-one/unknown.unknown"), - ).toBeUndefined(); - expect( - instance.getFilenameFromUrl( - "/static-one/unknown/unknown.unknown", - ), - ).toBeUndefined(); + it("should work", async () => { + await waitUntilValid(instance); - expect(instance.getFilenameFromUrl("/static-two/bundle.js")).toBe( - path.join(webpackMultiConfig[1].output.path, "/bundle.js"), - ); - expect( - instance.getFilenameFromUrl("/static-two/unknown.unknown"), - ).toBeUndefined(); - expect( - instance.getFilenameFromUrl( - "/static-two/unknown/unknown.unknown", - ), - ).toBeUndefined(); - - expect(instance.getFilenameFromUrl("/")).toBeUndefined(); - expect( - instance.getFilenameFromUrl("/static-one/unknown.unknown"), - ).toBeUndefined(); - expect( - instance.getFilenameFromUrl( - "/static-one/unknown/unknown.unknown", - ), - ).toBeUndefined(); + expect(instance.getFilenameFromUrl("/static-one/bundle.js")).toBe( + path.join(webpackMultiConfig[0].output.path, "/bundle.js"), + ); + expect(instance.getFilenameFromUrl("/static-one/")).toBe( + path.join(webpackMultiConfig[0].output.path, "/index.html"), + ); + expect(instance.getFilenameFromUrl("/static-one/index.html")).toBe( + path.join(webpackMultiConfig[0].output.path, "/index.html"), + ); + expect(instance.getFilenameFromUrl("/static-one/svg.svg")).toBe( + path.join(webpackMultiConfig[0].output.path, "/svg.svg"), + ); + expect( + instance.getFilenameFromUrl("/static-one/unknown.unknown"), + ).toBeUndefined(); + expect( + instance.getFilenameFromUrl("/static-one/unknown/unknown.unknown"), + ).toBeUndefined(); - done(); - }); + expect(instance.getFilenameFromUrl("/static-two/bundle.js")).toBe( + path.join(webpackMultiConfig[1].output.path, "/bundle.js"), + ); + expect( + instance.getFilenameFromUrl("/static-two/unknown.unknown"), + ).toBeUndefined(); + expect( + instance.getFilenameFromUrl("/static-two/unknown/unknown.unknown"), + ).toBeUndefined(); + + expect(instance.getFilenameFromUrl("/")).toBeUndefined(); + expect( + instance.getFilenameFromUrl("/static-one/unknown.unknown"), + ).toBeUndefined(); + expect( + instance.getFilenameFromUrl("/static-one/unknown/unknown.unknown"), + ).toBeUndefined(); }); }); }); @@ -782,34 +754,35 @@ describe.each([ await close(server, instance); }); - it("should work without callback", (done) => { - const doneSpy = jest.spyOn(getCompilerHooks(compiler).done[0], "fn"); + it("should work without callback", async () => { + const doneSpy = rs.spyOn(getCompilerHooks(compiler).done[0], "fn"); - instance.waitUntilValid(() => { + try { + await waitUntilValid(instance); instance.close(); expect(compiler.running).toBe(false); expect(doneSpy).toHaveBeenCalledTimes(1); - + } finally { doneSpy.mockRestore(); - - done(); - }); + } }); - it("should work with callback", (done) => { - const doneSpy = jest.spyOn(getCompilerHooks(compiler).done[0], "fn"); + it("should work with callback", async () => { + const doneSpy = rs.spyOn(getCompilerHooks(compiler).done[0], "fn"); - instance.waitUntilValid(() => { - instance.close(() => { - expect(compiler.running).toBe(false); - expect(doneSpy).toHaveBeenCalledTimes(1); - - doneSpy.mockRestore(); - - done(); + try { + await waitUntilValid(instance); + await new Promise((resolve) => { + instance.close(() => { + expect(compiler.running).toBe(false); + expect(doneSpy).toHaveBeenCalledTimes(1); + resolve(); + }); }); - }); + } finally { + doneSpy.mockRestore(); + } }); }); @@ -828,7 +801,7 @@ describe.each([ await close(server, instance); }); - it("should contain public properties", (done) => { + it("should contain public properties", async () => { expect(instance.context.state).toBeDefined(); expect(instance.context.options).toBeDefined(); expect(instance.context.compiler).toBeDefined(); @@ -837,9 +810,7 @@ describe.each([ // the compilation needs to finish, as it will still be running // after the test is done if not finished, potentially impacting other tests - compiler.hooks.done.tap("wdm-test", () => { - done(); - }); + await waitForCompilerDone(compiler); }); }); }); @@ -3919,7 +3890,7 @@ describe.each([ beforeAll(async () => { compiler = getCompiler(webpackConfig); - spy = jest.spyOn(compiler, "watch"); + spy = rs.spyOn(compiler, "watch"); [server, req, instance] = await frameworkFactory( name, @@ -3955,7 +3926,7 @@ describe.each([ beforeAll(async () => { compiler = getCompiler(webpackWatchOptionsConfig); - spy = jest.spyOn(compiler, "watch"); + spy = rs.spyOn(compiler, "watch"); [server, req, instance] = await frameworkFactory( name, @@ -3991,7 +3962,7 @@ describe.each([ beforeAll(async () => { compiler = getCompiler(webpackMultiWatchOptionsConfig); - spy = jest.spyOn(compiler, "watch"); + spy = rs.spyOn(compiler, "watch"); [server, req, instance] = await frameworkFactory( name, @@ -4066,39 +4037,35 @@ describe.each([ await close(server, instance); }); - it("should find the bundle file on disk", (done) => { - req.get("/public/bundle.js").expect(200, (error) => { - if (error) { - return done(error); - } + it("should find the bundle file on disk", async () => { + await req.get("/public/bundle.js").expect(200); - const bundlePath = path.resolve( - __dirname, - "./outputs/write-to-disk-true/bundle.js", - ); + const bundlePath = path.resolve( + __dirname, + "./outputs/write-to-disk-true/bundle.js", + ); - expect( - compiler.hooks.assetEmitted.taps.filter( - (hook) => hook.name === "DevMiddleware", - ), - ).toHaveLength(0); - expect(fs.existsSync(bundlePath)).toBe(true); + expect( + compiler.hooks.assetEmitted.taps.filter( + (hook) => hook.name === "DevMiddleware", + ), + ).toHaveLength(0); + expect(fs.existsSync(bundlePath)).toBe(true); - instance.invalidate(); + const donePromise = waitForCompilerDone( + compiler, + "DevMiddlewareWriteToDiskTest", + ); - return compiler.hooks.done.tap( - "DevMiddlewareWriteToDiskTest", - () => { - expect( - compiler.hooks.assetEmitted.taps.filter( - (hook) => hook.name === "DevMiddleware", - ), - ).toHaveLength(0); + instance.invalidate(); - done(); - }, - ); - }); + await donePromise; + + expect( + compiler.hooks.assetEmitted.taps.filter( + (hook) => hook.name === "DevMiddleware", + ), + ).toHaveLength(0); }); it("should not allow to get files above root", async () => { @@ -4163,40 +4130,36 @@ describe.each([ await close(server, instance); }); - it("should find the bundle file on disk", (done) => { - req.get("/bundle.js").expect(200, (error) => { - if (error) { - return done(error); - } + it("should find the bundle file on disk", async () => { + await req.get("/bundle.js").expect(200); - const bundlePath = path.resolve(outputPath, "bundle.js"); + const bundlePath = path.resolve(outputPath, "bundle.js"); - expect(fs.existsSync(path.resolve(outputPath, "test.json"))).toBe( - false, - ); + expect(fs.existsSync(path.resolve(outputPath, "test.json"))).toBe( + false, + ); - expect( - compiler.hooks.assetEmitted.taps.filter( - (hook) => hook.name === "DevMiddleware", - ), - ).toHaveLength(0); - expect(fs.existsSync(bundlePath)).toBe(true); + expect( + compiler.hooks.assetEmitted.taps.filter( + (hook) => hook.name === "DevMiddleware", + ), + ).toHaveLength(0); + expect(fs.existsSync(bundlePath)).toBe(true); - instance.invalidate(); + const donePromise = waitForCompilerDone( + compiler, + "DevMiddlewareWriteToDiskTest", + ); - return compiler.hooks.done.tap( - "DevMiddlewareWriteToDiskTest", - () => { - expect( - compiler.hooks.assetEmitted.taps.filter( - (hook) => hook.name === "DevMiddleware", - ), - ).toHaveLength(0); - - done(); - }, - ); - }); + instance.invalidate(); + + await donePromise; + + expect( + compiler.hooks.assetEmitted.taps.filter( + (hook) => hook.name === "DevMiddleware", + ), + ).toHaveLength(0); }); }); @@ -4224,39 +4187,35 @@ describe.each([ await close(server, instance); }); - it("should not find the bundle file on disk", (done) => { - req.get("/bundle.js").expect(200, (error) => { - if (error) { - return done(error); - } + it("should not find the bundle file on disk", async () => { + await req.get("/bundle.js").expect(200); - const bundlePath = path.resolve( - __dirname, - "./outputs/write-to-disk-false/bundle.js", - ); + const bundlePath = path.resolve( + __dirname, + "./outputs/write-to-disk-false/bundle.js", + ); - expect( - compiler.hooks.assetEmitted.taps.filter( - (hook) => hook.name === "DevMiddleware", - ), - ).toHaveLength(0); - expect(fs.existsSync(bundlePath)).toBe(false); + expect( + compiler.hooks.assetEmitted.taps.filter( + (hook) => hook.name === "DevMiddleware", + ), + ).toHaveLength(0); + expect(fs.existsSync(bundlePath)).toBe(false); - instance.invalidate(); + const donePromise = waitForCompilerDone( + compiler, + "DevMiddlewareWriteToDiskTest", + ); - return compiler.hooks.done.tap( - "DevMiddlewareWriteToDiskTest", - () => { - expect( - compiler.hooks.assetEmitted.taps.filter( - (hook) => hook.name === "DevMiddleware", - ), - ).toHaveLength(0); - - done(); - }, - ); - }); + instance.invalidate(); + + await donePromise; + + expect( + compiler.hooks.assetEmitted.taps.filter( + (hook) => hook.name === "DevMiddleware", + ), + ).toHaveLength(0); }); }); diff --git a/test/utils/ready.test.js b/test/utils/ready.test.js index 65f8905..842b616 100644 --- a/test/utils/ready.test.js +++ b/test/utils/ready.test.js @@ -2,7 +2,7 @@ import ready from "../../src/utils/ready"; describe("ready", () => { it("should call callback if state is true", () => { - const cb = jest.fn(); + const cb = rs.fn(); const context = { state: true, stats: "stats", @@ -14,12 +14,12 @@ describe("ready", () => { }); it("should save callback and log req.url if state is false with req.url set", () => { - const cb = jest.fn(); + const cb = rs.fn(); const context = { state: false, stats: "stats", logger: { - info: jest.fn(), + info: rs.fn(), }, callbacks: [], }; @@ -37,12 +37,12 @@ describe("ready", () => { }); it("should save callback and log callback.name if state is false with req.url not set", () => { - const cb = jest.fn(); + const cb = rs.fn(); const context = { state: false, stats: "stats", logger: { - info: jest.fn(), + info: rs.fn(), }, callbacks: [], }; diff --git a/test/utils/setupHooks.test.js b/test/utils/setupHooks.test.js index 8aaaa26..60349df 100644 --- a/test/utils/setupHooks.test.js +++ b/test/utils/setupHooks.test.js @@ -1,24 +1,24 @@ import setupHooks from "../../src/utils/setupHooks"; // Suppress unnecessary stats output -jest.spyOn(globalThis.console, "log").mockImplementation(); +rs.spyOn(globalThis.console, "log").mockImplementation(); describe("setupHooks", () => { let context; - const watchRunHook = jest.fn(); - const invalidHook = jest.fn(); - const doneHook = jest.fn(); - const loggerLog = jest.fn(); - const loggerInfo = jest.fn(); - const loggerWarn = jest.fn(); - const loggerError = jest.fn(); + const watchRunHook = rs.fn(); + const invalidHook = rs.fn(); + const doneHook = rs.fn(); + const loggerLog = rs.fn(); + const loggerInfo = rs.fn(); + const loggerWarn = rs.fn(); + const loggerError = rs.fn(); let nextTick; - const cb1 = jest.fn(); - const cb2 = jest.fn(); + const cb1 = rs.fn(); + const cb2 = rs.fn(); beforeEach(() => { - nextTick = jest.spyOn(process, "nextTick").mockImplementation(() => {}); + nextTick = rs.spyOn(process, "nextTick").mockImplementation(() => {}); context = { options: {}, compiler: { @@ -95,9 +95,9 @@ describe("setupHooks", () => { it("sets state, then logs stats and handles callbacks on nextTick from done hook", () => { setupHooks(context); doneHook.mock.calls[0][1]({ - toString: jest.fn(() => "statsString"), - hasErrors: jest.fn(() => false), - hasWarnings: jest.fn(() => false), + toString: rs.fn(() => "statsString"), + hasErrors: rs.fn(() => false), + hasWarnings: rs.fn(() => false), }); expect(context.stats).toBeTruthy(); expect(context.state).toBeTruthy(); @@ -142,14 +142,14 @@ describe("setupHooks", () => { doneHook.mock.calls[0][1]({ stats: [ { - toString: jest.fn(() => "statsString1"), - hasErrors: jest.fn(() => true), - hasWarnings: jest.fn(() => false), + toString: rs.fn(() => "statsString1"), + hasErrors: rs.fn(() => true), + hasWarnings: rs.fn(() => false), }, { - toString: jest.fn(() => "statsString2"), - hasErrors: jest.fn(() => false), - hasWarnings: jest.fn(() => true), + toString: rs.fn(() => "statsString2"), + hasErrors: rs.fn(() => false), + hasWarnings: rs.fn(() => true), }, ], }); diff --git a/test/utils/setupOutputFileSystem.test.js b/test/utils/setupOutputFileSystem.test.js index 89fb65d..3296cf7 100644 --- a/test/utils/setupOutputFileSystem.test.js +++ b/test/utils/setupOutputFileSystem.test.js @@ -2,7 +2,7 @@ import memfs from "memfs"; import setupOutputFileSystem from "../../src/utils/setupOutputFileSystem"; -const createFsFromVolume = jest.spyOn(memfs, "createFsFromVolume"); +const createFsFromVolume = rs.spyOn(memfs, "createFsFromVolume"); createFsFromVolume.mockReturnValue({ testFs: true, diff --git a/test/utils/setupWriteToDisk.test.js b/test/utils/setupWriteToDisk.test.js index 6f1640d..997bd84 100644 --- a/test/utils/setupWriteToDisk.test.js +++ b/test/utils/setupWriteToDisk.test.js @@ -2,14 +2,14 @@ import fs from "node:fs"; import setupWriteToDisk from "../../src/utils/setupWriteToDisk"; -const mkdirSpy = jest.spyOn(fs, "mkdir"); -const writeFileSpy = jest.spyOn(fs, "writeFile"); +const mkdirSpy = rs.spyOn(fs, "mkdir"); +const writeFileSpy = rs.spyOn(fs, "writeFile"); describe("setupWriteToDisk", () => { let context; - const emitHook = jest.fn(); - const assetEmittedHook = jest.fn(); - const getPath = jest.fn((outputPath) => outputPath); + const emitHook = rs.fn(); + const assetEmittedHook = rs.fn(); + const getPath = rs.fn((outputPath) => outputPath); beforeEach(() => { context = { @@ -28,8 +28,8 @@ describe("setupWriteToDisk", () => { }, }, logger: { - error: jest.fn(), - log: jest.fn(), + error: rs.fn(), + log: rs.fn(), }, }; }); @@ -60,12 +60,12 @@ describe("setupWriteToDisk", () => { }); it("filters out unwanted emits with writeToDisk", () => { - const filter = jest.fn(() => false); + const filter = rs.fn(() => false); context.options = { writeToDisk: filter, }; setupWriteToDisk(context); - const cb = jest.fn(); + const cb = rs.fn(); // webpack@5 info style runAssetEmitted( null, @@ -110,7 +110,7 @@ describe("setupWriteToDisk", () => { it(`tries to create directories and write file if not filtered out ${writeError.title}`, () => { context.options = {}; setupWriteToDisk(context); - const cb = jest.fn(); + const cb = rs.fn(); // webpack@5 info style runAssetEmitted( null, From 2c48306d189ac0d4a38084044a14c2d75402edf3 Mon Sep 17 00:00:00 2001 From: neverland Date: Sat, 14 Mar 2026 22:05:05 +0800 Subject: [PATCH 2/3] fix --- test/middleware.test.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/middleware.test.js b/test/middleware.test.js index 7df9d98..d94e77e 100644 --- a/test/middleware.test.js +++ b/test/middleware.test.js @@ -373,10 +373,7 @@ describe.each([ }); it("should work", async () => { - const doneSpy = rs.spyOn( - getCompilerHooks(compiler).done[0], - "fn", - ); + const doneSpy = rs.spyOn(getCompilerHooks(compiler).done[0], "fn"); try { await waitUntilValid(instance); @@ -408,10 +405,7 @@ describe.each([ }); it("should work", async () => { - const doneSpy = rs.spyOn( - getCompilerHooks(compiler).done[0], - "fn", - ); + const doneSpy = rs.spyOn(getCompilerHooks(compiler).done[0], "fn"); try { await waitUntilValid(instance); @@ -715,7 +709,9 @@ describe.each([ instance.getFilenameFromUrl("/static-one/unknown.unknown"), ).toBeUndefined(); expect( - instance.getFilenameFromUrl("/static-one/unknown/unknown.unknown"), + instance.getFilenameFromUrl( + "/static-one/unknown/unknown.unknown", + ), ).toBeUndefined(); expect(instance.getFilenameFromUrl("/static-two/bundle.js")).toBe( @@ -725,7 +721,9 @@ describe.each([ instance.getFilenameFromUrl("/static-two/unknown.unknown"), ).toBeUndefined(); expect( - instance.getFilenameFromUrl("/static-two/unknown/unknown.unknown"), + instance.getFilenameFromUrl( + "/static-two/unknown/unknown.unknown", + ), ).toBeUndefined(); expect(instance.getFilenameFromUrl("/")).toBeUndefined(); @@ -733,7 +731,9 @@ describe.each([ instance.getFilenameFromUrl("/static-one/unknown.unknown"), ).toBeUndefined(); expect( - instance.getFilenameFromUrl("/static-one/unknown/unknown.unknown"), + instance.getFilenameFromUrl( + "/static-one/unknown/unknown.unknown", + ), ).toBeUndefined(); }); }); From 2de8503e0abf5cf05102c04fc7140887241160c5 Mon Sep 17 00:00:00 2001 From: neverland Date: Sat, 14 Mar 2026 22:05:49 +0800 Subject: [PATCH 3/3] fix --- CONTRIBUTING.md | 2 +- test/middleware.test.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 18a0daa..3e014f3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -95,7 +95,7 @@ Must be one of the following: - **refactor**: A code change that neither fixes a bug nor adds a feature - **revert**: Used when reverting a committed change - **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons) -- **test**: Addition of or updates to Jest tests +- **test**: Addition of or updates to Rstest tests #### Scope diff --git a/test/middleware.test.js b/test/middleware.test.js index d94e77e..97d1045 100644 --- a/test/middleware.test.js +++ b/test/middleware.test.js @@ -1194,7 +1194,7 @@ describe.each([ }); it('should return the "404" code for the "GET" request to the deleted file', async () => { - const spy = jest + const spy = rs .spyOn(instance.context.outputFileSystem, "readFileSync") .mockImplementation(() => { throw new Error("error"); @@ -5348,7 +5348,7 @@ describe.each([ }, ); - isDirectory = jest + isDirectory = rs .spyOn(instance.context.outputFileSystem, "statSync") .mockReturnValue({ isFile: () => false,