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
+109
View File
@@ -0,0 +1,109 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
const { getSession } = vi.hoisted(() => ({
getSession: vi.fn()
}));
const { svelteKitHandler } = vi.hoisted(() => ({
svelteKitHandler: vi.fn()
}));
vi.mock('$app/environment', () => ({
building: false
}));
vi.mock('better-auth/svelte-kit', () => ({
svelteKitHandler
}));
vi.mock('$lib/auth', () => ({
auth: {
api: {
getSession
}
}
}));
import { handle } from './hooks.server';
function createMockEvent() {
return {
request: new Request('http://localhost/dashboard'),
locals: {} as Record<string, unknown>,
resolve: vi.fn()
} as any;
}
describe('hooks.server handle', () => {
beforeEach(() => {
getSession.mockReset();
svelteKitHandler.mockReset();
});
it('sets session and user on locals when authenticated', async () => {
const sessionData = {
session: { id: 'sess-1', userId: 'user-1', expiresAt: new Date() },
user: { id: 'user-1', name: 'Jane', email: 'jane@example.com' }
};
getSession.mockResolvedValue(sessionData);
const event = createMockEvent();
await handle({ event, resolve: event.resolve });
expect(event.locals.session).toEqual(sessionData.session);
expect(event.locals.user).toEqual(sessionData.user);
expect(svelteKitHandler).toHaveBeenCalledWith(
expect.objectContaining({
event,
resolve: event.resolve,
building: false
})
);
});
it('does not set locals when not authenticated', async () => {
getSession.mockResolvedValue(null);
const event = createMockEvent();
await handle({ event, resolve: event.resolve });
expect(event.locals.session).toBeUndefined();
expect(event.locals.user).toBeUndefined();
});
it('does not set locals when getSession returns undefined', async () => {
getSession.mockResolvedValue(undefined);
const event = createMockEvent();
await handle({ event, resolve: event.resolve });
expect(event.locals.session).toBeUndefined();
expect(event.locals.user).toBeUndefined();
});
it('passes building flag from $app/environment to svelteKitHandler', async () => {
getSession.mockResolvedValue(null);
const event = createMockEvent();
await handle({ event, resolve: event.resolve });
expect(svelteKitHandler).toHaveBeenCalledWith(
expect.objectContaining({ building: false })
);
});
it('calls svelteKitHandler with auth instance', async () => {
getSession.mockResolvedValue(null);
const event = createMockEvent();
await handle({ event, resolve: event.resolve });
expect(svelteKitHandler).toHaveBeenCalledWith(
expect.objectContaining({
auth: expect.objectContaining({
api: expect.objectContaining({ getSession })
})
})
);
});
});