0

我正在使用 NodeJS 和 KOA 创建一个 API。对于测试,我使用 chai (chai-http) 和 mocha。当我const { username } = ctx.state.user在控制器中使用来获取发送请求的用户的用户名时,就会出现问题。当使用我的应用程序(使用 Flutter)或使用 Postman 访问它们时,它可以工作,但是使用 mocha 运行测试时,我得到了错误TypeError: Cannot destructure property 'username' of 'undefined' or 'null'。调试代码时,我发现它ctx有一个键,state但该键的值是空的。我尝试了这些方法.set(...).send(...)但它们只修改了 and 内部ctx.request.header的值ctx.request.body

所以我的问题是:是否可以为ctx.statewith chai 设置一个值,如果可以,如何设置?我想放入类似的东西{user: {username: 'chai'}}

以下是2个主要部分,要测试的控制器部分和测试方法:

async function bar(ctx, next) {
    const { username } = ctx.state.user;
    const { value } = ctx.request.body;

    // do something with value and username

    ctx.status = 200;
}
it("With correct gameKey: should return the rating of the game", done => {
    chai
        .request('http://localhost:3000')
        .post('/foo/bar')
        .set('content-type', 'application/json')
        .send({value: 3});
        .end((err, res) => {
            // do some tests
            done();
        });
});

这是来自服务器索引和测试文件的完整代码:

const Koa = require('koa');
const Jwt = require('koa-jwt');
const Router = require('koa-router');
const Cors = require('@koa/cors');
const BodyParser = require('koa-bodyparser');
const Helmet = require('koa-helmet');

const app = new Koa();
const router = new Router();
router.post('/foo/bar', bar);

async function bar(ctx, next) {
    const { username } = ctx.state.user;
    const { value } = ctx.request.body;

    // do something with value and username

    ctx.status = 200;
}

app.use(Helmet());
app.use(Cors());
app.use(BodyParser({
    enableTypes: ['json'],
    strict: true,
    onerror(err, ctx) {
        ctx.throw('Request body could not be parsed', 422);
    },
}));
app.use(Jwt({ secret: process.env.SECRET }).unless({
    path: [
        // Whitelist routes that don't require authentication
        /^\/auth/,
    ],
}));

app.use(router.routes());
app.use(router.allowedMethods());

app.listen(3000, () => console.log(`API server started on localhost:3000`));
const chai = require("chai");
const chaiHttp = require("chai-http");
chai.use(chaiHttp);
const expect = require('chai').expect;

const userCredentials = {
  username: 'chai', 
  password: 'chai'
}

describe("Route: games/", () => {
    before(() => {
        chai
            .request('http://localhost:3000')
            .post('/auth')
            .set('content-type', 'application/json')
            .send(userCredentials)
            .end((err, res) => {
                expect(res.status).to.be.eql(200);
            });
    });

    describe("Sub-route: GET /", () => {
        describe("Sub-route: PUT /:gameKey/rating", () => {
            it("With correct gameKey: should return the rating of the game", done => {
                chai
                    .request('http://localhost:3000')
                    .post('/foo/bar')
                    .set('content-type', 'application/json')
                    .send({value: 3});
                    .end((err, res) => {
                        expect(res.status).to.be.eql(200);
                        done();
                    });
            });
        });
    });
});
4

2 回答 2

1

根据 KOA 文档ctx.state推荐的命名空间,用于通过中间件和前端视图传递信息。

app.use(function * (next) {
  var ctx = this

  ctx.request
  ctx.response

  ctx.body = 'hello'

  ctx.state.user = yield User.find(id).fetch()
  next()
}

所以我认为你可以设置ctx.state中间件函数,你可以在下一个请求处理程序中使用它。

于 2019-12-12T10:40:28.797 回答
0

感谢Sandeep Patel的评论,我想通了。我必须使用中间件,所以我保存了在before()方法中使用请求检索的令牌,并将其添加到其他请求中.set("Authorization", "Bearer " + token)

然后工作测试如下所示:

const chai = require("chai");
const chaiHttp = require("chai-http");
chai.use(chaiHttp);
const expect = require('chai').expect;

const userCredentials = {
  username: 'chai', 
  password: 'chai'
}

describe("Route: games/", () => {
    var token;
    before(() => {
        chai
            .request('http://localhost:3000')
            .post('/auth')
            .set('content-type', 'application/json')
            .send(userCredentials)
            .end((err, res) => {
                expect(res.status).to.be.eql(200);
                token = res.body.token;  // Added this
            });
    });

    describe("Sub-route: GET /", () => {
        describe("Sub-route: PUT /:gameKey/rating", () => {
            it("With correct gameKey: should return the rating of the game", done => {
                chai
                    .request('http://localhost:3000')
                    .post('/foo/bar')
                    .set("Authorization", "Bearer " + token)  // Added this
                    .set('content-type', 'application/json')
                    .send({value: 3});
                    .end((err, res) => {
                        expect(res.status).to.be.eql(200);
                        done();
                    });
            });
        });
    });
});
于 2019-12-12T12:43:19.070 回答