简体   繁体   中英

Why is this chai-as-promised AssertionError printing to the Console but not my Mocha test runner?

I'm tyring to test some code that uses Promises with chai-as-promised and Mocha . My test suite is also utilizing fetch-mock to mock AJAX requests that would normally be sent using the Fetch API.

Here's the code I'm trying to test:

/**
 * Sends a POST request to save (either insert or update) the record
 * @param  {object} record simple object of column name to column value mappings
 * @return {Promise}       Resolves when the POST request full response has arrived.
 * Rejects if the POST request's response contains an Authorization error.
 */
save(record) {
  var _this = this;
  return this._auth(record)
    .then(function() {
      return window.fetch(_this._getPostUrl(), {
        method: 'post',
        headers: {
          'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
        },
        body: _this._objToPostStr(record),
        credentials: 'include'
      });
    })
    .then(function(saveResp) {
      return saveResp.text();
    })
    .then(function(saveResp) {
      return new Promise(function(resolve, reject) {
        if (saveResp.indexOf('Authorization') !== -1) {
          reject('Request failed');
        } else {
          resolve(saveResp);
        }
      });
    });
}

In my most upper-level describe , I have this function that initially sets up my fetchMock object.

before(() => {
  fetchMock = new FetchMock({
    theGlobal: window,
    Response: window.Response,
    Headers: window.Headers,
    Blob: window.Blob,
    debug: console.log
  });
  fetchMock.registerRoute({
    name: 'auth',
    matcher: /tlist_child_auth.html/,
    response: {
      body: 'authResp',
      opts: {
        status: 200
      }
    }
  });
});

and here's the relevant test code:

describe('save', () => {
  it('save promise should reject if response contains the string Authorization', () => {

    fetchMock.mock({
      routes: ['auth', {
        name: 'save',
        matcher: /changesrecorded.white.html/,
        response: {
          body: 'Authorization',
          opts: {
            status: 200
          }
        }
      }]
    });

    let _getLocationStub = sinon.stub(client, '_getLocation');
    _getLocationStub.returns('/admin/home.html');

    client.foreignKey = 12345;
    let promise = client.save({
      foo: 'bar'
    });
    promise.should.eventually.be.fulfilled;
    fetchMock.unregisterRoute('save');
  });
});

The reason I'm defining the save route in the fetchMock.mock() call is I have another test that needs the save route to be redefined to return something else.

To make sure chai-as-promised is actually working and will notify me of failed tests, I wrote a failing test promise.should.eventually.be.fulfilled; . This will fail because the Promise returned by save will reject if the response contains Authorization , which it does. The Chrome Console shows the AssertionError with message: expected promise to be fulfilled but it was rejected with 'Request failed , but my Mocha test-runner.html page is showing that this test passed. For some reason, chai-as-promised isn't communicating properly with Mocha.

If you'd like to see my entire project, please see this repo on Github.

Any ideas why?

EDIT:

Here's my test setup code:

let expect = chai.expect;
mocha.setup('bdd');
chai.should();
chai.use(chaiAsPromised);

The value promise.should.eventually.be.fulfilled is a promise, which you should return so that Mocha can know when your test is over. I've created a small test file to simulate what you were seeing and I can completely replicate the behavior if, like you do, I just fail to return promise.should.eventually.be.fulfilled; . Here is an example that works:

import chai from "chai";
import chaiAsPromised from "chai-as-promised";

chai.use(chaiAsPromised);
chai.should();

describe("foo", () => {
    it("bar", () => {
        let promise = Promise.reject(new Error());
        return promise.should.eventually.be.fulfilled;
    });
});

In your code you had some cleanup code at the very end of your test: fetchMock.unregisterRoute('save'); . Based on what you show, I'd move this to an after hook so that it mirrors your before hook. In general, after should perform cleanup that corresponds to what is in before and afterEach to what is in beforeEach . However, if you need to have cleanup code inside a test for some reason, you could do:

        function cleanup() {
            console.log("cleanup");
        }

        return promise.should.eventually.be.fulfilled.then(
            // Called if there is no error, ie. if the promise was
            // fullfilled.
            cleanup,
            // Called if there is an error, ie. if the promise was
            // rejected.
            (err) => { cleanup(); if (err) throw err; });

Unfortunately, Chai seems to return something which looks like a ES6 Promise but only partially. Eventually, it will probably return a actual ES6 promise, and then you'll be able to call .finally to run cleanup code no matter what happens and have the error automatically propagate up.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM