openpencil/tools/checks/package-quality/tests/runtime.test.ts
Danila Poyarkov 1aa10a4fed
build(tools): group tools by role and gate them like the rest of the repo (#791)
Tools live under tools/<role>/<domain> (checks, generate, release, ci, dev), every tool is a workspace named @open-pencil/<domain>-tools, a shared tools/tsconfig.json backs the new check:tools gate that fixed 55 latent type errors, test:tools runs through bun --filter, the placement check is its own checks/test-homes package, and every tool resolves the repository through resolveWorkspaceRoot. Bun, Node, and mdast types live in a tools-root workspace so they never reach the app program.
2026-09-30 05:00:31 +04:00

108 lines
3 KiB
TypeScript

import { expect, test } from 'bun:test'
import { setImmediate } from 'node:timers/promises'
import { verifyPublicImports } from '#package-quality/smoke/runtime'
import { measurePhase } from '#package-quality/timing'
import type { CommandRequest } from '@open-pencil/package-artifacts-tools'
test('public imports retain separate bounded Node and Bun invocations and the stdio exclusion', async () => {
const requests: CommandRequest[] = []
const release = Promise.withResolvers<undefined>()
const verification = verifyPublicImports(
[
{
name: '@fixture/library',
version: '1.0.0',
exports: { '.': './index.js', './extra': './extra.js' }
},
{
name: '@open-pencil/mcp',
version: '1.0.0',
exports: { '.': './index.js', './stdio': './stdio.js' }
}
],
'/fixture',
async (request) => {
requests.push(request)
await release.promise
return { stdout: '', stderr: '' }
}
)
try {
await setImmediate()
expect(requests).toHaveLength(4)
} finally {
release.resolve(undefined)
await verification
}
expect(requests).toHaveLength(6)
for (const runtime of ['node', 'bun']) {
const calls = requests.filter(({ command }) => command === runtime)
expect(calls).toHaveLength(3)
expect(calls.map(({ args }) => args?.at(-1))).toEqual([
'await import("@fixture/library")',
'await import("@fixture/library/extra")',
'await import("@open-pencil/mcp")'
])
for (const request of calls) {
expect(request.cwd).toBe('/fixture')
expect(request.timeoutMs).toBe(30_000)
expect(request.args).toContain('--eval')
if (runtime === 'node') expect(request.args).toContain('--input-type=module')
}
}
})
test('phase timing preserves successful results when reporting throws', async () => {
const result = { verified: true }
expect(
await measurePhase(
'imports',
async () => result,
() => {
throw new Error('report failed')
}
)
).toBe(result)
})
test('phase timing preserves the original exception when reporting throws', async () => {
const error = new Error('failed import')
await expect(
measurePhase(
'imports',
async () => {
throw error
},
() => {
throw new Error('report failed')
}
)
).rejects.toBe(error)
})
test('phase timing preserves results and exceptions', async () => {
const reports: string[] = []
const result = { verified: true }
expect(
await measurePhase(
'imports',
async () => result,
(line) => reports.push(line)
)
).toBe(result)
const error = new Error('failed import')
await expect(
measurePhase(
'imports',
async () => {
throw error
},
(line) => reports.push(line)
)
).rejects.toBe(error)
expect(reports[0]).toMatch(/^\[package-quality\] imports: completed in \d+\.\d{2}s$/)
expect(reports[1]).toMatch(/^\[package-quality\] imports: failed in \d+\.\d{2}s$/)
})