Mocha - 测试 Promise,“完成”永远不会在 Promise 中被调用

Mocha - Testing Promise, `done` never gets called in Promise

我正在尝试测试将在承诺的 .then 块中调用的间谍,但 then 块中的 done 似乎不是完全执行。

我得到 timeout of 2000ms exceeded.

这是我正在测试的内容(异步):

/**
 * Passed down to the LoginForm component to
 * handle form submission.
 */
_submitHandler(data) {
  return function(evt) {
    evt.preventDefault && evt.preventDefault();
    evt.stopPropagation && evt.stopPropagation();

    return request('post', 'auth', data)
      .then((res) => {
        AuthActions.login();
        return res;
      })
  }
}

这是我的测试:

describe('when it succeeds', () => {
  it('should login', (done) => {
    sinon.spy(AuthActions, 'login');

    Instance._submitHandler({})({})
      .then((res) => {
        console.log('Called!!!');
        expect(AuthActions.login.called).to.equal(true);
        AuthActions.login.restore();
        done();
      }, done);
  });
});

我正在使用 Karma 运行 我的测试;柴和诗乃.

我几个小时后终于解决了这个问题。看起来 then 块没有被调用,因为 xhr.

引发了异常

让我详细说明。我正在使用 sinonFakeXMLHttpRequest,像这样:

var requests, xhr;
beforeEach(() => {
  requests = [];
  xhr = sinon.useFakeXMLHttpRequest();
  xhr.onCreate = (req) => {
    req.setResponseHeaders({ /* */ });
    requests.push(req);
  }
});

通过在 catch 块上放置一个 console.log,我发现我得到的错误是 INVALID_STATE_ERR EXCEPTION 0。这使我得出结论,xhr 一直是问题所在。

然后我发现了关于sinonfakeServer,并用它代替(但我不认为这实际上是解决这个问题的方法) .不是很相关,但我在这里也使用了 sandbox,因为这使我免于为存根等编写无数 .restore

describe('when it succeeds', () => {
  var sandbox, server, Instance;
  beforeEach(() => {
    sandbox = sinon.sandbox.create();
    sandbox.useFakeServer();
    server = sandbox.server;
    server.respondWith([200, { "Content-Type": "application/json" }, JSON.stringify({ data: { token: '' }})]);
    sandbox.spy(AuthActions, 'login');
    Instance = TestUtils.renderIntoDocument(<Component />);
  });
  afterEach(() => {
    sandbox.restore();
  });
  it('should login', (done) => {
    Instance._submitHandler({})({})
      .then(() => {
        expect(AuthActions.login.called).to.equal(true);
        done();
      }, done);

    setTimeout(() => {
      server.respond();
    }, 0);
  });
});

我也有这个问题,原因是在连接打开之前试图响应 XHR,例如

此代码将从 FakeXMLHttpRequest.setResponseHeaders:

抛出 INVALID_STATE_ERR - 0
describe("get", function () {

  beforeEach(function () {
    this.xhr = sinon.useFakeXMLHttpRequest();
    this.xhr.onCreate = function (request) {
      request.respond(200, null, "");
    };
  });

  afterEach(function () {
    this.xhr.restore();
  });

  it("should make a request", function () {
    myObject.get("testurl");
  });

});

此代码有效:

describe("get", function () {

  beforeEach(function () {
    this.xhr = sinon.useFakeXMLHttpRequest();
    this.requests = [];
    this.xhr.onCreate = function (request) {
      this.requests.push(request);
    };
  });

  afterEach(function () {
    this.xhr.restore();
  });

  it("should make a request", function () {
    myObject.get("testurl");
    this.requests[0].respond(200, null, "");
  });

});

阅读文档,它本身确实展示了推送到请求数组的相同技术,我下意识地和不准确地留下了这样的印象,即 onCreate,尽管它的名字,更像 "on request"。

myObject.get = function (url) {
  var http = new XMLHttpRequest(); 
  // the XHR instance exists
  // readyState is 0
  // onCreate runs now
  http.open("GET", url); 
  http.send(); 
  // readyState is 1
  // can call setResponseHeaders and respond 
}

结果是您必须在调用运行 XMLHttpRequestsend 的方法后放置您的响应代码,如:

myObject.get("testurl");
this.requests[0].respond(200, null, "");

我用的是respond方法,但是setResponseHeaders也是一样(respond调用setResponseHeaders)--在你的测试中调用的太早了.