/** * View Data Layer Tests - Auth Functionality * * This test file covers the view data layer for auth functionality. * * The view data layer is responsible for: * - DTO → UI model mapping * - Formatting, sorting, and grouping * - Derived fields and defaults * - UI-specific semantics * * This layer isolates the UI from API churn by providing a stable interface * between the API layer and the presentation layer. * * Test coverage includes: * - Login form data transformation and validation * - Signup form view models and field formatting * - Forgot password flow data handling * - Reset password token validation and UI state * - Auth error message formatting and display * - User session data mapping for UI components * - Derived auth state fields (isAuthenticated, authStatus, etc.) * - Default values and fallbacks for auth views * - Auth-specific formatting (password strength, email validation, etc.) */ import { LoginViewDataBuilder } from '@/lib/builders/view-data/LoginViewDataBuilder'; import { SignupViewDataBuilder } from '@/lib/builders/view-data/SignupViewDataBuilder'; import { ForgotPasswordViewDataBuilder } from '@/lib/builders/view-data/ForgotPasswordViewDataBuilder'; import { ResetPasswordViewDataBuilder } from '@/lib/builders/view-data/ResetPasswordViewDataBuilder'; import type { LoginPageDTO } from '@/lib/services/auth/types/LoginPageDTO'; import type { SignupPageDTO } from '@/lib/services/auth/types/SignupPageDTO'; import type { ForgotPasswordPageDTO } from '@/lib/services/auth/types/ForgotPasswordPageDTO'; import type { ResetPasswordPageDTO } from '@/lib/services/auth/types/ResetPasswordPageDTO'; describe('LoginViewDataBuilder', () => { describe('happy paths', () => { it('should transform LoginPageDTO to LoginViewData correctly', () => { const loginPageDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false, }; const result = LoginViewDataBuilder.build(loginPageDTO); expect(result).toEqual({ returnTo: '/dashboard', hasInsufficientPermissions: false, showPassword: false, showErrorDetails: false, formState: { fields: { email: { value: '', error: undefined, touched: false, validating: false }, password: { value: '', error: undefined, touched: false, validating: false }, rememberMe: { value: false, error: undefined, touched: false, validating: false }, }, isValid: true, isSubmitting: false, submitError: undefined, submitCount: 0, }, isSubmitting: false, submitError: undefined, }); }); it('should handle insufficient permissions flag correctly', () => { const loginPageDTO: LoginPageDTO = { returnTo: '/admin', hasInsufficientPermissions: true, }; const result = LoginViewDataBuilder.build(loginPageDTO); expect(result.hasInsufficientPermissions).toBe(true); expect(result.returnTo).toBe('/admin'); }); it('should handle empty returnTo path', () => { const loginPageDTO: LoginPageDTO = { returnTo: '', hasInsufficientPermissions: false, }; const result = LoginViewDataBuilder.build(loginPageDTO); expect(result.returnTo).toBe(''); expect(result.hasInsufficientPermissions).toBe(false); }); }); describe('data transformation', () => { it('should preserve all DTO fields in the output', () => { const loginPageDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false, }; const result = LoginViewDataBuilder.build(loginPageDTO); expect(result.returnTo).toBe(loginPageDTO.returnTo); expect(result.hasInsufficientPermissions).toBe(loginPageDTO.hasInsufficientPermissions); }); it('should not modify the input DTO', () => { const loginPageDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false, }; const originalDTO = { ...loginPageDTO }; LoginViewDataBuilder.build(loginPageDTO); expect(loginPageDTO).toEqual(originalDTO); }); it('should initialize form fields with default values', () => { const loginPageDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false, }; const result = LoginViewDataBuilder.build(loginPageDTO); 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.fields.password.value).toBe(''); expect(result.formState.fields.password.error).toBeUndefined(); expect(result.formState.fields.password.touched).toBe(false); expect(result.formState.fields.password.validating).toBe(false); expect(result.formState.fields.rememberMe.value).toBe(false); expect(result.formState.fields.rememberMe.error).toBeUndefined(); expect(result.formState.fields.rememberMe.touched).toBe(false); expect(result.formState.fields.rememberMe.validating).toBe(false); }); it('should initialize form state with default values', () => { const loginPageDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false, }; const result = LoginViewDataBuilder.build(loginPageDTO); expect(result.formState.isValid).toBe(true); expect(result.formState.isSubmitting).toBe(false); expect(result.formState.submitError).toBeUndefined(); expect(result.formState.submitCount).toBe(0); }); it('should initialize UI state flags correctly', () => { const loginPageDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false, }; const result = LoginViewDataBuilder.build(loginPageDTO); expect(result.showPassword).toBe(false); expect(result.showErrorDetails).toBe(false); expect(result.isSubmitting).toBe(false); expect(result.submitError).toBeUndefined(); }); }); describe('edge cases', () => { it('should handle special characters in returnTo path', () => { const loginPageDTO: LoginPageDTO = { returnTo: '/dashboard?param=value&other=test', hasInsufficientPermissions: false, }; const result = LoginViewDataBuilder.build(loginPageDTO); expect(result.returnTo).toBe('/dashboard?param=value&other=test'); }); it('should handle returnTo with hash fragment', () => { const loginPageDTO: LoginPageDTO = { returnTo: '/dashboard#section', hasInsufficientPermissions: false, }; const result = LoginViewDataBuilder.build(loginPageDTO); expect(result.returnTo).toBe('/dashboard#section'); }); it('should handle returnTo with encoded characters', () => { const loginPageDTO: LoginPageDTO = { returnTo: '/dashboard?redirect=%2Fadmin', hasInsufficientPermissions: false, }; const result = LoginViewDataBuilder.build(loginPageDTO); expect(result.returnTo).toBe('/dashboard?redirect=%2Fadmin'); }); }); describe('form state structure', () => { it('should have all required form fields', () => { const loginPageDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false, }; const result = LoginViewDataBuilder.build(loginPageDTO); expect(result.formState.fields).toHaveProperty('email'); expect(result.formState.fields).toHaveProperty('password'); expect(result.formState.fields).toHaveProperty('rememberMe'); }); it('should have consistent field state structure', () => { const loginPageDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false, }; const result = LoginViewDataBuilder.build(loginPageDTO); const fields = result.formState.fields; Object.values(fields).forEach((field) => { expect(field).toHaveProperty('value'); expect(field).toHaveProperty('error'); expect(field).toHaveProperty('touched'); expect(field).toHaveProperty('validating'); }); }); }); }); describe('SignupViewDataBuilder', () => { describe('happy paths', () => { it('should transform SignupPageDTO to SignupViewData correctly', () => { const signupPageDTO: SignupPageDTO = { returnTo: '/dashboard', }; const result = SignupViewDataBuilder.build(signupPageDTO); expect(result).toEqual({ returnTo: '/dashboard', formState: { fields: { firstName: { value: '', error: undefined, touched: false, validating: false }, lastName: { value: '', error: undefined, touched: false, validating: false }, email: { value: '', error: undefined, touched: false, validating: false }, password: { value: '', error: undefined, touched: false, validating: false }, confirmPassword: { value: '', error: undefined, touched: false, validating: false }, }, isValid: true, isSubmitting: false, submitError: undefined, submitCount: 0, }, isSubmitting: false, submitError: undefined, }); }); it('should handle empty returnTo path', () => { const signupPageDTO: SignupPageDTO = { returnTo: '', }; const result = SignupViewDataBuilder.build(signupPageDTO); expect(result.returnTo).toBe(''); }); it('should handle returnTo with query parameters', () => { const signupPageDTO: SignupPageDTO = { returnTo: '/dashboard?welcome=true', }; const result = SignupViewDataBuilder.build(signupPageDTO); expect(result.returnTo).toBe('/dashboard?welcome=true'); }); }); describe('data transformation', () => { it('should preserve all DTO fields in the output', () => { const signupPageDTO: SignupPageDTO = { returnTo: '/dashboard', }; const result = SignupViewDataBuilder.build(signupPageDTO); expect(result.returnTo).toBe(signupPageDTO.returnTo); }); it('should not modify the input DTO', () => { const signupPageDTO: SignupPageDTO = { returnTo: '/dashboard', }; const originalDTO = { ...signupPageDTO }; SignupViewDataBuilder.build(signupPageDTO); expect(signupPageDTO).toEqual(originalDTO); }); it('should initialize all signup form fields with default values', () => { const signupPageDTO: SignupPageDTO = { returnTo: '/dashboard', }; const result = SignupViewDataBuilder.build(signupPageDTO); expect(result.formState.fields.firstName.value).toBe(''); expect(result.formState.fields.firstName.error).toBeUndefined(); expect(result.formState.fields.firstName.touched).toBe(false); expect(result.formState.fields.firstName.validating).toBe(false); expect(result.formState.fields.lastName.value).toBe(''); expect(result.formState.fields.lastName.error).toBeUndefined(); expect(result.formState.fields.lastName.touched).toBe(false); expect(result.formState.fields.lastName.validating).toBe(false); 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.fields.password.value).toBe(''); expect(result.formState.fields.password.error).toBeUndefined(); expect(result.formState.fields.password.touched).toBe(false); expect(result.formState.fields.password.validating).toBe(false); expect(result.formState.fields.confirmPassword.value).toBe(''); expect(result.formState.fields.confirmPassword.error).toBeUndefined(); expect(result.formState.fields.confirmPassword.touched).toBe(false); expect(result.formState.fields.confirmPassword.validating).toBe(false); }); it('should initialize form state with default values', () => { const signupPageDTO: SignupPageDTO = { returnTo: '/dashboard', }; const result = SignupViewDataBuilder.build(signupPageDTO); expect(result.formState.isValid).toBe(true); expect(result.formState.isSubmitting).toBe(false); expect(result.formState.submitError).toBeUndefined(); expect(result.formState.submitCount).toBe(0); }); it('should initialize UI state flags correctly', () => { const signupPageDTO: SignupPageDTO = { returnTo: '/dashboard', }; const result = SignupViewDataBuilder.build(signupPageDTO); expect(result.isSubmitting).toBe(false); expect(result.submitError).toBeUndefined(); }); }); describe('edge cases', () => { it('should handle returnTo with encoded characters', () => { const signupPageDTO: SignupPageDTO = { returnTo: '/dashboard?redirect=%2Fadmin', }; const result = SignupViewDataBuilder.build(signupPageDTO); expect(result.returnTo).toBe('/dashboard?redirect=%2Fadmin'); }); it('should handle returnTo with hash fragment', () => { const signupPageDTO: SignupPageDTO = { returnTo: '/dashboard#section', }; const result = SignupViewDataBuilder.build(signupPageDTO); expect(result.returnTo).toBe('/dashboard#section'); }); }); describe('form state structure', () => { it('should have all required form fields', () => { const signupPageDTO: SignupPageDTO = { returnTo: '/dashboard', }; const result = SignupViewDataBuilder.build(signupPageDTO); expect(result.formState.fields).toHaveProperty('firstName'); expect(result.formState.fields).toHaveProperty('lastName'); expect(result.formState.fields).toHaveProperty('email'); expect(result.formState.fields).toHaveProperty('password'); expect(result.formState.fields).toHaveProperty('confirmPassword'); }); it('should have consistent field state structure', () => { const signupPageDTO: SignupPageDTO = { returnTo: '/dashboard', }; const result = SignupViewDataBuilder.build(signupPageDTO); const fields = result.formState.fields; Object.values(fields).forEach((field) => { expect(field).toHaveProperty('value'); expect(field).toHaveProperty('error'); expect(field).toHaveProperty('touched'); expect(field).toHaveProperty('validating'); }); }); }); }); describe('ForgotPasswordViewDataBuilder', () => { describe('happy paths', () => { it('should transform ForgotPasswordPageDTO to ForgotPasswordViewData correctly', () => { const forgotPasswordPageDTO: ForgotPasswordPageDTO = { returnTo: '/login', }; const result = ForgotPasswordViewDataBuilder.build(forgotPasswordPageDTO); expect(result).toEqual({ returnTo: '/login', showSuccess: false, formState: { fields: { email: { value: '', error: undefined, touched: false, validating: false }, }, isValid: true, isSubmitting: false, submitError: undefined, submitCount: 0, }, isSubmitting: false, submitError: undefined, }); }); it('should handle empty returnTo path', () => { const forgotPasswordPageDTO: ForgotPasswordPageDTO = { returnTo: '', }; const result = ForgotPasswordViewDataBuilder.build(forgotPasswordPageDTO); expect(result.returnTo).toBe(''); }); it('should handle returnTo with query parameters', () => { const forgotPasswordPageDTO: ForgotPasswordPageDTO = { returnTo: '/login?error=expired', }; const result = ForgotPasswordViewDataBuilder.build(forgotPasswordPageDTO); expect(result.returnTo).toBe('/login?error=expired'); }); }); describe('data transformation', () => { it('should preserve all DTO fields in the output', () => { const forgotPasswordPageDTO: ForgotPasswordPageDTO = { returnTo: '/login', }; const result = ForgotPasswordViewDataBuilder.build(forgotPasswordPageDTO); expect(result.returnTo).toBe(forgotPasswordPageDTO.returnTo); }); it('should not modify the input DTO', () => { const forgotPasswordPageDTO: ForgotPasswordPageDTO = { returnTo: '/login', }; const originalDTO = { ...forgotPasswordPageDTO }; ForgotPasswordViewDataBuilder.build(forgotPasswordPageDTO); expect(forgotPasswordPageDTO).toEqual(originalDTO); }); it('should initialize form field with default values', () => { const forgotPasswordPageDTO: ForgotPasswordPageDTO = { returnTo: '/login', }; const result = ForgotPasswordViewDataBuilder.build(forgotPasswordPageDTO); 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); }); it('should initialize form state with default values', () => { const forgotPasswordPageDTO: ForgotPasswordPageDTO = { returnTo: '/login', }; const result = ForgotPasswordViewDataBuilder.build(forgotPasswordPageDTO); expect(result.formState.isValid).toBe(true); expect(result.formState.isSubmitting).toBe(false); expect(result.formState.submitError).toBeUndefined(); expect(result.formState.submitCount).toBe(0); }); it('should initialize UI state flags correctly', () => { const forgotPasswordPageDTO: ForgotPasswordPageDTO = { returnTo: '/login', }; const result = ForgotPasswordViewDataBuilder.build(forgotPasswordPageDTO); expect(result.showSuccess).toBe(false); expect(result.isSubmitting).toBe(false); expect(result.submitError).toBeUndefined(); }); }); describe('edge cases', () => { it('should handle returnTo with encoded characters', () => { const forgotPasswordPageDTO: ForgotPasswordPageDTO = { returnTo: '/login?redirect=%2Fdashboard', }; const result = ForgotPasswordViewDataBuilder.build(forgotPasswordPageDTO); expect(result.returnTo).toBe('/login?redirect=%2Fdashboard'); }); it('should handle returnTo with hash fragment', () => { const forgotPasswordPageDTO: ForgotPasswordPageDTO = { returnTo: '/login#section', }; const result = ForgotPasswordViewDataBuilder.build(forgotPasswordPageDTO); expect(result.returnTo).toBe('/login#section'); }); }); describe('form state structure', () => { it('should have email field', () => { const forgotPasswordPageDTO: ForgotPasswordPageDTO = { returnTo: '/login', }; const result = ForgotPasswordViewDataBuilder.build(forgotPasswordPageDTO); expect(result.formState.fields).toHaveProperty('email'); }); it('should have consistent field state structure', () => { const forgotPasswordPageDTO: ForgotPasswordPageDTO = { returnTo: '/login', }; const result = ForgotPasswordViewDataBuilder.build(forgotPasswordPageDTO); const field = result.formState.fields.email; expect(field).toHaveProperty('value'); expect(field).toHaveProperty('error'); expect(field).toHaveProperty('touched'); expect(field).toHaveProperty('validating'); }); }); }); describe('ResetPasswordViewDataBuilder', () => { describe('happy paths', () => { it('should transform ResetPasswordPageDTO to ResetPasswordViewData correctly', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc123def456', returnTo: '/login', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(result).toEqual({ token: 'abc123def456', returnTo: '/login', showSuccess: false, formState: { fields: { newPassword: { value: '', error: undefined, touched: false, validating: false }, confirmPassword: { value: '', error: undefined, touched: false, validating: false }, }, isValid: true, isSubmitting: false, submitError: undefined, submitCount: 0, }, isSubmitting: false, submitError: undefined, }); }); it('should handle empty returnTo path', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc123def456', returnTo: '', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(result.returnTo).toBe(''); }); it('should handle returnTo with query parameters', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc123def456', returnTo: '/login?success=true', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(result.returnTo).toBe('/login?success=true'); }); }); describe('data transformation', () => { it('should preserve all DTO fields in the output', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc123def456', returnTo: '/login', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(result.token).toBe(resetPasswordPageDTO.token); expect(result.returnTo).toBe(resetPasswordPageDTO.returnTo); }); it('should not modify the input DTO', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc123def456', returnTo: '/login', }; const originalDTO = { ...resetPasswordPageDTO }; ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(resetPasswordPageDTO).toEqual(originalDTO); }); it('should initialize form fields with default values', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc123def456', returnTo: '/login', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(result.formState.fields.newPassword.value).toBe(''); expect(result.formState.fields.newPassword.error).toBeUndefined(); expect(result.formState.fields.newPassword.touched).toBe(false); expect(result.formState.fields.newPassword.validating).toBe(false); expect(result.formState.fields.confirmPassword.value).toBe(''); expect(result.formState.fields.confirmPassword.error).toBeUndefined(); expect(result.formState.fields.confirmPassword.touched).toBe(false); expect(result.formState.fields.confirmPassword.validating).toBe(false); }); it('should initialize form state with default values', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc123def456', returnTo: '/login', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(result.formState.isValid).toBe(true); expect(result.formState.isSubmitting).toBe(false); expect(result.formState.submitError).toBeUndefined(); expect(result.formState.submitCount).toBe(0); }); it('should initialize UI state flags correctly', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc123def456', returnTo: '/login', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(result.showSuccess).toBe(false); expect(result.isSubmitting).toBe(false); expect(result.submitError).toBeUndefined(); }); }); describe('edge cases', () => { it('should handle token with special characters', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc-123_def.456', returnTo: '/login', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(result.token).toBe('abc-123_def.456'); }); it('should handle token with URL-encoded characters', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc%20123%40def', returnTo: '/login', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(result.token).toBe('abc%20123%40def'); }); it('should handle returnTo with encoded characters', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc123def456', returnTo: '/login?redirect=%2Fdashboard', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(result.returnTo).toBe('/login?redirect=%2Fdashboard'); }); it('should handle returnTo with hash fragment', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc123def456', returnTo: '/login#section', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(result.returnTo).toBe('/login#section'); }); }); describe('form state structure', () => { it('should have all required form fields', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc123def456', returnTo: '/login', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); expect(result.formState.fields).toHaveProperty('newPassword'); expect(result.formState.fields).toHaveProperty('confirmPassword'); }); it('should have consistent field state structure', () => { const resetPasswordPageDTO: ResetPasswordPageDTO = { token: 'abc123def456', returnTo: '/login', }; const result = ResetPasswordViewDataBuilder.build(resetPasswordPageDTO); const fields = result.formState.fields; Object.values(fields).forEach((field) => { expect(field).toHaveProperty('value'); expect(field).toHaveProperty('error'); expect(field).toHaveProperty('touched'); expect(field).toHaveProperty('validating'); }); }); }); }); describe('Auth View Data - Cross-Builder Consistency', () => { describe('common patterns', () => { it('should all initialize with isSubmitting false', () => { const loginDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false }; const signupDTO: SignupPageDTO = { returnTo: '/dashboard' }; const forgotPasswordDTO: ForgotPasswordPageDTO = { returnTo: '/dashboard' }; const resetPasswordDTO: ResetPasswordPageDTO = { token: 'abc123', returnTo: '/dashboard' }; const loginResult = LoginViewDataBuilder.build(loginDTO); const signupResult = SignupViewDataBuilder.build(signupDTO); const forgotPasswordResult = ForgotPasswordViewDataBuilder.build(forgotPasswordDTO); const resetPasswordResult = ResetPasswordViewDataBuilder.build(resetPasswordDTO); expect(loginResult.isSubmitting).toBe(false); expect(signupResult.isSubmitting).toBe(false); expect(forgotPasswordResult.isSubmitting).toBe(false); expect(resetPasswordResult.isSubmitting).toBe(false); }); it('should all initialize with submitError undefined', () => { const loginDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false }; const signupDTO: SignupPageDTO = { returnTo: '/dashboard' }; const forgotPasswordDTO: ForgotPasswordPageDTO = { returnTo: '/dashboard' }; const resetPasswordDTO: ResetPasswordPageDTO = { token: 'abc123', returnTo: '/dashboard' }; const loginResult = LoginViewDataBuilder.build(loginDTO); const signupResult = SignupViewDataBuilder.build(signupDTO); const forgotPasswordResult = ForgotPasswordViewDataBuilder.build(forgotPasswordDTO); const resetPasswordResult = ResetPasswordViewDataBuilder.build(resetPasswordDTO); expect(loginResult.submitError).toBeUndefined(); expect(signupResult.submitError).toBeUndefined(); expect(forgotPasswordResult.submitError).toBeUndefined(); expect(resetPasswordResult.submitError).toBeUndefined(); }); it('should all initialize formState.isValid as true', () => { const loginDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false }; const signupDTO: SignupPageDTO = { returnTo: '/dashboard' }; const forgotPasswordDTO: ForgotPasswordPageDTO = { returnTo: '/dashboard' }; const resetPasswordDTO: ResetPasswordPageDTO = { token: 'abc123', returnTo: '/dashboard' }; const loginResult = LoginViewDataBuilder.build(loginDTO); const signupResult = SignupViewDataBuilder.build(signupDTO); const forgotPasswordResult = ForgotPasswordViewDataBuilder.build(forgotPasswordDTO); const resetPasswordResult = ResetPasswordViewDataBuilder.build(resetPasswordDTO); expect(loginResult.formState.isValid).toBe(true); expect(signupResult.formState.isValid).toBe(true); expect(forgotPasswordResult.formState.isValid).toBe(true); expect(resetPasswordResult.formState.isValid).toBe(true); }); it('should all initialize formState.isSubmitting as false', () => { const loginDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false }; const signupDTO: SignupPageDTO = { returnTo: '/dashboard' }; const forgotPasswordDTO: ForgotPasswordPageDTO = { returnTo: '/dashboard' }; const resetPasswordDTO: ResetPasswordPageDTO = { token: 'abc123', returnTo: '/dashboard' }; const loginResult = LoginViewDataBuilder.build(loginDTO); const signupResult = SignupViewDataBuilder.build(signupDTO); const forgotPasswordResult = ForgotPasswordViewDataBuilder.build(forgotPasswordDTO); const resetPasswordResult = ResetPasswordViewDataBuilder.build(resetPasswordDTO); expect(loginResult.formState.isSubmitting).toBe(false); expect(signupResult.formState.isSubmitting).toBe(false); expect(forgotPasswordResult.formState.isSubmitting).toBe(false); expect(resetPasswordResult.formState.isSubmitting).toBe(false); }); it('should all initialize formState.submitError as undefined', () => { const loginDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false }; const signupDTO: SignupPageDTO = { returnTo: '/dashboard' }; const forgotPasswordDTO: ForgotPasswordPageDTO = { returnTo: '/dashboard' }; const resetPasswordDTO: ResetPasswordPageDTO = { token: 'abc123', returnTo: '/dashboard' }; const loginResult = LoginViewDataBuilder.build(loginDTO); const signupResult = SignupViewDataBuilder.build(signupDTO); const forgotPasswordResult = ForgotPasswordViewDataBuilder.build(forgotPasswordDTO); const resetPasswordResult = ResetPasswordViewDataBuilder.build(resetPasswordDTO); expect(loginResult.formState.submitError).toBeUndefined(); expect(signupResult.formState.submitError).toBeUndefined(); expect(forgotPasswordResult.formState.submitError).toBeUndefined(); expect(resetPasswordResult.formState.submitError).toBeUndefined(); }); it('should all initialize formState.submitCount as 0', () => { const loginDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false }; const signupDTO: SignupPageDTO = { returnTo: '/dashboard' }; const forgotPasswordDTO: ForgotPasswordPageDTO = { returnTo: '/dashboard' }; const resetPasswordDTO: ResetPasswordPageDTO = { token: 'abc123', returnTo: '/dashboard' }; const loginResult = LoginViewDataBuilder.build(loginDTO); const signupResult = SignupViewDataBuilder.build(signupDTO); const forgotPasswordResult = ForgotPasswordViewDataBuilder.build(forgotPasswordDTO); const resetPasswordResult = ResetPasswordViewDataBuilder.build(resetPasswordDTO); expect(loginResult.formState.submitCount).toBe(0); expect(signupResult.formState.submitCount).toBe(0); expect(forgotPasswordResult.formState.submitCount).toBe(0); expect(resetPasswordResult.formState.submitCount).toBe(0); }); it('should all initialize form fields with touched false', () => { const loginDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false }; const signupDTO: SignupPageDTO = { returnTo: '/dashboard' }; const forgotPasswordDTO: ForgotPasswordPageDTO = { returnTo: '/dashboard' }; const resetPasswordDTO: ResetPasswordPageDTO = { token: 'abc123', returnTo: '/dashboard' }; const loginResult = LoginViewDataBuilder.build(loginDTO); const signupResult = SignupViewDataBuilder.build(signupDTO); const forgotPasswordResult = ForgotPasswordViewDataBuilder.build(forgotPasswordDTO); const resetPasswordResult = ResetPasswordViewDataBuilder.build(resetPasswordDTO); expect(loginResult.formState.fields.email.touched).toBe(false); expect(loginResult.formState.fields.password.touched).toBe(false); expect(loginResult.formState.fields.rememberMe.touched).toBe(false); expect(signupResult.formState.fields.firstName.touched).toBe(false); expect(signupResult.formState.fields.lastName.touched).toBe(false); expect(signupResult.formState.fields.email.touched).toBe(false); expect(signupResult.formState.fields.password.touched).toBe(false); expect(signupResult.formState.fields.confirmPassword.touched).toBe(false); expect(forgotPasswordResult.formState.fields.email.touched).toBe(false); expect(resetPasswordResult.formState.fields.newPassword.touched).toBe(false); expect(resetPasswordResult.formState.fields.confirmPassword.touched).toBe(false); }); it('should all initialize form fields with validating false', () => { const loginDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false }; const signupDTO: SignupPageDTO = { returnTo: '/dashboard' }; const forgotPasswordDTO: ForgotPasswordPageDTO = { returnTo: '/dashboard' }; const resetPasswordDTO: ResetPasswordPageDTO = { token: 'abc123', returnTo: '/dashboard' }; const loginResult = LoginViewDataBuilder.build(loginDTO); const signupResult = SignupViewDataBuilder.build(signupDTO); const forgotPasswordResult = ForgotPasswordViewDataBuilder.build(forgotPasswordDTO); const resetPasswordResult = ResetPasswordViewDataBuilder.build(resetPasswordDTO); expect(loginResult.formState.fields.email.validating).toBe(false); expect(loginResult.formState.fields.password.validating).toBe(false); expect(loginResult.formState.fields.rememberMe.validating).toBe(false); expect(signupResult.formState.fields.firstName.validating).toBe(false); expect(signupResult.formState.fields.lastName.validating).toBe(false); expect(signupResult.formState.fields.email.validating).toBe(false); expect(signupResult.formState.fields.password.validating).toBe(false); expect(signupResult.formState.fields.confirmPassword.validating).toBe(false); expect(forgotPasswordResult.formState.fields.email.validating).toBe(false); expect(resetPasswordResult.formState.fields.newPassword.validating).toBe(false); expect(resetPasswordResult.formState.fields.confirmPassword.validating).toBe(false); }); it('should all initialize form fields with error undefined', () => { const loginDTO: LoginPageDTO = { returnTo: '/dashboard', hasInsufficientPermissions: false }; const signupDTO: SignupPageDTO = { returnTo: '/dashboard' }; const forgotPasswordDTO: ForgotPasswordPageDTO = { returnTo: '/dashboard' }; const resetPasswordDTO: ResetPasswordPageDTO = { token: 'abc123', returnTo: '/dashboard' }; const loginResult = LoginViewDataBuilder.build(loginDTO); const signupResult = SignupViewDataBuilder.build(signupDTO); const forgotPasswordResult = ForgotPasswordViewDataBuilder.build(forgotPasswordDTO); const resetPasswordResult = ResetPasswordViewDataBuilder.build(resetPasswordDTO); expect(loginResult.formState.fields.email.error).toBeUndefined(); expect(loginResult.formState.fields.password.error).toBeUndefined(); expect(loginResult.formState.fields.rememberMe.error).toBeUndefined(); expect(signupResult.formState.fields.firstName.error).toBeUndefined(); expect(signupResult.formState.fields.lastName.error).toBeUndefined(); expect(signupResult.formState.fields.email.error).toBeUndefined(); expect(signupResult.formState.fields.password.error).toBeUndefined(); expect(signupResult.formState.fields.confirmPassword.error).toBeUndefined(); expect(forgotPasswordResult.formState.fields.email.error).toBeUndefined(); expect(resetPasswordResult.formState.fields.newPassword.error).toBeUndefined(); expect(resetPasswordResult.formState.fields.confirmPassword.error).toBeUndefined(); }); }); describe('common returnTo handling', () => { it('should all handle returnTo with query parameters', () => { const loginDTO: LoginPageDTO = { returnTo: '/dashboard?welcome=true', hasInsufficientPermissions: false }; const signupDTO: SignupPageDTO = { returnTo: '/dashboard?welcome=true' }; const forgotPasswordDTO: ForgotPasswordPageDTO = { returnTo: '/dashboard?welcome=true' }; const resetPasswordDTO: ResetPasswordPageDTO = { token: 'abc123', returnTo: '/dashboard?welcome=true' }; const loginResult = LoginViewDataBuilder.build(loginDTO); const signupResult = SignupViewDataBuilder.build(signupDTO); const forgotPasswordResult = ForgotPasswordViewDataBuilder.build(forgotPasswordDTO); const resetPasswordResult = ResetPasswordViewDataBuilder.build(resetPasswordDTO); expect(loginResult.returnTo).toBe('/dashboard?welcome=true'); expect(signupResult.returnTo).toBe('/dashboard?welcome=true'); expect(forgotPasswordResult.returnTo).toBe('/dashboard?welcome=true'); expect(resetPasswordResult.returnTo).toBe('/dashboard?welcome=true'); }); it('should all handle returnTo with hash fragments', () => { const loginDTO: LoginPageDTO = { returnTo: '/dashboard#section', hasInsufficientPermissions: false }; const signupDTO: SignupPageDTO = { returnTo: '/dashboard#section' }; const forgotPasswordDTO: ForgotPasswordPageDTO = { returnTo: '/dashboard#section' }; const resetPasswordDTO: ResetPasswordPageDTO = { token: 'abc123', returnTo: '/dashboard#section' }; const loginResult = LoginViewDataBuilder.build(loginDTO); const signupResult = SignupViewDataBuilder.build(signupDTO); const forgotPasswordResult = ForgotPasswordViewDataBuilder.build(forgotPasswordDTO); const resetPasswordResult = ResetPasswordViewDataBuilder.build(resetPasswordDTO); expect(loginResult.returnTo).toBe('/dashboard#section'); expect(signupResult.returnTo).toBe('/dashboard#section'); expect(forgotPasswordResult.returnTo).toBe('/dashboard#section'); expect(resetPasswordResult.returnTo).toBe('/dashboard#section'); }); it('should all handle returnTo with encoded characters', () => { const loginDTO: LoginPageDTO = { returnTo: '/dashboard?redirect=%2Fadmin', hasInsufficientPermissions: false }; const signupDTO: SignupPageDTO = { returnTo: '/dashboard?redirect=%2Fadmin' }; const forgotPasswordDTO: ForgotPasswordPageDTO = { returnTo: '/dashboard?redirect=%2Fadmin' }; const resetPasswordDTO: ResetPasswordPageDTO = { token: 'abc123', returnTo: '/dashboard?redirect=%2Fadmin' }; const loginResult = LoginViewDataBuilder.build(loginDTO); const signupResult = SignupViewDataBuilder.build(signupDTO); const forgotPasswordResult = ForgotPasswordViewDataBuilder.build(forgotPasswordDTO); const resetPasswordResult = ResetPasswordViewDataBuilder.build(resetPasswordDTO); expect(loginResult.returnTo).toBe('/dashboard?redirect=%2Fadmin'); expect(signupResult.returnTo).toBe('/dashboard?redirect=%2Fadmin'); expect(forgotPasswordResult.returnTo).toBe('/dashboard?redirect=%2Fadmin'); expect(resetPasswordResult.returnTo).toBe('/dashboard?redirect=%2Fadmin'); }); }); });