Testing extensions
Mount your extension in a real browser against a real server.
@conciv/extension-testkit boots your extension's real server half, builds and serves its real
client half, opens a real browser page, and hands you a typed API. No mocks, no stubs: the test
exercises the same contract the widget uses.
import {afterAll, beforeAll, expect, it} from 'vitest'
import {getExtensionTestApi, type ExtensionTestApi} from '@conciv/extension-testkit'
import deploy from '../conciv/extensions/deploy'
let api: ExtensionTestApi
beforeAll(async () => {
api = await getExtensionTestApi({
server: deploy,
clientEntry: 'conciv/extensions/deploy.tsx',
})
})
afterAll(() => api.dispose())
it('deploys to staging', async () => {
const result = await api.callTool('deploy_run', {env: 'staging'})
expect(result).toMatchObject({env: 'staging'})
})The test API
Prop
Type
Testing UI
page is a normal Playwright page. Assert through roles and text, and use waitFor for
visibility:
it('shows the deploy button in the composer', async () => {
await api.page.getByRole('button', {name: 'Deploy'}).waitFor()
})Two clients, one canvas
For collaborative features, secondClient() opens another page against the same session. What one
client writes must appear in the other:
it('syncs across clients', async () => {
const second = await api.secondClient()
await api.callTool('deploy_run', {env: 'staging'})
await second.page.getByText('staging.example.com').waitFor()
await second.close()
})The whiteboard's own integration tests are written on this harness. Browse them in
packages/extensions/whiteboard/test
for real-world patterns.