development-project.spec.ts 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs'
  2. import { tmpdir } from 'node:os'
  3. import { join } from 'node:path'
  4. import { afterEach, describe, expect, it } from 'vitest'
  5. import { prepareDevelopmentProject } from '../scripts/development-project.ts'
  6. import { DESKTOP_HOST_PROTOCOL_VERSION } from '../src/host-protocol.ts'
  7. import type { DesktopRelease } from '../src/release.ts'
  8. const roots: string[] = []
  9. function temporaryRoot(): string {
  10. const root = mkdtempSync(join(tmpdir(), 'dsh-desktop-development-test-'))
  11. roots.push(root)
  12. return root
  13. }
  14. function release(version = '1.2.3'): DesktopRelease {
  15. return {
  16. schemaVersion: 1,
  17. version,
  18. hostProtocolVersion: DESKTOP_HOST_PROTOCOL_VERSION,
  19. nodeVersion: '24.17.0',
  20. pnpmVersion: '11.7.0',
  21. }
  22. }
  23. afterEach(() => {
  24. for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true })
  25. })
  26. describe('desktop development project', () => {
  27. it('projects the built CLI package and its dependency graph without copying packages', () => {
  28. const root = temporaryRoot()
  29. const cli = join(root, 'apps', 'cli')
  30. const dependencies = join(root, 'workspace-dependencies')
  31. mkdirSync(join(cli, 'lib'), { recursive: true })
  32. mkdirSync(join(dependencies, '@scope'), { recursive: true })
  33. mkdirSync(join(dependencies, '@deepseek-ai', 'dsh'), { recursive: true })
  34. writeFileSync(join(cli, 'package.json'), '{"name":"@deepseek-ai/dsh","version":"1.2.3"}\n')
  35. writeFileSync(join(cli, 'lib', 'desktop-host.js'), '')
  36. writeFileSync(join(dependencies, '@deepseek-ai', 'dsh', 'package.json'), '{}\n')
  37. mkdirSync(join(dependencies, 'plain-dependency'))
  38. writeFileSync(join(dependencies, 'plain-dependency', 'package.json'), '{}\n')
  39. mkdirSync(join(dependencies, '@scope', 'dependency'))
  40. writeFileSync(join(dependencies, '@scope', 'dependency', 'package.json'), '{}\n')
  41. const project = prepareDevelopmentProject({
  42. projectDir: join(root, 'development'),
  43. cliDir: cli,
  44. dependencyDir: dependencies,
  45. release: release(),
  46. })
  47. expect(realpathSync(join(project, 'node_modules', '@deepseek-ai', 'dsh'))).toBe(realpathSync(cli))
  48. expect(realpathSync(join(project, 'node_modules', 'plain-dependency')))
  49. .toBe(realpathSync(join(dependencies, 'plain-dependency')))
  50. expect(realpathSync(join(project, 'node_modules', '@scope', 'dependency')))
  51. .toBe(realpathSync(join(dependencies, '@scope', 'dependency')))
  52. const manifest = JSON.parse(readFileSync(join(project, 'package.json'), 'utf8')) as {
  53. dependencies: Record<string, string>
  54. }
  55. expect(manifest.dependencies['@deepseek-ai/dsh']).toBe('1.2.3')
  56. })
  57. it('rejects a CLI package from another release', () => {
  58. const root = temporaryRoot()
  59. const cli = join(root, 'apps', 'cli')
  60. const dependencies = join(root, 'workspace-dependencies')
  61. mkdirSync(join(cli, 'lib'), { recursive: true })
  62. mkdirSync(dependencies, { recursive: true })
  63. writeFileSync(join(cli, 'package.json'), '{"name":"@deepseek-ai/dsh","version":"2.0.0"}\n')
  64. writeFileSync(join(cli, 'lib', 'desktop-host.js'), '')
  65. expect(() => prepareDevelopmentProject({
  66. projectDir: join(root, 'development'),
  67. cliDir: cli,
  68. dependencyDir: dependencies,
  69. release: release(),
  70. })).toThrow(/must be @deepseek-ai\/dsh@1\.2\.3/u)
  71. })
  72. })