← Public packages
@kody/openapi
Bind an OpenAPI spec and call selected operations with saved integration or secret names.
src/smoke-test.ts
95 lines · 2.5 KB · TypeScriptimport bind from './bind.ts'
import get from './get.ts'
import list from './list.ts'
import { parseOpenApiSpec } from './parse-spec-lib.ts'
import { resolveOpenApiSelection } from './selection.ts'
import unbind from './unbind.ts'
import { assertPinnedToApiBaseUrl, buildOperationUrl } from './url.ts'
const PING_SPEC = {
openapi: '3.0.3',
info: { title: 'Smoke API', version: '1.0.0' },
servers: [{ url: 'https://example.com' }],
paths: {
'/ping': {
get: {
operationId: 'ping',
summary: 'Ping',
responses: { '200': { description: 'ok' } },
},
},
'/items/{id}': {
delete: {
operationId: 'delete_item',
summary: 'Delete',
parameters: [
{
name: 'id',
in: 'path',
required: true,
schema: { type: 'string' },
},
],
responses: { '204': { description: 'gone' } },
},
},
},
}
/**
* Bind, list, get, and unbind an inline ping spec without calling a live API.
* Use after publish to confirm storage and selection still work.
*
* @returns ok plus the selected ping slug
*
* @example
* import smokeTest from 'kody:@<username>/openapi/smoke-test'
* const result = await smokeTest()
*/
export default async function smokeTest(): Promise<{
ok: boolean
operationSlugs: Array<string>
listed: number
url: string
}> {
const specText = JSON.stringify(PING_SPEC)
const parsed = parseOpenApiSpec(specText)
const resolved = resolveOpenApiSelection({
operations: parsed.operations,
selection: { operationIds: ['ping'] },
includeDestructive: false,
})
const bound = await bind({
name: 'smoke-ping',
specUrl: 'https://example.com/openapi.json',
apiBaseUrl: 'https://example.com',
auth: { kind: 'none' },
selection: { operationIds: ['ping'] },
specText,
})
const listed = await list()
const detail = await get({ name: 'smoke-ping' })
const url = buildOperationUrl({
apiBaseUrl: 'https://example.com',
path: '/ping',
params: {},
query: { n: 1 },
})
assertPinnedToApiBaseUrl(url, 'https://example.com')
await unbind({ name: 'smoke-ping' })
const after = await list()
const ok =
resolved.operations.length === 1 &&
bound.operationSlugs.includes('ping') &&
listed.bindings.some((binding) => binding.name === 'smoke-ping') &&
detail.operations[0]?.slug === 'ping' &&
url.toString() === 'https://example.com/ping?n=1' &&
after.bindings.every((binding) => binding.name !== 'smoke-ping')
return {
ok,
operationSlugs: bound.operationSlugs,
listed: listed.bindings.length,
url: url.toString(),
}
}