Why defaultTimeOut is not working when checking images if visible? - cypress

I need help on implementing the defaultTimeOut and I have this code:
it('Check Image if visible', () => {
//IMG
cy.get('[class^="image1"]:nth-child(1) img').should('have.length', 5)
.each(($el) => {
expect($el).to.be.visible
})
});
it('Check Image 2 if visible', () => {
//IMG
cy.get('[class^="image2"]:nth-child(1) img').should('have.length', 5)
.each(($el) => {
expect($el).to.be.visible
})
});
But it checks the images in an instant it doesn't wait 4000ms for the image to load and check if it's visible even if i set the {timeout:10000} in the element and defaultTimeOut:10000 on config. as far as i want i don't want to use cy.wait. Do you have any recommendations?

I think the reason is the <img> element is there but the image content has not loaded.
Try
cy.wrap($el)
.should('be.visible')
.and('have.prop', 'naturalWidth')
.should('be.greaterThan', 0)

Related

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 - how to compare href to anchor text

I'm wondering how to test using cypress libary if the href attribute include the text from anchor tag. The code is as follow:
I have a div with a lot of anchors with data attribute.
<div>
#hash1
#hash2
#hash3
// and many more
</div>
I stared testing with check if each element have "#", href attribute with "/tag/" :
describe('Test', () => {
it('should navigate to link from hashtag', () => {
cy.visit('/');
cy.get('[data-cy="hashtag"]').each((item) => {
cy.wrap(item).contains('#').should('have.attr', 'href').and('contain', '/tag/');
})
})
});
but how can I check if href include the displayed text from a tag?
Once you've yielded the element from your cy.get(), you can reference it as a jQuery object. In this case, we'll want to get the text.
describe('Test', () => {
it('should navigate to link from hashtag', () => {
cy.visit('/');
cy.get('[data-cy="hashtag"]').each((item) => {
cy.wrap(item).contains('#').should('have.attr', 'href', `/tag/${item.text().replace('#', '')}`)
})
})
});
If you simply wanted to see if the href contains the text, you could use the jQuery attr function.
describe('Test', () => {
it('should navigate to link from hashtag', () => {
cy.visit('/');
cy.get('[data-cy="hashtag"]').each((item) => {
expect(item.text()).to.contain('#');
expect(item.attr('href')).to.contain(item.text().replace('#', ''));
})
})
});

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.')
}
})
})
})

In Cypress, trying to have multiple contexts leads to tests not finishing

After years of reviewing answers here, I finally have a question ^^
I'm a new Cypress user and trying to make tests one after another, but doing so make the first context to finish before all its tests (line 29).
Please find code below :
describe('Home', () => {
beforeEach(() => {
cy.viewport(1920, 1080)
visit('home')
})
context('Content and links', ()=>{
before(() => {
getTransloco('market', 'fr').then(res => loco = res);
cy.clearFirestore();
cy.importData({
...marketWithSellers(market, [seller]),
...createStandaloneProducts(products, seller),
});
})
it('Contains all data and links', async () => {
cy.contains(loco.app)
cy.contains(loco.subtitle)
get('order').contains(loco.order)
cy.log('ongoing')
get('signin').contains(loco.signin)
get('link-home').should('exist')
get('link-market').should('exist').should('have.class','disabled')
get('link-orders').should('exist')
get('link-profiles').should('not.exist')
get('link-signin').should('exist') // <== the test stops here /!\
get('order').click()
cy.contains(loco['select-market'])
get('market_0').should('exist').contains(market.name!)
cy.get('[aria-roledescription="map"]').should('exist')
cy.get('[role="button"]').should('exist')
cy.contains(loco['sellers-list']).scrollIntoView().should('exist')
get('seller_0').contains(seller.name)
get('link-about').should('exist')
get('link-facebook').should('exist')
get('link-instagram').should('exist')
get('link-twitch').should('exist')
cy.contains(loco.contact)
get('link-contact').should('have.attr', 'href', 'mailto:contact#kampoy.com')
})
})
context('Top nav bar', ()=>{
before(() => {
getTransloco('buyer', 'fr').then(res => loco = res);
})
it('Nav bar appears after scrolling down', () => {
get('top-nav').should('not.have.class', 'visible')
get('link-contact').scrollIntoView()
get('top-nav').should('have.class', 'visible')
})
it('Nav bar appears only has home, auth and order links', () => {
get('top-nav').children().should('have.length', 3)
get('top-nav link-home').contains(loco['app-name'])
get('top-nav link-auth').contains(loco.signin)
get('top-nav link-order').contains(loco.order)
})
})
})
The strange part is, if I comment the second context (top nav bar), then all my first context is working fine...
Does anyone understand why ?
Thanks for your time !

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.

Resources