mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-02 20:30:10 +00:00
test(auth): add tests for token authentication
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Component: Admin User Login Token Tests
|
||||
* Documentation: documentation/testing.md
|
||||
*/
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { createPrismaMock } from '../helpers/prisma';
|
||||
|
||||
let authRequest: any;
|
||||
|
||||
const prismaMock = createPrismaMock();
|
||||
const requireAuthMock = vi.hoisted(() => vi.fn());
|
||||
const requireAdminMock = vi.hoisted(() => vi.fn());
|
||||
const generateApiTokenMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('@/lib/db', () => ({
|
||||
prisma: prismaMock,
|
||||
}));
|
||||
|
||||
vi.mock('@/lib/middleware/auth', () => ({
|
||||
requireAuth: requireAuthMock,
|
||||
requireAdmin: requireAdminMock,
|
||||
}));
|
||||
|
||||
vi.mock('@/lib/utils/api-token', () => ({
|
||||
generateApiToken: generateApiTokenMock,
|
||||
}));
|
||||
|
||||
describe('Admin login token routes', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
authRequest = { user: { id: 'admin-1', username: 'admin', role: 'admin' }, json: vi.fn() };
|
||||
requireAuthMock.mockImplementation((_req: any, handler: any) => handler(authRequest));
|
||||
requireAdminMock.mockImplementation((_req: any, handler: any) => handler());
|
||||
generateApiTokenMock.mockReturnValue({ fullToken: 'rmab_test_token' });
|
||||
});
|
||||
|
||||
describe('POST /api/admin/users/[id]/login-token', () => {
|
||||
it('generates a login token for an active user', async () => {
|
||||
prismaMock.user.findUnique.mockResolvedValueOnce({
|
||||
plexUsername: 'testuser',
|
||||
deletedAt: null,
|
||||
});
|
||||
prismaMock.user.update.mockResolvedValueOnce({});
|
||||
|
||||
const { POST } = await import('@/app/api/admin/users/[id]/login-token/route');
|
||||
const response = await POST({} as any, { params: Promise.resolve({ id: 'u1' }) });
|
||||
const payload = await response.json();
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
expect(payload.fullToken).toBe('rmab_test_token');
|
||||
});
|
||||
|
||||
it('returns 404 when user does not exist', async () => {
|
||||
prismaMock.user.findUnique.mockResolvedValueOnce(null);
|
||||
|
||||
const { POST } = await import('@/app/api/admin/users/[id]/login-token/route');
|
||||
const response = await POST({} as any, { params: Promise.resolve({ id: 'missing' }) });
|
||||
const payload = await response.json();
|
||||
|
||||
expect(response.status).toBe(404);
|
||||
expect(payload.error).toMatch(/User not found/);
|
||||
});
|
||||
|
||||
it('returns 403 when user is deleted', async () => {
|
||||
prismaMock.user.findUnique.mockResolvedValueOnce({
|
||||
plexUsername: 'deleteduser',
|
||||
deletedAt: new Date(),
|
||||
});
|
||||
|
||||
const { POST } = await import('@/app/api/admin/users/[id]/login-token/route');
|
||||
const response = await POST({} as any, { params: Promise.resolve({ id: 'u2' }) });
|
||||
const payload = await response.json();
|
||||
|
||||
expect(response.status).toBe(403);
|
||||
expect(payload.error).toMatch(/deleted user/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE /api/admin/users/[id]/login-token', () => {
|
||||
it('revokes the login token for a user', async () => {
|
||||
prismaMock.user.findUnique.mockResolvedValueOnce({
|
||||
plexUsername: 'testuser',
|
||||
});
|
||||
prismaMock.user.update.mockResolvedValueOnce({});
|
||||
|
||||
const { DELETE } = await import('@/app/api/admin/users/[id]/login-token/route');
|
||||
const response = await DELETE({} as any, { params: Promise.resolve({ id: 'u1' }) });
|
||||
const payload = await response.json();
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(payload.success).toBe(true);
|
||||
});
|
||||
|
||||
it('returns 404 when user does not exist', async () => {
|
||||
prismaMock.user.findUnique.mockResolvedValueOnce(null);
|
||||
|
||||
const { DELETE } = await import('@/app/api/admin/users/[id]/login-token/route');
|
||||
const response = await DELETE({} as any, { params: Promise.resolve({ id: 'missing' }) });
|
||||
const payload = await response.json();
|
||||
|
||||
expect(response.status).toBe(404);
|
||||
expect(payload.error).toMatch(/User not found/);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Component: Token Login Route Tests
|
||||
* Documentation: documentation/testing.md
|
||||
*/
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { createPrismaMock } from '../helpers/prisma';
|
||||
|
||||
const prismaMock = createPrismaMock();
|
||||
const generateAccessTokenMock = vi.hoisted(() => vi.fn());
|
||||
const generateRefreshTokenMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('@/lib/db', () => ({
|
||||
prisma: prismaMock,
|
||||
}));
|
||||
|
||||
vi.mock('@/lib/utils/jwt', () => ({
|
||||
generateAccessToken: generateAccessTokenMock,
|
||||
generateRefreshToken: generateRefreshTokenMock,
|
||||
}));
|
||||
|
||||
describe('GET /api/auth/token/login', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
generateAccessTokenMock.mockReturnValue('access-token');
|
||||
generateRefreshTokenMock.mockReturnValue('refresh-token');
|
||||
});
|
||||
|
||||
it('authenticates user with a valid token', async () => {
|
||||
prismaMock.user.findFirst.mockResolvedValueOnce({
|
||||
id: 'u1',
|
||||
plexId: 'plex-1',
|
||||
plexUsername: 'testuser',
|
||||
plexEmail: 'test@example.com',
|
||||
avatarUrl: null,
|
||||
role: 'user',
|
||||
});
|
||||
prismaMock.user.update.mockResolvedValueOnce({});
|
||||
|
||||
const { GET } = await import('@/app/api/auth/token/login/route');
|
||||
const request = { nextUrl: { searchParams: new URLSearchParams('token=rmab_valid_token') } };
|
||||
const response = await GET(request as any);
|
||||
const payload = await response.json();
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(payload.accessToken).toBe('access-token');
|
||||
expect(payload.refreshToken).toBe('refresh-token');
|
||||
expect(payload.user.username).toBe('testuser');
|
||||
expect(payload.user.email).toBe('test@example.com');
|
||||
});
|
||||
|
||||
it('returns 400 when token parameter is missing', async () => {
|
||||
const { GET } = await import('@/app/api/auth/token/login/route');
|
||||
const request = { nextUrl: { searchParams: new URLSearchParams() } };
|
||||
const response = await GET(request as any);
|
||||
const payload = await response.json();
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(payload.error).toMatch(/Missing token/);
|
||||
});
|
||||
|
||||
it('returns 401 when token is invalid or user not found', async () => {
|
||||
prismaMock.user.findFirst.mockResolvedValueOnce(null);
|
||||
|
||||
const { GET } = await import('@/app/api/auth/token/login/route');
|
||||
const request = { nextUrl: { searchParams: new URLSearchParams('token=rmab_invalid') } };
|
||||
const response = await GET(request as any);
|
||||
const payload = await response.json();
|
||||
|
||||
expect(response.status).toBe(401);
|
||||
expect(payload.error).toMatch(/Invalid token/);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user