import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import { createContainer } from '../../apps/website/lib/di/container'; import { SESSION_SERVICE_TOKEN, LEAGUE_MEMBERSHIP_SERVICE_TOKEN, LEAGUE_SERVICE_TOKEN, AUTH_SERVICE_TOKEN, DRIVER_SERVICE_TOKEN, TEAM_SERVICE_TOKEN, RACE_SERVICE_TOKEN, DASHBOARD_SERVICE_TOKEN, LOGGER_TOKEN, CONFIG_TOKEN, LEAGUE_API_CLIENT_TOKEN, AUTH_API_CLIENT_TOKEN, DRIVER_API_CLIENT_TOKEN, TEAM_API_CLIENT_TOKEN, RACE_API_CLIENT_TOKEN, } from '../../apps/website/lib/di/tokens'; /** * Integration test for website DI container * * This test verifies that all critical DI bindings are properly configured * and that the container can resolve all required services without throwing * binding errors or missing metadata errors. * * This is a fast, non-Playwright test that runs in CI to catch DI issues early. */ describe('Website DI Container Integration', () => { let container: ReturnType; let originalEnv: NodeJS.ProcessEnv; beforeAll(() => { // Save original environment originalEnv = { ...process.env }; // Set up minimal environment for DI container to work // The container needs API_BASE_URL to initialize process.env.API_BASE_URL = 'http://localhost:3001'; process.env.NEXT_PUBLIC_API_BASE_URL = 'http://localhost:3001'; process.env.NODE_ENV = 'test'; // Create the container once for all tests container = createContainer(); }); afterAll(() => { // Restore original environment process.env = originalEnv; }); it('creates container successfully', () => { expect(container).toBeDefined(); expect(container).not.toBeNull(); }); it('resolves core services without errors', () => { // Core services that should always be available expect(() => container.get(LOGGER_TOKEN)).not.toThrow(); expect(() => container.get(CONFIG_TOKEN)).not.toThrow(); const logger = container.get(LOGGER_TOKEN); const config = container.get(CONFIG_TOKEN); expect(logger).toBeDefined(); expect(config).toBeDefined(); }); it('resolves API clients without errors', () => { // API clients that services depend on const apiClients = [ LEAGUE_API_CLIENT_TOKEN, AUTH_API_CLIENT_TOKEN, DRIVER_API_CLIENT_TOKEN, TEAM_API_CLIENT_TOKEN, RACE_API_CLIENT_TOKEN, ]; for (const token of apiClients) { expect(() => container.get(token)).not.toThrow(); const client = container.get(token); expect(client).toBeDefined(); } }); it('resolves auth services including SessionService (critical for Symbol(Service.Session))', () => { // This specifically tests for the Symbol(Service.Session) binding issue expect(() => container.get(SESSION_SERVICE_TOKEN)).not.toThrow(); expect(() => container.get(AUTH_SERVICE_TOKEN)).not.toThrow(); const sessionService = container.get(SESSION_SERVICE_TOKEN); const authService = container.get(AUTH_SERVICE_TOKEN); expect(sessionService).toBeDefined(); expect(authService).toBeDefined(); // Verify the services have expected methods expect(typeof sessionService.getSession).toBe('function'); expect(typeof authService.login).toBe('function'); }); it('resolves league services including LeagueMembershipService (critical for metadata)', () => { // This specifically tests for the LeagueMembershipService metadata issue expect(() => container.get(LEAGUE_SERVICE_TOKEN)).not.toThrow(); expect(() => container.get(LEAGUE_MEMBERSHIP_SERVICE_TOKEN)).not.toThrow(); const leagueService = container.get(LEAGUE_SERVICE_TOKEN); const membershipService = container.get(LEAGUE_MEMBERSHIP_SERVICE_TOKEN); expect(leagueService).toBeDefined(); expect(membershipService).toBeDefined(); // Verify the services have expected methods expect(typeof leagueService.getAllLeagues).toBe('function'); expect(typeof membershipService.getLeagueMemberships).toBe('function'); }); it('resolves domain services without errors', () => { // Test other critical domain services expect(() => container.get(DRIVER_SERVICE_TOKEN)).not.toThrow(); expect(() => container.get(TEAM_SERVICE_TOKEN)).not.toThrow(); expect(() => container.get(RACE_SERVICE_TOKEN)).not.toThrow(); expect(() => container.get(DASHBOARD_SERVICE_TOKEN)).not.toThrow(); const driverService = container.get(DRIVER_SERVICE_TOKEN); const teamService = container.get(TEAM_SERVICE_TOKEN); const raceService = container.get(RACE_SERVICE_TOKEN); const dashboardService = container.get(DASHBOARD_SERVICE_TOKEN); expect(driverService).toBeDefined(); expect(teamService).toBeDefined(); expect(raceService).toBeDefined(); expect(dashboardService).toBeDefined(); }); it('resolves all services in a single operation (full container boot simulation)', () => { // This simulates what happens when the website boots and needs multiple services const tokens = [ SESSION_SERVICE_TOKEN, LEAGUE_MEMBERSHIP_SERVICE_TOKEN, LEAGUE_SERVICE_TOKEN, AUTH_SERVICE_TOKEN, DRIVER_SERVICE_TOKEN, TEAM_SERVICE_TOKEN, RACE_SERVICE_TOKEN, DASHBOARD_SERVICE_TOKEN, LOGGER_TOKEN, CONFIG_TOKEN, ]; // Resolve all tokens - if any binding is missing or metadata is wrong, this will throw const services = tokens.map(token => { try { return container.get(token); } catch (error) { throw new Error(`Failed to resolve token ${token.toString()}: ${error.message}`); } }); // Verify all services were resolved expect(services.length).toBe(tokens.length); services.forEach((service, index) => { expect(service).toBeDefined(); expect(service).not.toBeNull(); }); }); it('throws clear error for non-existent bindings', () => { const fakeToken = Symbol.for('Non.Existent.Service'); expect(() => container.get(fakeToken)).toThrow(); }); });