-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Error: Resolution method is overspecified. #2407
Comments
|
As the error states, you're not supposed to provide a function with an arity of >0 (meaning that it's accepting a The easiest way to fix it would be to omit the before(() => Promise.all([]).then(() => Model.insert(...))); |
Here's an example of both it('fires change event when calling blah.doSomethingThatFiresChange', async function (done) {
const blah = await getBlah()
blah.on('change', () => done())
blah.doSomethingThatFiresChange()
}) |
@elado That's an interesting use case, although from mocha's point of view it's the same situation -- a function that both takes a it('fires change event when calling blah.doSomethingThatFiresChange', async function () {
const blah = await getBlah()
return new Promise(resolve => {
blah.on('change', resolve)
blah.doSomethingThatFiresChange()
})
}) ... but I guess what you're getting at is that in this example, it would be better if mocha waited for both the promise to be resolved and the callback to be called? Unfortunately that particular combo is most often a bug in the test, which is why this error message was added in the first place. |
This seems like a bug, in any case. |
@ScottFreeCode Hmm, yeah, it seems to be because the "overspecified" error is issued in the function provided as the Lines 357 to 373 in 4944e31
... but we can of course determine that we have to fail with that error as soon as the function has returned. |
@ScottFreeCode What's the fix here? |
I'm going to guess it's "wait for the promise to resolve or reject, then reject with the 'overspecified' error"? |
If we're going to consider |
@ScottFreeCode I'm in agreement. So it's
Bonus question: What to do with the result of the Promise fulfillment? |
Ah, I think I get it -- even when we detect the error, we need to let the test run so it's not still running its code during the next test and, maybe, so we can also report the test result. Could a test also end up calling My inclination, re. what to do with the result of the test, is that if it times out (without having either called That's the best I can come up with at the moment, anyway, but I might have more insight if I can find the time to dig into this problem. |
Well, we can do this in phases. The first would be to ensure that if a Promise is returned and a It's conceivable that one could do something like this (with Bluebird): // to make this work, you need to omit `return`
it('should do something async for sure', function(done) {
return somethingAsync()
.then(makeAssertion)
.asCallback(done);
}); But that's just something you could do; I have yet to determine a use case for this. |
I think I've confused myself. I'm not sure there's a bug here at all. |
This is more of a "poor UI"-type issue |
Timing out waiting for it("should not time out", function(done) {
return new Promise(function(resolve, reject) {
setTimeout(resolve.bind(42), 50)
})
})
I'll look at the PR in any case... |
Interested parties should watch #2413. |
…ogic to return a promise *and* specify a done callback (see mochajs/mocha#2407)
I get the same error using multiple async beforeEach((cb) => connection.db.collection('users').remove({}, cb));
beforeEach((cb) => connection.db.collection('accounts').remove({}, cb));
beforeEach((cb) => connection.db.collection('accounts').insertOne(account1, cb)); Is not possible to still using async hooks in that way? |
I figured out my issue: my methods inside each hook are returning a |
I don't think this is a good idea. If one requests a callback I think they have made their intentions clear. The error here is just an annoyance. Please remove it. |
This isn't really a matter of intention. From #1320's description:
|
It's not ambiguous, the callback was requested. How is that ambiguous? |
I am agree with that @RobertWHurst there is no ambiguous here. Besides that I think this issue could be something "opinion based" and developers will have different point of views. I consider that is very extremist to do a breaking change and force people use that way. |
We didn't force anyone to do anything. We released a major, which by definition will have breaking changes. We didn't break semver. |
@tamoyal, yeah -- as elado posted back in Aug 3, 2016. Using async/await returns an implicit |
@victorsferreira, seems like this should have been the solution... it('should do something', () => {
return supertest(server)
.get(`/api/endpoint`)
.set('somekey', 'somevalue')
.expect(200);
}); |
@tamoyal Yep that was what tripped me up. It's very unintuitive to have a third party library looking into the parameters of a function I create and using that to make a decision without telling me that it did so. |
@mienaikoe, this exact scenario is explicitly documented, you know... |
@plroebuck two things:
It's not about calling done, it's about specifying |
|
@QauseenMZ, see no difference between your "before" and "after" code. You're also not returning your promise. Shouldn't it be more like the following? it('should receive successful RPC response', async () => {
return await getResponse(unitData)
.then((res) => {
expect(res).to.have.status(200);
});
}); PS. Your Node callback argument ordering is whacked... |
@plroebuck Thanks for mentioning! I just edited that. I'm not handling the promise because getResponse function is returning a callback. It was the only way I got it working. getResponse function is as follows: Here error is second parameter just because of the callback getResponse function is returning. Please let me know your thoughts about it. Thanks! |
Some parts seem kinda illogical. Just for clarity, which
PS. Please just paste the code itself rather than images of the code... |
@tamoyal You saved my life <3 |
This breaks and results into the same error:
|
To give you a fast solution to this issue, wrap your entire test in a promise, and use Turn this: it.only("Works with the database", async (done) => {
let browser = await puppeteer.launch();
let query = db.collection('lists').where('ownerId', '==', 'UJIXXwynaCj8oeuWfYa8');
let ct = 0;
query.onSnapshot(async querySnapshot => {
if (ct === 0) {
await addAPurpose(browser, session, sessionSig); // A function with a bunch of Puppeteer code.
ct++
} else {
expect(querySnapshot.size).to.equal(1);
expect(querySnapshot.docs[0].get().title).to.equal("Understand Mocha");
done();
}
console.log(`Received query snapshot of size ${querySnapshot.size}`);
}, err => {
console.log(`Encountered error: ${err}`);
});
}); into this: it.only("Works with the database", async () => {
const onSnap = new Promise(async (res, rej) => {
let browser = await puppeteer.launch();
let query = db.collection('lists').where('ownerId', '==', 'UJIo1gGMueoubgfWfYa8');
let ct = 0;
let unsubscribe = query.onSnapshot(async querySnapshot => {
if (ct === 0) {
await addAPurpose(browser, session, sessionSig);
ct++
} else {
expect(querySnapshot.size).to.equal(1);
expect(querySnapshot.docs[0].data().title).to.equal("Evolution");
// done();
unsubscribe();
res();
}
console.log(`Received query snapshot of size ${querySnapshot.size}`);
}, err => {
console.log(`Encountered error: ${err}`);
rej()
});
});
return onSnap;
}); And it works like you want. The need to remove
If they're both present, it should throw instead of letting my tests run up until I know you can use
to implement this. |
I was nearly SOL on this. I need to execute async code AND its expected that code won't finish executing(ever) so I HAVE to use done. The annoying hack-a-round was to wrap my async test code in a self invoking async function but leave the Solution: it("It shouldn't be like this", function (done) {
( async function(){
var life = require('InfiniteLife');
var asyncRes = await life.someCoolstuff();
assert(asyncRes);
setTimeout( function(){
done();
},letsCallItQuitsNow);
})();
}); |
An example of async functions with done breaking.
Success Case
|
You need neither it('If the credentials exists in the system it should return the token generated against it.', () => {
let adminObj = await admin.createAdmin();
return 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");
});
}); |
Your posted solution is for timing out the test if it takes too long. Mocha already has this functionality built in. it("It should be liek this", async function () {
this.timeout(letsCallItQuitsNow);
var life = require('InfiniteLife');
var asyncRes = await life.someCoolstuff();
assert(asyncRes);
}); Your example also doesn't seem to fail the test if the timeout is exceeded, so be careful with depending on the correctness of it |
` Using express/js, and firebase cloud functions, check api error responses, then get a token and try again. Make sure if using express you return .json and not .send, also functions logger bugs with mocha so use plain console.log.
})
}) |
==== Has a solution to this use case been found ? |
Yeah - it's not pretty, but you can wrap your code in an async closure: it("should error on fn", function (done) {
(async () => {
try {
await fn();
} catch (e) {
// assert some things here
done();
}
})();
}); |
Thanks for the answer @tom-james-watson ! Well, as you said, that's not pretty... I ended up doing this instead, not super pretty either, but a little bit clearer to me: it("should error on fn", () => {
try {
await fn();
assert.fail('Promise should have been rejected');
} catch (e) {
if (e instanceof AssertionError) {
throw e;
}
// assert some things here
}
}); It felt a little less confusing and a little more readable to me, but it's still pretty verbose, and it's a pain to add this every time... it("should error on fn", () => {
try {
await fn();
assert.fail('Promise should have been rejected');
} catch (e) {
if (e instanceof AssertionError) throw e;
// assert some things here
}
}); |
For that specific case yeah. Or you can just directly assert that the call throws. There are still some cases where you do need a mix of |
This is defn a bug on mocha that should be fixed. As others have pointed out, using This is what I've done in the meantime: it('hack for async done', async () => {
try {
await someFunction();
assert.isFalse(true); // This ensures we never actually get to here
} catch (e) {
// my assertion here
}
}); |
@maitrungduc1410 I'm using this pattern, but then the test never stops running. What I'm doing wrong?
I'm using the same pattern with the same function in a previous test. And there stops when the test is done. Here is the entire file (line 12): https://github.com/icra/snappAPI-v2/blob/main/tests/test-add-sci-study.js Thank you. |
That test looks fine; I'd guess something else is wrong. But this thread is not where that debugging should happen. (Used the wrong account the first time, sorry for the noise everyone). |
This:
will result in an error
Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.
Docs say:
The model call is resolving with a
Promise.<Object>
of the newly inserted entry, however if I omit.then(() => done())
then the test timeouts.The text was updated successfully, but these errors were encountered: