mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
7266ad99ae
* fix(server): set oxc:false in vitest so the SWC transform survives the Vite 8 bump * fix(server): switch coverage to the istanbul provider (v8 under-reports branches on Vite 8 + Vitest 4) * test(nest): cover controller/service branches to clear the 80% coverage gate
159 lines
6.1 KiB
TypeScript
159 lines
6.1 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import type { Request, Response } from 'express';
|
|
|
|
// The Nest service is a thin pass-through to the legacy OIDC helpers plus a few
|
|
// adjacent service modules. Mock each one and assert the wrapper forwards every
|
|
// argument and returns whatever the legacy function hands back.
|
|
const { oidc } = vi.hoisted(() => ({
|
|
oidc: {
|
|
getOidcConfig: vi.fn(),
|
|
discover: vi.fn(),
|
|
createState: vi.fn(),
|
|
consumeState: vi.fn(),
|
|
exchangeCodeForToken: vi.fn(),
|
|
verifyIdToken: vi.fn(),
|
|
getUserInfo: vi.fn(),
|
|
findOrCreateUser: vi.fn(),
|
|
touchLastLogin: vi.fn(),
|
|
generateToken: vi.fn(),
|
|
createAuthCode: vi.fn(),
|
|
consumeAuthCode: vi.fn(),
|
|
frontendUrl: vi.fn(),
|
|
},
|
|
}));
|
|
vi.mock('../../../src/services/oidcService', () => oidc);
|
|
|
|
const { getAppUrl } = vi.hoisted(() => ({ getAppUrl: vi.fn() }));
|
|
vi.mock('../../../src/services/notifications', () => ({ getAppUrl }));
|
|
|
|
const { resolveAuthToggles } = vi.hoisted(() => ({ resolveAuthToggles: vi.fn() }));
|
|
vi.mock('../../../src/services/authService', () => ({ resolveAuthToggles }));
|
|
|
|
const { setAuthCookie } = vi.hoisted(() => ({ setAuthCookie: vi.fn() }));
|
|
vi.mock('../../../src/services/cookie', () => ({ setAuthCookie }));
|
|
|
|
import { OidcService } from '../../../src/nest/oidc/oidc.service';
|
|
|
|
let s: OidcService;
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
s = new OidcService();
|
|
});
|
|
|
|
describe('OidcService', () => {
|
|
it('oidcLoginEnabled reads the resolved auth toggle', () => {
|
|
resolveAuthToggles.mockReturnValue({ oidc_login: true });
|
|
expect(s.oidcLoginEnabled()).toBe(true);
|
|
resolveAuthToggles.mockReturnValue({ oidc_login: false });
|
|
expect(s.oidcLoginEnabled()).toBe(false);
|
|
});
|
|
|
|
it('getOidcConfig delegates to the legacy helper', () => {
|
|
const cfg = { issuer: 'https://idp' };
|
|
oidc.getOidcConfig.mockReturnValue(cfg);
|
|
expect(s.getOidcConfig()).toBe(cfg);
|
|
});
|
|
|
|
it('getAppUrl delegates to notifications.getAppUrl', () => {
|
|
getAppUrl.mockReturnValue('https://app');
|
|
expect(s.getAppUrl()).toBe('https://app');
|
|
});
|
|
|
|
it('discover forwards the issuer and discovery url', () => {
|
|
const doc = { authorization_endpoint: 'https://idp/auth' };
|
|
oidc.discover.mockReturnValue(doc);
|
|
expect(s.discover('https://idp', 'https://idp/.well-known')).toBe(doc);
|
|
expect(oidc.discover).toHaveBeenCalledWith('https://idp', 'https://idp/.well-known');
|
|
});
|
|
|
|
it('discover works without a discovery url', () => {
|
|
oidc.discover.mockReturnValue('doc');
|
|
expect(s.discover('https://idp')).toBe('doc');
|
|
expect(oidc.discover).toHaveBeenCalledWith('https://idp', undefined);
|
|
});
|
|
|
|
it('createState forwards the redirect uri and invite token', () => {
|
|
const st = { state: 'st', codeChallenge: 'cc' };
|
|
oidc.createState.mockReturnValue(st);
|
|
expect(s.createState('https://app/cb', 'inv')).toBe(st);
|
|
expect(oidc.createState).toHaveBeenCalledWith('https://app/cb', 'inv');
|
|
});
|
|
|
|
it('createState works without an invite token', () => {
|
|
oidc.createState.mockReturnValue({ state: 'st', codeChallenge: 'cc' });
|
|
s.createState('https://app/cb');
|
|
expect(oidc.createState).toHaveBeenCalledWith('https://app/cb', undefined);
|
|
});
|
|
|
|
it('consumeState forwards the state', () => {
|
|
oidc.consumeState.mockReturnValue({ redirectUri: 'r', codeVerifier: 'v' });
|
|
expect(s.consumeState('st')).toEqual({ redirectUri: 'r', codeVerifier: 'v' });
|
|
expect(oidc.consumeState).toHaveBeenCalledWith('st');
|
|
});
|
|
|
|
it('exchangeCodeForToken spreads all arguments through', () => {
|
|
oidc.exchangeCodeForToken.mockReturnValue({ _ok: true });
|
|
const doc = { token_endpoint: 'https://idp/token' } as never;
|
|
expect(s.exchangeCodeForToken(doc, 'code', 'redir', 'cid', 'secret', 'verifier')).toEqual({ _ok: true });
|
|
expect(oidc.exchangeCodeForToken).toHaveBeenCalledWith(doc, 'code', 'redir', 'cid', 'secret', 'verifier');
|
|
});
|
|
|
|
it('verifyIdToken spreads all arguments through', () => {
|
|
oidc.verifyIdToken.mockReturnValue({ ok: true });
|
|
const doc = { issuer: 'https://idp' } as never;
|
|
expect(s.verifyIdToken('id_token', doc, 'cid', 'https://idp')).toEqual({ ok: true });
|
|
expect(oidc.verifyIdToken).toHaveBeenCalledWith('id_token', doc, 'cid', 'https://idp');
|
|
});
|
|
|
|
it('getUserInfo forwards the endpoint and access token', () => {
|
|
oidc.getUserInfo.mockReturnValue({ email: 'a@b.c' });
|
|
expect(s.getUserInfo('https://idp/ui', 'at')).toEqual({ email: 'a@b.c' });
|
|
expect(oidc.getUserInfo).toHaveBeenCalledWith('https://idp/ui', 'at');
|
|
});
|
|
|
|
it('findOrCreateUser spreads all arguments through', () => {
|
|
const result = { user: { id: 1 } };
|
|
oidc.findOrCreateUser.mockReturnValue(result);
|
|
const info = { email: 'a@b.c' } as never;
|
|
const cfg = { issuer: 'https://idp' } as never;
|
|
expect(s.findOrCreateUser(info, cfg, 'inv')).toBe(result);
|
|
expect(oidc.findOrCreateUser).toHaveBeenCalledWith(info, cfg, 'inv');
|
|
});
|
|
|
|
it('touchLastLogin forwards the user id', () => {
|
|
s.touchLastLogin(42);
|
|
expect(oidc.touchLastLogin).toHaveBeenCalledWith(42);
|
|
});
|
|
|
|
it('generateToken forwards the user', () => {
|
|
oidc.generateToken.mockReturnValue('jwt');
|
|
expect(s.generateToken({ id: 7 })).toBe('jwt');
|
|
expect(oidc.generateToken).toHaveBeenCalledWith({ id: 7 });
|
|
});
|
|
|
|
it('createAuthCode forwards the token', () => {
|
|
oidc.createAuthCode.mockReturnValue('ac');
|
|
expect(s.createAuthCode('jwt')).toBe('ac');
|
|
expect(oidc.createAuthCode).toHaveBeenCalledWith('jwt');
|
|
});
|
|
|
|
it('consumeAuthCode forwards the code', () => {
|
|
oidc.consumeAuthCode.mockReturnValue({ token: 'jwt' });
|
|
expect(s.consumeAuthCode('ac')).toEqual({ token: 'jwt' });
|
|
expect(oidc.consumeAuthCode).toHaveBeenCalledWith('ac');
|
|
});
|
|
|
|
it('frontendUrl forwards the path', () => {
|
|
oidc.frontendUrl.mockReturnValue('https://app/login');
|
|
expect(s.frontendUrl('/login')).toBe('https://app/login');
|
|
expect(oidc.frontendUrl).toHaveBeenCalledWith('/login');
|
|
});
|
|
|
|
it('setAuthCookie forwards res, token and req to the cookie helper', () => {
|
|
const res = {} as Response;
|
|
const req = {} as Request;
|
|
s.setAuthCookie(res, 'jwt', req);
|
|
expect(setAuthCookie).toHaveBeenCalledWith(res, 'jwt', req);
|
|
});
|
|
});
|