I wrote a function in one of my tests. I call this function in several parts of my test. All three function calls are made at the beginning of the test, one after another, regardless of when I called them in my test.
The code looks something like this:
const doSomething = () => {
console.log('Do something')
// ...
}
describe('Foo', () => {
it('Bar', () => {
// Some tests...
doSomething()
// Some tests...
doSomething()
// Some tests...
doSomething()
})
})
In my output, I see the logs of the doSomething() three times, one after the other, before any of the test parts run.
How can I avoid these function calls being evaluated ahead of time?
Cypress performs all the actions asynchronously.
So if you want to do some action synchronously, you can wrap you code inside a then callback:
const doSomething = () => {
cy.wrap(null).then(() => {
console.log('Do something')
// ...
})
}
Please also note that any cypress command may be issued directly in the test run time:
const doSomething = () => {
cy.log('Do something')
// ...
}
Cypress will only enqueue the log command and execute it asynchronously in the cypress event loop.
Already mentioned, the .then() callback schedules your code, but chain it off the test code that it should follow.
describe('Foo', () => {
it('Bar', () => {
// Some tests...
cy.get(...)
.should(...)
.then(() => doSomething())
// Some tests...
cy.get(...)
.should(...)
.then(() => doSomething())
})
})
Related
I want to skip and allow tests in the before each hook as follows
beforeEach(() =>{
if(Cypress.mocha.getRunner().suite.ctx.currentTest.title === `Skip this`){
// skip the first test case only but run the second one [How?]
}
});
it(`Skip this`, () => {
});
it(`Don't skip this`, () => {
});
In the place of [How?] I tried using the following:
cy.skipOn(true) from the cypress skip-test plugin but apparently it skips the beforeEach hook not the test itself.
this.skip() but apparently this is not a valid function. Also, if I changed the beforeEach from an arrow function expression, the skip function works but it skips the whole suite and not just the desired test case.
Any ideas?
Change the function type from arrow function to regular function, then you can use the built-in Mocha skip() method.
beforeEach(function() {
if (condition) {
this.skip()
}
})
Your code sample will look like this:
beforeEach(function() { // NOTE regular function
if (Cypress.mocha.getRunner().suite.ctx.currentTest.title === 'Skip this') {
this.skip()
}
});
it(`Skip this`, () => {
});
it(`Don't skip this`, () => {
});
Or use the Mocha context you already use for test title
beforeEach(() => { // NOTE arrow function is allowed
const ctx = Cypress.mocha.getRunner().suite.ctx
if (ctx.currentTest.title === 'Skip this') {
ctx.skip()
}
});
afterEach()
If you have an afterEach() hook, the this.skip() call does not stop it running for the skipped test.
You should check the condition inside that hook also,
afterEach(function() {
if (condition) return;
... // code that should not run for skipped tests.
})
I try to use aftereach() but it will execute either the testcase is passed or failed. I need to know the context of that should i use for example if condition or what?
For example:
describe('TestSuite', function(){
it('THIS TEST CASE PASSED', function(){
})
it('THIS TEST CASE FAILED', function(){
})
})
I need to make it like this. If the a testcase is passed do the actions
...
...
...
and if the testcase failed do the actions
...
...
...
You didn't give much info about your code, so I will suggest a solution that might not be suited for you. I would use a variable that gets set to "fail" if an assertion fails in the previous test and use that to determine the action in the 2nd test, e.g.
describe('check if first test passed or failed then do A or B', () => {
let result
it('test 1', () => {
cy.request({url: Cypress.env('url')}).its('status').then((status) => {
if (status === 500) {
result = 'fail'
}
})
})
it('test 2', () => {
if (result === 'fail') {
cy.log('Previous test failed, so I did Action A')
Code Action A
}
else
{
cy.log('Previous test passed, so I did Action B')
Code Action B
}
})
})
i am new to cypress and i am trying to check if the element exists on a page once the api call is finished.
i do a http post to url 'things/thing1' and once this api finishes i want to check if span element is present on page.
i have tried something like below.
const setUp = () => {
cy.apiPatchSomethings(something1)
.then(() => {
cy.reload();
});
}
describe('Suite name', () => {
before(() => {
setUp();
});
it('test case', () => {
cy.contains('span');
}
});
the above code doesnt work. even before span element is seen on page it checks for span element.
if i use cy.wait(10000) like below it works
it('test case', () => {
cy.wait(10000);
cy.contains('span');
});
but i dont want to use cy.wait. is there some other way to solve this. could someone help me with this. thanks.
Cypress command cy.contains() when called with a single argument is looking for content,
Syntax
cy.contains(content)
cy.contains(content, options)
cy.contains(selector, content)
cy.contains(selector, content, options)
but I'm guessing you are looking for a span element, so use
cy.get('span')
or
cy.contains('span', 'my-content-in-span')
Assuming that's not the problem, just some arbitrary sample code...
Your can modify the setup function to return a promise, in order to wait for the reload.
const setUp = () => {
return cy.apiPatchSomethings(something1) // need a return here
.then(() => {
return new Cypress.Promise(resolve => { // inner return also
cy.reload()
resolve(true) // resolve will signal reload is finished
})
});
}
Because setup() is invoked inside before() Cypress will wait for the promise to resolve before proceeding.
Please don't add extra waits or timeouts, which is too often suggested. This will only lead to flaky tests.
Note if you don't mind ditching the setup() function, it becomes a lot simpler
describe('Suite name', () => {
before(() => {
cy.apiPatchSomethings(something1)
.then(() => cy.reload() ); // all commands here will be completed
// before the tests start
});
it('test case', () => {
cy.contains('span', 'my-content-in-span');
}
});
1.You can wait for span to be visible. The default timeout that cypress provides is 4 seconds.
cy.contains('span').should('be.visible')
2.If you want to give a custom timeout(eg. 10 sec) specific to this command, you can use:
cy.contains('span', { timeout: 10000 }).should('be.visible')
3.If you want to increase the timeout globally you mention this in your cypress.json file:
"defaultCommandTimeout": 10000
and, then just use:
cy.contains('span').should('be.visible')
Now, all your commands will have a default timeout for 10 seconds.
I need to run a function before my tests, but after all beforeEaches. Is there a way of prioritise beforeEaches, reorder them or monkeypatching something so that I can run a function before test gets executed?
Reason: I want to count how many database calls my tests do, but not include those that beforeEach calls.
Mocha executes the beforeEach hooks that pertain to a test in the order in which it encountered them in your code, so there should not be a need to monkeypatch. For instance:
describe("top", () => {
beforeEach(() => {
console.log("A");
});
describe("down", () => {
beforeEach(() => {
console.log("B");
});
beforeEach(() => {
console.log("C");
// Put your code here.
});
it("test 1", () => {});
it("test 2", () => {});
});
});
The above outputs:
top
down
A
B
C
✓ test 1
A
B
C
✓ test 2
I'm trying to test my asyn thunk middleware function using mocha, chai and sinon (my first time!).
Please consider my files:
ayncActionCreators.js
export const fetchCurrentUser = () => {
return (dispatch) => {
setTimeout(dispatch, 100);
}
};
ayncActionCreators.spec.js
//...
it('Should work', () => {
const dispatch = sinon.spy();
const action = fetchCurrentUser();
action(dispatch);
expect(dispatch.called).to.be.true;
});
I did not yet implement the fetchCurrentUser function - just assumed it will take some "server" time and then it will call 'dispatch()'.
The spec fails, due to the async flow. If I add a setTimeout of 101 ms before the expect - it passes.
My code will use some DB API that returns promise, so the async function will eventually look like:
//...
return (dispatch) => {
return dbAPI.fetchUser().then(dispatch(....));
}
So I tried to require dbAPI and create a sinon.stub().returns(Promise.resolve()) inside the test and it didn't work as well (I thought that since the stub returns a resolved promise - the async function will act like a synchronous function).
Any ideas how should I test async functions like that?
Thank,
Amit.
Don't mock dispatch with sinon, write your own and call Mocha's done() in that when it's done.
it('Should work', (done) => {
const dispatch = () => {
// Do your tests here
done();
};
const action = fetchCurrentUser();
action(dispatch)
// Also allow quick failures if your promise fails
.catch(done);
})
If you're just wanting to ensure that the dispatch is called, then mocha will time out. The catch on the returned promise from your async action creator allows errors to be shown in the right place and for the test to fail rather than time out.
Well, I think I've found a solution:
Assuming my async function looks like this:
//...
return (dispatch) => {
return dbAPI.fetchUser().then(dispatch(....));
}
Then I can write the spec as follows:
it('Should work', () => {
dbAPI.fetchUser = sinon.stub().returns(Promise.resolve({username: 'John'}));
const dispatch = sinon.spy();
const action = fetchCurrentUser();
action(dispatch).then(() => {
expect(dispatch.called).to.be.true;
});
});
I don't know if this is a workaround or not, but it works. I would appreciate your opinions of a better way of doing this...
Thanks,
Amit.