/** * Tests routes /api/v1/views/* — Patch 031 JWT manager integration. * * Valide : * - GET /api/v1/views/table/:slug fonctionne quand user JWT configure (mock manager) * - GET /api/v1/views/table/:slug renvoie 500 clair quand creds absentes * (le repo remonte BASEROW_USER_AUTH_NOT_CONFIGURED qui devient 500 via error-handler) * - Slug resolution fonctionne avec le JWT manager active */ import { afterEach, describe, expect, it } from 'vitest'; import { View } from '../../src/domain/view.js'; import type { BaserowJwtManager } from '../../src/lib/baserow-jwt-manager.js'; import { BaserowAuthError, BaserowJwtManagerDisabled } from '../../src/lib/baserow-jwt-manager.js'; import type { RepoSet } from '../../src/lib/container.js'; import { errors } from '../../src/lib/errors.js'; import type { ViewDataResult } from '../../src/repos/baserow-views-repo.js'; import { ADMIN_TOKEN, READ_TOKEN, buildTestApp, installTestContainer, resetTestContainer, } from '../helpers/test-app.js'; // --------------------------------------------------------------------------- // Stub JWT managers // --------------------------------------------------------------------------- /** JWT manager enabled — returns a fixed fake JWT. */ class StubJwtManagerEnabled implements BaserowJwtManager { public callCount = 0; isEnabled(): boolean { return true; } async getToken(): Promise { this.callCount++; return 'fake.jwt.token'; } } /** JWT manager that simulates unconfigured creds (503). */ class StubJwtManagerUnconfigured implements BaserowJwtManager { isEnabled(): boolean { return false; } async getToken(): Promise { throw new BaserowAuthError( 'BASEROW_USER_AUTH_NOT_CONFIGURED: set BASEROW_USER_EMAIL and BASEROW_USER_PASSWORD', 503, ); } } // --------------------------------------------------------------------------- // Fake repos // --------------------------------------------------------------------------- class FakeTablesRepo { async list(_databaseId: number) { return []; } async get(_tableId: number) { throw errors.notFound('Table', _tableId); } } class FakeFieldsRepo { async list(_tableId: number) { return []; } } class FakeRowsRepo { async list() { return { items: [], meta: { page: 1, per_page: 50, total: 0, total_pages: 1 } }; } async get(_tableId: number, rowId: number) { throw errors.notFound('Row', rowId); } } class FakeViewsRepoJwt { public listByTableCalls: number[] = []; public jwtManager: BaserowJwtManager | undefined; private views: View[]; constructor(views: View[] = [], jwtManager?: BaserowJwtManager) { this.views = views; this.jwtManager = jwtManager; } async list(tableId: number): Promise { return this.listByTable(tableId); } async listByTable(tableId: number): Promise { this.listByTableCalls.push(tableId); // Simulate the repo's behavior: call jwtManager.getToken() if configured if (this.jwtManager) { await this.jwtManager.getToken(); // throws if not configured } return this.views; } async runGrid(_viewId: number, _tableId: number) { return { items: [], meta: { page: 1, per_page: 50, total: 0, total_pages: 1 } }; } async getViewData(_viewId: number, _tableId: number): Promise { return { items: [], meta: { page: 1, per_page: 100, total: 0, total_pages: 1 }, viewType: 'grid' }; } } function buildFakeRepos(viewsRepo: FakeViewsRepoJwt): RepoSet { return { tables: new FakeTablesRepo() as unknown as RepoSet['tables'], fields: new FakeFieldsRepo() as unknown as RepoSet['fields'], views: viewsRepo as unknown as RepoSet['views'], rows: new FakeRowsRepo() as unknown as RepoSet['rows'], }; } afterEach(resetTestContainer); // --------------------------------------------------------------------------- // Tests — JWT manager enabled // --------------------------------------------------------------------------- describe('GET /api/v1/views/table/:tableId — JWT manager enabled', () => { it('200 liste vide quand JWT manager configure et retourne token', async () => { const jwtMgr = new StubJwtManagerEnabled(); const viewsRepo = new FakeViewsRepoJwt([], jwtMgr); const repos = buildFakeRepos(viewsRepo); const container = installTestContainer({ repos, baserowJwt: jwtMgr }); const app = buildTestApp(container); const res = await app.request('/api/v1/views/table/5', { headers: { Authorization: `Bearer ${READ_TOKEN}` }, }); expect(res.status).toBe(200); const body = (await res.json()) as { data: unknown[]; total: number }; expect(body.data).toHaveLength(0); expect(body.total).toBe(0); }); it('200 liste avec vues quand JWT configure', async () => { const jwtMgr = new StubJwtManagerEnabled(); const views = [ new View({ id: 1, name: 'Tous', type: 'grid', tableId: 5, order: 0 }), new View({ id: 2, name: 'Actifs', type: 'grid', tableId: 5, order: 1 }), ]; const viewsRepo = new FakeViewsRepoJwt(views, jwtMgr); const repos = buildFakeRepos(viewsRepo); const container = installTestContainer({ repos, baserowJwt: jwtMgr }); const app = buildTestApp(container); const res = await app.request('/api/v1/views/table/5', { headers: { Authorization: `Bearer ${ADMIN_TOKEN}` }, }); expect(res.status).toBe(200); const body = (await res.json()) as { data: Array<{ id: number }>; total: number }; expect(body.total).toBe(2); expect(body.data[0]?.id).toBe(1); }); it('JWT manager getToken() is called when listing views', async () => { const jwtMgr = new StubJwtManagerEnabled(); const viewsRepo = new FakeViewsRepoJwt([], jwtMgr); const repos = buildFakeRepos(viewsRepo); const container = installTestContainer({ repos, baserowJwt: jwtMgr }); const app = buildTestApp(container); await app.request('/api/v1/views/table/42', { headers: { Authorization: `Bearer ${READ_TOKEN}` }, }); expect(jwtMgr.callCount).toBeGreaterThan(0); expect(viewsRepo.listByTableCalls).toContain(42); }); }); // --------------------------------------------------------------------------- // Tests — JWT manager not configured // --------------------------------------------------------------------------- describe('GET /api/v1/views/table/:tableId — JWT manager not configured', () => { it('500 quand creds JWT absentes', async () => { const jwtMgr = new StubJwtManagerUnconfigured(); const viewsRepo = new FakeViewsRepoJwt([], jwtMgr); const repos = buildFakeRepos(viewsRepo); const container = installTestContainer({ repos, baserowJwt: jwtMgr }); const app = buildTestApp(container); const res = await app.request('/api/v1/views/table/5', { headers: { Authorization: `Bearer ${READ_TOKEN}` }, }); // The repo transforms 503 BaserowAuthError into an INTERNAL error (500) expect(res.status).toBe(500); }); it('disabled manager getToken() rejects with BaserowAuthError 503', async () => { const mgr = new BaserowJwtManagerDisabled(); await expect(mgr.getToken()).rejects.toMatchObject({ statusCode: 503 }); }); });