test(core): cover the parseSchema contract
Assert add_connection advertises fullSchema as its inputSchema (never the refined schema) and applies an optional parseSchema in the handler: a refinement rejection surfaces as an error and skips registry.add, while a passing config persists. Locks the wire/parse split at the core level.
This commit is contained in:
1 parent
63bb2a5c99
commit
82d2392e31
1 file changed
+34
-2
@@ -98,7 +98,7 @@ describe('registerConnectionTools', () => {
|
|||||||
let registry: FakeRegistry
|
let registry: FakeRegistry
|
||||||
let manager: FakeManager
|
let manager: FakeManager
|
||||||
let handlers: Map<string, Handler>
|
let handlers: Map<string, Handler>
|
||||||
let configs: Map<string, { description?: string }>
|
let configs: Map<string, { description?: string; inputSchema?: unknown }>
|
||||||
|
|
||||||
const invoke = (name: string, args: Record<string, unknown> = {}): Promise<CallToolResult> => {
|
const invoke = (name: string, args: Record<string, unknown> = {}): Promise<CallToolResult> => {
|
||||||
const handler = handlers.get(name)
|
const handler = handlers.get(name)
|
||||||
@@ -113,7 +113,11 @@ describe('registerConnectionTools', () => {
|
|||||||
handlers = new Map()
|
handlers = new Map()
|
||||||
configs = new Map()
|
configs = new Map()
|
||||||
vi.spyOn(server, 'registerTool').mockImplementation(
|
vi.spyOn(server, 'registerTool').mockImplementation(
|
||||||
(name: string, config: { description?: string }, handler: unknown) => {
|
(
|
||||||
|
name: string,
|
||||||
|
config: { description?: string; inputSchema?: unknown },
|
||||||
|
handler: unknown
|
||||||
|
) => {
|
||||||
configs.set(name, config)
|
configs.set(name, config)
|
||||||
handlers.set(name, handler as Handler)
|
handlers.set(name, handler as Handler)
|
||||||
return {
|
return {
|
||||||
@@ -212,6 +216,34 @@ describe('registerConnectionTools', () => {
|
|||||||
expect(text(result)).toContain('already exists')
|
expect(text(result)).toContain('already exists')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('add_connection advertises fullSchema and applies parseSchema in the handler', async () => {
|
||||||
|
const parseSchema = schema.superRefine((c, ctx) => {
|
||||||
|
if (c.host === 'bad') {
|
||||||
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'bad host' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
registry.add.mockImplementation((config: TestConfig) => resolved(config))
|
||||||
|
register({ parseSchema })
|
||||||
|
|
||||||
|
// The advertised wire schema is always fullSchema, never the refined one
|
||||||
|
// (a ZodEffects has no .shape and would publish an empty inputSchema).
|
||||||
|
expect(configs.get('add_connection')?.inputSchema).toBe(schema)
|
||||||
|
|
||||||
|
const rejected = await invoke('add_connection', { name: 'x', type: 'mysql', host: 'bad' })
|
||||||
|
expect(rejected.isError).toBe(true)
|
||||||
|
expect(text(rejected)).toContain('bad host')
|
||||||
|
expect(registry.add).not.toHaveBeenCalled()
|
||||||
|
|
||||||
|
const accepted = await invoke('add_connection', { name: 'y', type: 'mysql', host: 'good' })
|
||||||
|
expect(accepted.isError).toBeFalsy()
|
||||||
|
expect(registry.add).toHaveBeenCalledWith({
|
||||||
|
name: 'y',
|
||||||
|
type: 'mysql',
|
||||||
|
host: 'good',
|
||||||
|
readonly: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('update_connection patches, invalidates the cache and returns the public view', async () => {
|
it('update_connection patches, invalidates the cache and returns the public view', async () => {
|
||||||
registry.update.mockReturnValue(
|
registry.update.mockReturnValue(
|
||||||
resolved({ name: 'c', type: 'postgres', host: 'new', readonly: false })
|
resolved({ name: 'c', type: 'postgres', host: 'new', readonly: false })
|
||||||
|
|||||||
Reference in new issue
Block a user