// server/test/middleware.auth.test.js import { describe, it, expect, vi } from 'vitest'; import { requireAuth } from '../src/middleware/auth.js'; function mockRes() { return { statusCode: 200, body: null, headers: {}, status(c) { this.statusCode = c; return this; }, json(b) { this.body = b; return this; }, redirect(url) { this.headers.location = url; this.statusCode = 302; return this; }, }; } describe('middleware/requireAuth', () => { it('已登录 → 放行', () => { const req = { session: { userId: 1 } }; const next = vi.fn(); requireAuth(req, mockRes(), next); expect(next).toHaveBeenCalledOnce(); }); it('未登录 + /api/ 路径 → 401 JSON', () => { const req = { session: {}, path: '/api/washes', originalUrl: '/api/washes' }; const res = mockRes(); const next = vi.fn(); requireAuth(req, res, next); expect(next).not.toHaveBeenCalled(); expect(res.statusCode).toBe(401); expect(res.body.error.code).toBe('UNAUTHORIZED'); }); it('未登录 + 非 /api 路径 → 302 redirect 到 /login?return_to=', () => { const req = { session: {}, path: '/settings', originalUrl: '/settings?tab=profile' }; const res = mockRes(); const next = vi.fn(); requireAuth(req, res, next); expect(next).not.toHaveBeenCalled(); expect(res.statusCode).toBe(302); expect(res.headers.location).toMatch(/^\/login\?return_to=/); }); it('未登录 + originalUrl 含特殊字符 → URL 编码', () => { const req = { session: {}, path: '/foo', originalUrl: '/foo?x=1&y=2' }; const res = mockRes(); requireAuth(req, res, vi.fn()); expect(decodeURIComponent(res.headers.location.split('return_to=')[1])).toBe('/foo?x=1&y=2'); }); it('未登录 + 无 session 对象 → 401', () => { const req = { path: '/api/x' }; const res = mockRes(); requireAuth(req, res, vi.fn()); expect(res.statusCode).toBe(401); }); it('session.userId = 0/false/空 → 视为未登录', () => { for (const uid of [0, false, null, '']) { const req = { session: { userId: uid }, path: '/api/x' }; const res = mockRes(); requireAuth(req, res, vi.fn()); expect(res.statusCode).toBe(401); } }); });