Files
classroomio/apps/dashboard/src/lib/utils/proxy-api-request.test.ts
T

135 lines
4.7 KiB
TypeScript
Raw Normal View History

import { buildProxiedApiResponse, proxyRequestToApi, shouldForwardToApi } from './proxy-api-request';
describe('shouldForwardToApi', () => {
it('forwards /proxy and /api/auth paths', () => {
expect(shouldForwardToApi('/proxy')).toBe(true);
expect(shouldForwardToApi('/proxy/account')).toBe(true);
expect(shouldForwardToApi('/api/auth')).toBe(true);
expect(shouldForwardToApi('/api/auth/get-session')).toBe(true);
});
it('does not forward unrelated paths', () => {
expect(shouldForwardToApi('/login')).toBe(false);
expect(shouldForwardToApi('/api/csp-report')).toBe(false);
});
});
describe('buildProxiedApiResponse', () => {
it('strips content-encoding and content-length so the browser does not re-decode', async () => {
const upstream = new Response('{"user":null}', {
status: 200,
headers: {
'content-type': 'application/json',
'content-encoding': 'gzip',
'content-length': '13',
'transfer-encoding': 'chunked'
}
});
const proxied = buildProxiedApiResponse(upstream);
expect(proxied.status).toBe(200);
expect(proxied.headers.get('content-type')).toBe('application/json');
expect(proxied.headers.get('content-encoding')).toBeNull();
expect(proxied.headers.get('content-length')).toBeNull();
expect(proxied.headers.get('transfer-encoding')).toBeNull();
expect(await proxied.text()).toBe('{"user":null}');
});
it('preserves multiple Set-Cookie headers without collapsing Expires commas', async () => {
const upstreamHeaders = new Headers({
'content-type': 'application/json',
'content-encoding': 'gzip'
});
upstreamHeaders.append(
'set-cookie',
'better-auth.session_token=abc; Path=/; HttpOnly; Expires=Wed, 21 Oct 2026 07:28:00 GMT'
);
upstreamHeaders.append(
'set-cookie',
'better-auth.csrf_token=xyz; Path=/; HttpOnly; Expires=Thu, 22 Oct 2026 07:28:00 GMT'
);
const proxied = buildProxiedApiResponse(
new Response('{"ok":true}', {
status: 200,
headers: upstreamHeaders
})
);
expect(proxied.headers.getSetCookie()).toEqual([
'better-auth.session_token=abc; Path=/; HttpOnly; Expires=Wed, 21 Oct 2026 07:28:00 GMT',
'better-auth.csrf_token=xyz; Path=/; HttpOnly; Expires=Thu, 22 Oct 2026 07:28:00 GMT'
]);
expect(proxied.headers.get('content-encoding')).toBeNull();
expect(await proxied.text()).toBe('{"ok":true}');
});
});
describe('proxyRequestToApi', () => {
const originalPrivateServerUrl = process.env.PRIVATE_SERVER_URL;
const originalFetch = global.fetch;
afterEach(() => {
if (originalPrivateServerUrl === undefined) {
delete process.env.PRIVATE_SERVER_URL;
} else {
process.env.PRIVATE_SERVER_URL = originalPrivateServerUrl;
}
global.fetch = originalFetch;
jest.restoreAllMocks();
});
it('returns 502 when PRIVATE_SERVER_URL is missing', async () => {
delete process.env.PRIVATE_SERVER_URL;
const response = await proxyRequestToApi(new Request('https://app.example/api/auth/get-session'));
expect(response.status).toBe(502);
expect(await response.text()).toBe('API upstream not configured');
});
it('requests identity encoding and returns a stripped response', async () => {
process.env.PRIVATE_SERVER_URL = 'http://api.internal:3081';
const fetchMock = jest.fn().mockResolvedValue(
new Response('{"session":null}', {
status: 200,
headers: {
'content-type': 'application/json',
'content-encoding': 'gzip',
'content-length': '16'
}
})
);
global.fetch = fetchMock as typeof fetch;
const response = await proxyRequestToApi(
new Request('https://dashboard.example/api/auth/get-session', {
headers: {
accept: 'application/json',
'accept-encoding': 'gzip, deflate, br',
cookie: 'better-auth.session_token=test'
}
})
);
expect(fetchMock).toHaveBeenCalledTimes(1);
const [upstreamUrl, init] = fetchMock.mock.calls[0] as [URL, RequestInit];
expect(String(upstreamUrl)).toBe('http://api.internal:3081/api/auth/get-session');
expect(init.method).toBe('GET');
const upstreamHeaders = new Headers(init.headers);
expect(upstreamHeaders.get('accept-encoding')).toBe('identity');
expect(upstreamHeaders.get('host')).toBe('api.internal:3081');
expect(upstreamHeaders.get('x-forwarded-host')).toBe('dashboard.example');
expect(upstreamHeaders.get('cookie')).toBe('better-auth.session_token=test');
expect(response.status).toBe(200);
expect(response.headers.get('content-encoding')).toBeNull();
expect(response.headers.get('content-length')).toBeNull();
expect(await response.text()).toBe('{"session":null}');
});
});