support.ts 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. // Shared plumbing for the web smoke tests (dist location, free port, failure shots).
  2. import { existsSync, mkdirSync } from 'node:fs'
  3. import { createServer } from 'node:net'
  4. import { fileURLToPath } from 'node:url'
  5. import type { Page } from 'playwright'
  6. /** The built page under test; `pnpm run test:web` rebuilds it before running. */
  7. export const DIST_INDEX = fileURLToPath(new URL('../dist/index.html', import.meta.url))
  8. export const REPO_ROOT = fileURLToPath(new URL('../../..', import.meta.url))
  9. /** Fail loud on a stale checkout instead of testing yesterday's bundle. */
  10. export function requireDist(): void {
  11. if (!existsSync(DIST_INDEX)) {
  12. throw new Error('web app dist not built — run `pnpm --filter @deepseek-ai/dsh-frontend build` (pnpm run test:web does this first)')
  13. }
  14. }
  15. /**
  16. * OS-assigned free port, released before use. startWebServer echoes
  17. * options.port instead of the bound one, so passing 0 directly is unusable.
  18. */
  19. export function probeFreePort(): Promise<number> {
  20. return new Promise((resolvePort, reject) => {
  21. const probe = createServer()
  22. probe.once('error', reject)
  23. probe.listen(0, '127.0.0.1', () => {
  24. const address = probe.address()
  25. if (address === null || typeof address === 'string') {
  26. probe.close(() => { reject(new Error('port probe returned no address')) })
  27. return
  28. }
  29. probe.close(() => { resolvePort(address.port) })
  30. })
  31. })
  32. }
  33. /** Failure evidence goes to the gitignored .artifacts/ (repo convention). */
  34. export async function saveFailureShot(page: Page, name: string): Promise<void> {
  35. const dir = fileURLToPath(new URL('../../../.artifacts', import.meta.url))
  36. mkdirSync(dir, { recursive: true })
  37. try {
  38. await page.screenshot({ path: `${dir}/${name}.png`, fullPage: true })
  39. } catch {
  40. // Best-effort evidence: a dead page/browser at failure time must not mask the real assertion error.
  41. }
  42. }