import { Test, type TestingModule } from '@nestjs/testing'; import type { INestApplication } from '@nestjs/common'; import { ValidationPipe } from '@nestjs/common'; import request from 'supertest'; import cookieParser from 'cookie-parser'; import { AppModule } from '../src/app.module'; import { PrismaService } from '../src/prisma/prisma.service'; describe('Auth (e2e)', () => { let app: INestApplication; let prisma: PrismaService; const SENIOR_EMAIL = 'senior@local'; const SENIOR_PASSWORD = process.env.SEED_PASSWORD_SENIOR ?? 'senior123'; beforeAll(async () => { const module: TestingModule = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = module.createNestApplication(); app.use(cookieParser()); app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true })); await app.init(); prisma = app.get(PrismaService); }); afterAll(async () => { await app.close(); }); it('GET /health is public', async () => { const res = await request(app.getHttpServer()).get('/health'); expect(res.status).toBe(200); expect(res.body.status).toBe('ok'); }); it('GET /auth/me requires auth', async () => { const res = await request(app.getHttpServer()).get('/auth/me'); expect(res.status).toBe(401); }); it('POST /auth/login returns access cookie and userId', async () => { const res = await request(app.getHttpServer()) .post('/auth/login') .send({ email: SENIOR_EMAIL, password: SENIOR_PASSWORD }); expect(res.status).toBe(200); expect(res.body.userId).toBeDefined(); const cookies = (res.headers['set-cookie'] as unknown as string[]) ?? []; expect(cookies.some((c) => c.startsWith('access_token='))).toBe(true); expect(cookies.some((c) => c.startsWith('refresh_token='))).toBe(true); }); it('GET /auth/me with cookie returns user + role', async () => { const loginRes = await request(app.getHttpServer()) .post('/auth/login') .send({ email: SENIOR_EMAIL, password: SENIOR_PASSWORD }); const cookies = (loginRes.headers['set-cookie'] as unknown as string[]) ?? []; const meRes = await request(app.getHttpServer()) .get('/auth/me') .set('Cookie', cookies); expect(meRes.status).toBe(200); expect(meRes.body.email).toBe(SENIOR_EMAIL); expect(meRes.body.role).toBe('SENIOR_ADMIN'); }); it('POST /auth/login with bad password → 401', async () => { const res = await request(app.getHttpServer()) .post('/auth/login') .send({ email: SENIOR_EMAIL, password: 'wrong-password' }); expect(res.status).toBe(401); }); it('POST /auth/logout clears tokens', async () => { const loginRes = await request(app.getHttpServer()) .post('/auth/login') .send({ email: SENIOR_EMAIL, password: SENIOR_PASSWORD }); const cookies = (loginRes.headers['set-cookie'] as unknown as string[]) ?? []; const logoutRes = await request(app.getHttpServer()) .post('/auth/logout') .set('Cookie', cookies); expect(logoutRes.status).toBe(200); // Используем тот же refresh — должен быть отозван. const refreshCookie = cookies.find((c) => c.startsWith('refresh_token=')); expect(refreshCookie).toBeDefined(); const refreshRes = await request(app.getHttpServer()) .post('/auth/refresh') .set('Cookie', refreshCookie!); expect(refreshRes.status).toBe(401); }); describe('refresh token rotation', () => { it('issues new tokens with valid refresh', async () => { const loginRes = await request(app.getHttpServer()) .post('/auth/login') .send({ email: SENIOR_EMAIL, password: SENIOR_PASSWORD }); const cookies = (loginRes.headers['set-cookie'] as unknown as string[]) ?? []; const refreshCookie = cookies.find((c) => c.startsWith('refresh_token='))!; const refreshRes = await request(app.getHttpServer()) .post('/auth/refresh') .set('Cookie', refreshCookie); expect(refreshRes.status).toBe(200); const newCookies = (refreshRes.headers['set-cookie'] as unknown as string[]) ?? []; expect(newCookies.some((c) => c.startsWith('access_token='))).toBe(true); // Старый refresh теперь невалиден — должен быть отозван. const reuseRes = await request(app.getHttpServer()) .post('/auth/refresh') .set('Cookie', refreshCookie); expect(reuseRes.status).toBe(401); }); }); });