authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-03-04 22:04:56-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-05 10:20:34-08:00
log9abf96770044612038eb37740a1dfb4c38e1d272
tree1a3201ad63c0fb3f6a394ae10d9a4211a107ac0b
parentcc83094bc6b1e819b916e4447e12cde6f8f05ff9

Use vitest-browser-react in ChatView browser tests

- replace manual `createRoot` mounting with `render`/`unmount` from vitest-browser-react - add `vitest-browser-react` to web devDependencies and lockfile

3 files changed, 12 insertions(+), 11 deletions(-)

apps/web/package.json+2-1
...@@ -50,6 +50,7 @@...@@ -50,6 +50,7 @@
50 "tailwindcss": "^4.0.0",50 "tailwindcss": "^4.0.0",
51 "typescript": "catalog:",51 "typescript": "catalog:",
52 "vite": "^8.0.0-beta.12",52 "vite": "^8.0.0-beta.12",
53 "vitest": "catalog:"53 "vitest": "catalog:",
54 "vitest-browser-react": "^2.0.5"
54 }55 }
55}56}
apps/web/src/components/ChatView.browser.tsx+7-10
...@@ -15,8 +15,8 @@ import {...@@ -15,8 +15,8 @@ import {
15import { RouterProvider, createMemoryHistory } from "@tanstack/react-router";15import { RouterProvider, createMemoryHistory } from "@tanstack/react-router";
16import { HttpResponse, http, ws } from "msw";16import { HttpResponse, http, ws } from "msw";
17import { setupWorker } from "msw/browser";17import { setupWorker } from "msw/browser";
18import { createRoot, type Root } from "react-dom/client";
19import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";18import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
19import { render } from "vitest-browser-react";
2020
21import { getRouter } from "../router";21import { getRouter } from "../router";
22import { useStore } from "../store";22import { useStore } from "../store";
...@@ -92,11 +92,7 @@ function createUserMessage(options: {...@@ -92,11 +92,7 @@ function createUserMessage(options: {
92 };92 };
93}93}
9494
95function createAssistantMessage(options: {95function createAssistantMessage(options: { id: MessageId; text: string; offsetSeconds: number }) {
96 id: MessageId;
97 text: string;
98 offsetSeconds: number;
99}) {
100 return {96 return {
101 id: options.id,97 id: options.id,
102 role: "assistant" as const,98 role: "assistant" as const,
...@@ -359,8 +355,9 @@ async function renderAndMeasureUserRow(options: {...@@ -359,8 +355,9 @@ async function renderAndMeasureUserRow(options: {
359 }),355 }),
360 );356 );
361357
362 const root: Root = createRoot(host);358 const screen = await render(<RouterProvider router={router} />, {
363 root.render(<RouterProvider router={router} />);359 container: host,
360 });
364361
365 try {362 try {
366 await waitForLayout();363 await waitForLayout();
...@@ -372,7 +369,7 @@ async function renderAndMeasureUserRow(options: {...@@ -372,7 +369,7 @@ async function renderAndMeasureUserRow(options: {
372369
373 let row: HTMLElement | null = null;370 let row: HTMLElement | null = null;
374 const timeoutAt = performance.now() + 8_000;371 const timeoutAt = performance.now() + 8_000;
375 while (performance.now() < timeoutAt) {372 while (performance.now() < timeoutAt) {
376 scrollContainer.scrollTop = 0;373 scrollContainer.scrollTop = 0;
377 scrollContainer.dispatchEvent(new Event("scroll"));374 scrollContainer.dispatchEvent(new Event("scroll"));
378 await waitForLayout();375 await waitForLayout();
...@@ -424,7 +421,7 @@ async function renderAndMeasureUserRow(options: {...@@ -424,7 +421,7 @@ async function renderAndMeasureUserRow(options: {
424421
425 return { measuredRowHeightPx, timelineWidthMeasuredPx, renderedInVirtualizedRegion };422 return { measuredRowHeightPx, timelineWidthMeasuredPx, renderedInVirtualizedRegion };
426 } finally {423 } finally {
427 root.unmount();424 await screen.unmount();
428 host.remove();425 host.remove();
429 }426 }
430}427}
bun.lock+3
...@@ -100,6 +100,7 @@...@@ -100,6 +100,7 @@
100 "typescript": "catalog:",100 "typescript": "catalog:",
101 "vite": "^8.0.0-beta.12",101 "vite": "^8.0.0-beta.12",
102 "vitest": "catalog:",102 "vitest": "catalog:",
103 "vitest-browser-react": "^2.0.5",
103 },104 },
104 },105 },
105 "packages/contracts": {106 "packages/contracts": {
...@@ -1506,6 +1507,8 @@...@@ -1506,6 +1507,8 @@
15061507
1507 "vitest": ["vitest@4.0.18", "", { "dependencies": { "@vitest/expect": "4.0.18", "@vitest/mocker": "4.0.18", "@vitest/pretty-format": "4.0.18", "@vitest/runner": "4.0.18", "@vitest/snapshot": "4.0.18", "@vitest/spy": "4.0.18", "@vitest/utils": "4.0.18", "es-module-lexer": "^1.7.0", "expect-type": "^1.2.2", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.0.3", "vite": "^6.0.0 || ^7.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.0.18", "@vitest/browser-preview": "4.0.18", "@vitest/browser-webdriverio": "4.0.18", "@vitest/ui": "4.0.18", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ=="],1508 "vitest": ["vitest@4.0.18", "", { "dependencies": { "@vitest/expect": "4.0.18", "@vitest/mocker": "4.0.18", "@vitest/pretty-format": "4.0.18", "@vitest/runner": "4.0.18", "@vitest/snapshot": "4.0.18", "@vitest/spy": "4.0.18", "@vitest/utils": "4.0.18", "es-module-lexer": "^1.7.0", "expect-type": "^1.2.2", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.0.3", "vite": "^6.0.0 || ^7.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.0.18", "@vitest/browser-preview": "4.0.18", "@vitest/browser-webdriverio": "4.0.18", "@vitest/ui": "4.0.18", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ=="],
15081509
1510 "vitest-browser-react": ["vitest-browser-react@2.0.5", "", { "peerDependencies": { "@types/react": "^18.0.0 || ^19.0.0", "@types/react-dom": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "vitest": "^4.0.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YODQX8mHTJCyKNVYTWJrLEYrUtw+QfLl78owgvuE7C5ydgmGBq6v5s4jK2w6wdPhIZsN9PpV1rQbmAevWJjO9g=="],
1511
1509 "wait-on": ["wait-on@8.0.5", "", { "dependencies": { "axios": "^1.12.1", "joi": "^18.0.1", "lodash": "^4.17.21", "minimist": "^1.2.8", "rxjs": "^7.8.2" }, "bin": { "wait-on": "bin/wait-on" } }, "sha512-J3WlS0txVHkhLRb2FsmRg3dkMTCV1+M6Xra3Ho7HzZDHpE7DCOnoSoCJsZotrmW3uRMhvIJGSKUKrh/MeF4iag=="],1512 "wait-on": ["wait-on@8.0.5", "", { "dependencies": { "axios": "^1.12.1", "joi": "^18.0.1", "lodash": "^4.17.21", "minimist": "^1.2.8", "rxjs": "^7.8.2" }, "bin": { "wait-on": "bin/wait-on" } }, "sha512-J3WlS0txVHkhLRb2FsmRg3dkMTCV1+M6Xra3Ho7HzZDHpE7DCOnoSoCJsZotrmW3uRMhvIJGSKUKrh/MeF4iag=="],
15101513
1511 "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="],1514 "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="],