mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 13:36:48 +00:00
724c88c201
A mechanical prettier --write over server/src, server/tests, server/scripts and shared/src with the workspaces' .prettierrc; nothing but layout and import order changes, and every file keeps the same set of imports. shared is formatted throughout and its format baseline is empty. The server baseline keeps the 35 files that Prettier would grow past their lint:size limit (they need a split first, which is not a formatting change), and the generated entity files stay as their generator writes them.
155 lines
5.5 KiB
TypeScript
155 lines
5.5 KiB
TypeScript
/**
|
|
* Settings integration tests — SET-001 through SET-008.
|
|
* Covers GET /api/settings, PUT /api/settings, POST /api/settings/bulk.
|
|
*/
|
|
import { buildApp } from '../../src/bootstrap';
|
|
import { db as testDb } from '../../src/db/database';
|
|
import { authCookie } from '../helpers/auth';
|
|
import { createUser } from '../helpers/factories';
|
|
import { resetTestDb, resetRateLimits } from '../helpers/test-db';
|
|
import type { INestApplication } from '@nestjs/common';
|
|
|
|
import type { Application } from 'express';
|
|
import request from 'supertest';
|
|
import { describe, it, expect, vi, beforeAll, beforeEach, afterAll } from 'vitest';
|
|
|
|
vi.mock('../../src/db/database', async () => {
|
|
const { createSnapshotTestDb, buildDbMock } = await import('../helpers/db-mock');
|
|
return buildDbMock(createSnapshotTestDb());
|
|
});
|
|
|
|
let nestApp: INestApplication;
|
|
let app: Application;
|
|
|
|
beforeAll(async () => {
|
|
nestApp = await buildApp();
|
|
app = nestApp.getHttpAdapter().getInstance();
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
resetTestDb(testDb);
|
|
await resetRateLimits(nestApp);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await nestApp.close();
|
|
testDb.close();
|
|
});
|
|
|
|
describe('Settings', () => {
|
|
it('SET-001: GET /api/settings returns empty object for new user', async () => {
|
|
const { user } = createUser(testDb);
|
|
const res = await request(app).get('/api/settings').set('Cookie', authCookie(user.id));
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.settings).toBeDefined();
|
|
expect(typeof res.body.settings).toBe('object');
|
|
// New user has no custom settings
|
|
expect(Object.keys(res.body.settings)).toHaveLength(0);
|
|
});
|
|
|
|
it('SET-002: PUT /api/settings sets a key/value pair', async () => {
|
|
const { user } = createUser(testDb);
|
|
const res = await request(app)
|
|
.put('/api/settings')
|
|
.set('Cookie', authCookie(user.id))
|
|
.send({ key: 'theme', value: 'dark' });
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.success).toBe(true);
|
|
expect(res.body.key).toBe('theme');
|
|
expect(res.body.value).toBe('dark');
|
|
});
|
|
|
|
it('SET-003: PUT /api/settings updates an existing key', async () => {
|
|
const { user } = createUser(testDb);
|
|
await request(app).put('/api/settings').set('Cookie', authCookie(user.id)).send({ key: 'theme', value: 'dark' });
|
|
|
|
const res = await request(app)
|
|
.put('/api/settings')
|
|
.set('Cookie', authCookie(user.id))
|
|
.send({ key: 'theme', value: 'light' });
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.value).toBe('light');
|
|
|
|
// Verify the GET reflects the updated value
|
|
const getRes = await request(app).get('/api/settings').set('Cookie', authCookie(user.id));
|
|
expect(getRes.body.settings.theme).toBe('light');
|
|
});
|
|
|
|
it('SET-004: POST /api/settings/bulk upserts multiple settings', async () => {
|
|
const { user } = createUser(testDb);
|
|
const res = await request(app)
|
|
.post('/api/settings/bulk')
|
|
.set('Cookie', authCookie(user.id))
|
|
.send({ settings: { theme: 'dark', language: 'en', compact_mode: 'true' } });
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.success).toBe(true);
|
|
expect(res.body.updated).toBeGreaterThanOrEqual(3);
|
|
});
|
|
|
|
it('SET-005: GET /api/settings reflects previously upserted values', async () => {
|
|
const { user } = createUser(testDb);
|
|
await request(app)
|
|
.post('/api/settings/bulk')
|
|
.set('Cookie', authCookie(user.id))
|
|
.send({ settings: { theme: 'dark', language: 'fr' } });
|
|
|
|
const res = await request(app).get('/api/settings').set('Cookie', authCookie(user.id));
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.settings.theme).toBe('dark');
|
|
expect(res.body.settings.language).toBe('fr');
|
|
});
|
|
|
|
it('SET-006: GET /api/settings without auth returns 401', async () => {
|
|
const res = await request(app).get('/api/settings');
|
|
expect(res.status).toBe(401);
|
|
});
|
|
|
|
it('SET-007: PUT /api/settings without key returns 400', async () => {
|
|
const { user } = createUser(testDb);
|
|
const res = await request(app).put('/api/settings').set('Cookie', authCookie(user.id)).send({ value: 'dark' });
|
|
expect(res.status).toBe(400);
|
|
expect(res.body.error).toBeDefined();
|
|
});
|
|
|
|
it('SET-008: PUT /api/settings with masked value is ignored (no-op)', async () => {
|
|
const { user } = createUser(testDb);
|
|
// First set a real value
|
|
await request(app)
|
|
.put('/api/settings')
|
|
.set('Cookie', authCookie(user.id))
|
|
.send({ key: 'webhook_url', value: 'https://example.com/hook' });
|
|
|
|
// Then try to "save" the masked placeholder
|
|
const res = await request(app)
|
|
.put('/api/settings')
|
|
.set('Cookie', authCookie(user.id))
|
|
.send({ key: 'webhook_url', value: '••••••••' });
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.unchanged).toBe(true);
|
|
});
|
|
|
|
it('SET-009: POST /api/settings/bulk without settings object returns 400', async () => {
|
|
const { user } = createUser(testDb);
|
|
const res = await request(app)
|
|
.post('/api/settings/bulk')
|
|
.set('Cookie', authCookie(user.id))
|
|
.send({ settings: null });
|
|
expect(res.status).toBe(400);
|
|
});
|
|
|
|
it('SET-010: settings are user-scoped (user A cannot see user B settings)', async () => {
|
|
const { user: userA } = createUser(testDb);
|
|
const { user: userB } = createUser(testDb);
|
|
|
|
await request(app)
|
|
.put('/api/settings')
|
|
.set('Cookie', authCookie(userA.id))
|
|
.send({ key: 'secret_setting', value: 'user_a_secret' });
|
|
|
|
const res = await request(app).get('/api/settings').set('Cookie', authCookie(userB.id));
|
|
expect(res.status).toBe(200);
|
|
expect(res.body.settings.secret_setting).toBeUndefined();
|
|
});
|
|
});
|