使用supertest配合jest测试express接口时设置请求头认证token的问题
问题原因
首先顶层的console.log(token)输出空属于正常行为:beforeAll钩子是测试框架异步调度的,会在所有测试用例执行前运行,但顶层同步代码会在测试框架初始化阶段就执行,此时beforeAll的回调还没触发,所以拿到的是初始空值。
如果测试用例内部也拿不到token,通常是两个原因:
- 原回调写法没有做错误处理,如果接口请求失败不会抛出错误,也不会触发
done(),测试框架会直接跳过继续执行用例,导致token始终为空 - 部分版本的测试框架对回调式异步钩子的调度存在兼容问题,容易出现执行顺序异常
解决方案
方案1:替换为async/await写法的beforeAll(优先使用)
把回调式的supertest请求改成await写法,避免done回调的各种坑,同时记得给需要鉴权的请求加Authorization头:
let token = ""; // 改成async类型的beforeAll beforeAll(async () => { const response = await supertest(app) .get("/authentication/test"); // 可选:加断言确保登录接口返回正常,提前发现问题 expect(response.statusCode).toBe(200); token = response.body.token; }); describe("Simple post test using auth", () => { test.only("should respond with a 200 status code", async () => { console.log({ POSTTest:token }); // 此时可以拿到正确的token // 给请求加认证头,Bearer前缀需要和你后端jwt中间件的要求保持一致 const response = await supertest(app) .post("/tests/simple") .set('Authorization', `Bearer ${token}`) .send(); expect(response.statusCode).toBe(200); }); });
方案2:统一封装带认证的请求方法
如果多个测试用例都需要带认证头,可以抽成公共方法,避免每个用例重复写头逻辑:
let token = ""; beforeAll(async () => { const response = await supertest(app).get("/authentication/test"); token = response.body.token; }); // 封装带认证的请求实例 const requestWithAuth = () => { return supertest(app).set('Authorization', `Bearer ${token}`); }; // 测试用例直接调用即可 test("should respond with 200", async () => { const response = await requestWithAuth().post("/tests/simple").send(); expect(response.statusCode).toBe(200); })
方案3:全局设置默认认证头
如果所有测试接口都需要jwt鉴权,可以直接设置supertest全局默认头,后续所有请求会自动携带认证信息:
let token = ""; beforeAll(async () => { const response = await supertest(app).get("/authentication/test"); token = response.body.token; // 全局设置默认头 supertest.agent(app).defaults.set('Authorization', `Bearer ${token}`); });
内容的提问来源于stack exchange,提问作者JimmyTheCode
相关产品推荐
相关产品推荐

