test: add unit tests for all auth backend logic

- Register: edge cases for non-Error throws, error message assertions,
  and verify signUpEmail was called with correct payload
- Forgot-password: empty/missing email, Error/non-Error throws
- Reset-password: load (missing/expired/valid token) and action (short
  password, mismatch, throw, success redirect)
- Account setup: load (unauthorized, returns user), action (redirect,
  falsy create, throws, isRedirect passthrough)
- Email-verification: correct URL construction, sendMail delegation,
  throw propagation
- Hooks: sets/omits locals, passes building/auth to svelteKitHandler
- Fix Svelte 5  warning on setup page by using  with
  one-time guard instead of top-level prop read
This commit is contained in:
NeilClack
2026-07-07 09:22:56 -05:00
parent 1e391c9252
commit 6ff8e878a4
7 changed files with 670 additions and 5 deletions
@@ -0,0 +1,102 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { isActionFailure } from '@sveltejs/kit';
import { createFormRequest } from '$lib/test-utils';
const { requestPasswordReset } = vi.hoisted(() => ({
requestPasswordReset: vi.fn()
}));
vi.mock('$lib/db', () => ({
prisma: {}
}));
vi.mock('$lib/auth', () => ({
auth: {
api: {
requestPasswordReset
}
}
}));
import { actions } from './+page.server';
const invokeDefault = (request: Request) => actions.default({ request } as any);
describe('forgot-password page server action', () => {
beforeEach(() => {
requestPasswordReset.mockReset();
});
it('returns fail(400) when email is empty', async () => {
const request = createFormRequest({ email: '' });
const result = await invokeDefault(request);
expect(isActionFailure(result)).toBe(true);
if (isActionFailure(result)) {
expect(result.data).toEqual({ error: 'Email is required.' });
}
expect(requestPasswordReset).not.toHaveBeenCalled();
});
it('returns fail(400) when email is missing from form', async () => {
const request = createFormRequest({});
const result = await invokeDefault(request);
expect(isActionFailure(result)).toBe(true);
if (isActionFailure(result)) {
expect(result.data).toEqual({ error: 'Email is required.' });
}
expect(requestPasswordReset).not.toHaveBeenCalled();
});
it('returns success on successful request', async () => {
requestPasswordReset.mockResolvedValue(undefined);
const request = createFormRequest({ email: 'jane@example.com' });
const result = await invokeDefault(request);
expect(result).toEqual({ success: true });
expect(requestPasswordReset).toHaveBeenCalledWith({
body: {
email: 'jane@example.com',
redirectTo: '/reset-password'
}
});
});
it('returns fail(400) with error message when requestPasswordReset throws', async () => {
requestPasswordReset.mockRejectedValue(new Error('User not found'));
const request = createFormRequest({ email: 'jane@example.com' });
const result = await invokeDefault(request);
expect(isActionFailure(result)).toBe(true);
if (isActionFailure(result)) {
expect(result.data).toEqual({ error: 'User not found' });
}
});
it('returns fail(400) with default message when non-Error is thrown', async () => {
requestPasswordReset.mockRejectedValue('unexpected');
const request = createFormRequest({ email: 'jane@example.com' });
const result = await invokeDefault(request);
expect(isActionFailure(result)).toBe(true);
if (isActionFailure(result)) {
expect(result.data).toEqual({ error: 'Failed to send reset email.' });
}
});
it('returns fail(400) with default message when thrown value is null', async () => {
requestPasswordReset.mockRejectedValue(null);
const request = createFormRequest({ email: 'jane@example.com' });
const result = await invokeDefault(request);
expect(isActionFailure(result)).toBe(true);
if (isActionFailure(result)) {
expect(result.data).toEqual({ error: 'Failed to send reset email.' });
}
});
});