/** * 客户端托管冒烟测试(任务 A1.5)。 * * 验证「构建后由平台服务单端口托管」这条路:GET / 返回客户端页面,静态资源可取, * 同时 /v1 接口不受影响。 */ import assert from 'node:assert/strict'; import { execFileSync } from 'node:child_process'; import { test } from 'node:test'; import { fileURLToPath } from 'node:url'; const ROOT = fileURLToPath(new URL('..', import.meta.url)); const isWindows = process.platform === 'win32'; test('平台服务托管客户端产物,且 API 不受影响', async () => { execFileSync('pnpm', ['--filter', '@aps/client-app', 'run', 'build'], { cwd: ROOT, stdio: 'pipe', shell: isWindows }); const { startServer } = await import('../server/dist/index.js'); const server = await startServer({ host: '127.0.0.1', port: 0, version: 'test', databasePath: ':memory:' }); try { const page = await fetch(`${server.url}/`); assert.equal(page.status, 200, 'GET / 应返回客户端页面'); const html = await page.text(); assert.match(html, /
/, '返回的应是客户端 index.html'); const assetPath = html.match(/src="([^"]+\.js)"/)?.[1]; assert.ok(assetPath, 'index.html 里应有脚本引用'); const asset = await fetch(`${server.url}${assetPath}`); assert.equal(asset.status, 200, '静态资源应可取'); const assetBody = await asset.text(); assert.ok(assetBody.length > 1000, '脚本内容应非空'); const health = await (await fetch(`${server.url}/v1/health`)).json(); assert.equal(health.status, 'ok', 'API 不应被静态托管影响'); const spaFallback = await fetch(`${server.url}/some/deep/link`); assert.equal(spaFallback.status, 200, '非 API 路径应回退到 index.html'); const apiMissing = await fetch(`${server.url}/v1/nope`); assert.equal(apiMissing.status, 404, 'API 路径仍走协议错误处理'); } finally { await server.close(); } });