30 lines
1.3 KiB
TypeScript
30 lines
1.3 KiB
TypeScript
/** @jest-environment node */
|
|||
|
|
import { GET } from '@/app/(frontend)/release.json/route';
|
||
|
|
import { readFile } from 'node:fs/promises';
|
||
|
|
|
||
|
|
jest.mock('node:fs/promises', () => ({ readFile: jest.fn() }));
|
||
|
|
const realFetch = global.fetch;
|
||
|
|
const identity = { sha: 'a'.repeat(40), build_id: 'b'.repeat(32) };
|
||
|
|
beforeEach(() => {
|
||
|
|
jest.mocked(readFile).mockResolvedValue(JSON.stringify(identity));
|
||
|
|
global.fetch = jest.fn(async () => Response.json(identity));
|
||
|
|
});
|
||
|
|
afterEach(() => { global.fetch = realFetch; jest.resetAllMocks(); });
|
||
|
|
|
||
|
|
test('reports immutable file identity and backend identity without caching', async () => {
|
||
|
|
const response = await GET();
|
||
|
|
expect(response.status).toBe(200);
|
||
|
|
expect(response.headers.get('Cache-Control')).toBe('no-store');
|
||
|
|
expect(await response.json()).toEqual({ frontend: identity, backend: identity });
|
||
|
|
expect(fetch).toHaveBeenCalledWith(expect.stringMatching(/\/api\/release$/), expect.objectContaining({ cache: 'no-store', signal: expect.anything() }));
|
||
|
|
});
|
||
|
|
|
||
|
|
test('missing build metadata cannot pass the release gate', async () => {
|
||
|
|
jest.mocked(readFile).mockRejectedValueOnce(new Error('missing file'));
|
||
|
|
expect((await GET()).status).toBe(503);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('backend failure cannot pass the release gate', async () => {
|
||
|
|
jest.mocked(fetch).mockResolvedValueOnce(new Response('', { status: 503 }));
|
||
|
|
expect((await GET()).status).toBe(503);
|
||
|
|
});
|