admin: Superforms + Zod validation, three-address-defaults schema, profiles toast fix

- Add Superforms + Zod 4 for all admin form validation
- Replace address isDefault with three separate boolean defaults (Mailing, Billing, Shipping)
- Update profiles page with three-checkbox address form and toast improvements
- Convert all admin page server actions to pass request directly to crud
- Export superFormErrorsToFieldErrors helper for profiles server actions
- Regenerate Prisma client for new schema fields
This commit is contained in:
NeilClack
2026-07-07 13:36:23 -05:00
parent 38347f5f24
commit 38d1752f5b
98 changed files with 3408 additions and 1758 deletions
+124
View File
@@ -0,0 +1,124 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { createLocals, mockUser } from '$lib/test-utils';
import { getModelConfig } from './registry';
vi.mock('$lib/db', () => ({
prisma: {
userRole: {
findMany: vi.fn(),
create: vi.fn(),
update: vi.fn(),
delete: vi.fn(),
findUnique: vi.fn(),
findFirst: vi.fn()
}
}
}));
import { prisma } from '$lib/db';
import { loadRecords, upsertRecord, deleteRecord } from './crud';
const findMany = prisma.userRole.findMany as ReturnType<typeof vi.fn>;
const create = prisma.userRole.create as ReturnType<typeof vi.fn>;
const update = prisma.userRole.update as ReturnType<typeof vi.fn>;
const deletes = prisma.userRole.delete as ReturnType<typeof vi.fn>;
const findUnique = prisma.userRole.findUnique as ReturnType<typeof vi.fn>;
const findFirst = prisma.userRole.findFirst as ReturnType<typeof vi.fn>;
const config = getModelConfig('user-roles')!;
describe('crud loadRecords', () => {
beforeEach(() => {
findMany.mockReset();
});
it('returns records', async () => {
findMany.mockResolvedValue([{ id: 1, name: 'Admin' }]);
const locals = createLocals(mockUser() as any);
const result = await loadRecords(locals, config);
expect(result.records).toEqual([{ id: 1, name: 'Admin' }]);
});
it('returns empty records array', async () => {
findMany.mockResolvedValue([]);
const locals = createLocals(mockUser() as any);
const result = await loadRecords(locals, config);
expect(result.records).toEqual([]);
});
});
describe('crud upsertRecord', () => {
beforeEach(() => {
create.mockReset();
update.mockReset();
findUnique.mockReset();
findFirst.mockReset();
});
it('creates a new record when no id', async () => {
create.mockResolvedValue({ id: 2, name: 'Editor' });
const fd = new FormData();
fd.set('name', 'Editor');
const locals = createLocals(mockUser() as any);
const result = await upsertRecord(fd, config, locals);
expect(create).toHaveBeenCalledWith({ data: { name: 'Editor' } });
expect(result).toEqual({ success: true });
});
it('updates an existing record when id is present', async () => {
findUnique.mockResolvedValue({ id: 1, name: 'Old Name' });
const fd = new FormData();
fd.set('id', '1');
fd.set('name', 'New Name');
const locals = createLocals(mockUser() as any);
const result = await upsertRecord(fd, config, locals);
expect(update).toHaveBeenCalledWith({ where: { id: 1 }, data: { name: 'New Name' } });
expect(result).toEqual({ success: true });
});
it('returns error when updating non-existent record', async () => {
findUnique.mockResolvedValue(null);
const fd = new FormData();
fd.set('id', '999');
fd.set('name', 'Ghost');
const locals = createLocals(mockUser() as any);
const result = await upsertRecord(fd, config, locals);
expect(result).toEqual({ success: false, error: 'Record not found' });
});
});
describe('crud deleteRecord', () => {
beforeEach(() => {
deletes.mockReset();
});
it('deletes a record by id', async () => {
deletes.mockResolvedValue({ id: 1, name: 'Admin' });
const fd = new FormData();
fd.set('id', '1');
const locals = createLocals(mockUser() as any);
const result = await deleteRecord(fd, config, locals);
expect(deletes).toHaveBeenCalledWith({ where: { id: 1 } });
expect(result).toEqual({ success: true });
});
it('returns error when id is missing', async () => {
const fd = new FormData();
const locals = createLocals(mockUser() as any);
const result = await deleteRecord(fd, config, locals);
expect(result).toEqual({ success: false, error: 'Missing id' });
});
});