website refactor
This commit is contained in:
66
tests/unit/website/FeatureFlagHelpers.test.ts
Normal file
66
tests/unit/website/FeatureFlagHelpers.test.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { getEnabledFlags, isFeatureEnabled, fetchFeatureFlags, FeatureFlagData } from '../../shared/website/FeatureFlagHelpers';
|
||||
|
||||
describe('FeatureFlagHelpers', () => {
|
||||
const mockFeatureData: FeatureFlagData = {
|
||||
features: {
|
||||
'feature.a': 'enabled',
|
||||
'feature.b': 'disabled',
|
||||
'feature.c': 'coming_soon',
|
||||
'feature.d': 'enabled',
|
||||
},
|
||||
timestamp: '2026-01-17T16:00:00Z',
|
||||
};
|
||||
|
||||
describe('getEnabledFlags()', () => {
|
||||
it('should return only enabled flags', () => {
|
||||
const enabled = getEnabledFlags(mockFeatureData);
|
||||
expect(enabled).toEqual(['feature.a', 'feature.d']);
|
||||
});
|
||||
|
||||
it('should return empty array if no features', () => {
|
||||
expect(getEnabledFlags({ features: {}, timestamp: '' })).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle null/undefined features', () => {
|
||||
expect(getEnabledFlags({ features: null as unknown as Record<string, string>, timestamp: '' })).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isFeatureEnabled()', () => {
|
||||
it('should return true for enabled features', () => {
|
||||
expect(isFeatureEnabled(mockFeatureData, 'feature.a')).toBe(true);
|
||||
expect(isFeatureEnabled(mockFeatureData, 'feature.d')).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for non-enabled features', () => {
|
||||
expect(isFeatureEnabled(mockFeatureData, 'feature.b')).toBe(false);
|
||||
expect(isFeatureEnabled(mockFeatureData, 'feature.c')).toBe(false);
|
||||
expect(isFeatureEnabled(mockFeatureData, 'non-existent')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetchFeatureFlags()', () => {
|
||||
it('should fetch and return feature flags', async () => {
|
||||
const mockFetcher = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => mockFeatureData,
|
||||
status: 200,
|
||||
});
|
||||
|
||||
const result = await fetchFeatureFlags(mockFetcher, 'http://api.test');
|
||||
|
||||
expect(mockFetcher).toHaveBeenCalledWith('http://api.test/features');
|
||||
expect(result).toEqual(mockFeatureData);
|
||||
});
|
||||
|
||||
it('should throw error if fetch fails', async () => {
|
||||
const mockFetcher = vi.fn().mockResolvedValue({
|
||||
ok: false,
|
||||
status: 500,
|
||||
});
|
||||
|
||||
await expect(fetchFeatureFlags(mockFetcher, 'http://api.test')).rejects.toThrow('Failed to fetch feature flags: 500');
|
||||
});
|
||||
});
|
||||
});
|
||||
73
tests/unit/website/WebsiteRouteManager.test.ts
Normal file
73
tests/unit/website/WebsiteRouteManager.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { WebsiteRouteManager } from '../../shared/website/WebsiteRouteManager';
|
||||
import { routes } from '../../../apps/website/lib/routing/RouteConfig';
|
||||
|
||||
describe('WebsiteRouteManager - Route Classification Contract', () => {
|
||||
const routeManager = new WebsiteRouteManager();
|
||||
|
||||
describe('getAccessLevel()', () => {
|
||||
it('should correctly classify public routes', () => {
|
||||
expect(routeManager.getAccessLevel('/')).toBe('public');
|
||||
expect(routeManager.getAccessLevel('/auth/login')).toBe('public');
|
||||
expect(routeManager.getAccessLevel('/leagues')).toBe('public');
|
||||
});
|
||||
|
||||
it('should correctly classify dashboard routes as auth', () => {
|
||||
expect(routeManager.getAccessLevel('/dashboard')).toBe('auth');
|
||||
expect(routeManager.getAccessLevel('/profile')).toBe('auth');
|
||||
});
|
||||
|
||||
it('should correctly classify admin routes', () => {
|
||||
expect(routeManager.getAccessLevel('/admin')).toBe('admin');
|
||||
expect(routeManager.getAccessLevel('/admin/users')).toBe('admin');
|
||||
});
|
||||
|
||||
it('should correctly classify sponsor routes', () => {
|
||||
expect(routeManager.getAccessLevel('/sponsor')).toBe('sponsor');
|
||||
expect(routeManager.getAccessLevel('/sponsor/dashboard')).toBe('sponsor');
|
||||
});
|
||||
|
||||
it('should correctly classify dynamic route patterns', () => {
|
||||
// League detail is public
|
||||
expect(routeManager.getAccessLevel('/leagues/any-id')).toBe('public');
|
||||
expect(routeManager.getAccessLevel('/races/any-id')).toBe('public');
|
||||
|
||||
// Nested protected routes
|
||||
expect(routeManager.getAccessLevel('/leagues/any-id/settings')).toBe('auth');
|
||||
});
|
||||
});
|
||||
|
||||
describe('RouteConfig Contract', () => {
|
||||
it('should fail loudly if RouteConfig paths change unexpectedly', () => {
|
||||
// These assertions act as a contract. If the paths change in RouteConfig,
|
||||
// these tests will fail, forcing a conscious update of the contract.
|
||||
expect(routes.public.home).toBe('/');
|
||||
expect(routes.auth.login).toBe('/auth/login');
|
||||
expect(routes.protected.dashboard).toBe('/dashboard');
|
||||
expect(routes.admin.root).toBe('/admin');
|
||||
expect(routes.sponsor.root).toBe('/sponsor');
|
||||
|
||||
// Dynamic patterns
|
||||
expect(routes.league.detail('test-id')).toBe('/leagues/test-id');
|
||||
expect(routes.league.scheduleAdmin('test-id')).toBe('/leagues/test-id/schedule/admin');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Representative Subset Verification', () => {
|
||||
const testCases = [
|
||||
{ path: '/', expected: 'public' },
|
||||
{ path: '/auth/login', expected: 'public' },
|
||||
{ path: '/dashboard', expected: 'auth' },
|
||||
{ path: '/admin', expected: 'admin' },
|
||||
{ path: '/sponsor', expected: 'sponsor' },
|
||||
{ path: '/leagues/123', expected: 'public' },
|
||||
{ path: '/races/456', expected: 'public' },
|
||||
];
|
||||
|
||||
testCases.forEach(({ path, expected }) => {
|
||||
it(`should classify ${path} as ${expected}`, () => {
|
||||
expect(routeManager.getAccessLevel(path)).toBe(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user