Can we preserve cookies in cypress? - cypress

I wanted to know is there any way by which i can preserve cookies in cypress.
I tried automating a feature in cypress for my application and i'm unable to load the page.

Cypress.Cookies.defaults({
whitelist: ["cookie_name", "cookie_name" ]
});
// test describe function
afterEach(() => {
Cypress.Cookies.preserveOnce();
});

Related

Saving requests made during Cypress test as curls

Is it possible to save requests made during Cypress test as curls to be reviewed later? E.g. for importing them in Postman.
Network tab, of DevTools of Cypress application, logs request from Cypress app, not from application under test itself.
The network tab will show requests from the AUT, but if you want to find all the requests use intercept
const requests = []
cy.intercept('/api/*', (request) => {
console.log(request.url) // get them from the console
requests.push(request.url) // or save them to a file at end of spec
})
...
after(() => {
cy.writeFile('cypress/fixtures/requests.json', requests)
})
To gain detailed information about the request and response including the response time, you can utilize the HAR file format (http://www.softwareishard.com/blog/har-12-spec/). To generate a HAR file on the fly during the execution of your Cypress tests you can use the cypress-har-generator.
describe('my tests', () => {
before(() => {
// start recording
cy.recordHar();
});
after(() => {
// save the HAR file
cy.saveHar({ waitForIdle: true });
});
it('does something', () => {
cy.visit('https://example.com');
// ...
});
});
This plugin will generate a HAR file that can be imported to the network panel of developer tools (https://developer.chrome.com/blog/new-in-devtools-76/#HAR) or Postman (https://blog.postman.com/postman-now-supports-importing-har-files/), for further analysis.

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

cy.visit() generates GET request to different page than requested in run mode

I have a very basic Cypress test, per below
describe("Tests for Site users Page", () => {
beforeEach(() => {
cy.login();
});
it("visits the manage users page", () => {
cy.visit("/sites/2/users");
cy.contains("Contact Name").should("exist");
});
For some reason, Cypress does not visit /sites/2/users and instead goes to /sites/2/global (even though I did not request that). Can someone please tell me what is going on and how this issue can be resolved? In my cypress.json i have the baseUrl set to http://localhost:3002. Note, in the screenshot I have seen it says (new url) http://localhost:3002/sites/2/global directly after attempting to visit /sites/2/users
This is a bit of wild-guess territory, but maybe the login is not successful, and /sites/2/global is the default page for not-logged-in.
To test it, check where do you go with cy.visit('/') and with cy.login() commented out for the moment.
If it's /sites/2/global, then cy.login() is the problem.

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

Save local storage across tests to avoid re-authentication

I'm wondering if it is possible to save the state of localStorage across tests.
Mainly because I want to avoid re-authentication on each test. I realize that I can create a command that sends an API request to our backend to avoid going through the auth flow but for various reasons this won't work in my situation.
I am asking if it possible to have a workflow like this:
Go to login page: Authenticate get back response and save session to local storage
Persist local storage somehow...
Go through other tests as authenticated user
You can use the cypress-localstorage-commands package to persist localStorage between tests, so you'll be able to do login only once:
In support/commands.js:
import "cypress-localstorage-commands";
In your tests:
before(() => {
// Do your login stuff here
cy.saveLocalStorage();
});
beforeEach(() => {
cy.restoreLocalStorage();
});
Here's what I ended up doing:
Go to login page: Authenticate
At this point we have data we want to persist between tests in localStorage but we are not allowed to whitelist localStorage.
However, we are allow to whitelist cookies
I have some code like this inside my support/commands.js that act as helpers
const sessionKeys = {
authTokens: 'auth.tokens',
sessionConfig: 'session.config',
};
// The concatenation of username and cid will be the key to set the session
Cypress.Commands.add('persistSession', (key) => {
const authTokens = localStorage.getItem(key);
cy.setCookie(key, authTokens);
});
Cypress.Commands.add('restoreSession', (key) => {
cy.getCookie(key).then(authTokens => {
localStorage.setItem(key, authTokens.value);
});
});
So we call cy.persistSession(key) after we login, which means we have all the authentication saved as cookies which are whitelisted inside of support/index.js with code.
Like this:
Cypress.Cookies.defaults({
whitelist: function(cookie){
// Persist auth stuff
const reAuthTokens = new RegExp('.*auth\.tokens');
if(reAuthTokens.test(cookie.name)){
return true;
}
return false;
}
});
Now anytime we need our auth tokens inside our other tests before running them we cy.restoreSession(key) and we should be good!
Here is the useful link that solves my problem like yours: Preserve cookies through multiple tests
my code like:
const login = () => {
cy.visit('http://0.0.0.0:8080/#/login');
cy.get('#username').type('username');
cy.get('#password').type('1234password$');
cy.get('#login-button').click();
}
describe('UI', () => {
// beforeEach(login);
beforeEach(() => {
login();
Cypress.Cookies.preserveOnce('session_id', 'remember_token');
});
});
hope can help you.
Anything you can do in JS you can do in a cypress test. If you have some way to store creds (auth token, etc.) in local storage, I see no reason why you can't do that. If cypress is clearing out your local storage between tests, you will have to write a beforeEach hook that saves an authenticated token (hard-coded by you) to local storage before each test.

Resources