I am trying to use the global hook afterEach to close the browser after each test, but once the first test completes it does not perform the global afterEach. Here is an example of my global.js, any help would be amazing!
module.exports = {
afterEach: function (browser, done) {
browser.end(function () {
done();
})
},
}
documentation says it'll run after each test suite, not after each test, so that might be what you're experiencing :)
Related
I understand what cy.task() provides. It allows Cypress developers to create an event handler with the intent outside of the Cypress workspace.
Correct me if my description is not correct.
What I would like to understand is how cy.task() works within the Cypress Test Framework.
For example, from Cypress documentation, cy.task() usage. It does what is expected, but how?
// in plugins file
module.exports = (on, config) => {
on('task', {
log(message) {
console.log(message)
return null
},
})
}
The diagram below is a work in progress, and I want to add to it where cy.task() are handled:
Thank you
I've got the following test using cypress:
// myTest.spec.ts
console.log("the test is starting");
describe("My Test Describe", () => {
const testEmail = makeRandomEmail();
console.log("test email", testEmail);
it("should set up the profile", () => {
// setupProfile just makes some requests and returns a promise
cy.wrap(setupProfile(testEmail), {
timeout: 15000,
});
});
it("should test the thing", () => {
// makeAppUrl just returns a string
cy.visit(makeAppURL());
/* test stuff happens here which relies on the generated testEmail */
});
});
This works fine when I run against my dev env (which has no port in the url since it's on 443).
However, I'm running into a weird scenario where, when I run the tests against my local server (on port 3000), the following happens:
it logs "the test is starting" and "test email generatedTestEmail" in the browser console
it runs the setupProfile fine and that test passes.
Then, it reloads the entire test seemingly and relogs what's in (1) (with a new generated email), but (2) is still shown as passing.
It tries to run my it("should test the thing") block which fails because now I have a new user test email.
When I switch out only my host to point at my dev env instead of local, it works fine and doesn't reload as described in (3).
Has anyone run into something like this before? Could it be related to the fact that I have the port in the URL?
The issue was with the baseUrl configuration. This was pointed to the dev env, and the script to run against local did not override this config as described here: https://docs.cypress.io/guides/references/configuration#Command-Line
This solution works for me:
You need to put real baseUrl in configuration file. See example below.
Common problems
baseUrl is not set
Make sure you do not accidentally place the baseUrl or another top-level config variable into the env block. The following configuration is incorrect and WILL NOT WORK:
//DOES NOT WORK
{
"env": {
"baseUrl": "http://localhost:3030",
"FOO": "bar"
}
}
Solution: place the baseUrl property at the top level, outside the env object.
//THE CORRECT WAY
{
"baseUrl": "https://.....",
"env": {
"FOO": "bar"
}
}
Please see here for more details
https://docs.cypress.io/guides/references/configuration#Common-problems
I would try and make use of mocha's before() functionality, to maintain the same data across all tests in the describe() block.
// myTest.spec.ts
describe("My Test Describe", () => {
let testEmail;
before(() => {
console.log("the test is starting");
testEmail = makeRandomEmail();
console.log("test email", testEmail);
});
it("should set up the profile", () => {
cy.wrap(setupProfile(testEmail), {
timeout: 15000,
});
});
it("should test the thing", () => {
cy.visit(makeAppURL());
/* test stuff happens here which relies on the generated testEmail */
});
});
I would like to make pause each test.
I've create this function:
afterEach:function(browser){
browser.pause(2000);
},
But when I run tests, I will get error:
TypeError: browser.pause is not a function
Why ? In tests browser.pause is function.
The answer, provided by beatfactor, on the linked GitHub issue, is
When using afterEach you need to use the done callback argument always if you want to use the browser object. That is for backwards compatibility. So you need to do either:
afterEach(browser, done) {
// ...
done();
}
I've written on GitHub as issue and I've got a solution: https://github.com/nightwatchjs/nightwatch/issues/921
RESOLVE:
use
afterEach(done) {
// ...
done();
}
instead of
afterEach(browser, done) {
// ...
done();
}
When using afterEach, if you want access to the browser object then you need to add the done callback argument after browser to your function.
So your function should look like this:
afterEach(browser, done) {
// ...
done();
}
Note that you have to call done() to signify the completion of the test.
If you only have one argument in afterEach then it's the done argument.
afterEach(done) {
// ...
done();
}
In other words, if you write
afterEach(browser) {
// ...
}
browser is actually the done callback. You've named it browser but that's not what it is.
My dear friend you have to do "something" and then pause!
(i.e. assert the url and then pause!)
Does it works?
afterEach:function(browser){
browser
.assert.urlEquals('http://www.google.com')
.pause(2000)
},
I want to build a test that makes sure the Jasmine Test is using a file called SpecRunner.html".
How do I do that?
You can check window.location (at least if you are running tests in browser).
Quick POC code:
describe("File name", function () {
it("ends with SpecRunner.html", function () {
var fileName = window.location.pathname.split("/").pop();
expect(window.location.pathname).toMatch(/SpecRunner.html$/);
});
});
I am currently writing tests protractor and I was wondering if there is some possibility to cancel test execution as soon as something in the beforeEach fails (and return some useful message like "precondition failed: could not login user").
I.e. I have some helper methods in the beforeEach that login the user and then do some setup.
beforeEach:
1) login user
2) set some user properties
Obviously it does not make any sense to execute the 2nd step if the first one fails (actually its quite harmful as the user gets locked which is not nice). I tried to add an "expect" as part of the 1st step, but the 2nd step was still executed -> fresh out of ideas.
Strictly answering your question and without external dependencies:
beforeEach(function() {
// 1) login user
expect(1).toBe(1);
// This works on Jasmine 1.3.1
if (this.results_.failedCount > 0) {
// Hack: Quit by filtering upcoming tests
this.env.specFilter = function(spec) {
return false;
};
} else {
// 2) set some user properties
expect(2).toBe(2);
}
});
it('does your thing (always runs, even on prior failure)', function() {
// Below conditional only necessary in this first it() block
if (this.results_.failedCount === 0) {
expect(3).toBe(3);
}
});
it('does more things (does not run on prior failure)', function() {
expect(4).toBe(4);
});
So if 1 fails, 2,3,4,N won't run as you expect.
There is also jasmine-bail-fast but I'm not sure how it will behave in your before each scenario.
jasmine.Env.prototype.bailFast = function() {
var env = this;
env.afterEach(function() {
if (!this.results().passed()) {
env.specFilter = function(spec) {
return false;
};
}
});
};
then just call:
jasmine.getEnv().bailFast();
(credit goes to hurrymaplelad who wrote an npm that does just that, however you don't need to use it)
jasmine-bail-fast does exactly what you did overriding the specFilter function, but does it on afterEach. So it will only fail after the first "it" is run. It won't help solving this specific case.
with jasmine2 we can set throwOnExpectationFailure to true.
For example in protractor config:
//protractor.conf.js
exports.config = {
//...
onPrepare: () => {
jasmine.getEnv().throwOnExpectationFailure(true);
}
};