refactor: consolidate formatting utilities and add testing infrastructure

- Replace 8 duplicate formatCurrency functions with shared utility
- Add comprehensive formatter utilities (currency, date, number, etc.)
- Set up Vitest for unit testing with 38 passing tests
- Set up Playwright for E2E testing
- Consolidate database connection to single source (src/utils/db.ts)
- Add auth middleware helpers to reduce code duplication
- Fix display bug: remove spurious minus sign in recent activity amounts
- Add path aliases for cleaner imports ($utils, $models)
- Add project documentation (CODEMAP.md, REFACTORING_PLAN.md)

Test coverage: 38 unit tests passing
Build: successful with no breaking changes
This commit is contained in:
2025-11-18 15:24:22 +01:00
parent a2df59f11d
commit 8dd1e3852e
58 changed files with 11127 additions and 131 deletions

View File

@@ -0,0 +1,132 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { requireAuth, optionalAuth } from '$lib/server/middleware/auth';
describe('auth middleware', () => {
describe('requireAuth', () => {
it('should return user when authenticated', async () => {
const mockLocals = {
auth: vi.fn().mockResolvedValue({
user: {
nickname: 'testuser',
name: 'Test User',
email: 'test@example.com',
image: 'https://example.com/avatar.jpg'
}
})
};
const user = await requireAuth(mockLocals as any);
expect(user).toEqual({
nickname: 'testuser',
name: 'Test User',
email: 'test@example.com',
image: 'https://example.com/avatar.jpg'
});
});
it('should throw 401 error when no session', async () => {
const mockLocals = {
auth: vi.fn().mockResolvedValue(null)
};
await expect(requireAuth(mockLocals as any)).rejects.toThrow();
});
it('should throw 401 error when no user in session', async () => {
const mockLocals = {
auth: vi.fn().mockResolvedValue({})
};
await expect(requireAuth(mockLocals as any)).rejects.toThrow();
});
it('should throw 401 error when no nickname in user', async () => {
const mockLocals = {
auth: vi.fn().mockResolvedValue({
user: {
name: 'Test User'
}
})
};
await expect(requireAuth(mockLocals as any)).rejects.toThrow();
});
it('should handle user with only nickname', async () => {
const mockLocals = {
auth: vi.fn().mockResolvedValue({
user: {
nickname: 'testuser'
}
})
};
const user = await requireAuth(mockLocals as any);
expect(user).toEqual({
nickname: 'testuser',
name: undefined,
email: undefined,
image: undefined
});
});
});
describe('optionalAuth', () => {
it('should return user when authenticated', async () => {
const mockLocals = {
auth: vi.fn().mockResolvedValue({
user: {
nickname: 'testuser',
name: 'Test User',
email: 'test@example.com'
}
})
};
const user = await optionalAuth(mockLocals as any);
expect(user).toEqual({
nickname: 'testuser',
name: 'Test User',
email: 'test@example.com',
image: undefined
});
});
it('should return null when no session', async () => {
const mockLocals = {
auth: vi.fn().mockResolvedValue(null)
};
const user = await optionalAuth(mockLocals as any);
expect(user).toBeNull();
});
it('should return null when no user in session', async () => {
const mockLocals = {
auth: vi.fn().mockResolvedValue({})
};
const user = await optionalAuth(mockLocals as any);
expect(user).toBeNull();
});
it('should return null when no nickname in user', async () => {
const mockLocals = {
auth: vi.fn().mockResolvedValue({
user: {
name: 'Test User'
}
})
};
const user = await optionalAuth(mockLocals as any);
expect(user).toBeNull();
});
});
});