tenant-config-store.test.ts125 lines · main
1import { describe, expect, test } from 'bun:test';
2
3import { ValidationError } from '@briven/shared';
4
5import {
6 DEFAULT_AUTH_CONFIG,
7 __authConfigSchema,
8 mergeAuthConfig,
9 type AuthConfig,
10} from './tenant-config-store.js';
11
12describe('tenant-config-store — pure helpers (BUILD_PLAN.md §6)', () => {
13 test('DEFAULT_AUTH_CONFIG passes its own zod schema', () => {
14 const parsed = __authConfigSchema.safeParse(DEFAULT_AUTH_CONFIG);
15 expect(parsed.success).toBe(true);
16 });
17
18 test('DEFAULT_AUTH_CONFIG enables emailPassword + passwordless starter pack', () => {
19 // Clerk-simple: magic / OTP / passkey ON so login works without a second toggle.
20 expect(DEFAULT_AUTH_CONFIG.providers.emailPassword.enabled).toBe(true);
21 expect(DEFAULT_AUTH_CONFIG.providers.magicLink.enabled).toBe(true);
22 expect(DEFAULT_AUTH_CONFIG.providers.emailOtp.enabled).toBe(true);
23 expect(DEFAULT_AUTH_CONFIG.providers.passkey.enabled).toBe(true);
24 // OAuth stays off until client id + secret exist.
25 expect(DEFAULT_AUTH_CONFIG.providers.google.enabled).toBe(false);
26 expect(DEFAULT_AUTH_CONFIG.providers.github.enabled).toBe(false);
27 expect(DEFAULT_AUTH_CONFIG.providers.discord.enabled).toBe(false);
28 expect(DEFAULT_AUTH_CONFIG.providers.microsoft.enabled).toBe(false);
29 });
30
31 test('DEFAULT_AUTH_CONFIG carries briven brand defaults', () => {
32 expect(DEFAULT_AUTH_CONFIG.branding.primaryColor).toBe('#00e87a');
33 expect(DEFAULT_AUTH_CONFIG.branding.senderName).toBe('briven auth');
34 expect(DEFAULT_AUTH_CONFIG.branding.senderDomain).toBeNull();
35 expect(DEFAULT_AUTH_CONFIG.branding.logoUrl).toBeNull();
36 });
37
38 test('DEFAULT_AUTH_CONFIG is frozen — accidental mutation throws', () => {
39 expect(() => {
40 (DEFAULT_AUTH_CONFIG.providers as { emailPassword: { enabled: boolean } }).emailPassword.enabled = false;
41 }).toThrow();
42 });
43
44 test('merge with empty patch returns equal config (no-op)', () => {
45 const out = mergeAuthConfig(DEFAULT_AUTH_CONFIG, {});
46 expect(out).toEqual(DEFAULT_AUTH_CONFIG);
47 });
48
49 test('merge applies a single provider toggle without touching others', () => {
50 const out = mergeAuthConfig(DEFAULT_AUTH_CONFIG, {
51 providers: { google: { enabled: true, clientId: 'gho_public_id' } },
52 });
53 expect(out.providers.google).toEqual({ enabled: true, clientId: 'gho_public_id' });
54 expect(out.providers.github.enabled).toBe(false); // untouched
55 expect(out.providers.emailPassword.enabled).toBe(true); // untouched
56 });
57
58 test('merge deep-merges branding without losing untouched keys', () => {
59 const out = mergeAuthConfig(DEFAULT_AUTH_CONFIG, {
60 branding: { senderDomain: 'mail.customerapp.com' },
61 });
62 expect(out.branding.senderDomain).toBe('mail.customerapp.com');
63 // Other branding fields stay at defaults.
64 expect(out.branding.primaryColor).toBe('#00e87a');
65 expect(out.branding.senderName).toBe('briven auth');
66 expect(out.branding.logoUrl).toBeNull();
67 });
68
69 test('merge rejects malformed primaryColor (zod regex enforces hex shape)', () => {
70 expect(() =>
71 mergeAuthConfig(DEFAULT_AUTH_CONFIG, {
72 branding: { primaryColor: 'rgb(255,0,0)' },
73 }),
74 ).toThrow(ValidationError);
75 });
76
77 test('merge rejects malformed senderDomain', () => {
78 expect(() =>
79 mergeAuthConfig(DEFAULT_AUTH_CONFIG, {
80 branding: { senderDomain: 'not a domain at all' },
81 }),
82 ).toThrow(ValidationError);
83 });
84
85 test('merge rejects out-of-range magicLink expiry', () => {
86 expect(() =>
87 mergeAuthConfig(DEFAULT_AUTH_CONFIG, {
88 providers: { magicLink: { enabled: true, expiryMinutes: 999 } },
89 }),
90 ).toThrow(ValidationError);
91 });
92
93 test('merge rejects out-of-range otp codeLength', () => {
94 expect(() =>
95 mergeAuthConfig(DEFAULT_AUTH_CONFIG, {
96 providers: { emailOtp: { enabled: true, codeLength: 99, expiryMinutes: 5 } },
97 }),
98 ).toThrow(ValidationError);
99 });
100
101 test('merge strips unknown top-level keys (zod default strip mode)', () => {
102 const out = mergeAuthConfig(DEFAULT_AUTH_CONFIG, {
103 unknownTopLevel: { foo: 'bar' },
104 providers: { google: { enabled: true, clientId: 'x' } },
105 } as unknown as Partial<AuthConfig>);
106 expect('unknownTopLevel' in out).toBe(false);
107 expect(out.providers.google.enabled).toBe(true);
108 });
109
110 test('merge rejects non-object patches', () => {
111 expect(() => mergeAuthConfig(DEFAULT_AUTH_CONFIG, null)).toThrow(ValidationError);
112 expect(() => mergeAuthConfig(DEFAULT_AUTH_CONFIG, 'not an object')).toThrow(ValidationError);
113 expect(() => mergeAuthConfig(DEFAULT_AUTH_CONFIG, 42)).toThrow(ValidationError);
114 });
115
116 test('merge preserves provider isolation — toggling google does not enable github', () => {
117 const out = mergeAuthConfig(DEFAULT_AUTH_CONFIG, {
118 providers: { google: { enabled: true, clientId: 'a' } },
119 });
120 expect(out.providers.google.enabled).toBe(true);
121 expect(out.providers.github.enabled).toBe(false);
122 expect(out.providers.discord.enabled).toBe(false);
123 expect(out.providers.microsoft.enabled).toBe(false);
124 });
125});