authorgravatar for me@t3.ggTheo Browne <me@t3.gg> 2026-09-03 19:50:20-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-03 19:50:20-07:00
logfee2e0ff8168b82ab19f496fcc874c1f3871f522
treee3c4d5e7e8e0c068300182b61a13e54e1a0ea5ae
parent9e1bc36a0843699db54ee28abbdac70584ae8f33
signature Signed by PGP key B5690EEEBB952194

test(web): fix flaky startup and Tailwind tests (#9558)


2 files changed, 21 insertions(+), 15 deletions(-)

apps/web/src/bootstrap.test.ts+4-3
...@@ -30,9 +30,6 @@ describe("app startup failures", () => {...@@ -30,9 +30,6 @@ describe("app startup failures", () => {
3030
31 beforeEach(() => {31 beforeEach(() => {
32 vi.resetModules();32 vi.resetModules();
33 vi.doMock("./main", () => {
34 throw new Error("@vitejs/plugin-react can't detect preamble. Something is wrong.");
35 });
36 bootShell = new BootElement("div");33 bootShell = new BootElement("div");
37 vi.stubGlobal("document", {34 vi.stubGlobal("document", {
38 getElementById: () => bootShell,35 getElementById: () => bootShell,
...@@ -51,12 +48,16 @@ describe("app startup failures", () => {...@@ -51,12 +48,16 @@ describe("app startup failures", () => {
51 });48 });
5249
53 afterEach(() => {50 afterEach(() => {
51 vi.doUnmock("./main");
54 vi.unstubAllGlobals();52 vi.unstubAllGlobals();
55 vi.unstubAllEnvs();53 vi.unstubAllEnvs();
56 vi.restoreAllMocks();54 vi.restoreAllMocks();
57 });55 });
5856
59 it("replaces the splash when an app import throws before main can run", async () => {57 it("replaces the splash when an app import throws before main can run", async () => {
58 vi.doMock("./main", () => {
59 throw new Error("@vitejs/plugin-react can't detect preamble. Something is wrong.");
60 });
60 const reload = vi.fn();61 const reload = vi.fn();
61 vi.stubGlobal("window", { location: { reload } });62 vi.stubGlobal("window", { location: { reload } });
6263
apps/web/src/bundledDev.test.ts+17-12
...@@ -147,7 +147,8 @@ it("hot updates Tailwind classes when a source file changes in bundled dev", asy...@@ -147,7 +147,8 @@ it("hot updates Tailwind classes when a source file changes in bundled dev", asy
147 );147 );
148 const logger = createLogger("silent");148 const logger = createLogger("silent");
149 logger.error = (message) => events.emit("error", new Error(message));149 logger.error = (message) => events.emit("error", new Error(message));
150 const built = NodeEvents.EventEmitter.once(events, "built");150 const connected = NodeEvents.EventEmitter.once(events, "connected");
151 const ready = NodeEvents.EventEmitter.once(events, "ready");
151 server = await createServer({152 server = await createServer({
152 configFile: false,153 configFile: false,
153 root,154 root,
...@@ -168,19 +169,18 @@ it("hot updates Tailwind classes when a source file changes in bundled dev", asy...@@ -168,19 +169,18 @@ it("hot updates Tailwind classes when a source file changes in bundled dev", asy
168 transform(code, id) {169 transform(code, id) {
169 if (id.endsWith("/style.css")) css = code;170 if (id.endsWith("/style.css")) css = code;
170 },171 },
171 generateBundle() {172 async generateBundle() {
172 events.emit("built");173 // Keep the build pending until the socket can receive Vite's ready message.
174 await connected;
173 },175 },
174 },176 },
175 ],177 ],
176 server: { host: "127.0.0.1", port: 0 },178 server: { host: "127.0.0.1", port: 0 },
177 });179 });
178 await server.listen();180 await server.listen();
179 await built;
180 const address = server.httpServer?.address();181 const address = server.httpServer?.address();
181 if (!address || typeof address === "string") throw new Error("Vite did not bind a port");182 if (!address || typeof address === "string") throw new Error("Vite did not bind a port");
182183
183 const connected = NodeEvents.EventEmitter.once(events, "connected");
184 server.ws.on("vite:client-connected", () => events.emit("connected"));184 server.ws.on("vite:client-connected", () => events.emit("connected"));
185 socket = new WebSocket(185 socket = new WebSocket(
186 `ws://127.0.0.1:${address.port}/?token=${server.config.webSocketToken}`,186 `ws://127.0.0.1:${address.port}/?token=${server.config.webSocketToken}`,
...@@ -197,16 +197,21 @@ it("hot updates Tailwind classes when a source file changes in bundled dev", asy...@@ -197,16 +197,21 @@ it("hot updates Tailwind classes when a source file changes in bundled dev", asy
197 });197 });
198 socket.addEventListener("message", ({ data }) => {198 socket.addEventListener("message", ({ data }) => {
199 const message: unknown = JSON.parse(String(data));199 const message: unknown = JSON.parse(String(data));
200 if (200 if (message !== null && typeof message === "object" && "type" in message) {
201 message !== null &&201 // generateBundle runs before Vite stores the files for HTTP requests.
202 typeof message === "object" &&202 if (
203 "type" in message &&203 message.type === "full-reload" &&
204 message.type === "bundled-dev-update"204 "ifFallback" in message &&
205 ) {205 message.ifFallback === true
206 events.emit("updated");206 ) {
207 events.emit("ready");
208 } else if (message.type === "bundled-dev-update") {
209 events.emit("updated");
210 }
207 }211 }
208 });212 });
209 await connected;213 await connected;
214 await ready;
210 const entry = await fetch(`http://127.0.0.1:${address.port}/assets/index.js`);215 const entry = await fetch(`http://127.0.0.1:${address.port}/assets/index.js`);
211 expect(entry.headers.get("content-type")).toContain("javascript");216 expect(entry.headers.get("content-type")).toContain("javascript");
212 await entry.text();217 await entry.text();