问题
I am trying to use nock to intercept/mock some HTTP traffic in my application for testing purposes. Our app authenticates to another one of our sites, and I need nock to imitate an HTTP 200 (with JSON data) and an HTTP 401 (with no data) to test behaviors when the user is or isn't logged in there (respectively).
I have two tests which both work correctly when run alone, but if I run the entire test suite, one of them always fails. I realize that nock is shared state because it modifies how node.js itself handles network traffic and I assume that's the cause of the race condition, but I can't be the only person who's ever used two different nock interceptors for the same request in two different tests, so I know I'm missing something.
Can anyone help me figure out why these tests are stepping on each other?
My question is related to How to retest same URL using Mocha and Nock? but I did the things suggested there and they didn't help.
My test files (which, again, both work fine if called individually, but fail when run as part of the same test pass) look like this:
import { expect } from 'chai';
import nock from 'nock';
import * as actionTypes from '../../src/constants/action-types';
import * as panoptes from '../../src/services/panoptes';
import { user } from '../modules/users/test-data';
const stagingHost = 'https://my-staging-server.org';
describe('Panoptes', () => {
afterEach(function (done) {
nock.cleanAll();
nock.disableNetConnect();
done();
});
beforeEach(function (done) {
nock.cleanAll();
nock.disableNetConnect();
done();
});
describe('with a valid user', function (done) {
let lastAction = null;
const scope = nock(stagingHost)
.get(/^\/oauth\/authorize/)
.reply(302, '', {
'location': 'https://localhost:3000',
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'X-Frame-Options': 'SAMEORIGIN',
'X-XSS-Protection': '1; mode=block',
});
scope
.get(/^\/api\/me/)
.reply(200, {
users: [user],
});
panoptes.checkLoginUser((action) => { lastAction = action; }).then(() => {
nock.removeInterceptor(scope);
done();
});
it('should know when somebody is logged in', function () {
expect(lastAction).to.not.be.null;
expect(lastAction.type).to.equal(actionTypes.SET_LOGIN_USER);
expect(lastAction.user).to.not.be.null;
expect(lastAction.user.id).to.equal(user.id);
expect(lastAction.user.login).to.equal(user.login);
});
});
});
and
import { expect } from 'chai';
import nock from 'nock';
import * as actionTypes from '../../src/constants/action-types';
import * as panoptes from '../../src/services/panoptes';
const stagingHost = 'https://my-staging-server.org';
describe('Panoptes', () => {
afterEach(function (done) {
nock.cleanAll();
nock.disableNetConnect();
done();
});
beforeEach(function (done) {
nock.cleanAll();
nock.disableNetConnect();
done();
});
describe('with no user', function (done) {
let lastAction = null;
const scope = nock(stagingHost)
.get(/^\/oauth\/authorize/)
.reply(302, '', {
'Cache-Control': 'no-cache',
'location': 'https://my-staging-server.org/users/sign_in',
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'X-Frame-Options': 'SAMEORIGIN',
'X-XSS-Protection': '1; mode=block',
});
scope
.get(/^\/api\/me/)
.reply(401);
panoptes.checkLoginUser((action) => { lastAction = action; }).then(() => {
nock.removeInterceptor(scope);
done();
});
it('should know that nobody is logged in', function () {
expect(lastAction).to.not.be.null;
expect(lastAction.type).to.equal(actionTypes.SET_LOGIN_USER);
expect(lastAction.user).to.be.null;
});
});
});
回答1:
I think the problem is not in nock, but with the order of your mocha hook's execution order:
Take this example:
describe('Panoptes', () => {
afterEach(function () {
console.log('ORDER: after each');
});
beforeEach(function () {
console.log('ORDER: before each');
});
describe('with a valid user', function () {
console.log('ORDER: with a valid user');
it('should know when somebody is logged in', function () {
console.log('ORDER: should know when somebody is logged in');
});
});
describe('with no user', function () {
console.log('ORDER: with no user');
it('should know that nobody is logged in', function () {
console.log('ORDER: should know that nobody is logged in');
});
});
});
When we run it we get the following order on output:
ORDER: with a valid user
ORDER: with no user
ORDER: before each
ORDER: should know when somebody is logged in
ORDER: after each
ORDER: before each
ORDER: should know that nobody is logged in
ORDER: after each
afterEach
/beforeEach
runs before and after each it
, however the describe
body gets evaluated before those hooks are called. You should wrap each of your nocks inside a before
. (Also describe
does not use a done
argument)
Something like this should work:
describe('with no user', function () {
before(function() {
const scope = nock(stagingHost)
.get(/^\/oauth\/authorize/)
.reply(302, '', {
'Cache-Control': 'no-cache',
'location': 'https://my-staging-server.org/users/sign_in',
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'X-Frame-Options': 'SAMEORIGIN',
'X-XSS-Protection': '1; mode=block',
});
scope
.get(/^\/api\/me/)
.reply(401);
});
it('should know that nobody is logged in', function (done) {
panoptes.checkLoginUser((action) => {
expect(action).to.not.be.null;
expect(action.type).to.equal(actionTypes.SET_LOGIN_USER);
expect(action.user).to.be.null;
done();
});
});
});
回答2:
I used sanketh-katta's answer, which I'm giving credit for the solve, but slightly modified the it
block, so I'm including my code for completeness:
it('should know when somebody is logged in', function(done) {
panoptes.checkLoginUser((action) => {
try {
expect(action).to.not.be.null;
expect(action.type).to.equal(actionTypes.SET_LOGIN_USER);
expect(action.user).to.not.be.null;
expect(action.user.id).to.equal(user.id);
expect(action.user.login).to.equal(user.login);
done();
} catch (ex) {
done(ex);
}
});
});
Before, when one of the tests would fail, the done()
call would never be reached, and so I'd get the message that the test had timed out instead of a specific failure.
来源:https://stackoverflow.com/questions/41619376/how-do-i-make-nock-and-mocha-play-well-together