import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; /** * Unit tests for the API config module (config.ts). * * Tests getApiBaseUrl() and getCurrentTenant() which depend on: * - $app/environment (browser flag) * - $env/dynamic/public (environment variables) * - window.location (hostname, protocol) */ // Mutable env object so we can change values per-test const mockEnv: Record = {}; // Mock $app/environment - default to browser=true let mockBrowser = true; vi.mock('$app/environment', () => ({ get browser() { return mockBrowser; } })); // Mock $env/dynamic/public vi.mock('$env/dynamic/public', () => ({ env: new Proxy(mockEnv, { get(target, prop: string) { return target[prop]; } }) })); describe('API config', () => { let configModule: typeof import('$lib/api/config'); beforeEach(async () => { // Reset env between tests Object.keys(mockEnv).forEach((key) => delete mockEnv[key]); mockBrowser = true; // Reset modules to get a fresh import vi.resetModules(); configModule = await import('$lib/api/config'); }); afterEach(() => { vi.restoreAllMocks(); }); // ========================================================================== // getApiBaseUrl // ========================================================================== describe('getApiBaseUrl', () => { it('should return protocol://hostname:port/api when in browser with PUBLIC_API_PORT', () => { mockBrowser = true; mockEnv['PUBLIC_API_PORT'] = '18000'; // jsdom provides window.location - set it for the test // Default jsdom location is http://localhost, so we work with that const result = configModule.getApiBaseUrl(); expect(result).toBe(`${window.location.protocol}//${window.location.hostname}:18000/api`); }); it('should return /api when in browser without PUBLIC_API_PORT', () => { mockBrowser = true; // PUBLIC_API_PORT is not set (undefined) const result = configModule.getApiBaseUrl(); expect(result).toBe('/api'); }); it('should return PUBLIC_API_URL when in SSR and PUBLIC_API_URL is set', () => { mockBrowser = false; mockEnv['PUBLIC_API_URL'] = 'https://api.classeo.fr/api'; const result = configModule.getApiBaseUrl(); expect(result).toBe('https://api.classeo.fr/api'); }); it('should return http://php:8000/api as SSR fallback', () => { mockBrowser = false; // PUBLIC_API_URL is not set const result = configModule.getApiBaseUrl(); expect(result).toBe('http://php:8000/api'); }); }); // ========================================================================== // getCurrentTenant // ========================================================================== describe('getCurrentTenant', () => { it('should return null when not in browser', () => { mockBrowser = false; const result = configModule.getCurrentTenant(); expect(result).toBeNull(); }); it('should extract subdomain correctly from hostname', () => { mockBrowser = true; mockEnv['PUBLIC_BASE_DOMAIN'] = 'classeo.local'; // Override window.location.hostname for this test // jsdom default is "localhost" which won't match "classeo.local" // We need to use Object.defineProperty since location is readonly const originalHostname = window.location.hostname; Object.defineProperty(window, 'location', { value: { ...window.location, hostname: 'ecole-alpha.classeo.local' }, writable: true }); const result = configModule.getCurrentTenant(); expect(result).toBe('ecole-alpha'); // Restore Object.defineProperty(window, 'location', { value: { ...window.location, hostname: originalHostname }, writable: true }); }); it('should return null for www subdomain', () => { mockBrowser = true; mockEnv['PUBLIC_BASE_DOMAIN'] = 'classeo.fr'; Object.defineProperty(window, 'location', { value: { ...window.location, hostname: 'www.classeo.fr' }, writable: true }); const result = configModule.getCurrentTenant(); expect(result).toBeNull(); // Restore Object.defineProperty(window, 'location', { value: { ...window.location, hostname: 'localhost' }, writable: true }); }); it('should return null when hostname does not match base domain', () => { mockBrowser = true; mockEnv['PUBLIC_BASE_DOMAIN'] = 'classeo.fr'; Object.defineProperty(window, 'location', { value: { ...window.location, hostname: 'other-domain.com' }, writable: true }); const result = configModule.getCurrentTenant(); expect(result).toBeNull(); // Restore Object.defineProperty(window, 'location', { value: { ...window.location, hostname: 'localhost' }, writable: true }); }); }); });