Frontend testing
See Testing for setup and conventions. This page covers what is specific to UI.
Component tests
Seven files under apps/web/__tests__/components/, weighted toward the call
UI: CallUI, CallProvider, CallComponents, CallResponsiveness,
TrashPanel, ImagePreview, LargeFileViewer.
cd apps/web
npx vitest run __tests__/components
Patterns
Query the way a user perceives the UI
// Good — survives a style refactor
screen.getByRole("button", { name: /accept call/i });
screen.getByTitle(/Group selection/);
// Fragile
container.querySelector(".btn-primary");
Provider-dependent components
Wrap in the same providers the app uses, or the component throws:
function renderWithProviders(ui: React.ReactElement) {
return render(
<SessionProvider session={{ user: { id: "u1" }, expires: "" }}>
{ui}
</SessionProvider>,
);
}
Responsiveness
CallResponsiveness.test.tsx drives layout by stubbing viewport width:
function setViewport(width: number) {
vi.stubGlobal("innerWidth", width);
window.dispatchEvent(new Event("resize"));
}
it("stacks tiles on mobile", () => {
setViewport(375);
render(<CallGrid participants={two} />);
// assert the stacked layout
});
What component tests cannot reach
Be honest about the boundary — these need manual checks:
- Canvas drag, marquee selection, group-drag on React Flow
- Live cursors and presence across two clients
- Real camera, microphone and screen share
- CodeMirror editing, syntax highlighting, lint gutters
- Visual contrast in dark and light mode
Manual checklist
Before shipping UI work:
- Both themes — the app defaults to dark; light mode is where contrast bugs hide
- 320 px, 768 px, 1440 px
- Keyboard-only navigation with a visible focus ring
- Empty, loading and error states, not just the happy path
- Two windows for anything collaborative