Files
gridpilot.gg/apps/website/tests/services/auth/AuthPageService.test.ts
Marc Mintel fb1221701d
Some checks failed
Contract Testing / contract-tests (push) Failing after 6m7s
Contract Testing / contract-snapshot (push) Failing after 4m46s
add tests
2026-01-22 11:52:42 +01:00

621 lines
19 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { AuthPageService } from '@/lib/services/auth/AuthPageService';
import { AuthPageParams } from '@/lib/services/auth/AuthPageParams';
import { LoginPageDTO } from '@/lib/services/auth/types/LoginPageDTO';
import { ForgotPasswordPageDTO } from '@/lib/services/auth/types/ForgotPasswordPageDTO';
import { ResetPasswordPageDTO } from '@/lib/services/auth/types/ResetPasswordPageDTO';
import { SignupPageDTO } from '@/lib/services/auth/types/SignupPageDTO';
describe('AuthPageService', () => {
let service: AuthPageService;
beforeEach(() => {
service = new AuthPageService();
});
describe('processLoginParams', () => {
describe('happy paths', () => {
it('should process login params with returnTo', async () => {
const params: AuthPageParams = {
returnTo: '/dashboard',
};
const result = await service.processLoginParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe('/dashboard');
expect(dto.hasInsufficientPermissions).toBe(true);
});
it('should process login params with null returnTo', async () => {
const params: AuthPageParams = {
returnTo: null,
};
const result = await service.processLoginParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe('/dashboard');
expect(dto.hasInsufficientPermissions).toBe(false);
});
it('should process login params with undefined returnTo', async () => {
const params: AuthPageParams = {};
const result = await service.processLoginParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe('/dashboard');
expect(dto.hasInsufficientPermissions).toBe(false);
});
it('should process login params with empty string returnTo', async () => {
const params: AuthPageParams = {
returnTo: '',
};
const result = await service.processLoginParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe('');
expect(dto.hasInsufficientPermissions).toBe(true);
});
});
describe('decision branches', () => {
it('should handle different returnTo paths', async () => {
const paths = [
'/dashboard',
'/settings',
'/profile',
'/admin',
'/projects/123',
'/projects/123/tasks',
];
for (const path of paths) {
const params: AuthPageParams = {
returnTo: path,
};
const result = await service.processLoginParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe(path);
expect(dto.hasInsufficientPermissions).toBe(true);
}
});
it('should handle special characters in returnTo path', async () => {
const paths = [
'/dashboard?param=value',
'/dashboard#section',
'/dashboard/with/slashes',
'/dashboard/with-dashes',
'/dashboard/with_underscores',
];
for (const path of paths) {
const params: AuthPageParams = {
returnTo: path,
};
const result = await service.processLoginParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe(path);
expect(dto.hasInsufficientPermissions).toBe(true);
}
});
it('should handle different returnTo values and hasInsufficientPermissions', async () => {
const testCases = [
{ returnTo: '/dashboard', expectedHasInsufficientPermissions: true },
{ returnTo: null, expectedHasInsufficientPermissions: false },
{ returnTo: undefined, expectedHasInsufficientPermissions: false },
{ returnTo: '', expectedHasInsufficientPermissions: true },
];
for (const testCase of testCases) {
const params: AuthPageParams = {
returnTo: testCase.returnTo as string | null | undefined,
};
const result = await service.processLoginParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.hasInsufficientPermissions).toBe(testCase.expectedHasInsufficientPermissions);
}
});
});
describe('aggregation logic', () => {
it('should aggregate login params into DTO correctly', async () => {
const params: AuthPageParams = {
returnTo: '/dashboard',
};
const result = await service.processLoginParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
// Verify all fields are correctly aggregated
expect(dto.returnTo).toBe('/dashboard');
expect(dto.hasInsufficientPermissions).toBe(true);
expect(typeof dto.returnTo).toBe('string');
expect(typeof dto.hasInsufficientPermissions).toBe('boolean');
});
it('should handle empty params object', async () => {
const params: AuthPageParams = {};
const result = await service.processLoginParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
// Verify default values are used
expect(dto.returnTo).toBe('/dashboard');
expect(dto.hasInsufficientPermissions).toBe(false);
});
});
});
describe('processForgotPasswordParams', () => {
describe('happy paths', () => {
it('should process forgot password params with returnTo', async () => {
const params: AuthPageParams = {
returnTo: '/auth/login',
};
const result = await service.processForgotPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe('/auth/login');
});
it('should process forgot password params with null returnTo', async () => {
const params: AuthPageParams = {
returnTo: null,
};
const result = await service.processForgotPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe('/auth/login');
});
it('should process forgot password params with undefined returnTo', async () => {
const params: AuthPageParams = {};
const result = await service.processForgotPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe('/auth/login');
});
});
describe('decision branches', () => {
it('should handle different returnTo paths', async () => {
const paths = [
'/auth/login',
'/auth/signup',
'/dashboard',
'/settings',
];
for (const path of paths) {
const params: AuthPageParams = {
returnTo: path,
};
const result = await service.processForgotPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe(path);
}
});
it('should handle special characters in returnTo path', async () => {
const paths = [
'/auth/login?param=value',
'/auth/login#section',
'/auth/login/with/slashes',
];
for (const path of paths) {
const params: AuthPageParams = {
returnTo: path,
};
const result = await service.processForgotPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe(path);
}
});
});
describe('aggregation logic', () => {
it('should aggregate forgot password params into DTO correctly', async () => {
const params: AuthPageParams = {
returnTo: '/auth/login',
};
const result = await service.processForgotPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
// Verify all fields are correctly aggregated
expect(dto.returnTo).toBe('/auth/login');
expect(typeof dto.returnTo).toBe('string');
});
it('should handle empty params object', async () => {
const params: AuthPageParams = {};
const result = await service.processForgotPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
// Verify default values are used
expect(dto.returnTo).toBe('/auth/login');
});
});
});
describe('processResetPasswordParams', () => {
describe('happy paths', () => {
it('should process reset password params with token and returnTo', async () => {
const params: AuthPageParams = {
token: 'reset-token-123',
returnTo: '/auth/login',
};
const result = await service.processResetPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.token).toBe('reset-token-123');
expect(dto.returnTo).toBe('/auth/login');
});
it('should process reset password params with token and null returnTo', async () => {
const params: AuthPageParams = {
token: 'reset-token-123',
returnTo: null,
};
const result = await service.processResetPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.token).toBe('reset-token-123');
expect(dto.returnTo).toBe('/auth/login');
});
it('should process reset password params with token and undefined returnTo', async () => {
const params: AuthPageParams = {
token: 'reset-token-123',
};
const result = await service.processResetPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.token).toBe('reset-token-123');
expect(dto.returnTo).toBe('/auth/login');
});
});
describe('failure modes', () => {
it('should return error when token is missing', async () => {
const params: AuthPageParams = {
returnTo: '/auth/login',
};
const result = await service.processResetPasswordParams(params);
expect(result.isErr()).toBe(true);
expect(result.getError().type).toBe('validation');
expect(result.getError().message).toBe('Missing reset token');
});
it('should return error when token is null', async () => {
const params: AuthPageParams = {
token: null,
returnTo: '/auth/login',
};
const result = await service.processResetPasswordParams(params);
expect(result.isErr()).toBe(true);
expect(result.getError().type).toBe('validation');
expect(result.getError().message).toBe('Missing reset token');
});
it('should return error when token is empty string', async () => {
const params: AuthPageParams = {
token: '',
returnTo: '/auth/login',
};
const result = await service.processResetPasswordParams(params);
expect(result.isErr()).toBe(true);
expect(result.getError().type).toBe('validation');
expect(result.getError().message).toBe('Missing reset token');
});
});
describe('decision branches', () => {
it('should handle different token formats', async () => {
const tokens = [
'reset-token-123',
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
'token-with-special-chars-!@#$%^&*()',
];
for (const token of tokens) {
const params: AuthPageParams = {
token,
returnTo: '/auth/login',
};
const result = await service.processResetPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.token).toBe(token);
}
});
it('should handle different returnTo paths', async () => {
const paths = [
'/auth/login',
'/auth/signup',
'/dashboard',
'/settings',
];
for (const path of paths) {
const params: AuthPageParams = {
token: 'reset-token-123',
returnTo: path,
};
const result = await service.processResetPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe(path);
}
});
it('should handle special characters in returnTo path', async () => {
const paths = [
'/auth/login?param=value',
'/auth/login#section',
'/auth/login/with/slashes',
];
for (const path of paths) {
const params: AuthPageParams = {
token: 'reset-token-123',
returnTo: path,
};
const result = await service.processResetPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe(path);
}
});
});
describe('aggregation logic', () => {
it('should aggregate reset password params into DTO correctly', async () => {
const params: AuthPageParams = {
token: 'reset-token-123',
returnTo: '/auth/login',
};
const result = await service.processResetPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
// Verify all fields are correctly aggregated
expect(dto.token).toBe('reset-token-123');
expect(dto.returnTo).toBe('/auth/login');
expect(typeof dto.token).toBe('string');
expect(typeof dto.returnTo).toBe('string');
});
it('should handle params with only token', async () => {
const params: AuthPageParams = {
token: 'reset-token-123',
};
const result = await service.processResetPasswordParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
// Verify default returnTo is used
expect(dto.token).toBe('reset-token-123');
expect(dto.returnTo).toBe('/auth/login');
});
});
});
describe('processSignupParams', () => {
describe('happy paths', () => {
it('should process signup params with returnTo', async () => {
const params: AuthPageParams = {
returnTo: '/onboarding',
};
const result = await service.processSignupParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe('/onboarding');
});
it('should process signup params with null returnTo', async () => {
const params: AuthPageParams = {
returnTo: null,
};
const result = await service.processSignupParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe('/onboarding');
});
it('should process signup params with undefined returnTo', async () => {
const params: AuthPageParams = {};
const result = await service.processSignupParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe('/onboarding');
});
});
describe('decision branches', () => {
it('should handle different returnTo paths', async () => {
const paths = [
'/onboarding',
'/dashboard',
'/settings',
'/projects',
];
for (const path of paths) {
const params: AuthPageParams = {
returnTo: path,
};
const result = await service.processSignupParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe(path);
}
});
it('should handle special characters in returnTo path', async () => {
const paths = [
'/onboarding?param=value',
'/onboarding#section',
'/onboarding/with/slashes',
];
for (const path of paths) {
const params: AuthPageParams = {
returnTo: path,
};
const result = await service.processSignupParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
expect(dto.returnTo).toBe(path);
}
});
});
describe('aggregation logic', () => {
it('should aggregate signup params into DTO correctly', async () => {
const params: AuthPageParams = {
returnTo: '/onboarding',
};
const result = await service.processSignupParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
// Verify all fields are correctly aggregated
expect(dto.returnTo).toBe('/onboarding');
expect(typeof dto.returnTo).toBe('string');
});
it('should handle empty params object', async () => {
const params: AuthPageParams = {};
const result = await service.processSignupParams(params);
expect(result.isOk()).toBe(true);
const dto = result.unwrap();
// Verify default values are used
expect(dto.returnTo).toBe('/onboarding');
});
});
});
describe('error handling', () => {
it('should handle unexpected error types in processLoginParams', async () => {
const params: AuthPageParams = {
returnTo: '/dashboard',
};
// This should not throw an error
const result = await service.processLoginParams(params);
expect(result.isOk()).toBe(true);
});
it('should handle unexpected error types in processForgotPasswordParams', async () => {
const params: AuthPageParams = {
returnTo: '/auth/login',
};
// This should not throw an error
const result = await service.processForgotPasswordParams(params);
expect(result.isOk()).toBe(true);
});
it('should handle unexpected error types in processResetPasswordParams', async () => {
const params: AuthPageParams = {
token: 'reset-token-123',
returnTo: '/auth/login',
};
// This should not throw an error
const result = await service.processResetPasswordParams(params);
expect(result.isOk()).toBe(true);
});
it('should handle unexpected error types in processSignupParams', async () => {
const params: AuthPageParams = {
returnTo: '/onboarding',
};
// This should not throw an error
const result = await service.processSignupParams(params);
expect(result.isOk()).toBe(true);
});
});
});