Как сделать так, чтобы Нок и Мокка хорошо играли вместе?

Я пытаюсь использовать nock, чтобы перехватить / смоделировать некоторый HTTP-трафик в моем приложении для целей тестирования. Наше приложение аутентифицируется на другом из наших сайтов, и мне нужно nock для имитации HTTP 200 (с данными JSON) и HTTP 401 (без данных) для проверки поведения, когда пользователь вошел или не вошел в систему (соответственно),

У меня есть два теста, которые оба работают правильно, когда запускаются в одиночку, но если я запускаю весь набор тестов, один из них всегда дает сбой. Я понимаю, что nock является общим состоянием, потому что он изменяет, как сам node.js обрабатывает сетевой трафик, и я предполагаю, что это является причиной состояния гонки, но я не могу быть единственным человеком, который когда-либо использовал два разных перехватчика nock для одного и того же запроса в два разных теста, так что я знаю, что что-то упустил.

Может кто-нибудь помочь мне понять, почему эти тесты наступают друг на друга?

Мой вопрос связан с тем, как повторно протестировать один и тот же URL, используя Mocha и Nock? но я сделал то, что предложил там, и они не помогли.

Мои тестовые файлы (которые, опять же, оба работают нормально, если они вызываются по отдельности, но не запускаются при выполнении одного и того же теста), выглядят так:

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);
    });
  });
});

а также

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;
    });
  });
});

2 ответа

Решение

Я думаю, что проблема не в nock, а в том, что касается порядка выполнения вашего мокко-хука:

Возьмите этот пример:

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');
    });

  });

});

Когда мы запускаем его, мы получаем следующий порядок вывода:

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 работает до и после каждого it, Тем не менее describe Тело вычисляется до вызова этих хуков. Вы должны обернуть каждый из ваших носков внутри before, (Также describe не использует done аргумент)

Примерно так должно работать:

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();
    });
  });

});

Я использовал ответ Санкет-Катты, который я дал за решение, но немного изменил it блок, так что я включаю мой код для полноты:

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);
    }
  });
});

До того, как один из тестов потерпит неудачу, done() звонок никогда не будет достигнут, и поэтому я получу сообщение о том, что время теста истекло, а не конкретный сбой.

Другие вопросы по тегам