Blank page after running Cypress tests - cypress

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.

Related

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()
});

How to visit pre-defined URLs from file

If I have 30 pages to check, for example, EN has a disclaimer, but other 29 language don't, what would be the best way to do this? For example, right now I have it like this:
const urls = ['http://google.com/en',
'http://google.com/bg'
]
describe('Disclaimer check', () => {
urls.forEach((url) => {
it(`Checks disclaimer text ${url}`, () => {
cy.visit(url)
cy.get('.Disclaimer').should('be.visible')
.and('contain', 'This is disclaimer.')
})
})
})
For 2 sites it's fine to define them in the same code but other file that checks that Disclaimer isn't there would be 29 different URL-s. What would be the best practice here? One idea is to separate all the test but that would mean 30 tests for each feature which doesn't sound too great.
As url I'm working with uses many different values in it, making it short with baseurl doesn't seem to fit also.
Thank you in advance!
You were on the right path. This will be a good case for using cypress-each. Cypress-each will run all tests regardless if one or more fail. Depending on how long it takes, you may want to break down the it.each test into another file.
import 'cypress-each' // can included in /support/index.js
describe('Disclaimer check', () => {
// baseUrl: http://google.com
const noDisclaimerUrl = [
'/bg',
// all other languages
]
it('/en does have disclaimer text', () => {
cy.visit('/en')
// test code
})
it.each((noDisclaimerUrl)
`%s does not have disclaimer text`
(url) => {
cy.visit(url)
// test code
})
})
Adding all of your data to a data object, import that data object, and then using Cypress Lodash to iterate a number of times should achieve your goal.
// data.js
// defining data
export const data =[{
"url": "www.google.com",
"hasDisclaimer": true
}, {
"url": "www.other-url.com",
"hasDisclaimer": false
}...
]
You can then wrap the returned array and use it in a Cypress chain.
import { data } from './path/to/data'
describe('Tests', () => {
Cypress._.times(data.length, (index) => {
const curr = data[index];
it(`Checks disclaimer text ${curr.url}`, () => {
cy.visit(curr.url).then(() => {
if (curr.hasDisclaimer) {
cy.get('.Disclaimer').should('be.visible')
.and('contain', 'This is disclaimer.');
} else {
// code for checking disclaimer does not exist
}
});
});
});
});
Under your Fixtures folder create a urls.json file like this:
[
"https://google.com/en",
"https://google.com/bg",
"https://url3.com",
"https://url4.com"
]
Now assuming that you know which URLs don't have the disclaimer, you can simply add them in the If condition and apply the not.exist assertion.
import urls from '../fixtures/urls.json'
describe('Disclaimer check', () => {
urls.forEach((url) => {
it(`Checks disclaimer text ${url}`, () => {
cy.visit(url)
if (url == 'https://google.com/en' || url == 'https://url3.com') {
//Check for URL's where disclaimer doesn't exist
cy.get('.Disclaimer').should('not.exist')
} else {
//Check for URL's where disclaimer exists
cy.get('.Disclaimer')
.should('be.visible')
.and('contain', 'This is disclaimer.')
}
})
})
})

How to wait for the api call to finish and then check if element present using cypress?

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.

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.

Root level `beforeEachFile` and `afterEachFile`

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(() => {
})
})

Resources