import jwt from '@fastify/jwt' import Fastify from 'fastify' import { afterAll, beforeEach, beforeAll, describe, expect, it } from 'vitest' import { prisma } from '../../lib/prisma.js' import { registerAuthOAuthRoutes } from '../auth-oauth.js' const JWT_SECRET = 'test-secret' async function buildApp() { const app = Fastify({ logger: false }) await app.register(jwt, { secret: JWT_SECRET }) app.decorate('authenticate', async function (request, reply) { try { await request.jwtVerify() } catch { return reply.code(401).send({ error: 'Unauthorized' }) } }) app.decorate('eventBus', { emit: () => {} }) await registerAuthOAuthRoutes(app) await app.ready() return app } function signToken(app, userId, email) { return app.jwt.sign({ sub: userId, email }) } async function createUser(email) { const user = await prisma.user.create({ data: { email, displayName: 'Test', avatar: null, avatarStyle: 'avataaars' }, }) await prisma.notificationPreference.create({ data: { userId: user.id, globalEnabled: true } }) return user } describe('DELETE /api/me/oauth/:provider', () => { let app, user, token const email = `test-unlink-${Date.now()}@example.com` beforeAll(async () => { app = await buildApp() }) afterAll(async () => { await prisma.oAuthAccount.deleteMany({ where: { user: { email } } }) await prisma.notificationPreference.deleteMany({ where: { user: { email } } }) await prisma.user.deleteMany({ where: { email } }) await app.close() }) beforeEach(async () => { await prisma.oAuthAccount.deleteMany({ where: { user: { email } } }) await prisma.user.deleteMany({ where: { email } }) user = await createUser(email) token = signToken(app, user.id, email) }) it('returns 404 for non-linked provider', async () => { const res = await app.inject({ method: 'DELETE', url: '/api/me/oauth/vk', headers: { authorization: `Bearer ${token}` }, }) expect(res.statusCode).toBe(404) }) it('unlinks a provider', async () => { await prisma.user.update({ where: { id: user.id }, data: { passwordHash: 'hashed' } }) await prisma.oAuthAccount.create({ data: { provider: 'vk', providerUserId: '123', userId: user.id }, }) const res = await app.inject({ method: 'DELETE', url: '/api/me/oauth/vk', headers: { authorization: `Bearer ${token}` }, }) expect(res.statusCode).toBe(200) const count = await prisma.oAuthAccount.count({ where: { userId: user.id } }) expect(count).toBe(0) }) it('rejects removing last method without password', async () => { await prisma.oAuthAccount.create({ data: { provider: 'vk', providerUserId: '123', userId: user.id }, }) const res = await app.inject({ method: 'DELETE', url: '/api/me/oauth/vk', headers: { authorization: `Bearer ${token}` }, }) expect(res.statusCode).toBe(400) expect(JSON.parse(res.body).error).toContain('последний метод') }) })