import { describe, it, before, after, beforeEach } from 'node:test'; import assert from 'node:assert/strict'; import Koa from 'koa'; import bodyParser from 'koa-bodyparser'; import supertest from 'supertest'; import { rateLimit } from '../middleware/ratelimit.js'; describe('rateLimit 中间件', () => { let app, agent; before(() => { app = new Koa(); app.use(bodyParser()); app.use(rateLimit(3, 60_000)); app.use(async (ctx) => { ctx.body = { ok: true }; }); agent = supertest(app.callback()); }); it('前3次请求应正常通过', async () => { for (let i = 0; i < 3; i++) { const res = await agent.post('/test').send({}); assert.equal(res.status, 200); assert.equal(res.body.ok, true); } }); it('第4次请求应被限流', async () => { const res = await agent.post('/test').send({}); assert.equal(res.status, 200); // HTTP 200,业务码 429 assert.equal(res.body.code, 429); assert.ok(res.body.msg.includes('请求过于频繁')); assert.ok(res.headers['retry-after']); }); it('限流响应头应包含 X-RateLimit 信息', async () => { // 新建一个不受之前计数影响的中间件(不同限流阈值 + 不同路径) const freshApp = new Koa(); freshApp.use(bodyParser()); freshApp.use(rateLimit(100, 60_000)); freshApp.use(async (ctx) => { ctx.body = { ok: true }; }); const freshAgent = supertest(freshApp.callback()); const res = await freshAgent.post('/headercheck').send({}); assert.equal(res.headers['x-ratelimit-limit'], '100'); assert.equal(res.headers['x-ratelimit-remaining'], '99'); }); });