I have 2 methods inside class
methodA()
methodB()
Code:
const myModule1 = require('./foo');
const myModule2 = require('./bar');
const obj = {
value: 100,
text: "Hello"
};
const updatedObj = {
value: 200,
text: "Hello"
}
// Inside beforeEach block
myModule.methodA.mockReturnValue(() => obj);
myModule2.methodB.mockReturnValue(() => updatedObj);
Now methodA is returning mock object but the class which I am testing is using methodB and methodA both. Now methodB is updating same mock object which methodA returns and updates obj.value to 200 from 100.
Below expect code is meaningless if I use updatedObj because in that case what is the point of testing.
expect(updatedObj.value).toEqual(200) ---> No point in testing like this
How can I do something like this:
expect(obj.value).toEqual(200) assuming I am mocking return value of methodB which updates same object which returns same mocked obj. How can I achieve this?
So basically I want to mock methodA and methodB both but how to use same object instead of using two different is that possible?
Your understanding is flawed. You do not test mocked objects. You assume that these work as intended. You want to test the code that uses those objects.
The things you do with mocks are:
check the result of the function that uses the mock object (i.e. do not consider the mock state, just provide mocks that return the correct value for that specific example)
You can verify the calls, so you can be sure that the calls to methodA were done with the correct parameters.
In other words you do not check that obj.value was mutated to 200, you check that methodA was called with the correct parameters (such that the real implementation would have modified the object to set the parameter to 200).
You can look at Jest documentation that shows how to fetch the calls to the mock functions and so you'll have to make assertions about the calls, not the actions that the real implementation of the function would have performed.
So if myModule.methodA is a mock function you will check:
expect(myModule.methodA.mock.calls).toEqual([[200]])
This will test that the code made one call to methodA with a parameter of 200.
Whether the real methodA would then have modified obj is an implementation detail that shouldn't really matter.
(You did not show the arguments of methodA or B, so obviously that will change depending on how it is called.
This said, be aware that unit testing try to isolate the different parts of the system, and to do this we use mocks. However it is also very useful to have integration tests. Basically just run methodA for real using in memory databases or webservers in place of the real stuff.
Basically checking that obj is changed with a value of 200 in this situation should be part of integration testing, not of the unit tests for the code that uses the mocked versions of methodA/B.
Related
I'm trying to access the window object of my App in Cypress in the following manner.
cy.url().should('include', '/home').then(async () => {
const window = await cy.window();
console.log(window);
});
The above method is not working for me as window is returned as undefined.
However, the answer in this SO post states the following:
Or you can use cy.state('window') which returns the window object
synchronously, but this is undocumented and may change in the future.
This method does return the window value successfully.
cy.url().should('include', '/home').then(async () => {
const window = cy.state('window');
console.log(window);
});
As the answer suggests, cy.state('window') is undocumented so I would still rather use cy.window(). Is there any reason why it's returning undefined? (I started learning cypress today.)
This comes up frequently. Cypress has some documentation stating Commands are not Promises. I did a write up using a custom command to force a Command Chain to behave like a promise, but it is still experimental and nuanced.
First I'll give your example almost verbatim to what you're trying to accomplish:
cy.url().should('include', '/home').then(() => {
cy.window().then(win => {
console.log(win) // The window of your app, not `window` which is the Cypress window object
})
})
Your example could be written a number of ways, but maybe explaining a bit how Cypress works will help more.
Cypress has something called "Commands" that return new "Chainers". It is fluid syntax like JQuery:
// fill and submit form
cy
.get('#firstname')
.type('Nicholas')
.get('#lastname')
.type('Boll')
.get('#submit')
.click()
You can (and should) break up chains to be more like sentences:
// fill and submit form
cy.get('#firstname').type('Nicholas')
cy.get('#lastname').type('Boll')
cy.get('#submit').click()
You might have guessed that all Cypress Chainer commands are asynchronous. They have a .then, but they aren't actually promises. Cypress commands actually enqueue. Cypress hooks into mocha's lifecycle to make sure a before, beforeEach, it, afterEach, after block waits until Cypress commands are no longer enqueued before continuing.
Let's look at this example:
it('should enter the first name', () => {
cy.get('#firstname').type('Nicholas')
})
What actually happens is Cypress sees the cy.get Command and enqueues the get command with the argument '#firstname'. This immediately (synchronously) returns execution to the test. Cypress then sees the cy.type command with the argument 'Nicholas' and returns immediately to the test. The test is technically done at this point since there is no done callback and no Promise was returned. But Cypress hooks into the lifecycle of mocha and doesn't release the test until enqueued commands are completed.
Now that we have 2 enqueued commands and the test is waiting for Cypress to release the test, the get command is popped off the queue. Cypress will try to find an element on the page with an id of firstname until it finds it or times out. Assuming it finds the element, it will set a state variable called subject (cy.state('subject'), but don't rely on that). The next enqueued command type will grab the previous subject and attempt to type each key from the string 'Nicholas' one at a time with a default delay of 50ms until the string is done. Now there are no more enqueued commands and Cypress releases the test and the runner continues to the next test.
That was a bit simplified - Cypress does a lot more to make sure .type only runs on elements that can receive focus and are interactable, etc.
Now, knowing this, you can write your example a bit more simply:
cy.url().should('include', '/home')
// No need for `.then` chaining or async/await. This is an enqueued command
cy.window().then(win => {
console.log(win)
})
For me, the accepted answer is good but not really showing me what is necessary.
For me, it is awesome that everything is synchronous and you can do things like
let bg1 = null;
// simply store the value of a global object in the DOM
cy.window().then((win) => {
bg1 = win.myPreciousGlobalObj.color;
});
// Do something that changes a global object
cy.get('a.dropdown-toggle').contains('File').click();
cy.window().then((win) => {
const bg2 = win.myPreciousGlobalObj.color;
// check if nodes and edges are loaded
expect(bg1 != bg2).to.eq(true);
});
Here the interesting thing is even the things inside the then blocks are synchronous. This is so useful.
I'm running into problems with the validated method package in my app tests. I'm calling my methods through the _execute function in order to be able to pass a userId to simulate a logged-in user while testing. The problem is that my asserts right underneath that _execute are called before the method has a chance of completing. I know my test works though because it only happens sometimes, mostly because mongo isn't always returning results quite as fast.
I looked around and found a todos app that uses the _execute function in its tests. I can't get those tests to fail no matter how many times I rerun them, though.
This is an example of my test code.
describe('clients.add', function() {
it('should add an empty (draft) client', function() {
const res = clients_add._execute({ userId: 'CURRENTUSERID' }, { company_id: c1._id });
assert.instanceOf(res, Mongo.ObjectID, 'method returns the newly created clients ID');
const db_client = Clients.findOne(res);
assert.isTrue(db_client.draft, 'client is drafted');
assert.isDefined(db_client.created, 'there\'s a created date');
});
});
clients_add does quite a few permission checks and can therefor take a little while before completing. Rerunning this test 20 times will fail about 5 times and pass the other 15.
Shouldn't the _execute function be synchronous? How do I make it? What am I missing?
In server code, if you provide a callback to database modification functions like insert, it returns the created ID instantaneously, and runs the callback only once the database has acknowledged the write. If you don't provide a callback, the insert call is synchronous and throws an error if the operation fails. See more about this in Meteor docs.
It seems that you have provided an error-handling callback to the insert-function in your method code. This causes the inconsistent behavior, since the database might not actually have had time to do the write before you call findOne in your test. Also, this is redundant since if an error occurs in the insert, the method has already returned and the error is never shown to the user. It's better to simply omit the error-handling callback altogether:
return Clients.insert(new_client);
There are three seperate questions that are similar to this one but none of them resembles the case I have.
So I basically have a function which takes a function as a parameter
var myfunc ( func_outer ) {
return func_outer().func_inner();
}
In my unit tests I want to be able to make a stub of a myfunc2. Basically I need to be able to stub a stub which is a nested stub. I currently use this kind of a manual stub but I would rather do it using sinon stubs if there is a way.
const func_outer = () => {
return {
func_inner: () => {return mockResponse;}
}
};
Has anyone ever faced this situation. Is there an easy way to solve this issue?
From sinon documentation you can check the returns section
stub.returns(obj);
Makes the stub return the provided value.
You can try the following:
First you should make sure that you stub your inner function, and then make it return the value you want.
func_innerStub = sinon.stub().returns('mockResponse')
Then stub your outer function and make it return the object with your stubbed inner function.
func_outerStub = sinon.stub().returns({func_inner: func_innerStub})
You can follow this pattern with the myfunc function, as well and pass as a param the func_outerStub.
I have the following code in my react component
componentDidMount() {
ajax.call().then((data)=> {
this.setState({a:data.a});
});
}
Im making a simple call to a function that returns a promise.
My test looks like this when I am trying to test that the state gets set correctly from the resolved promise.
it('should set state of a', (done)=> {
let ajax = {
call: ()=>{}
};
spyOn(ajax, 'call').and.returnValue(Promise.resolve({a:'a'}));
let component = TestUtils.renderIntoDocument(<MyComp/>);
expect(component.state.a).toEqual('a');
});
I am pretty sure the state is actually getting set from the data returned by the promise, but the problem is I have nowhere to call the jasmine 'done()' function to tell jasmine the async operation has finished and that the assert on the state can be tested.
The React community mostly agrees that state is better managed through
"as if' it appears synchronously so it can be snapshotted. This gives us the view as a function of a single state variable and makes our code easy to test. If you're not invested in an architecture - I suggest you try FLUX like architectures and check out common libraries like redux and este.
That said, it's perfectly fine to explicitly set state of a component after AJAX like you did. I'd separate the testing into two bits:
Set a state variable to the return of the AJAX, you can test this by simply checking that the object changed.
Call render to re-render the components you're testing (rather than setStateing).
Then, you can test the rendering and the promise setting the state differently making your rendering tests easy to reason about (they're synchronous) and the AJAX testing easy (it's just objects).
In general, when you test promises with mocha you can use the dedicated promise syntax, since you're using React you're using Babel anyway so you might as well use new JavaScript features in your code:
it('does ajax', async function(){ // can also `async () =>`
var result = await ajax.call(); // call the ajax, get response, can be mocked
var state = result;
var str = React.renderToString(<MyComp prop={result} />);
// assert against the returned HTML, can also test against DOM
});
I have some promise-based code (MyLib) that I want to run on every model save so I extend the save function:
DS.Model.extend
save: ->
parentSave = #_super.bind this, arguments...
deferred = Ember.RSVP.defer()
MyLib.func().then((val) =>
#set 'prop', val
parentSave()
.then(deferred.resolve)
.fail(deferred.reject)
)
DS.PromiseObject.create promise: deferred.promise
Note that the promise returned by MyLib.func() is an rsvp.js promise and not an Ember.RSVP promise.
This seems to work in practice but some of my tests are failing with You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in an Ember.run.
Even after I wrap the #set and parentSave calls with Ember.run, I still have async issues in my tests.
My question is: how do I extend the save function with async code in a way that also satisfies my tests?
Two things:
The immediate error you're seeing is because all asynchronous code must run in Ember's run loop. That means that when your promise resolves and runs the deffered.resolve method, it must run that code inside of the run loop. So you have to do something like this:
parentSave().then(() ->
Em.run.next(() ->
deferred.resolve()
)
)
Hopefully that's right. Let me know if I'm missing something.
As of Ember 1.5.0, you can't call _super in that manner. You must call it inline and not asynchronously.