Flux + Sinon + Promises test always passes or times out - javascript

I am currently attempting to test Flux with Sinon + Sinon-As-Promised, but I am struggling to find relevant examples, and having an issue with my test always returning true, no matter the assertion.
My test currently looks like this:
it('Form store should contain encounter object', function() {
var stub = sinon.stub(restService, "loadForm").resolves(mockDataEncounter.Encounter);
stub().then(function(value){
console.log('Inside frmSrv');
formStore._currentForm = value;
expect(formStore._currentForm).to.have.property('Name');
})
console.log('calling action creator');
actionCreator.loadForm("123456789012345678910003");
})
What I was expecting to happen was -
Call action creator -> Action creator usually makes the API call,
but in this case calls the stubbed method instead -> Promise is
resolved, _currentForm is set to the mock data, and then the assertion
is checked.
However what actually happens is:
Call action creator -> Test passes -> Promise resolves
If I add a done callback to the test, and then call done after the assertion, this causes things to execute in my expected order, but then if I modify the expected property to "Name1"(which doesnt exist), the test fails with a timeout error rather than the correct error to say the property doesnt exist.
Am I missing something fundamental here, or just going about things completely the wrong way?

So after some more fiddling I worked it out, I had to add a catch to the promise, and then call done passing in the error in order to get the correct failure message to display.
it('Form store should contain encounter object', function(done) {
var stub = sinon.stub(restService, "loadForm").resolves(mockDataEncounter.Encounter);
stub().then(function(value){
console.log('Inside frmSrv');
formStore._currentForm = value;
expect(formStore._currentForm).to.have.property('Name');
done();
}).catch(function(err){
done(err);
});
console.log('calling action creator');
actionCreator.loadForm("123456789012345678910003");
})

Related

Method inside class is not getting executed in unit test

I have a class which contains methods.Now after initializing the class i want to invoke the methods but my test flow is not to the method and getting error like Uncaught error outside test suite.Below is my code
describe('Test Stu positive', () => {
it("Test Stu positive", (done) => {
const stuDetails = new masterDetails(getdetails);
expect(stuDetails.retrieveStudent(res => {
console.log(res);
done()
}))
});
});
Now, in the above code i am not able to print console.log(res);. What i am doing wrong?
I believe that you are using Mocha as your testing framework and looks like the error is not being handled by mocha, because is an asynchronous operation and you are not passing the error to the done callback method as described in the mocha documentation
it is really hard to tell how your function works, if it returns a promise or if it just uses a callback and the error is handled inside the function, so I can't provide you a code example on how to accomplish this. if you mind providing your function declaration I can update my answer with an example solution.

Promise.reject and wait for correct execution order when testing with Jest and Enzyme [duplicate]

This question already has answers here:
Testing with React's Jest and Enzyme when simulated clicks call a function that calls a promise
(2 answers)
Closed 4 years ago.
I am testing a component that uses an external Api.js file. When testing the component, I'm mocking the function using
import {
apiCall,
} from './Api';
jest.mock('./Api');
I want to test a case where the Api call fails, to check that my component shows the correct error. In order to do that, I'm faking the Api response to be:
apiCall.mockImplementation(
() => Promise.reject({ error: 'This is my error' }),
);
However, when mocking the response in this way, I am not able to make it execute before the test case is evaluated. Is there any way to wait for that response to happen before finishing the test?
I have created a codesandbox as simple as I can showing the issue. Since seems that codesandbox does not allow to use jest.mock, I'm just making the original API call to return Promise.reject.
https://codesandbox.io/s/6y0rn74mzw
The behaviour is simple: A text "No error" and a button, that when clicked it calls to the API method that automatically returns Promise.reject. In the response, we change the text to "There is an error". The first test just looks for the word 'error' to make the test pass and show the full evaluation of the code (the test stops if something fails), and the second test is the test I would expect to pass if the correct order was applied.
What would be the way to assure the proper execution order in the test case?
When it comes to dealing with Promises in jest tests, what I've done is as follows:
it('test script description', (done) => {
apiCall()
.then((response) => {
// Verify the response from the promise
done();
});
});
I'm obviously not saying that this is the best solution (perhaps someone can point you in a better direction) but it's the only one that worked for me!
So the solution is to use setImmediate.
If I change the test case to be:
it("should pass but fails due to execution order", done => {
console.log("-----------");
expect(true).toBe(true);
const wrapper = mount(<App />);
wrapper.find("button").simulate("click");
setImmediate(() => {
const newWrapper = wrapper.update();
expect(newWrapper.html()).toContain("There is an error");
done();
});
console.log("Third");
console.log("-----------");
});
It passes.
A good explanation here: https://github.com/kentcdodds/react-testing-library/issues/11

promise & mocha: done() in before or not?

I am reading some tutorials on promise tests in mocha. There is a piece of codes:
before(function(done) {
return Promise.resolve(save(article)).then(function() {
done();
});
});
Why done() called in the then() in the before()? What is the difference between the above codes and the following codes:
before(function(done) {
return Promise.resolve(save(article));
});
Thanks
UPDATE
My question is to compare with the following codes:
before(function() {
return Promise.resolve(save(article));
});
Sorry for the typo.
The first code snippet with the before hook returns a promise and calls done. In Mocha 3.x and over, it will result in this error:
Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.
It used to be that it did not particularly matter if you used done and returned a promise, but eventually the Mocha devs figured that specifying both done and returning a promise just meant the test designer made a mistake and it was better to have Mocha pitch a fit rather than silently allow it.
In your 2nd snippet, you have the done argument and return a promise but Mocha will still wait for done to be called and will timeout. (It really should detect the argument and raise an error like in the 1st case, but it doesn't...)
Generally, if you are testing an asynchronous operation that produces a promise, it is simpler to return the promise than use done. Here's an example illustrating the problem:
const assert = require("assert");
// This will result in a test timeout rather than give a nice error
// message.
it("something not tested properly", (done) => {
Promise.resolve(1).then((x) => {
assert.equal(x, 2);
done();
});
});
// Same test as before, but fixed to give you a good error message
// about expecting a value of 2. But look at the code you have to
// write to get Mocha to give you a nice error message.
it("something tested properly", (done) => {
Promise.resolve(1).then((x) => {
assert.equal(x, 2);
done();
}).catch(done);
});
// If you just return the promise, you can avoid having to pepper your
// code with catch closes and calls to done.
it("something tested properly but much simpler", () => {
return Promise.resolve(1).then((x) => {
assert.equal(x, 2);
});
});
With regards to the completion of asynchronous operations, it works the same whether you are using it, before, beforeEach, after or afterEach so even though the example I gave is with it, the same applies to all the hooks.
I am not sure if I understood 100% the question, but the tests will not start until done is called.
beforeEach(function(done) {
setTimeout(function() {
value = 0;
done();
}, 1);
});
This test will not start until the done function is called in the call to beforeEach above. And this spec will not complete until its done is called.
it("should support async execution of test preparation and expectations", function(done) {
value++;
expect(value).toBeGreaterThan(0);
done();
});
You don't have to pass done in your example, just:
before(function() {
return Promise.resolve(save(article));
});
If you do pass done the test runner will expect to be called before continue, otherwise it will probably throw a timeout error.
In this particular case there is no functional difference. The callback, often called done, was introduced to handle asynchronous tests when using callbacks. Returning a Promise is sufficient, but note that you cannot define the done callback, because the test suite will wait until it's called. Use done when you can't easily return a Promise. In your case the second test will be infinite, because you define done, which you never actually call.

How to handle nested asynchronous operation in unit tests

I have a Javascript module, which is accessing Promise object from another module and then transforming that for it's own use. I am using Bluebird library which ensures, that all promise handlers are called asynchronously. That's quite problem for the testing, especially when that internal promise is not exposed.
module.exports = (testedModule, app) ->
app.module('otherModule').somePromise.then transformValue
transformValue = (val) ->
return new Extra.TransformedValue(val)
In the tests, I am mocking that first promise, so I have access to that. Second promise stays inside the module and I don't want to expose it just for the sake of the tests. Note that I am using Mocha+Chai+Sinon.
beforeEach ->
#initModule = -> app.module('testedModule', testedModule) # prepare function to initialize tested module
#dfd = dfd = Promise.defer() # defer promise resolution to tests
app.module 'otherModule', (otherModule) ->
otherModule.somePromise = dfd.promise
#transformSpy = sinon.spy Extra, 'TransformedValue' # spy on the constructor function
#promiseTransform = dfd.promise.then =>
# this usually fails as the spy is called more then once due to async nature of the tests
#transformSpy.should.have.been.calledOnce
# promise gets resolved with the return value of the spy
# thus it should contain created instance of the TransformedValue
return #transformSpy.firstCall.returnValue
afterEach ->
#transformSpy.restore()
Some preparations for each test. Simply there is promiseTransform, that gets resolved using dfd.resolve() in each test separately. However the transformSpy itself is attached to global object which is shared by all tests (maybe that should be stubbed too). Most of the tests looks like this:
it 'should test whatever...', ->
#init() # initialize module
# something else is tested here, doesn't matter
# note that #dfd is not resolved here, thus transformValue is not called yet
That works just fine, but then comes the test that actually resolves dfd and everything gets messy here. Sometimes spy is resolved more than once or not at all. It's very confusing race of async operations.
it 'should instantiate TransformedValue with correct argument', (done) ->
expected = {foo: "bar"}
#promiseTransform.then (transformed) =>
# test here that TransformedValue constructor has been called once
# ... it actually FAILS, because it was called twice already!
#transformSpy.withArgs(expected).should.have.been.calledOnce
transformed.should.be.an.instanceof Extra.TransformedValue
# somehow this resolves promise for previous test and
# it causes `transformValue` to be called back there
#dfd.resolve expected
#init()
I have spent like 2 days on this and it's driving me nuts already. Tests should be a tool and the actual code to create. There is probably some obvious solution I am missing out.
Do you have any general (or concrete) tips how to handle this with less confusion and more control and determinism? Currently I am thinking about stubbing whole Promise to actually make it synchronous. But it seems to me, that it sort of invalidates the tests, because the workflow can be different than in real run.
What's with the spies? You wouldn't use spies if this was synchronous code. If everything was synchronous, how would you write the test?
Why not write the test as:
it('should instantiate TransformedValue with correct argument', function() {
var expected = {};
return transform(expected).then(function(val) {
assert.deepEqual(Extra.TransformedValue.value, expected)
assert(val instanceof Extra.TransformedValue);
});
});

How do async tests work in intern?

How do asynchronous tests work in Intern testing framework? I have tried to get them run exactly as in the example, but the async test passes immediately without waiting for the callback to be run.
it('should connect in 5 seconds', function () {
var dfd = this.async(5000);
conn.connect(credentials, dfd.callback(function(result) {
expect(result).to.... something
}));
}
The test passes immediately. What am I doing wrong?
dfd.callback doesn’t execute anything until it itself is executed. Keep in mind that it is designed for promise callbacks (i.e. the function passed to promise.then), not Node.js-style callbacks where the argument might be an error (i.e. function (error, result) {}). It will not check to see if an error is passed as an argument.
Without knowing what conn is, but seeing how you are passing dfd.callback as an argument to something that is not a promise, my suspicion is you are trying to use a Node.js-style callback and the call is erroring immediately. We may provide a convenience wrapper for these types of callbacks in the future to convert them to a promise interface, but until then, you probably just need to do something like this:
it('should connect in 5 seconds', function () {
var dfd = this.async(5000);
conn.connect(credentials, dfd.callback(function(error, result) {
if (error) {
throw error;
}
expect(result).to.... something
}));
});
Otherwise, without knowing what conn is and seeing what your actual assertion is, it’s too hard to say what the issue is here. So long as nothing inside the callback throws an error, the test will be considered successful.
Edit: So based on your comments above it sounds like your callback is an event listener called multiple times with different information. In this case, what you could do is something like this:
it('should connect in 5 seconds', function () {
var dfd = this.async(5000);
conn.connect(credentials, dfd.rejectOnError(function (result) {
if (result !== 'what I want') {
return;
}
expect(result).to.... something
// all other tests…
// nothing threw an error, so it is a successful test
dfd.resolve();
}));
});
dfd.rejectOnError works just like dfd.callback except it does not automatically resolve the promise; you do that yourself at the end.
Your structure is okay. dfd sets a timeout of 5 seconds for the test to succeed, then immediately tries conn.connect(), which is not part of the intern framework. If you are trying a simple XHR request, try the getUrlCallback function instead.
They have a pretty cool list of tests at this url: https://github.com/theintern/intern/wiki/Writing-Tests . Look for the two async examples.

Categories

Resources