Cypress e2e: unable to test multi-domain using cy.origin()? - cypress

I am learning cy.origin concept and found below snippet from internet said it's working good. I am getting an error as unable to find element: #login_field. I've also set true chromeWebSecurity & experimentalSessionAndOrigin but still error. Kindly help to solve.
describe('Test login to Netlify using Github', () => {
it("should login to netlify with github", () => {
// visit netlify
cy.visit("https://www.netlify.com/");
cy.get("#cta-mainNav-login").click({ force: true });
cy.wait(5000)
cy.contains("Log in").click({ force: true });
cy.contains("GitHub").click({ force: true });
// click on 'login with Github' button
cy.origin("https://github.com", () => {
cy.get('#login_field').type("*****#gmail.com");
cy.get("#password").type("********");
cy.get("input").contains("Sign in").click();
});
// should login to netlify and open dashboard
cy.url().should("contain", "https://app.netlify.com/");
});
});

Related

Cypress automation

When i am entering otp in the cypress automation E2E then click on submit still it is in same page it is not moving to the next page.
describe('Check-Eligibility-client', () => {
it('KYC Page', () => {
cy.get('[data-test="mobile-number"]').click().type('9742368997');
cy.get('[data-test="get-started"]').should('be.visible');
cy.get('[data-test="get-started"]').click();
cy.get('[id^=otp_0_]', { timeout: 10000 }).should('be.visible');
cy.wait(10000);
cy.get('[data-test="confirm-otp"]').click();
});
});

Why Cypress throw this error: Step implementation missing for...(even when there is implemented step def.)

I am using Cypress version 10.9.0 for e2e testing. Of course, there are more step defs but it stops at the first then step as it can be seen from the SS image.
When('I enter an invalid username on the login page', () => {
cy.get('#username').type('portal').invoke('removeAttr', 'value').click({ force: true }, { timeout: 30000 })
cy.get('#password').type('SwY66bc3VZLUFR9')
cy.get('[type="submit"]').click()
})
Then('an error message is displayed with the text Invalid username/password', () => {
cy.get(".invalid.text-left").should('contain.text', 'Invalid username/password')
})
Cypress GUI error
DOM element
The error says cannot find #username but clearly it is present, so you may have a shadowroot in the DOM above the <input>.
If so, add a configuration to allow searching within, in cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:1234'
},
includeShadowDom: true,
})
If you don't see shadowroot, look for an <iframe> element.
Handling an iframe is best done with Cypress iframe

Cypress with Auth0.com login and redirects

We have changed our login page so it's now redirecting to auth0.com and then back to our domain after you login to auth0. The issue is now when I login I get redirected to our QA environment which requires authentication so once the test submits the form I get a 401.
Before auth0 I was getting around the 401 by overwritting the visit function passing in a auth header.
If I try to visit our QA environment first before going to our login page I get
You may only cy.visit() same-origin URLs within a single test.
I've seen other questions asked about auth0 but not with also requiring authentication in the redirect, is it possible to still run tests on our QA environment?
While the Cypress team works to resolve max 1 site... support visiting multiple superdomains in one test on work around I have used in the past is this: detailed again below.
In commands.js
// -- Save localStorage between tests
let LOCAL_STORAGE_MEMORY = {};
Cypress.Commands.add('saveLocalStorage', () => {
Object.keys(localStorage).forEach(key => {
LOCAL_STORAGE_MEMORY[key] = localStorage[key];
});
});
Cypress.Commands.add('restoreLocalStorage', () => {
Object.keys(LOCAL_STORAGE_MEMORY).forEach(key => {
localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]);
});
});
// -- Visit multiple domains in one test
Cypress.Commands.add('forceVisit', url => {
cy.window().then(win => {
return win.open(url, '_self');
});
});
In test.spec.js
/// <reference types="cypress" />
context('Force Visit', () => {
it('should be able to visit and assert on two domains', () => {
cy.forceVisit('https://example.cypress.io');
cy.title().should('eq', 'Cypress.io: Kitchen Sink');
cy.forceVisit('https://www.google.com');
cy.title().should('eq', 'Google');
});
});
context('Auth Flow', () => {
before(() => {
cy.forceVisit('<auth url>');
cy.get('<username input>').type('<username>');
cy.get('<password input>').type('<password>');
cy.intercept('POST', '<auth login request>').as('auth');
cy.get('<submit button>').click();
cy.wait('#auth');
});
afterEach(() => {
cy.saveLocalStorage();
});
beforeEach(() => {
cy.restoreLocalStorage();
// Preserve Cookies between tests
Cypress.Cookies.defaults({
preserve: /[\s\S]*/,
});
});
it('should be able to start in authorized state', () => {
cy.visit('<site url>');
});
});

Cypress: why do I need to run cy.wait(0) before each test?

I'm testing the following app: https://objective-benz-e53b25.netlify.app/
It's a bootstrap dashboard and I'm just testing clicking on a drop-down menu, then clicking and item, and checking that I'm being redirected.
this is are tests I run:
describe('Sapper template app', () => {
beforeEach(() => {
cy.visit('/')
// cy.wait(0);
});
it('has the correct <h1>', () => {
cy.contains('h1', 'Dashboard')
});
it('navigates to /settings', () => {
cy.get('nav a.dropdown-toggle').click();
cy.get('nav a.dropdown-item').contains('Settings').click();
cy.url().should('include', '/settings');
cy.contains('h3', 'Settings')
});
it('navigates to /logout', () => {
cy.get('nav a.dropdown-toggle').click();
cy.get('nav a.dropdown-item').contains('Logout').click();
cy.url().should('include', '/pages/authentication/login');
cy.contains('h3', 'Login')
});
});
And it gives me the following error:
2 passing (10s)
1 failing
1) Sapper template app navigates to /settings:
CypressError: Timed out retrying: cy.click() failed because this element is not visible:
<a class="dropdown-item" href="settings">Settings</a>
This element <a.dropdown-item> is not visible because its parent <div.dropdown-menu.dropdown-menu-right> has CSS property: display: none
If I switched the logout (third) test for the settings (second) test, then the failing one is logout.
I had to add a cy.wait(0) on the beofreEach and it solved it.
The strange thing is that now it is working ok, even with the cy.wait commented out.
I shared the code with a colleague of mine and he had the same trouble.
Any idea why it was failling, and why now it seems to work ok?
Issue is hapening with cy.get('nav a.dropdown-toggle').click();
click is not working on User Icon hence the drop down is not visible and test fails.
One of the solution is to use { force: true }. This option is to disable error checking on drop down click.
beforeEach(() => {
cy.visit("https://objective-benz-e53b25.netlify.app/");
});
it("has the correct <h1>", () => {
cy.contains("h1", "Dashboard");
});
it("navigates to /settings", () => {
cy.get("nav a.dropdown-toggle").click({ force: true });
cy.get("nav a.dropdown-item").contains("Settings").click({ force: true });
cy.url().should("include", "/settings");
cy.contains("h3", "Settings");
});
it("navigates to /logout", () => {
cy.get("nav a.dropdown-toggle").click({ force: true });
cy.get("nav a.dropdown-item").contains("Logout").click({ force: true });
cy.url().should("include", "/pages/authentication/login");
cy.contains("h3", "Login");
});
});

Running into Error while waiting for Protractor to sync with the page with basic protractor test

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

Resources