mirror of
https://github.com/colanode/colanode.git
synced 2026-07-10 04:19:19 +02:00
119 lines
2.8 KiB
TypeScript
119 lines
2.8 KiB
TypeScript
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
|
|
import { ApiErrorCode } from '@colanode/core';
|
|
import { database } from '@colanode/server/data/database';
|
|
import { buildTestApp } from '../helpers/app';
|
|
import {
|
|
createAccount,
|
|
createDevice,
|
|
createUser,
|
|
createWorkspace,
|
|
} from '../helpers/seed';
|
|
|
|
const app = buildTestApp();
|
|
|
|
beforeAll(async () => {
|
|
await app.ready();
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await app.close();
|
|
});
|
|
|
|
describe('POST /client/v1/auth/email/login', () => {
|
|
it('returns EmailOrPasswordIncorrect for unknown email', async () => {
|
|
const response = await app.inject({
|
|
method: 'POST',
|
|
url: '/client/v1/auth/email/login',
|
|
payload: {
|
|
email: 'missing@example.com',
|
|
password: 'nope',
|
|
},
|
|
});
|
|
|
|
expect(response.statusCode).toBe(400);
|
|
expect(response.json()).toMatchObject({
|
|
code: ApiErrorCode.EmailOrPasswordIncorrect,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('token lifecycle', () => {
|
|
it('creates a device on login and deletes it on logout', async () => {
|
|
const account = await createAccount({
|
|
email: 'login-user@example.com',
|
|
password: 'Password123!',
|
|
});
|
|
|
|
const workspace = await createWorkspace({
|
|
createdBy: account.id,
|
|
});
|
|
|
|
await createUser({
|
|
workspaceId: workspace.id,
|
|
account,
|
|
role: 'owner',
|
|
});
|
|
|
|
const loginResponse = await app.inject({
|
|
method: 'POST',
|
|
url: '/client/v1/auth/email/login',
|
|
payload: {
|
|
email: account.email,
|
|
password: 'Password123!',
|
|
},
|
|
});
|
|
|
|
expect(loginResponse.statusCode).toBe(200);
|
|
const loginBody = loginResponse.json();
|
|
expect(loginBody).toMatchObject({
|
|
type: 'success',
|
|
account: { id: account.id },
|
|
});
|
|
|
|
const deviceId = loginBody.deviceId as string;
|
|
const token = loginBody.token as string;
|
|
|
|
const device = await database
|
|
.selectFrom('devices')
|
|
.selectAll()
|
|
.where('id', '=', deviceId)
|
|
.executeTakeFirst();
|
|
|
|
expect(device).not.toBeNull();
|
|
|
|
const logoutResponse = await app.inject({
|
|
method: 'DELETE',
|
|
url: '/client/v1/auth/logout',
|
|
headers: {
|
|
authorization: `Bearer ${token}`,
|
|
},
|
|
});
|
|
|
|
expect(logoutResponse.statusCode).toBe(200);
|
|
|
|
const deletedDevice = await database
|
|
.selectFrom('devices')
|
|
.selectAll()
|
|
.where('id', '=', deviceId)
|
|
.executeTakeFirst();
|
|
|
|
expect(deletedDevice).toBeUndefined();
|
|
|
|
const logoutBody = logoutResponse.json();
|
|
expect(logoutBody).toMatchObject({});
|
|
});
|
|
|
|
it('rejects logout without a token', async () => {
|
|
const logoutResponse = await app.inject({
|
|
method: 'DELETE',
|
|
url: '/client/v1/auth/logout',
|
|
});
|
|
|
|
expect(logoutResponse.statusCode).toBe(401);
|
|
expect(logoutResponse.json()).toMatchObject({
|
|
code: ApiErrorCode.TokenMissing,
|
|
});
|
|
});
|
|
});
|