Close the two "[test coverage]" review gaps on PR #116 (mobile bootstrap): - auth.controller.spec.ts: unit-test AuthController.login() returnToken branches via direct instantiation. returnToken:true returns exactly { authToken } alongside the httpOnly cookie; omitted/explicit-false return strictly undefined (the token must never leak into the response body for web clients) while the cookie is still set. - environment.service.spec.ts: table-driven tests for getCorsAllowedOrigins() (split/trim/filter of CORS_ALLOWED_ORIGINS) and isSwaggerEnabled() (case-insensitive SWAGGER_ENABLED === 'true'), the two parsers feeding the CORS allowlist and Swagger exposure trust boundaries. Tests only; no production code changed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
83 lines
2.7 KiB
TypeScript
83 lines
2.7 KiB
TypeScript
import { EnvironmentService } from './environment.service';
|
|
|
|
// Direct instantiation with a stub ConfigService, mirroring the rest of these
|
|
// unit specs.
|
|
describe('EnvironmentService', () => {
|
|
let service: EnvironmentService;
|
|
|
|
beforeEach(() => {
|
|
service = new EnvironmentService(
|
|
{} as any, // configService
|
|
);
|
|
});
|
|
|
|
it('should be defined', () => {
|
|
expect(service).toBeDefined();
|
|
});
|
|
});
|
|
|
|
// Fake ConfigService that honors the (key, default) signature: returns the
|
|
// mapped value when the key is present, otherwise the provided default. This
|
|
// matters because getCorsAllowedOrigins/isSwaggerEnabled call .split/.toLowerCase
|
|
// on the result, so an unset key MUST fall back to the default string.
|
|
const makeConfig = (map: Record<string, string>) =>
|
|
new EnvironmentService({
|
|
get: (key: string, def?: string) => (key in map ? map[key] : def),
|
|
} as any);
|
|
|
|
// These two parsers feed trust boundaries (CORS allowlist + Swagger exposure),
|
|
// so a parsing bug has a direct security effect. Style mirrors
|
|
// trust-proxy.util.spec.ts.
|
|
describe('EnvironmentService.getCorsAllowedOrigins', () => {
|
|
it.each([
|
|
['key unset -> empty list', {}, []],
|
|
['empty string -> empty list', { CORS_ALLOWED_ORIGINS: '' }, []],
|
|
[
|
|
'single origin',
|
|
{ CORS_ALLOWED_ORIGINS: 'https://app.example' },
|
|
['https://app.example'],
|
|
],
|
|
[
|
|
'multiple origins',
|
|
{ CORS_ALLOWED_ORIGINS: 'https://a.example,https://b.example' },
|
|
['https://a.example', 'https://b.example'],
|
|
],
|
|
[
|
|
'trims surrounding and inner spaces',
|
|
{ CORS_ALLOWED_ORIGINS: ' https://a.example , https://b.example ' },
|
|
['https://a.example', 'https://b.example'],
|
|
],
|
|
[
|
|
'double/trailing commas produce no empty strings',
|
|
{ CORS_ALLOWED_ORIGINS: 'a,, ,b' },
|
|
['a', 'b'],
|
|
],
|
|
[
|
|
'leading/trailing commas with spaces',
|
|
{ CORS_ALLOWED_ORIGINS: ' , a , , b ' },
|
|
['a', 'b'],
|
|
],
|
|
])('%s', (_label, map, expected) => {
|
|
expect(makeConfig(map as Record<string, string>).getCorsAllowedOrigins()).toEqual(
|
|
expected,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('EnvironmentService.isSwaggerEnabled', () => {
|
|
it.each([
|
|
["'true' -> true", { SWAGGER_ENABLED: 'true' }, true],
|
|
["'TRUE' -> true", { SWAGGER_ENABLED: 'TRUE' }, true],
|
|
["'True' -> true", { SWAGGER_ENABLED: 'True' }, true],
|
|
['key unset -> false', {}, false],
|
|
["'false' -> false", { SWAGGER_ENABLED: 'false' }, false],
|
|
["empty string -> false", { SWAGGER_ENABLED: '' }, false],
|
|
["'yes' -> false", { SWAGGER_ENABLED: 'yes' }, false],
|
|
["'1' -> false", { SWAGGER_ENABLED: '1' }, false],
|
|
])('%s', (_label, map, expected) => {
|
|
expect(makeConfig(map as Record<string, string>).isSwaggerEnabled()).toBe(
|
|
expected,
|
|
);
|
|
});
|
|
});
|