built-lib.e2e.ts 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import { existsSync } from 'node:fs'
  2. import { mkdtemp, readdir, rm, symlink, unlink } from 'node:fs/promises'
  3. import { tmpdir } from 'node:os'
  4. import { join } from 'node:path'
  5. import { fileURLToPath } from 'node:url'
  6. import { execa } from 'execa'
  7. import { describe, expect, it } from 'vitest'
  8. import { pnpmInvocation } from '../../../../scripts/pnpm-invocation.ts'
  9. const packageDirectory = fileURLToPath(new URL('..', import.meta.url))
  10. const built = [
  11. 'lib/index.js',
  12. 'node_modules/@deepseek-ai/schemastery/lib/index.mjs',
  13. ].every(file => existsSync(join(packageDirectory, file)))
  14. describe.skipIf(!built)('experimental Inspector built artifact', () => {
  15. it('packs its sibling Worker and evaluates the Host from the tarball through plain Node', { retry: 0 }, async (test) => {
  16. const root = await mkdtemp(join(tmpdir(), 'dsh-inspector-packed-'))
  17. const consumer = join(root, 'package')
  18. const dependencies = join(consumer, 'node_modules')
  19. let linked = false
  20. let pending: Promise<string> = Promise.resolve('')
  21. test.onTestFinished(async () => {
  22. try {
  23. await pending
  24. } finally {
  25. if (linked) await unlink(dependencies)
  26. await rm(root, { recursive: true, force: true })
  27. }
  28. })
  29. const run = (command: string, args: string[], cwd: string): Promise<string> => {
  30. pending = execa(command, args, {
  31. cwd,
  32. stdin: 'ignore',
  33. timeout: test.task.timeout,
  34. cancelSignal: test.signal,
  35. killSignal: 'SIGKILL',
  36. reject: false,
  37. }).then((result) => {
  38. expect(result.timedOut, `stderr:\n${result.stderr}`).toBe(false)
  39. expect(result.isCanceled, `stderr:\n${result.stderr}`).toBe(false)
  40. expect(result.signal, `stderr:\n${result.stderr}`).toBeUndefined()
  41. expect(result.exitCode, `stderr:\n${result.stderr}`).toBe(0)
  42. return result.stdout
  43. })
  44. return pending
  45. }
  46. const invocation = pnpmInvocation(['pack', '--pack-destination', root])
  47. await run(invocation.command, invocation.args, packageDirectory)
  48. const archives = (await readdir(root)).filter(name => name.endsWith('.tgz'))
  49. expect(archives).toHaveLength(1)
  50. await run('tar', ['-xzf', join(root, archives[0]!), '-C', root], root)
  51. expect(existsSync(join(consumer, 'lib/worker.js'))).toBe(true)
  52. await symlink(join(packageDirectory, 'node_modules'), dependencies, process.platform === 'win32' ? 'junction' : 'dir')
  53. linked = true
  54. const script = `
  55. const { startInspector } = await import('@deepseek-ai/dsh-experimental-inspector')
  56. const { default: WebSocket } = await import('ws')
  57. globalThis.__builtInspectorProbe = 42
  58. const inspector = await startInspector({ port: 0, captureFetch: false, startupTimeoutMs: ${String(test.task.timeout)} })
  59. const socket = new WebSocket(inspector.endpoint.webSocketDebuggerUrl)
  60. try {
  61. await new Promise((resolve, reject) => {
  62. socket.once('open', resolve)
  63. socket.once('error', reject)
  64. })
  65. const response = new Promise((resolve, reject) => {
  66. const timer = setTimeout(() => reject(new Error('CDP response timeout')), 5000)
  67. socket.on('message', data => {
  68. const message = JSON.parse(Buffer.from(data).toString('utf8'))
  69. if (message.id !== 1) return
  70. clearTimeout(timer)
  71. resolve(message)
  72. })
  73. })
  74. socket.send(JSON.stringify({
  75. id: 1,
  76. method: 'Runtime.evaluate',
  77. params: { expression: 'globalThis.__builtInspectorProbe', returnByValue: true },
  78. }))
  79. const message = await response
  80. console.log(JSON.stringify(message.result.result))
  81. } finally {
  82. socket.terminate()
  83. await inspector.close()
  84. }
  85. `
  86. const stdout = await run(process.execPath, ['--input-type=module', '-e', script], consumer)
  87. expect(JSON.parse(stdout.trim()) as unknown).toEqual({ type: 'number', value: 42, description: '42' })
  88. })
  89. })