test(integration): add real-stack integration test suite with PGlite
- PGlite (in-memory WASM Postgres) hosted in a child process, exposed via TCP socket; real migrations applied with prisma migrate deploy - Vitest harness (vitest.integration.config.ts, global-setup spawns PGlite + built Nuxt server, per-test TRUNCATE, factories, cookie-jar API client); no mocks, zero production code changes - 50 tests across auth, hunt, team, submit, review, showcase, diashow incl. SuperJSON envelope check; *.itest.ts keeps bun test untouched - CI: parallel unit + integration jobs in .github/workflows/test.yml - tests/ covered by nuxt typecheck via tests/tsconfig.json reference
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
import { beforeEach, describe, expect, it } from 'vitest';
|
||||
import { newClient } from '../helpers/api';
|
||||
import { resetDatabase } from '../helpers/database';
|
||||
import { createUser, TEST_PASSWORD } from '../helpers/factories';
|
||||
|
||||
beforeEach(resetDatabase);
|
||||
|
||||
describe('register', () => {
|
||||
it('creates a user and starts a session', async () => {
|
||||
const client = newClient();
|
||||
const res = await client.register(
|
||||
'new-user@test.dev',
|
||||
'New User',
|
||||
'verysecret1'
|
||||
);
|
||||
expect(res.status).toBe(200);
|
||||
const body = await res.json();
|
||||
expect(body.success).toBe(true);
|
||||
expect(body.user.id).toBeTypeOf('number');
|
||||
|
||||
// The register response already carries a session cookie.
|
||||
const profile = await client.get('/api/auth/profile');
|
||||
expect(profile.status).toBe(200);
|
||||
expect(await profile.json()).toMatchObject({
|
||||
name: 'New User',
|
||||
email: 'new-user@test.dev',
|
||||
uploadedFiles: []
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects invalid input with 400', async () => {
|
||||
const client = newClient();
|
||||
// password too short
|
||||
expect(
|
||||
(await client.register('short@test.dev', 'Short', 'short')).status
|
||||
).toBe(400);
|
||||
// invalid email
|
||||
expect(
|
||||
(await client.register('not-an-email', 'NoMail', 'longenough1')).status
|
||||
).toBe(400);
|
||||
// empty name
|
||||
expect(
|
||||
(await client.register('empty@test.dev', '', 'longenough1')).status
|
||||
).toBe(400);
|
||||
});
|
||||
|
||||
it('rejects duplicate email with 409', async () => {
|
||||
await createUser({ email: 'dupe@test.dev' });
|
||||
const client = newClient();
|
||||
const res = await client.register('dupe@test.dev', 'Dupe', 'verysecret1');
|
||||
expect(res.status).toBe(409);
|
||||
});
|
||||
});
|
||||
|
||||
describe('login', () => {
|
||||
it('logs in with correct credentials', async () => {
|
||||
const user = await createUser({ email: 'login@test.dev' });
|
||||
const client = newClient();
|
||||
const res = await client.login('login@test.dev', TEST_PASSWORD);
|
||||
expect(res.status).toBe(200);
|
||||
expect(await res.json()).toEqual({
|
||||
success: true,
|
||||
user: { id: user.id }
|
||||
});
|
||||
|
||||
const profile = await client.get('/api/auth/profile');
|
||||
expect(profile.status).toBe(200);
|
||||
});
|
||||
|
||||
it('rejects wrong password and unknown email with 404', async () => {
|
||||
await createUser({ email: 'known@test.dev' });
|
||||
const client = newClient();
|
||||
expect(
|
||||
(await client.login('known@test.dev', 'wrong-password-1')).status
|
||||
).toBe(404);
|
||||
expect((await client.login('unknown@test.dev', TEST_PASSWORD)).status).toBe(
|
||||
404
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('profile', () => {
|
||||
it('requires a session', async () => {
|
||||
const res = await newClient().get('/api/auth/profile');
|
||||
expect(res.status).toBe(401);
|
||||
});
|
||||
|
||||
it('updates name and email', async () => {
|
||||
await createUser({ email: 'update-me@test.dev' });
|
||||
const client = newClient();
|
||||
await client.login('update-me@test.dev', TEST_PASSWORD);
|
||||
|
||||
const res = await client.post('/api/auth/profile', {
|
||||
name: 'Updated Name',
|
||||
email: 'updated@test.dev'
|
||||
});
|
||||
expect(res.status).toBe(200);
|
||||
expect(await res.json()).toEqual({ ok: true });
|
||||
|
||||
const profile = await client.get('/api/auth/profile');
|
||||
expect(await profile.json()).toMatchObject({
|
||||
name: 'Updated Name',
|
||||
email: 'updated@test.dev'
|
||||
});
|
||||
|
||||
// login works with the new email afterwards
|
||||
expect(
|
||||
(await newClient().login('updated@test.dev', TEST_PASSWORD)).status
|
||||
).toBe(200);
|
||||
});
|
||||
|
||||
it('rejects taking an existing email with 409', async () => {
|
||||
await createUser({ email: 'first@test.dev' });
|
||||
await createUser({ email: 'second@test.dev' });
|
||||
const client = newClient();
|
||||
await client.login('first@test.dev', TEST_PASSWORD);
|
||||
|
||||
const res = await client.post('/api/auth/profile', {
|
||||
name: 'First User',
|
||||
email: 'second@test.dev'
|
||||
});
|
||||
expect(res.status).toBe(409);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user