import { describe, it, expect } from 'vitest'; import { ForgotPasswordViewModelBuilder } from './ForgotPasswordViewModelBuilder'; import type { ForgotPasswordViewData } from '@/lib/builders/view-data/types/ForgotPasswordViewData'; describe('ForgotPasswordViewModelBuilder', () => { describe('happy paths', () => { it('should transform ForgotPasswordViewData to ForgotPasswordViewModel correctly', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result).toBeDefined(); expect(result.returnTo).toBe('/dashboard'); expect(result.formState).toBeDefined(); expect(result.formState.fields).toBeDefined(); expect(result.formState.fields.email).toBeDefined(); expect(result.formState.fields.email.value).toBe(''); expect(result.formState.fields.email.error).toBeUndefined(); expect(result.formState.fields.email.touched).toBe(false); expect(result.formState.fields.email.validating).toBe(false); expect(result.formState.isValid).toBe(true); expect(result.formState.isSubmitting).toBe(false); expect(result.formState.submitError).toBeUndefined(); expect(result.formState.submitCount).toBe(0); expect(result.hasInsufficientPermissions).toBe(false); expect(result.error).toBeNull(); expect(result.successMessage).toBeNull(); expect(result.isProcessing).toBe(false); }); it('should handle different returnTo paths', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/login', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/login'); }); it('should handle empty returnTo', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe(''); }); }); describe('data transformation', () => { it('should preserve all viewData fields in the output', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe(forgotPasswordViewData.returnTo); }); it('should not modify the input viewData', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard', }; const originalViewData = { ...forgotPasswordViewData }; ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(forgotPasswordViewData).toEqual(originalViewData); }); }); describe('edge cases', () => { it('should handle null returnTo', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: null, }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBeNull(); }); it('should handle undefined returnTo', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: undefined, }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBeUndefined(); }); it('should handle complex returnTo paths', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard/leagues/league-123/settings', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard/leagues/league-123/settings'); }); it('should handle returnTo with query parameters', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?tab=settings', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?tab=settings'); }); it('should handle returnTo with hash', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard#section', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard#section'); }); it('should handle returnTo with special characters', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard/leagues/league-123/settings?tab=general#section', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard/leagues/league-123/settings?tab=general#section'); }); it('should handle very long returnTo path', () => { const longPath = '/dashboard/leagues/league-123/settings/section/subsection/item/' + 'a'.repeat(100); const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: longPath, }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe(longPath); }); it('should handle returnTo with encoded characters', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard/leagues/league-123/settings?name=John%20Doe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard/leagues/league-123/settings?name=John%20Doe'); }); it('should handle returnTo with multiple query parameters', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?tab=settings&filter=active&sort=name', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?tab=settings&filter=active&sort=name'); }); it('should handle returnTo with fragment identifier', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard#section-1', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard#section-1'); }); it('should handle returnTo with multiple fragments', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard#section-1#subsection-2', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard#section-1#subsection-2'); }); it('should handle returnTo with trailing slash', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard/', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard/'); }); it('should handle returnTo with leading slash', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: 'dashboard', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('dashboard'); }); it('should handle returnTo with dots', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard/../login', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard/../login'); }); it('should handle returnTo with double dots', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard/../../login', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard/../../login'); }); it('should handle returnTo with percent encoding', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard/leagues/league-123/settings?name=John%20Doe&email=test%40example.com', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard/leagues/league-123/settings?name=John%20Doe&email=test%40example.com'); }); it('should handle returnTo with plus signs', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?query=hello+world', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?query=hello+world'); }); it('should handle returnTo with ampersands', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?tab=settings&filter=active', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?tab=settings&filter=active'); }); it('should handle returnTo with equals signs', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?tab=settings=value', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?tab=settings=value'); }); it('should handle returnTo with multiple equals signs', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?tab=settings=value&filter=active=true', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?tab=settings=value&filter=active=true'); }); it('should handle returnTo with semicolons', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard;jsessionid=123', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard;jsessionid=123'); }); it('should handle returnTo with colons', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard:section', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard:section'); }); it('should handle returnTo with commas', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?filter=a,b,c', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?filter=a,b,c'); }); it('should handle returnTo with spaces', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John Doe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John Doe'); }); it('should handle returnTo with tabs', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John\tDoe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John\tDoe'); }); it('should handle returnTo with newlines', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John\nDoe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John\nDoe'); }); it('should handle returnTo with carriage returns', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John\rDoe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John\rDoe'); }); it('should handle returnTo with form feeds', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John\fDoe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John\fDoe'); }); it('should handle returnTo with vertical tabs', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John\vDoe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John\vDoe'); }); it('should handle returnTo with backspaces', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John\bDoe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John\bDoe'); }); it('should handle returnTo with null bytes', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John\0Doe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John\0Doe'); }); it('should handle returnTo with bell characters', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John\aDoe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John\aDoe'); }); it('should handle returnTo with escape characters', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John\eDoe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John\eDoe'); }); it('should handle returnTo with unicode characters', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John\u00D6Doe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John\u00D6Doe'); }); it('should handle returnTo with emoji', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John😀Doe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John😀Doe'); }); it('should handle returnTo with special symbols', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard?name=John!@#$%^&*()_+-=[]{}|;:,.<>?Doe', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard?name=John!@#$%^&*()_+-=[]{}|;:,.<>?Doe'); }); it('should handle returnTo with mixed special characters', () => { const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: '/dashboard/leagues/league-123/settings?name=John%20Doe&email=test%40example.com&filter=active=true&sort=name#section-1', }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe('/dashboard/leagues/league-123/settings?name=John%20Doe&email=test%40example.com&filter=active=true&sort=name#section-1'); }); it('should handle returnTo with very long path', () => { const longPath = '/dashboard/leagues/league-123/settings/section/subsection/item/' + 'a'.repeat(1000); const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: longPath, }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe(longPath); }); it('should handle returnTo with very long query string', () => { const longQuery = '/dashboard?' + 'a'.repeat(1000) + '=value'; const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: longQuery, }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe(longQuery); }); it('should handle returnTo with very long fragment', () => { const longFragment = '/dashboard#' + 'a'.repeat(1000); const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: longFragment, }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe(longFragment); }); it('should handle returnTo with mixed very long components', () => { const longPath = '/dashboard/leagues/league-123/settings/section/subsection/item/' + 'a'.repeat(500); const longQuery = '?' + 'b'.repeat(500) + '=value'; const longFragment = '#' + 'c'.repeat(500); const forgotPasswordViewData: ForgotPasswordViewData = { returnTo: longPath + longQuery + longFragment, }; const result = ForgotPasswordViewModelBuilder.build(forgotPasswordViewData); expect(result.returnTo).toBe(longPath + longQuery + longFragment); }); }); });