Restructure route organization

This commit is contained in:
NeilClack
2026-05-03 20:59:43 -05:00
parent e563a66dc7
commit 3d1d713308
15 changed files with 0 additions and 0 deletions
@@ -0,0 +1,255 @@
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: { update: vi.fn(), findUnique: vi.fn() },
address: { create: vi.fn() }
}
}));
import { prisma } from '$lib/db';
import { load, actions } from './+page.server';
const userFindUnique = prisma.user.findUnique as ReturnType<typeof vi.fn>;
const profileUpdate = prisma.profile.update as ReturnType<typeof vi.fn>;
const profileFindUnique = prisma.profile.findUnique as ReturnType<typeof vi.fn>;
const addressCreate = prisma.address.create as ReturnType<typeof vi.fn>;
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();
profileUpdate.mockReset();
profileFindUnique.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 user = mockUserWithProfileAndAddresses();
userFindUnique.mockResolvedValue(user);
const locals = createLocals(mockUser() as any);
const result = (await load({ locals } as any)) as any;
expect(result.user).toEqual(user);
expect(result.user.profile.addresses).toHaveLength(1);
});
it('includes addresses in the query', async () => {
userFindUnique.mockResolvedValue(mockUserWithProfileAndAddresses());
const locals = createLocals(mockUser() as any);
await load({ locals } as any);
expect(userFindUnique).toHaveBeenCalledWith({
where: { id: 'user-1' },
include: { profile: { 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 () => {
profileUpdate.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(profileUpdate).toHaveBeenCalledWith({
where: { userId: 'user-1' },
data: { firstName: 'Jane', lastName: 'Smith', phoneNumber: '8175551234' }
});
});
it('returns fail(500) when prisma update throws', async () => {
profileUpdate.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 () => {
profileFindUnique.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 () => {
profileFindUnique.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 () => {
profileFindUnique.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);
});
});
});