Cypress: The command was expected to run against origin - cypress

I try to realize multi-tabs test which is supported in Cypress 12 by changing the origin of test with cy.origin(). I use https://www.blender.org/ as my baseUrl set in config file, from the Blender main page I extract href to Instagram and change the origin to it. Cypress gives me the following error:
The command was expected to run against origin https://instagram.com but the application is at origin https://www.instagram.com.
Here what I do in the test:
When('I change the origin of my test configuration', () => {
cy.window().then((win) => {
cy.stub(win, 'open').as('Open');
});
const url = Cypress.config('baseUrl');
cy.visit(url);
cy.window().scrollTo('bottom');
var instaUrlString;
cy.get('.social-icons__instagram')
.invoke('attr', 'href')
.then(($instaUrl) => {
instaUrlString = $instaUrl.toString();
cy.origin(instaUrlString, { args: instaUrlString }, (instaUrlString) => {
cy.visit(instaUrlString);
cy.wait(2000);
cy.contains('Allow essential and optional cookies').click();
});
});
cy.visit(url);
});
When I pass hardcoded string to cy.origin() it works fine. What am I doing wrong?

You are missing the www part of https://www.instagram.com. Cypress is comparing the protocol, path and port number but the paths are different.
The shorthand version you have passed in via the link href is not acceptable in this situation. The DSN will resolve the shorthand, Cypress will not.
You could create a function to correct the short version, but what is the point? Just add the correct and working parameter to your cy.origin() command.

Related

cy.origin() unable to find any elements on Auth0 page

I'm trying to automate a login process for our site which uses Auth0 & Google Sign in. On the login page if you click Google sign in you get sent to an Auto0 page with a form and another Google sign in link, the page contains a URL something like:
https://OURDOMAIN.auth0.com/login?state=*REMOVED*
It's the first time I'm trying to use cy.origin() In my test I'm trying this:
cy.get("a[testid='googleSignInButton']").click()
cy.origin('https://OURDOMAIN.auth0.com/', () => {
cy.get("input[type='email']").type('anEmail#me.com')
})
The problem is whatever I try to do in the origin block just returns a timeout trying to find the element.
I've set experimentalSessionAndOrigin: true is there something I'm doing wrong? Unfortuantly the way we are using Auth0 and Google Sign in means it's not possible to do it via API calls.
try without cy.origin()
I had the same problem, and it was fixed by removing the cy.origin()
Try this one:
Cypress.Commands.add('loginSession', (email, password) => { cy.session([email, password], () => {
cy.visit('/').then(() => {
//cy.origin('auth0.com', { args: [email, password] }, ([email, password]) => {
cy.get('#username').type(email)
cy.get('#password').type(password)
cy.get("button[type='submit']").click({ force: true })
// })
})
cy.get('[data-cy="logo"]').should('be.visible')
})
});

How do I log a specific field in API requests within Cypress

I want to cypress.log() out a specific field in the request header whenever my webapp makes requests that way when it fails and adds screenshots/logs I can grab that that requestId that failed.
Is there a way to setup cypress so that for all network requests it checks for this field and log it?
I can add a cy.intercept within each individual file but I want a more generic way to handle this.
Cypress.log is the synchronous version of cy.log().
Add middleware: true to the intercept to pass request to other intercepts.
cy.intercept({ url: '*', middleware: true }, (req) => {
const headerValue = req.headers?['x-custom-headers']
if (headerValue) {
Cypress.log({
name: 'x-custom-header',
message: headerValue
})
}
})
You'll get an Cypress promise error if you try to use cy.log() to log out every request header in an cy.intercept() within a routeHandler callback. This would also make it kind of tough to log to a CI terminal as well.
Instead you can console.log to dev tools. To make it apply to all tests, you can wrap it in a beforeEach() and place it in the support/index.js file.
// support/index.js
beforeEach(() => {
cy.intercept('*', (req) => {
req.continue((res) => {
console.log(JSON.stringify(req.headers))
})
})
})

Capture a variable in a stubbed function

I have a test case which opens a secondary window. From what I read online, you should prevent this second window opening and visit the url that should have been opened. However, in all the test example I saw, the second url is static. In my case, I need it to be dynamic. This is why I'm using a cy.stub() to a window opening and trying to get the url from it.
cy.visit('https://myUrl.com');
cy.window().then(win => {
cy.stub(win, 'open', newUrl => {
cy.wrap(newUrl).as('newUrl');
});
});
cy.get('#myButton').click(); // opens new window at new url with generated keys
cy.get('#newUrl').then(newUrl => {
cy.visit(newUrl);
});
However, the cy.wrap() inside the cy.stub() triggers this error:
Error: CypressError: Cypress detected that you returned a promise from a command while also invoking one or more cy commands in that promise.
The command that returned the promise was:
> `cy.click()`
The cy command you invoked inside the promise was:
> `cy.wrap()`
Because Cypress commands are already promise-like, you don't need to wrap them or return your own promise.
Basically my question is how to capture the url in a stub for later use. Thanks in advance.
The problem is using cy.wrap() or any cy commands inside an event listener. The code you have is valid, and the error should actually be a warning IMO.
One way to handle it is with a plain JS variable.
You may also need a cy.origin() wrapper for this test.
In a recent similar question How to access new tab by clicking on "href" it was found that the cy.visit(newUrl) was causing a reload of the test window, which looses all the data (variables and aliases) previously obtained.
cy.visit('https://myUrl.com');
let nextUrl;
cy.window().then(win => {
cy.stub(win, 'open', newUrl => {
nextUrl = newUrl
});
});
cy.get('#myButton').click(); // opens new window at new url with generated keys
cy.then(() => {
const newOrigin = nextUrl.split('?')[0] // remove query params
.replace('http://', 'https://') // correct for secure protocol
cy.origin(newOrigin, { args: { nextUrl } }, ({ nextUrl }) => {
cy.visit(nextUrl)
})
})
Alternative way to alias
Looking again at your code, you may be able to apply the alias this way
cy.window().then(win => {
cy.stub(win, 'open').as('newUrl');
})
cy.get('#myButton').click();
cy.get('#newUrl').then(newUrl => {
cy.visit(newUrl);
})

Hide XHR calls on Cypress test runner

I am trying to hide XHR calls on cypress test runner. I have added the below code in my support/index.js but it still doesn't work. Could anyone please suggest how it works?
Cypress.Server.defaults({
delay:500,
force404:false,
ignore: (xhr) => {
return false;
},
})
Try this, works for me
Add the following to cypress/support/index.js:
// Hide fetch/XHR requests
const app = window.top;
if (!app.document.head.querySelector('[data-hide-command-log-request]')) {
const style = app.document.createElement('style');
style.innerHTML =
'.command-name-request, .command-name-xhr { display: none }';
style.setAttribute('data-hide-command-log-request', '');
app.document.head.appendChild(style);
}
Referred and obtained details https://gist.github.com/simenbrekken/3d2248f9e50c1143bf9dbe02e67f5399
It looks like Cypress.Server is deprecated along with cy.server() (possibly it's the same thing).
An intercept might do what you want
cy.intercept(url, (req) => {
if (req.type === 'xhr') {
// custom logic for handling
}
})
But I don't think the example code you used was intended to "hide" the xhr requests. What is it you want to do with them?
You can also use this command:
Cypress.Server.defaults({
ignore: (xhr) => bool
})
Note: At least is working for the 9.7.0 Cypress version

Cypress.io - sitemap.xml validation test

:) I chose for automated testing a tool Cypress.io.
I need some tests for my sitemap.xml document and I dont know how to do that :(
I have tried install an npm package libxmljs
npm install libxmljs --save
and load it as plugin in cypress/plugins/index.js
const libxmljs = require('libxmljs');
But there is a problem with this. It shows an error
The plugins file is missing or invalid.
Your pluginsFile is set to /home/my-app/cypress/plugins/index.js, but
either the file is missing,
it contains a syntax error, or threw an error when required.
The pluginsFile must be a .js or .coffee file.
Please fix this, or set pluginsFile to false if a plugins file is not
necessary for your project.
Error: The module '/home/my-app/node_modules/libxmljs/build/Release/xmljs.node'
Please help me, how can I use libxmljs in Cypress.io or how i should write tests for Sitemap.xml in this end-to-end testing tool.
Thanks for your time! :)
Although #NoriSte's answer is correct, I found a simpler alternative without the need for any 3rd party code.
Cypress API exposes all the necessary methods to:
load a file (the sitemap.xml in your case): cy.request.
parse XML file (it exposes the jQuery API): Cypress.$
check if a page successfully loads (with a 200 status code): cy.visit
This is the following test that I use to test if all of the pages declared in the sitemap are loading (and make sure it doesn't point to any 404):
describe('Sitemap', () => {
// initialize the url array
let urls = []
// be sure to get the url list before executing any tests
before(async () => {
// getch the sitemap content
const response = await cy.request('sitemap.xml')
// convert sitemap xml body to an array of urls
urls = Cypress.$(response.body)
// according to the sitemap.xml spec,
// the url value should reside in a <loc /> node
// https://www.google.com/sitemaps/protocol.html
.find('loc')
// map to a js array
.toArray()
// get the text of the <loc /> node
.map(el => el.innerText)
})
it('should succesfully load each url in the sitemap', () => {
urls.forEach(cy.visit)
})
})
If you want to use libxmljs to parse your sitemap you should
read the sitemap itself with cy.request
add a custom task to Cypress (because libxmljs is a node library, cy.task is the only way to consume Node.js scripts from your Cypress tests)
returns the parsed data from your task
assert about it in a Cypress test
Those are the high-level steps you need to do 😉
To add to a great answer by gion_13, here’s his solution refactored to utilize Cypress promise-like-commands instead of async calls.
describe('Sitemap', () => {
let urls = [];
before(() => {
cy.request('sitemap.xml')
.as('sitemap')
.then((response) => {
urls = Cypress.$(response.body)
.find('loc')
.toArray()
.map(el => el.innerText);
});
});
it('should succesfully load each url in the sitemap', () => {
urls.forEach(cy.visit);
});
});
Using async in Cypress may raise error ‘Cypress detected that you returned a promise in a test, but also invoked one or more cy commands inside of that promise’.
describe('Sitemap', () => {
let urls = [];
before(() => {
const parser = new DOMParser();
cy.request('/sitemap.xml').then((response) => {
const document = parser.parseFromString(response.body, 'application/xml');
const parsedUrls = document.getElementsByTagName('loc');
urls = Array.from(parsedUrls).map((item) => item.innerHTML);
});
});
it('Should load each url from the sitemap', () => {
urls.forEach(cy.visit);
});
});

Resources