Why am I getting "Error: Resolution method is overspecified"?

node.jsmocha.js

node.js Problem Overview


After the upgrade, Mocha can not even run a simple test here is the code

const assert = require('assert');

it('should complete this test', function (done) {
  return new Promise(function (resolve) {
    assert.ok(true);
    resolve();
   })
  .then(done);
});

I took this code from [here][1]

I understood that it now throws an exception Error: Resolution method is overspecified. Specify a callback * or * return a Promise; not both.

But how to make it work? I did not understand. I have

node -v 6.9.4

mocha -v 3.2.0

How to run this code are now in a new and correct format? [1]: https://github.com/mochajs/mocha/blob/master/CHANGELOG.md#boom-breaking-changes

node.js Solutions


Solution 1 - node.js

Just drop
.then(done); and replace function(done) with function()

You are returning a Promise so calling done is redundant as it said in error message

In the elder versions you had to use callback in case of async methods like that

it ('returns async', function(done) {
   callAsync()
   .then(function(result) {
      assert.ok(result);
      done();
   });
})

Now you have an alternative of returning a Promise

it ('returns async', function() {
  return new Promise(function (resolve) {
     callAsync()
       .then(function(result) {
          assert.ok(result);
          resolve();
       });
  });
})

But using both is misleading (see for example here https://github.com/mochajs/mocha/issues/2407)

Solution 2 - node.js

Mocha allows to either use a callback:

it('should complete this test', function (done) {
  new Promise(function (resolve) {
    assert.ok(true);
    resolve();
   })
  .then(done);
});

OR return a promise:

it('should complete this test', function () {
  return new Promise(function (resolve) {
    assert.ok(true);
    resolve();
   });
});

// Or in the async manner
it('should complete this test', async () => {
    await Promise.resolve();
    assert.ok(true);
});

You can't do both.

Solution 3 - node.js

I had to removed the done from the function parameter and the done() of the function call Before

   before(async function (done) {
        user = new User({ ...});
        await user.save();
        done()
    });

After

   before(async function () {
        user = new User({ ...});
        await user.save();
    });

These works for me

Solution 4 - node.js

I had this same issue. A lot of times Mocha is paired with another library called Chai. Chai has a package called "chai-as-promised". It gives you the super simple ability to write less code and test promises. In your case of just testing if a promise resolves, it seems perfect.

const chai = require('chai');
const chaiAsPromised = require("chai-as-promised");
const should = require("chai").should();
chai.use(chaiAsPromised);

describe("Testing with correct syntax and non repeated names", () => {
    it("Should give us a positive response", () => {
      graphQL.sendToGQL(model,"specialEndpoint").should.eventually.be.an("Object");
    })
})

Solution 5 - node.js

An example of async functions with done breaking.

Failure Case

it('If the credentials exists in the system it should return the token generated against it.', async (done) => {
    let aObj = await admin.createAdmin();
    chai.request(server)
    .post("/authenticate")
    .set("Content-Type", "application/x-www-form-urlencoded")
    .send({username: aObj.login,password:aObj.password})
    .end((err, res) => {
        res.should.have.status(200);
        res.body.should.be.a("string");
        done();
    });
});

Success Case

it('If the credentials exists in the system it should return the token generated against it.', async () => {
    let adminObj = await admin.createAdmin();
    chai.request(server)
    .post("/auth/login")
    .set("Content-Type", "application/x-www-form-urlencoded")
    .send({username: adminObj.login,password:adminObj.password})
    .end((err, res) => {
        res.should.have.status(200);
        res.body.should.be.a("string");
        // done();
    });
});

Solution 6 - node.js

If you don't have callbacks, prior answers (which suggest deleting the done) is correct.

If need to both await some external promise, and then exercise a callback/errback-based implementation in your test, that solution doesn't help you.

You can use a library like pify to convert the callback API to use promises.

Alternatively, you can use a Latch in your callback:

  it("test", async () => {
    const l = new Latch()
    const v = await promiseValue()
    s.methodThatTakesCallback((err, result) => {
      expect(result).to.eql(expected)
      l.resolve() // < notifies mocha your test is done
    })
    return l.promise
  })

In TypeScript, here's a very stripped-down Latch implementation:

/**
 * Simple one-count concurrent barrier
 */
export class Latch {
  readonly promise: Promise<void>
  resolve!: () => void
  constructor() {
    this.promise = new Promise<void>(resolve => (this.resolve = resolve))
  }
}

Solution 7 - node.js

Just emit done callback completely and use async instead. (This implementation is based on an express api running on firebase functions, using a custom jsonwebtoken)

const { FIREBASE_UID } = require('dotenv').config()?.parsed
const chai = require('chai');
const chaiHttp = require('chai-http');
const server = require('../lib/api').API;
const should = chai.should();
const expect = chai.expect

chai.use(chaiHttp)

const test = chai.request(server).keepOpen()

// get your token with an earlier mock request and store to a var
describe('Just checking a token', () => {

 let some_token
 it('should print custom jwt for testing, status: 200'), async () => {
    try {
        const res = await test.get(`/createCustomFirebaseToken/${FIREBASE_UID}`).send()
        res.should.exist
        res.should.have.status(200);
        res.should.have.json
        some_token = (JSON.parse(res.text)).token
    } catch (error) {
        throw error
    }
}
 it('should print details:PING, status:200'), async () => {
    try {
        const res = await test.get('/').set('Authorization',`Bearer ${some_token}`)
                              .send()
        res.should.exist
        res.should.have.status(200);
        res.should.have.json
        const { details, status } = JSON.parse(res.text)
        expect(details).to.equal('PING')
        expect(status).to.equal(200)
    } catch (error) {
        throw error
    }
 }
 after(() => test.close())
})

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questioncoder fireView Question on Stackoverflow
Solution 1 - node.jsIgor PopovView Answer on Stackoverflow
Solution 2 - node.jsSimon BoudriasView Answer on Stackoverflow
Solution 3 - node.jskheengzView Answer on Stackoverflow
Solution 4 - node.jsJustin RiceView Answer on Stackoverflow
Solution 5 - node.jsHaisum UsmanView Answer on Stackoverflow
Solution 6 - node.jsmrmView Answer on Stackoverflow
Solution 7 - node.jsChristos SirmakezisView Answer on Stackoverflow