Testing
The SDK ships a mock context so your tests exercise the exact shape production uses.
createMockPlatformContext
Defaults model a realistic single-building operator — a mall ops manager viewing their building in English, light theme. Override only what your test cares about:
import { createMockPlatformContext } from '@tv/extension-sdk/testing';
import { PlatformProvider } from '@tv/extension-sdk/react';
import { render, screen } from '@testing-library/react';
import Shell from './Shell';
test('renders the building name', () => {
const ctx = createMockPlatformContext({
building: {
id: 'b1',
slug: 'demo-mall',
name: 'Demo Mall',
type: 'mall',
timezone: 'Europe/Moscow',
},
});
render(
<PlatformProvider value={ctx}>
<Shell />
</PlatformProvider>,
);
expect(screen.getByText(/Demo Mall/)).toBeInTheDocument();
});Overrides are shallow
createMockPlatformContext(overrides) takes a Partial<PlatformContext> — shallow, not deep. Whatever top-level key you override, you supply whole. A building override needs every field of PlatformBuilding (id, slug, name, type, timezone); a partial one is a type error.
To tweak a single field, spread the default instead of hand-writing it:
const base = createMockPlatformContext();
const ctx = createMockPlatformContext({
building: { ...base.building!, name: 'Demo Mall' },
user: { ...base.user, roles: ['manager'] },
});Why use the mock vs. rolling your own
If you hand-build a PlatformContext in your tests, you can drift from the real shape — and your tests pass while production breaks. createMockPlatformContext() is built from the same types the platform injects, so:
- Type changes to the context surface break your tests at compile time (good — you find out early).
- The
apiclient mock has the same method signatures as the real one.
Stubbing API responses
Same rule: api is a top-level key, so an override supplies the whole client. Spread the default and replace the verbs you exercise:
const base = createMockPlatformContext();
const ctx = createMockPlatformContext({
api: {
...base.api,
get: vi.fn().mockResolvedValue([{ id: 's1', name: 'Unit 3B' }]),
},
});The default eventBus is a no-op (subscribe returns an empty unsubscribe, publish resolves) — override it the same way when you need to assert on published events.
The self-diagnosis checklist
Before opening a support ticket, run through this — most issues resolve here:
- Which SDK version?
cat node_modules/@tv/extension-sdk/package.json | jq .version - Manifest valid?
npx @tv/extension-sdk validate module-manifest.json - Federation expose right?
npx @tv/extension-sdk check-exposes module-manifest.json - Subscriptions fit the producers?
npx @tv/extension-sdk check-pact module-manifest.json - Using an
@experimentalsymbol? Grep your imports — those can change between releases. - Heartbeat reporting? Check your module's dot in the Building OS sidebar.
- Tests use
createMockPlatformContext()?
If all seven are clean and it still breaks, it's on the platform — file a ticket with the checklist output.