Skip to content

Commit d25fc03

Browse files
test: cover InterfacePlugin route behavior
Adds focused Vitest coverage for registration, request data-source capture, template rendering, and route matching.
1 parent bb22735 commit d25fc03

1 file changed

Lines changed: 120 additions & 0 deletions

File tree

plugins/interface/index.test.tsx

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { describe, expect, it, vi } from 'vitest'
2+
import type { StarbaseApp } from '../../src/handler'
3+
import type { DataSource } from '../../src/types'
4+
import { InterfacePlugin } from './index'
5+
6+
type MockContext = {
7+
get: ReturnType<typeof vi.fn>
8+
render?: ReturnType<typeof vi.fn>
9+
}
10+
11+
type SupportedRouteState = {
12+
_supportedRoutes: Array<{ path: string; page: string }>
13+
}
14+
15+
describe('InterfacePlugin', () => {
16+
it('initializes with public interface metadata and no routes', () => {
17+
const plugin = new InterfacePlugin()
18+
19+
expect(plugin.name).toBe('starbasedb:interface')
20+
expect(plugin.opts).toEqual({ requiresAuth: false })
21+
expect(plugin.pathPrefix).toBe('/unused-but-required')
22+
expect(plugin.supportedRoutes).toEqual([])
23+
expect(plugin.matchesRoute('/template')).toBe(false)
24+
})
25+
26+
it('registers middleware, the JSX renderer, and the template route', async () => {
27+
const plugin = new InterfacePlugin()
28+
const use = vi.fn()
29+
const get = vi.fn()
30+
const app = { use, get } as unknown as StarbaseApp
31+
32+
await plugin.register(app)
33+
34+
expect(use).toHaveBeenCalledTimes(2)
35+
expect(use.mock.calls[0]).toHaveLength(1)
36+
expect(use.mock.calls[0][0]).toEqual(expect.any(Function))
37+
expect(use.mock.calls[1][0]).toBe('*')
38+
expect(use.mock.calls[1][1]).toEqual(expect.any(Function))
39+
expect(get).toHaveBeenCalledTimes(1)
40+
expect(get).toHaveBeenCalledWith('/template', expect.any(Function))
41+
expect(plugin.supportedRoutes).toEqual(['/template'])
42+
})
43+
44+
it('captures the request data source before continuing middleware', async () => {
45+
const plugin = new InterfacePlugin()
46+
const use = vi.fn()
47+
const get = vi.fn()
48+
const app = { use, get } as unknown as StarbaseApp
49+
50+
await plugin.register(app)
51+
52+
const dataSource = { rpc: {} } as unknown as DataSource
53+
const next = vi.fn().mockResolvedValue(undefined)
54+
const context: MockContext = {
55+
get: vi.fn((key: string) =>
56+
key === 'dataSource' ? dataSource : undefined
57+
),
58+
}
59+
const middleware = use.mock.calls[0][0] as (
60+
c: MockContext,
61+
next: () => Promise<void>
62+
) => Promise<void>
63+
64+
await middleware(context, next)
65+
66+
expect(context.get).toHaveBeenCalledWith('dataSource')
67+
expect(plugin.dataSource).toBe(dataSource)
68+
expect(next).toHaveBeenCalledTimes(1)
69+
})
70+
71+
it('renders the template mount point from the registered route handler', async () => {
72+
const plugin = new InterfacePlugin()
73+
const use = vi.fn()
74+
const get = vi.fn()
75+
const app = { use, get } as unknown as StarbaseApp
76+
77+
await plugin.register(app)
78+
79+
const routeHandler = get.mock.calls[0][1] as (c: {
80+
render: (node: unknown) => unknown
81+
}) => unknown
82+
const render = vi.fn((node: unknown) => node)
83+
84+
const result = routeHandler({ render })
85+
86+
expect(render).toHaveBeenCalledTimes(1)
87+
expect(result).toBe(render.mock.results[0].value)
88+
89+
const node = render.mock.calls[0][0] as {
90+
toString(): string | Promise<string>
91+
}
92+
const html = await Promise.resolve(node.toString())
93+
94+
expect(html).toContain('id="root"')
95+
expect(html).toContain('data-client="template"')
96+
})
97+
98+
it('matches exact routes and rejects extra or different segments', async () => {
99+
const plugin = new InterfacePlugin()
100+
const app = { use: vi.fn(), get: vi.fn() } as unknown as StarbaseApp
101+
102+
await plugin.register(app)
103+
104+
expect(plugin.matchesRoute('/template')).toBe(true)
105+
expect(plugin.matchesRoute('/template/extra')).toBe(false)
106+
expect(plugin.matchesRoute('/other')).toBe(false)
107+
})
108+
109+
it('supports parameterized route matching through the public matcher', () => {
110+
const plugin = new InterfacePlugin()
111+
const state = plugin as unknown as SupportedRouteState
112+
113+
state._supportedRoutes.push({ path: '/items/:id', page: 'item' })
114+
115+
expect(plugin.matchesRoute('/items/123')).toBe(true)
116+
expect(plugin.matchesRoute('/items/abc')).toBe(true)
117+
expect(plugin.matchesRoute('/items')).toBe(false)
118+
expect(plugin.matchesRoute('/items/123/edit')).toBe(false)
119+
})
120+
})

0 commit comments

Comments
 (0)