Files
Genarrative/apps/preview-deployer-web/src/api.test.ts
T
kdletters 41874ab391
Project CI / Repository checks (push) Successful in 1m16s
Project CI / Frontend tests (push) Successful in 3m1s
Project CI / Backend tests (push) Successful in 4m2s
Project CI / Native shell tests (push) Successful in 17m2s
新增内网容器预览部署控制面
新增分支与指定提交的预览部署 SPA 和 Jenkins 代理服务
新增多实例 Docker 预览流水线、端口租约、实时健康状态和卸载能力
新增 /build 内网路由、systemd 部署资产和运维文档
修正容器 Nginx 健康检查探针
2026-08-15 17:18:10 +08:00

115 lines
3.1 KiB
TypeScript

import { afterEach, expect, test, vi } from 'vitest';
import {
createDeployment,
createSession,
deleteSession,
getSession,
listDeployments,
uninstallDeployment,
} from './api';
afterEach(() => {
vi.unstubAllGlobals();
});
test('lists deployments from the same-origin control plane', async () => {
const fetchMock = vi.fn().mockResolvedValue(
new Response(
JSON.stringify({
deployments: [
{
id: 'preview-1',
branch: 'feature/demo',
status: 'running',
health: 'healthy',
createdAt: '2026-08-15T00:00:00Z',
updatedAt: '2026-08-15T00:01:00Z',
},
],
}),
{ status: 200, headers: { 'Content-Type': 'application/json' } },
),
);
vi.stubGlobal('fetch', fetchMock);
const deployments = await listDeployments();
expect(deployments).toHaveLength(1);
expect(fetchMock).toHaveBeenCalledWith(
'/api/preview-deployer/deployments',
expect.objectContaining({ credentials: 'same-origin' }),
);
});
test('uses an http-only session without browser token persistence', async () => {
const fetchMock = vi
.fn()
.mockImplementation((_url: string, init: RequestInit) =>
Promise.resolve(
new Response(
init.method === 'DELETE'
? null
: JSON.stringify({ authenticated: true }),
{ status: 200, headers: { 'Content-Type': 'application/json' } },
),
),
);
vi.stubGlobal('fetch', fetchMock);
expect(await getSession()).toEqual({ authenticated: true });
await createSession('team-access-token');
await deleteSession();
expect(fetchMock).toHaveBeenNthCalledWith(
2,
'/api/preview-deployer/session',
expect.objectContaining({
method: 'POST',
credentials: 'same-origin',
body: JSON.stringify({ accessToken: 'team-access-token' }),
}),
);
expect(fetchMock).toHaveBeenNthCalledWith(
3,
'/api/preview-deployer/session',
expect.objectContaining({ method: 'DELETE' }),
);
});
test('submits only branch and optional commit to fixed endpoints', async () => {
const buildResponse = () =>
new Response(
JSON.stringify({
id: 'preview-2',
branch: 'master',
status: 'queued',
health: 'pending',
createdAt: '2026-08-15T00:00:00Z',
updatedAt: '2026-08-15T00:00:00Z',
}),
{ status: 200, headers: { 'Content-Type': 'application/json' } },
);
const fetchMock = vi
.fn()
.mockImplementation(() => Promise.resolve(buildResponse()));
vi.stubGlobal('fetch', fetchMock);
await createDeployment({ branch: 'master', commitHash: 'aa5221abc' });
await uninstallDeployment('preview/2');
expect(fetchMock).toHaveBeenNthCalledWith(
1,
'/api/preview-deployer/deployments',
expect.objectContaining({
method: 'POST',
body: JSON.stringify({ branch: 'master', commitHash: 'aa5221abc' }),
}),
);
expect(fetchMock).toHaveBeenNthCalledWith(
2,
'/api/preview-deployer/deployments/preview%2F2/uninstall',
expect.objectContaining({ method: 'POST' }),
);
});