File size: 3,049 Bytes
46252cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import { NotImplementedException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { ConfigService } from '@nestjs/config';
import { SettingsController } from './settings.controller';
import { REQUIRED_ROLE_KEY } from '../auth/decorators/auth.decorators';
import { ApiKeyRole } from '../auth/entities/api-key.entity';

// ConfigService stub: return the supplied default for every key.
const configStub = {
  get: <T>(_key: string, def?: T): T | undefined => def,
} as unknown as ConfigService;

describe('SettingsController', () => {
  it('GET /settings returns the environment-derived settings', () => {
    const settings = new SettingsController(configStub).get();
    expect(settings).toHaveProperty('general');
    expect(settings.general).not.toHaveProperty('sessionTimeout');
    expect(settings).toHaveProperty('api');
    expect(settings).toHaveProperty('notifications');
  });

  it('reports enableDocs from the real ENABLE_SWAGGER gate, not a hardcoded true', () => {
    const prev = process.env.ENABLE_SWAGGER;
    try {
      process.env.ENABLE_SWAGGER = 'false';
      expect(new SettingsController(configStub).get().api.enableDocs).toBe(false);
      process.env.ENABLE_SWAGGER = 'true';
      expect(new SettingsController(configStub).get().api.enableDocs).toBe(true);
    } finally {
      if (prev === undefined) delete process.env.ENABLE_SWAGGER;
      else process.env.ENABLE_SWAGGER = prev;
    }
  });

  it('reports apiBaseUrl from BASE_URL when the operator configured one', () => {
    const prev = process.env.BASE_URL;
    try {
      process.env.BASE_URL = 'https://wa.example.com';
      expect(new SettingsController(configStub).get().general.apiBaseUrl).toBe('https://wa.example.com');
    } finally {
      if (prev === undefined) delete process.env.BASE_URL;
      else process.env.BASE_URL = prev;
    }
  });

  // The previous PUT mutated an in-memory field and returned 200 'updated' while persisting
  // nothing and applying nothing to the runtime — a false success. Settings are env-derived and
  // read-only at runtime, so the write path must say so (501) rather than fake success.
  it('PUT /settings is read-only and throws 501 instead of a false-success 200', () => {
    const controller = new SettingsController(configStub);
    expect(() => controller.update()).toThrow(NotImplementedException);
  });

  it('PUT /settings still requires the ADMIN role', () => {
    const proto = SettingsController.prototype as unknown as Record<string, (...args: unknown[]) => unknown>;
    const role = new Reflector().get<ApiKeyRole | undefined>(REQUIRED_ROLE_KEY, proto.update);
    expect(role).toBe(ApiKeyRole.ADMIN);
  });

  it('GET /settings requires the ADMIN role (env-derived config is not for low-privilege keys)', () => {
    const proto = SettingsController.prototype as unknown as Record<string, (...args: unknown[]) => unknown>;
    const role = new Reflector().get<ApiKeyRole | undefined>(REQUIRED_ROLE_KEY, proto.get);
    expect(role).toBe(ApiKeyRole.ADMIN);
  });
});