import { describe, it, expect, vi, beforeEach } from 'vitest'; import { isHttpError, isActionFailure } from '@sveltejs/kit'; import { createLocals, createFormRequest, mockUser, mockUserWithProfileAndAddresses } from '$lib/test-utils'; vi.mock('$lib/db', () => ({ prisma: { user: { findUnique: vi.fn() }, profile: { findFirst: vi.fn(), updateMany: vi.fn() }, address: { create: vi.fn() } } })); import { prisma } from '$lib/db'; import { load, actions } from './+page.server'; const userFindUnique = prisma.user.findUnique as ReturnType; const profileFindFirst = prisma.profile.findFirst as ReturnType; const profileUpdateMany = prisma.profile.updateMany as ReturnType; const addressCreate = prisma.address.create as ReturnType; const invokeAction = (name: string, request: Request, locals: App.Locals) => (actions as any)[name]({ request, locals } as any); describe('(protected)/account page server', () => { beforeEach(() => { userFindUnique.mockReset(); profileFindFirst.mockReset(); profileUpdateMany.mockReset(); addressCreate.mockReset(); }); describe('load', () => { it('throws 403 when locals.user is undefined', async () => { const err = await Promise.resolve(load({ locals: createLocals() } as any)).catch( (e: unknown) => e ); expect(isHttpError(err, 403)).toBe(true); }); it('throws 403 when user is not found in the database', async () => { userFindUnique.mockResolvedValue(null); const locals = createLocals(mockUser() as any); const err = await Promise.resolve(load({ locals } as any)).catch((e: unknown) => e); expect(isHttpError(err, 403)).toBe(true); }); it('returns user with profile and addresses', async () => { const { profile, ...user } = mockUserWithProfileAndAddresses() as any; userFindUnique.mockResolvedValue(user); profileFindFirst.mockResolvedValue(profile); const locals = createLocals(mockUser() as any); const result = (await load({ locals } as any)) as any; expect(result.user).toEqual({ ...user, profile }); expect(result.user.profile.addresses).toHaveLength(1); }); it('loads the profile with addresses by user id', async () => { userFindUnique.mockResolvedValue(mockUser()); profileFindFirst.mockResolvedValue({ id: 'profile-1' }); const locals = createLocals(mockUser() as any); await load({ locals } as any); expect(profileFindFirst).toHaveBeenCalledWith({ where: { userId: 'user-1' }, include: { addresses: true } }); }); }); describe('updateProfile action', () => { it('throws 403 when locals.user is undefined', async () => { const request = createFormRequest({ firstName: 'Jane', lastName: 'Doe', phoneNumber: '(555) 010-0100' }); const err = await Promise.resolve( invokeAction('updateProfile', request, createLocals()) ).catch((e: unknown) => e); expect(isHttpError(err, 403)).toBe(true); }); it('returns fail(400) when firstName is missing', async () => { const request = createFormRequest({ firstName: '', lastName: 'Doe', phoneNumber: '(555) 010-0100' }); const locals = createLocals(mockUser() as any); const result = await invokeAction('updateProfile', request, locals); expect(isActionFailure(result)).toBe(true); expect((result as any).data.error).toBe('All fields are required.'); }); it('returns fail(400) when lastName is missing', async () => { const request = createFormRequest({ firstName: 'Jane', lastName: '', phoneNumber: '(555) 010-0100' }); const locals = createLocals(mockUser() as any); const result = await invokeAction('updateProfile', request, locals); expect(isActionFailure(result)).toBe(true); }); it('returns fail(400) when phoneNumber is missing', async () => { const request = createFormRequest({ firstName: 'Jane', lastName: 'Doe', phoneNumber: '' }); const locals = createLocals(mockUser() as any); const result = await invokeAction('updateProfile', request, locals); expect(isActionFailure(result)).toBe(true); }); it('updates profile with server-formatted phone number on success', async () => { profileUpdateMany.mockResolvedValue({}); const request = createFormRequest({ firstName: 'Jane', lastName: 'Smith', phoneNumber: '(817) 555-1234' }); const locals = createLocals(mockUser() as any); const result = await invokeAction('updateProfile', request, locals); expect(result).toEqual({ success: true, action: 'updateProfile' }); expect(profileUpdateMany).toHaveBeenCalledWith({ where: { userId: 'user-1' }, data: { firstName: 'Jane', lastName: 'Smith', phoneNumber: '8175551234' } }); }); it('returns fail(500) when prisma update throws', async () => { profileUpdateMany.mockRejectedValue(new Error('db error')); const request = createFormRequest({ firstName: 'Jane', lastName: 'Doe', phoneNumber: '(555) 010-0100' }); const locals = createLocals(mockUser() as any); const result = await invokeAction('updateProfile', request, locals); expect(isActionFailure(result)).toBe(true); expect((result as any).status).toBe(500); }); }); describe('addAddress action', () => { it('throws 403 when locals.user is undefined', async () => { const request = createFormRequest({ street: '123 Main St', city: 'Dallas', state: 'TX', postalCode: '75001', country: 'US' }); const err = await Promise.resolve(invokeAction('addAddress', request, createLocals())).catch( (e: unknown) => e ); expect(isHttpError(err, 403)).toBe(true); }); it('returns fail(400) when a required field is missing', async () => { const request = createFormRequest({ street: '123 Main St', city: '', state: 'TX', postalCode: '75001', country: 'US' }); const locals = createLocals(mockUser() as any); const result = await invokeAction('addAddress', request, locals); expect(isActionFailure(result)).toBe(true); expect((result as any).data.error).toBe('All address fields are required.'); }); it('throws 400 when profile is not found', async () => { profileFindFirst.mockResolvedValue(null); const request = createFormRequest({ street: '123 Main St', city: 'Dallas', state: 'TX', postalCode: '75001', country: 'US' }); const locals = createLocals(mockUser() as any); const err = await Promise.resolve(invokeAction('addAddress', request, locals)).catch( (e: unknown) => e ); expect(isHttpError(err, 400)).toBe(true); }); it('creates address linked to profile on success', async () => { profileFindFirst.mockResolvedValue({ id: 'profile-1' }); addressCreate.mockResolvedValue({}); const request = createFormRequest({ street: '456 Oak Ave', city: 'Austin', state: 'TX', postalCode: '73301', country: 'US' }); const locals = createLocals(mockUser() as any); const result = await invokeAction('addAddress', request, locals); expect(result).toEqual({ success: true, action: 'addAddress' }); expect(addressCreate).toHaveBeenCalledWith({ data: { profileId: 'profile-1', street: '456 Oak Ave', city: 'Austin', state: 'TX', postalCode: '73301', country: 'US' } }); }); it('returns fail(500) when prisma create throws', async () => { profileFindFirst.mockResolvedValue({ id: 'profile-1' }); addressCreate.mockRejectedValue(new Error('db error')); const request = createFormRequest({ street: '123 Main St', city: 'Dallas', state: 'TX', postalCode: '75001', country: 'US' }); const locals = createLocals(mockUser() as any); const result = await invokeAction('addAddress', request, locals); expect(isActionFailure(result)).toBe(true); expect((result as any).status).toBe(500); }); }); });