test(api): centralize auth helpers on server-side createUser

This commit is contained in:
Bas van Rossem
2026-06-17 17:29:46 +02:00
parent 8bfdfb736e
commit f6bd8eb036
5 changed files with 72 additions and 110 deletions

View File

@@ -1,45 +1,12 @@
import { describe, it, expect } from 'vitest';
import type { Hono } from 'hono';
import { createApp } from '../src/app';
import { db } from '../src/db/client';
import { workSessions } from '../src/db/schema';
import { eq } from 'drizzle-orm';
import { authToken, bearer, seedActivity } from './helpers';
const json = { 'content-type': 'application/json' };
// Sign up + sign in a user, returning the bearer token.
async function authToken(app: Hono, email: string): Promise<string> {
const password = 'sterk-wachtwoord-123';
await app.request('/api/auth/sign-up/email', {
method: 'POST',
headers: json,
body: JSON.stringify({ email, password, name: email.split('@')[0] }),
});
const signin = await app.request('/api/auth/sign-in/email', {
method: 'POST',
headers: json,
body: JSON.stringify({ email, password }),
});
const token = signin.headers.get('set-auth-token');
if (!token) throw new Error('no token');
return token;
}
function bearer(token: string): Record<string, string> {
return { authorization: `Bearer ${token}`, 'content-type': 'application/json' };
}
// Create an activity via the API and return its id.
async function createActivity(app: Hono, token: string, name: string): Promise<number> {
const res = await app.request('/api/activities', {
method: 'POST',
headers: bearer(token),
body: JSON.stringify({ name, insole_types: ['Kurk', 'Berk', '3D'] }),
});
const body = await res.json();
return body.id as number;
}
describe('session lifecycle', () => {
it('401s start/stop/discard without a token', async () => {
const app = createApp();
@@ -61,7 +28,7 @@ describe('session lifecycle', () => {
it('starts an active session', async () => {
const app = createApp();
const token = await authToken(app, 'sess-start@example.com');
const activityId = await createActivity(app, token, 'Frezen');
const activityId = await seedActivity('Frezen');
const res = await app.request('/api/sessions/start', {
method: 'POST',
@@ -109,7 +76,7 @@ describe('session lifecycle', () => {
it('completes a session and computes duration', async () => {
const app = createApp();
const token = await authToken(app, 'sess-complete@example.com');
const activityId = await createActivity(app, token, 'Slijpen');
const activityId = await seedActivity('Slijpen');
const startRes = await app.request('/api/sessions/start', {
method: 'POST',
@@ -138,7 +105,7 @@ describe('session lifecycle', () => {
it('409s stopping an already-completed session', async () => {
const app = createApp();
const token = await authToken(app, 'sess-doublestop@example.com');
const activityId = await createActivity(app, token, 'Bekleden');
const activityId = await seedActivity('Bekleden');
const startRes = await app.request('/api/sessions/start', {
method: 'POST',
@@ -163,7 +130,7 @@ describe('session lifecycle', () => {
it('discards an active session', async () => {
const app = createApp();
const token = await authToken(app, 'sess-discard@example.com');
const activityId = await createActivity(app, token, 'Afwerken');
const activityId = await seedActivity('Afwerken');
const startRes = await app.request('/api/sessions/start', {
method: 'POST',
@@ -186,7 +153,7 @@ describe('session lifecycle', () => {
const app = createApp();
const tokenA = await authToken(app, 'sess-ownerA@example.com');
const tokenB = await authToken(app, 'sess-ownerB@example.com');
const activityId = await createActivity(app, tokenA, 'Printen');
const activityId = await seedActivity('Printen');
const startRes = await app.request('/api/sessions/start', {
method: 'POST',
@@ -222,8 +189,8 @@ describe('session reads', () => {
it("returns the user's sessions joined with activity name, newest first", async () => {
const app = createApp();
const token = await authToken(app, 'reads-history@example.com');
const frezenId = await createActivity(app, token, 'Frezen');
const slijpenId = await createActivity(app, token, 'Slijpen');
const frezenId = await seedActivity('Frezen');
const slijpenId = await seedActivity('Slijpen');
const firstRes = await app.request('/api/sessions/start', {
method: 'POST',
@@ -263,7 +230,7 @@ describe('session reads', () => {
const app = createApp();
const tokenA = await authToken(app, 'reads-scopeA@example.com');
const tokenB = await authToken(app, 'reads-scopeB@example.com');
const activityId = await createActivity(app, tokenA, 'Bekleden');
const activityId = await seedActivity('Bekleden');
const startRes = await app.request('/api/sessions/start', {
method: 'POST',
@@ -282,7 +249,7 @@ describe('session reads', () => {
it('returns only active sessions from /api/sessions/active', async () => {
const app = createApp();
const token = await authToken(app, 'reads-active@example.com');
const activityId = await createActivity(app, token, 'Afwerken');
const activityId = await seedActivity('Afwerken');
// One session stays active.
const activeRes = await app.request('/api/sessions/start', {