Reputation: 2309
I'm correctly working on refactoring my clone of the express-decorator NPM package. This includes refactoring the unit tests that were previously done using AVA. I decided to rewrite them using Mocha and Chai because I like the way they define tests a lot more.
So, what is my issue? Take a look at this code (I broke it down to illustrate the problem):
test('express', (t) => {
@web.basePath('/test')
class Test {
@web.get('/foo/:id')
foo(request, response) {
/* The test in question. */
t.is(parseInt(request.params.id), 5);
response.send();
}
}
let app = express();
let controller = new Test();
web.register(app, controller);
t.plan(1);
return supertest(app)
.get('/test/foo/5')
.expect(200);
});
This code works.
Here's (basically) the same code, now using Mocha and Chai and multiple tests:
describe('The test express server', () => {
@web.basePath('/test')
class Test {
@web.get('/foo/:id')
foo(request, response) {
/* The test in question. */
it('should pass TEST #1',
() => expect(toInteger(request.params.id)).to.equal(5))
response.send()
}
}
const app = express()
const controller = new Test()
web.register(app, controller)
it('should pass TEST #2', (done) => {
return chai.request(app)
.get('/test/foo/5')
.end((err, res) => {
expect(err).to.be.null
expect(res).to.have.status(200)
done()
})
})
})
The problem is that the TEST #1
is ignored by Mocha although that part of the code is run during the tests. I tried to console.log
something there and it appeared in the Mocha log where I expected it to appear.
So how do I get that test to work? My idea would be to somehow pass down the context (the test suite) to the it
function, but that's not possible with Mocha, or is it?
Upvotes: 1
Views: 662
Reputation: 151380
It looks like you are moving from tape
or some similar test runner to Mocha. You're going to need to significantly change your approach because Mocha works significantly differently.
tape
and similar runners don't need to know ahead of time what tests exist in the suite. They discover tests as they go along executing your test code, and a test can contain another test. Mocha on the other hand requires that the entire suite be discoverable before running any test.* It needs to know each and every test that will exist in your suite. It has some disadvantages in that you cannot add tests while the Mocha is running the test. You could not have a before
hook for instance do a query from a database and from that create tests. You'd have instead to perform the query before the suite has started. However, this way of doing things also has some advantages. You can use the --grep
option to select only a subset of tests and Mocha will do it without any trouble. You can also use it.only
to select a single test without trouble. Last I checked, tape
and its siblings have trouble doing this.
So the reason your Mocha code is not working is because you are creating a test after Mocha has started running the tests. Mocha won't right out crash on you but when you do this, the behavior you get is undefined. I've seen cases where Mocha would ignore the new test, and I've seen cases where it executed it in an unexpected order.
If this were my test what I'd do is:
Remove the call to it
from foo
.
Modify foo
to simply record the request parameters I care about on the controller instance.
foo(request, response) {
// Remember to initialize this.requests in the constructor...
this.requests.push(request);
response.send()
}
Have the test it("should pass test #2"
check the requests recorded on the controller:
it('should pass TEST #2', (done) => {
return chai.request(app)
.get('/test/foo/5')
.end((err, res) => {
expect(err).to.be.null
expect(res).to.have.status(200)
expect(controler.requests).to.have.lengthOf(1);
// etc...
done()
})
})
And would use a beforeEach
hook to reset the controller between tests so that tests are isolated.
Upvotes: 2