Current behavior:
I run cypress tests and they pass. The UI will display the page the last test visited. When I expand each test to display the steps, I try to click on each step in the test body. For example, get, find, click. The UI goes blank, completely white and it does not highlight the page that particular step visited or the button the step clicked on. There is an icon indicating the element is not visible.
Image 1
Desired behavior
I watched the cypress tutorials on youtube and it appears the UI should highlight, for example, the button that was clicked. Or, if I get on the get step, it should highlight the element that was retrieved
Please see example from Lesson 4 of Cypress IO's recent tutorial video:
image
Notice the UI displays the page and there is no icon indicating the element is not visible.
Code:
Test code to reproduce
describe("home page", () => {
beforeEach(() => {
cy.visit("http://localhost:3000")
cy.clearLocalStorage();
})
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("Course Testing Your First Next.js Application", () => {
cy.getByData('course-0')
.find('a')
.eq(3)
.click()
cy.location('pathname').should('eq', '/testing-your-first-application')
})
it("Testing Foundations", () => {
cy.getByData('course-1')
.find('a')
.eq(3)
.click()
cy.location('pathname').should('eq', '/testing-foundations')
})
it("Cypress Fundamentals", () => {
cy.getByData('course-2')
.find('a')
.eq(3)
.click()
cy.location('pathname').should('eq', '/cypress-fundamentals')
})
})
})
I have the following Cypress test:
describe(`sign in`, () => {
const getIframe = () => {
return cy
.get('iframe[id=my-iframe]')
.its('0.contentDocument.body')
.should('not.be.empty')
.then(cy.wrap)
.as('iFrame')
}
it('signs in', () => {
cy.visit(PATH.SIGN_IN)
getIframe()
cy.get('#iFrame').find('input[name=email]').click().type('user#test.test')
cy.get('#iFrame').find('input[name=password]').click().type('test-password')
cy.get('#iFrame').find('button').contains(/^Sign in$/).click()
// signin is successful and the contents of the page refresh to show a page containing <h3>Hello user</h3>
cy.get('#iFrame').find('h3').contains('Hello user').should('be.visible')
// the above line fails...
})
})
The test fails on the last line. Even though the contents inside the iframe successfully refresh and Hello user is visible, Cypress is not able to find this text inside cy.get('#iFrame').
How should I handle this situation correctly with Cypress?
We have written cypresstests that we now want to divide into code blocks. Before starting do divide code all tests ran accordingly and passed. But since changing into blocks we started to get errors about 401 authentication.
Is this the right syntax for code blocks in Cypress?
/* eslint-disable no-undef */
describe('Log in', () => {
it('Successfully loads', function () {
cy.visit('/')
.get('input[type="email"]')
.type('XXXX')
.get('input[type="password"]')
.type('XXXX')
.get('[style="text-align: center;"] > .ui').click()
})
describe('The Assignments Page', () => {
it('Add Assignment', function () {
cy.get('[href="/assignments"]').click()
cy.get('.grey').click()
cy.get('.ui > .search').type('Astra Zeneca')
cy.get(':nth-child(2) > .ui > input').type('System Development')
cy.get('textarea').type('This is a short text')
cy.get(':nth-child(4) > .ui').click()
cy.get('a.ui').click()
})
})
This makes total sense :) In the second test block "The Assignments Page" you're not logged in. You should log in using beforeEach hook in every test block. In cypress, every test is executed on clean canvas to ensure that no errors from previous tests fail the next test. Means you HAVE TO login before every test. That's why you need beforeEach hook.
Also the best practice here is to login programatically - means instead of clicking input field and typing (cy.type), send your login request with cy.request and check if it's successful in the response.
Example code of login in beforeEach hook:
beforeEach(() => {
cy.request({
method: "POST",
url: '<YOUR LOGIN ENDPOINT>',
body: {
email: <VALUE>,
pass: <VALUE>
},
form: true
}).then(response => {
expect(response.status).to.eq(200);
expect(response.body.success).to.be.true;
});
};
}
I have a button on my page, I want to write an e2e test using Protractor. What I want to implement is that when clicking the button, page change to http://localhost:8100/#/booking. How can I implement that?
describe('booking function', function() {
it('should go to booking page', function() {
broswer.get(localHostCruises);
element(by.css('.button.button-stable.button-block')).click();
//sudo code
expect(page change to "http://localhost:8100/#/book" );
})
})
you need to use the browser.getCurrentUrl() method, so something like this:
element(by.css('.button.button-stable.button-block')).click().then(function () {
expect(browser.getCurrentUrl()).toEqual("http://localhost:8100/#/book");
})
You can achieve this with below code.
let targetLocation = 'your/target/location';
browser.get('localHostCruises'); // Login page.
element(by.css('.button.button-stable.button-block')).click(); // click on button.
browser.setLocation(targetLocation);
// If Login takes some time, so wait until it's done.
browser.wait(() => {
return browser.getCurrentUrl().then((url) => {
let isMatch = url.match(targetLocation);
if (isMatch) {
page = new Page; // I assume you writing test cases in page object.
} else {
browser.setLocation(targetLocation);
}
return isMatch;
});
}, 2000, 'Should throw an error message.');
describe('my homepage', function() {
var ptor = protractor.getInstance();
beforeEach(function(){
// ptor.ignoreSynchronization = true;
ptor.get('http://localhost/myApp/home.html');
// ptor.sleep(5000);
})
describe('login', function(){
var email = element.all(protractor.By.id('email'))
, pass = ptor.findElement(protractor.By.id('password'))
, loginBtn = ptor.findElement(protractor.By.css('#login button'))
;
it('should input and login', function(){
// email.then(function(obj){
// console.log('email', obj)
// })
email.sendKeys('josephine#hotmail.com');
pass.sendKeys('shakalakabam');
loginBtn.click();
})
})
});
the above code returns
Error: Error while waiting for Protractor to sync with the page: {}
and I have no idea why this is, ptor load the page correctly, it seem to be the selection of the elements that fails.
TO SSHMSH:
Thanks, your almost right, and gave me the right philosophy, so the key is to ptor.sleep(3000) to have each page wait til ptor is in sync with the project.
I got the same error message (Angular 1.2.13). My tests were kicked off too early and Protractor didn't seem to wait for Angular to load.
It appeared that I had misconfigured the protractor config file. When the ng-app directive is not defined on the BODY-element, but on a descendant, you have to adjust the rootElement property in your protractor config file to the selector that defines your angular root element, for example:
// protractor-conf.js
rootElement: '.my-app',
when your HTML is:
<div ng-app="myApp" class="my-app">
I'm using ChromeDriver and the above error usually occurs for the first test. I've managed to get around it like this:
ptor.ignoreSynchronization = true;
ptor.get(targetUrl);
ptor.wait(
function() {
return ptor.driver.getCurrentUrl().then(
function(url) {
return targetUrl == url;
});
}, 2000, 'It\'s taking too long to load ' + targetUrl + '!'
);
Essentially you are waiting for the current URL of the browser to become what you've asked for and allow 2s for this to happen.
You probably want to switch the ignoreSynchronization = false afterwards, possibly wrapping it in a ptor.wait(...). Just wondering, would uncommenting the ptor.sleep(5000); not help?
EDIT:
After some experience with Promise/Deferred I've realised the correct way of doing this would be:
loginBtn.click().then(function () {
ptor.getCurrentUrl(targetUrl).then(function (newURL){
expect(newURL).toBe(whatItShouldBe);
});
});
Please note that if you are changing the URL (that is, moving away from the current AngularJS activated page to another, implying the AngularJS library needs to reload and init) than, at least in my experience, there's no way of avoiding the ptor.sleep(...) call. The above will only work if you are staying on the same Angular page, but changing the part of URL after the hashtag.
In my case, I encountered the error with the following code:
describe("application", function() {
it("should set the title", function() {
browser.getTitle().then(function(title) {
expect(title).toEqual("Welcome");
});
});
});
Fixed it by doing this:
describe("application", function() {
it("should set the title", function() {
browser.get("#/home").then(function() {
return browser.getTitle();
}).then(function(title) {
expect(title).toEqual("Welcome");
});
});
});
In other words, I was forgetting to navigate to the page I wanted to test, so Protractor was having trouble finding Angular. D'oh!
The rootElement param of the exports.config object defined in your protractor configuration file must match the element containing your ng-app directive. This doesn't have to be uniquely identifying the element -- 'div' suffices if the directive is in a div, as in my case.
From referenceConf.js:
// Selector for the element housing the angular app - this defaults to
// body, but is necessary if ng-app is on a descendant of <body>
rootElement: 'div',
I got started with Protractor by watching the otherwise excellent egghead.io lecture, where he uses a condensed exports.config. Since rootElement defaults to body, there is no hint as to what is wrong with your configuration if you don't start with a copy of the provided reference configuration, and even then the
Error while waiting for Protractor to sync with the page: {}
message doesn't give much of a clue.
I had to switch from doing this:
describe('navigation', function(){
browser.get('');
var navbar = element(by.css('#nav'));
it('should have a link to home in the navbar', function(){
//validate
});
it('should have a link to search in the navbar', function(){
//validate
});
});
to doing this:
describe('navigation', function(){
beforeEach(function(){
browser.get('');
});
var navbar = element(by.css('#nav'));
it('should have a link to home in the navbar', function(){
//validate
});
it('should have a link to search in the navbar', function(){
//validate
});
});
the key diff being:
beforeEach(function(){
browser.get('');
});
hope this may help someone.
I was getting this error:
Failed: Error while waiting for Protractor to sync with the page: "window.angular is undefined. This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping. See http://git.io/v4gXM for details"
The solution was to call page.navigateTo() before page.getTitle().
Before:
import { AppPage } from './app.po';
describe('App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should have the correct title', () => {
expect(page.getTitle()).toEqual('...');
})
});
After:
import { AppPage } from './app.po';
describe('App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
page.navigateTo();
});
it('should have the correct title', () => {
expect(page.getTitle()).toEqual('...');
})
});
If you are using
browser.restart()
in your spec some times, it throws the same error.
Try to use
await browser.restart()