Set up `sdk/` as a package shaped exactly like `component/`: its own package.json with peer dependencies, the pnpm workspace marker so a host can install it as a git dependency, a build tsconfig for type emission, and a vite lib config with an externals list that `pnpm lint:externals` now checks for both library builds. The package holds only the interface for now. `createRtcSession` returns an empty object; `RtcSession`, `RtcMember`, `MemberMedia` and `TransportMetadata` are the contract Element Call's `CallViewModel` will be rebuilt on (see sdk-plan.md). The shared primitives are re-exported from `src` until the first implementation slice moves them. `sdk/dev` is the smallest consumer of the SDK: a plain page that logs in, joins a room and renders one tile per member, served by `pnpm dev:sdk` on port 3002. Playwright starts it as a third web server, and `playwright/sdk/smoke.spec.ts` has two browsers join one session. It fails on the status line with the SDK's own error until there is an implementation behind the interface. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2.8 KiB
Testing
Three layers; a user-facing feature needs all three. Unit proves the logic, Storybook proves the rendering, e2e proves the feature. Codecov gates 80% on the lines a PR touches.
Unit
- View model tests use
withTestScheduler+testScope()fromsrc/utils/test.tsand read as ASCII timelines. CopyLayoutSwitchViewModel.test.ts. - Component tests use Testing Library, queried by role and accessible name.
- Reuse the factories in
src/utils/test.ts—mockRemoteParticipant,mockMatrixRoom,mockLivekitRoom,MockRTCSession. Hand-rolled mocks drift. - Snapshots live in
__snapshots__/; update withpnpm test <Name> -u. - How often something redraws is testable: drive the frames and count commits, not render calls. An effect with no dependency array runs once per commit.
component/**/*.test.tsruns in the same jsdom project assrc.
Storybook
A deliverable, not documentation: pnpm test:storybook runs every story as a real
browser test in the same CI job as the unit suite. A UI change without a story is
incomplete. Only three stories exist so far, so copy CallFooter.stories.tsx.
- Drive the component from a snapshot via
useStaticViewModel, never internals. - One named story per state that matters — loading, error, empty, denied, mobile.
- Assert in a
playfunction withuserEvent/expectfromstorybook/test. - Mobile is
globals: { viewport: { value: "mobile2" } }, not a second component. - Expose interesting props through
argTypes.
.storybook/preview.tsx supplies TooltipProvider, src/index.css and English
translations. The browser is Playwright's, so a fresh clone needs
pnpm playwright install once.
End-to-end
playwright/*.spec.ts— standalone, on Chromium and Firefox.playwright/widget/— widget mode, where cross-context bugs surface.playwright/component/— the component in a host page, via the harness on port 3001 that Playwright starts as a second web server. Catches container-relative layout, styles escaping the root, two instances on a page, host-bridge reports.playwright/sdk/— the MatrixRTC SDK through its harness on port 3002, a page with none of Element Call on it. The smoke test is what the implementation is built against.playwright/mobile/— Pixel 7,mobileproject only.
Test what a user observes: the peer sees the change, it survives a reconnect, it is
right after a reload. Reuse playwright/spa-helpers.ts,
playwright/widget/test-helpers.ts, playwright/fixtures/.
pnpm test # unit + storybook
pnpm backend # Synapse + LiveKit, required for e2e
pnpm test:playwright # or :open
pnpm dev:component # component harness, port 3001
pnpm dev:sdk # SDK harness, port 3002