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.
})
Related
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())
})
})
This question is not about a problem which I can't solve, it is just a curiosity. I'm not very experienced with Mocha, but there's something interesting I've stumbled upon already.
What I want is to use done() to tell Mocha the promise has been resolved.
The following code DOESN'T work:
beforeEach((done) => {
user = new User({ name: 'Dummy' })
user.save()
.then(done)
})
I know I'm passing the result of the user.save() promise to done, but I think it shouldn't be a problem.
Instead this other code works:
beforeEach((done) => {
user = new User({ name: 'Dummy' })
user.save()
.then(() => done())
})
It seems to me that Mocha done() has some kind of control flow which leads to: Error: done() invoked with non-Error: {"_id":"5b65b9d2669f7b2ec0a3d503","name":"Dummy","__v":0}
Is it because done() wants strictly an error as its argument?
Why done() does even care about what I pass to it?
Can you make some example showing why done() argument to be an Error is useful?
Thanks in advance ;)
It is because done() in Mocha only accepts Error argument. In your case, your save() method returns json object not an Error ie new Error('failed save').
If we take a look at mocha test file, we can see that it won't accept other type of arguments.
// https://github.com/mochajs/mocha/blob/master/test/unit/runnable.spec.js#L358
describe('when done() is invoked with a string', function () {
it('should invoke the callback', function (done) {
var test = new Runnable('foo', function (done) {
done('Test error'); // specify done with string/text argument
});
test.run(function (err) {
assert(err.message === 'done() invoked with non-Error: Test error');
done();
});
});
});
But if we see the test when the argument is Error, it works
// https://github.com/mochajs/mocha/blob/master/test/unit/runnable.spec.js#L345
describe('when an error is passed', function () {
it('should invoke the callback', function (done) {
var test = new Runnable('foo', function (done) {
done(new Error('fail'));
});
test.run(function (err) {
assert(err.message === 'fail');
done();
});
});
});
Btw, I suggest that you avoid using done since mocha supports promise by specifying return statement. So, we change the code into
beforeEach(() => {
user = new User({ name: 'Dummy' })
return user.save().then(user => {
// antyhing todo with user
});
});
Hope it helps.
I've written tons of Nightwatch custom commands which use execute and everything has been fine except now I want to do something that doesn't use execute or any of the element API.
I've found that in it's simplest form like below, it breaks all my tests from running. The callback is triggered but no subsequent tests will run, and the after callback is not called. As soon as I do something that uses the element API in this command, everything is fine.
// getTest.js command
exports.command = function (callback) {
// this.execute(function () {}, [], function () {}); uncomment this and everything works
if (typeof callback === 'function') {
callback.call(this, 'test');
}
return this;
};
module.exports = {
'this test does run': client => {
client
.getTest((res) => {
console.log(res); // 'test'
});
},
'nope, this will not run': client => {
console.log('Please run!'); // NOPE
}
};
I'm using nightwatch to run my end to end tests but I would like to conditionally run certain tests based on some global settings at runtime.
// globals.js
module.exports = {
FLAG: true
};
// test.js
describe('Something', () => {
it('should do something', client => {
if (client.globals.FLAG) {
expect(1).to.equal(1);
}
});
});
The above works fine, but I want to silent the whole test and conditionally include the it e.g:
// test.js
describe('Something', () => {
// client does not exist out here so it does not work.
if (client.globals.FLAG) {
it('should do something', client => {
expect(1).to.equal(1);
});
}
});
I am aware I can skip tests by defining them in the nightwatch.js and excluding files etc etc but thats not the approach I can use in this implementation. Another solution might be to use tags but I'm not sure this is possible using Mocha.
You could access the flag in the second example by importing your module globals.js:
// test.js
const globals = require('../globals.js');
describe('Something', () => {
if (globals.FLAG) {
it('should do something', client => {
expect(1).to.equal(1);
});
}
});
you could also create a function to ignore the test when the condition is met:
// test.js
const FLAG = require('../globals.js').FLAG;
const not = function(v){ return {it: v ? function(){}: it} };
describe('Something', () => {
not(FLAG).it('should do something', client => {
expect(1).to.equal(1);
});
});
Is there a way to NOT execute beforeEach function only for certain tests ('it' blocks). Lets say I have 10 it blocks, I do not want beforeEach to be executed for two of the blocks. Is it possible?
You can group specs which you want to run with beforeEach into a separate describe:
it('should 1...', function () {});
it('should 2...', function () {});
describe('group', function () {
beforeEach(function () {
// ...
});
it('should 3...', function () {});
it('should 4...', function () {});
// ...
});
I currently managed this with a work around as follows:
var executeBeforeEach = true;
function beforeEach() {
if(!executeBeforeEach) return;
//your before each code here.
}
describe('some test case 1', function(){
it('Start', function(){
//this is a dummy block to disable beforeeach for next test
})
it('The test that does not need beforeEach', function(){
//this test does not need before each.
})
it('Start', function(){
//this is a dummy block to enable beforeeach for next test
})
})
But, I am wondering if there is a more elegant way!?!