Root level `beforeEachFile` and `afterEachFile` - mocha.js

I am trying to do a root-level before that runs before each test file, and after each test file completes. So in other words I want it to run before and after the "top most" describe.
The only way I got this to work was by adding into each of my files top-most describe a before and after. However it is getting very redundant, can I just do it at root level?

Does wrapping all of your describes in another describe solve it (no pun intended)?
describe('all stuff', () => {
before(() => {
}
describe('something', () => {
it('...', ()=> {
})
it('...', ()=> {
})
})
after(() => {
})
})

Related

Local storage is set to wrong domain in Cypress

Trying to test two subdomains in integration.
However, localStorage is always set to first visited subdomain.
Is it possible to set localStorage value to the later visited subdomain (bar.company.com) in the example below?
describe('Login', () => {
it('Logins foo', () => {
cy.visit('https://foo.company.com');
localStorage.setItem('foo', 'foo');
});
it('Logins bar', () => {
cy.visit('https://bar.company.com');
// this will set the entry to foo.company.com
localStorage.setItem('bar', 'bar');
});
});
Now if we check localStorage at bar.company.com it is empty.
And foo.company.com has the both foo and bar entries.
You should either set testIsolation: true or call cy.clearAllLocalStorage() before all tests.
TestIsolation is designed to overcome this sort of issue, but you may not want it if there is some sort of continuity between tests (i.e data carries over).
Here is a reproducible example. There are two contexts, one with testIsolation on and one with it off.
Comment out the cy.clearAllLocalStorage() and you will see the tests start to fail.
Note that localstorage entries persist across runs in the Cypress UI.
context("localstorage - isolated", { testIsolation: true }, () => {
it("one", () => {
cy.visit("https://docs.cypress.io");
localStorage.setItem("one", "1");
cy.getAllLocalStorage().should("deep.eq", {
"https://docs.cypress.io": { one: "1" }
});
})
it("two", () => {
cy.visit('https://example.com/')
localStorage.setItem("two", "2");
cy.getAllLocalStorage().should("deep.eq", {
"https://example.com": { two: "2" }
});
})
})
context("localstorage - not isolated", { testIsolation: false }, () => {
before(() => {
cy.clearAllLocalStorage()
})
it("one", () => {
cy.visit('https://docs.cypress.io');
localStorage.setItem("one", "1");
cy.getAllLocalStorage().should("deep.eq", {
"https://docs.cypress.io": { one: "1" }
});
})
it("two", () => {
cy.visit('https://example.com')
localStorage.setItem("two", "2");
cy.getAllLocalStorage().should("deep.eq", {
"https://example.com": { two: "2" }
});
})
})

Blank page after running Cypress tests

Whenever I run a new cypress test, the page that is supposed to show the UI is blank. Even when I click on each part of each test it remains blank. Please see image below.
image
Cypress package version: 10.4.0
Node v16.16.0
Code:
describe("home page", () => {
beforeEach(() => {
cy.visit("http://localhost:3000")
})
context("Hero section", () => {
it("the h1 contains the correct text", () => {
cy.getByData("hero-heading").contains(
"Testing Next.js Applications with Cypress"
)
})
it("the features on the homepage are correct", () => {
cy.get("dt").eq(0).contains("4 Courses")
cy.get("dt").eq(1).contains("25+ Lessons")
cy.get("dt").eq(2).contains("Free and Open Source")
})
})
context("Courses section", () => {
it("CourseL Testing Your First Next.js Application", () => {
cy.getByData('course-0')
.find('a')
.eq(3)
.contains('Get started')
})
})
})
/// <reference types="cypress" />
Cypress.Commands.add('getByData', (selector) => {
return cy.get(`[data-test=${selector}]`);
});
I faced the same issue in Cypress version 12.0.0 and I solved it by adding this configuration to cypress.config.js
testIsolation: false,
Try adding 's' to http; this might solve that else here is similar issue reported which might give you clue to your problem https://github.com/cypress-io/cypress/issues/4235
You might have put the it() describe() statements in the wrong place. Try creating the most simple test file possible or better still use an example test that cypress provides strip it down and continue to test it until it is barebones.
I have a "solution" in my tests - it seems that the it steps lose the URL.
Remove all the it steps:
describe('Register Native', () => {
// it("Verify1", () => {
: a
// })
// it("Verify2", () => {
: b
// })
})
Now I have a structure like this (only one it step):
describe('Registrer Native', () => {
it('Whole test- Without IT parts', () => {
: a
: b
: c
})
})
It is not an optimal solution as I now have a long test without intermediary it sections.

Cypress: Code in page object file is being executed as a test case before the before hook

I was trying to use a condition as a function within a page object.
class Folders {
DropdownCheckFunction(){
cy.get('.more-less-container').then((dropdown) => {
if(dropdown.find('.name').contains('More')){
cy.get('more-less-container').click()
}
else{
console.log('folders are in expanded state')
}
})
}
Drafts(){
this.DropdownCheckFunction()
cy.get('.category-content').find('[title="Drafts"]').click()
.get(".folder-details").should('contain.text', 'Drafts')
}
Issue here is that the page object is getting executed as a test case and is happening before the code in BEFORE hook is being run. Below is the test file code
describe('Testing all cases related to Drafts', () => {
before(() => {
cy.login()
})
})
it('Needs to open the Drafts folder', () => {
openFolder.Drafts()
});
Attaching the error seen on the test runner for reference
The problem is bad formatting.
If you line up your code, you can see it - your test is outside the scope of the before().
describe('Testing all cases related to Drafts', () => {
before(() => {
cy.login()
})
}) // move this bracket to below the `it()`
it ('Needs to open the Drafts folder', () => {
openFolder.Drafts()
});

Looking for a way tu use Cypress fixtures for all my custom commands outside an it block

I'm building some custom commands and trying to use my fixtures data for all my commands. Right now I'm forced to define it inside an it block.
Looks similar to this:
it("Commands", () => {
cy.fixture("fixtureFile").as("data");
cy.get("#data").then((data) => {
Cypress.Commands.add('login', () => {
cy.visit("/login");
cy.get('#login-email').type(data.userEmail);
cy.get('#login-pass').type(data.userPass, {log: false});
cy.get('.btn').debug().click();
})
Cypress.Commands.add('createTagMedia', () => {
cy.get(".close").click();
cy.get("#form-field-name").type(data.releaseVersion);
cy.get(".form-group-adTag > .CodeMirror > .CodeMirror-scroll").type(data.mediaTag);
cy.get("#media-save-btn").click();
})
})
})
This it block is being count as a test case, Is there a better way to pass this for more than one command at the same time?
The workaround I found was to put everything inside a before block, for example:
before(() => {
cy.fixture("fixtureFile").as("data");
cy.get("#data").then((data) => {
Cypress.Commands.add('login', () => {
cy.visit("/login");
cy.get('#login-email').type(data.userEmail);
cy.get('#login-pass').type(data.userPass, {log: false});
cy.get('.btn').debug().click();
})
Cypress.Commands.add('createTagMedia', () => {
cy.get(".close").click();
cy.get("#form-field-name").type(data.releaseVersion);
cy.get(".form-group-adTag > .CodeMirror > .CodeMirror-scroll").type(data.mediaTag);
cy.get("#media-save-btn").click();
})
})
})
Is there a reason why you won't use the following:
import {data} from '../fixtures/FixtureFile'
Considering you have the following JSON file:
{
"data": {
"userEmail": "blah",
"userPass": "blah",
"releaseVersion": "1"
}
}
You can include this on your tests, commands (Cypress.custom.commands), etc.
before(() => {
const data = cy.fixture("fixtureFile");
cy.login(data);
cy.createTagMedia(data);
})
You could literally do something like the above. With your Cypress.Commands in your command.ts or js whichever you're using.
And make the commands take in a parameter. Then the above before hook would just be in your tests.

How to detect all tests (in multiple files) finished

I would like to drop database after all tests in all files ran. Is there a hook for it in Mocha?
after() hook can be applied only within 1 file only.
There is a root level hook in mocha. For your case, you can create a new file and specify drop database command in after function. That's it!
// init-test.js
after(function() {
// drop database
});
You don't need to move any test in other test file for this solution.
Reference:
https://mochajs.org/#root-level-hooks
Create a parent file that includes/requires all other tests, then use after within that file:
describe('User', () => {
require('../user/user.spec.js')
})
describe('Post', () => {
require('../post/post.spec.js')
})
describe('Tag', () => {
require('../tag/tag.spec.js')
})
describe('Routes', () => {
require('./routes.spec.js')
})
after(() => {
// drop database
})
I'm using process.on('exit'). It works when running only one file as well as when running tests from package.json.
database.mocha-base.js:
db.connect()
process.on('exit', async () => {
console.log('All tests finished. Droping database')
db.dropDatabase(dbName)
db.disconnect()
})
module.exports = {
applyHooks() {
before(async () => {
// truncate tables
})
}
}
I'm including database.mocha-base.js in all tests that need database access:
const dbMochaBase = require('./path/to/database.mocha-base.js')
describe('Tests', () => {
dbMochaBase.applyHooks()
...
})

Resources