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

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.

Related

Timed out retrying after 4000ms: The command was expected to run against origin https://google.com but the application is at origin https://google.com

I am trying to test my website from cypress.io, but i am constantly getting above error.
I am facing issue will Signing in with google. I am using the cy.origin() method.
/// <reference types="cypress" />
describe('Basic tests', () => {
it.only('Login should happen', ()=>{
// cy.viewport(1280, 720)
cy.visit('https://internetcomputerservices.com')
cy.contains('Dashboard').click()
cy.contains('Sign in with Google').click()
cy.origin('https://accounts.google.com/o/oauth2/auth', ()=>{
cy.get('[aria-label="Email or phone"]').click().type('haswrfbi20#gmail.com')
});
})
})
Please help me
Although I haven't able to find the solution for testing google login, i have connected with team and they will most likely resolve this issue in cypress 10.10.0.
For meanwhile, you can use token to directly login, by-pass the google-login and test the website.
you can find the token by going to developer tools and there you will find Application, click on it, there you will find the token, copy it and paste it in below code.
Make sure to install the package before hand:
npm i cypress-localstorage-commands
Code:
describe("Basic tests", () => {
before(() => {
cy.visit("---your-website-url---", {
onBeforeLoad(win) {
win.localStorage.setItem(
"token",
"---token-here---"
);
},
});
});
it.only("should be able to run test 1", async () => {
// write your first test here ----
});
});

Cypress cy.visit() is not redirecting to correct URL

I am trying to bypass the UI login by using cy.request() to log a user in and cy.visit() to go to the restricted route. I have followed this doc: https://docs.cypress.io/guides/end-to-end-testing/testing-your-app#Bypassing-your-UI
However, the test fails because the visit URL ('http://localhost:3000/join-or-create') is not loaded and instead the home page URL is loaded (http://localhost:3000/).
This is my test code:
describe('when user is signed in but has not joined a group', () => {
beforeEach(() => {
cy.request('POST', 'http://localhost:5000/api/testing/reset');
const user = {
name: 'Joe Bloggs',
email: 'Joe#Bloggs.com',
password: 'Password',
};
cy.request('POST', 'http://localhost:5000/register', user);
cy.request('POST', 'http://localhost:5000/sign-in', user);
cy.visit('http://localhost:3000/join-or-create');
});
it.only('should allow a logged in user to join or create a group', () => {
cy.contains('Join a group');
cy.contains('Create a group');
});
});
If I change cy.contains('Join a group'); to cy.contains('Welcome'); (which is content on the URL 'http://localhost:3000/') then the test passes.
If I use:
cy.visit('http://localhost:3000');
cy.get('[data-testid="email"]').type('Joe#Bloggs.com');
cy.get('[data-testid="password"]').type('Password');
cy.contains('sign in').click();
instead of cy.visit('http://localhost:3000/join-or-create'); the test passes.
The output of the test body shows that is redirecting to a new URL 'http://localhost:3000/' (as shown in the screenshot below) but I can't figure out why.
Thanks for any help.
In the bypass code, check the response from the POST request
cy.request('POST', 'http://localhost:5000/sign-in', user)
.then(response => console.log(response))
to see what tokens are returned.
Then in the form-login code, look at what happens to the same token after cy.contains('sign in').click() and see where the browser stores same token.
That's probably the step missing in the bypass code. You'll need to add something to do the same, e.g
cy.request('POST', 'http://localhost:5000/sign-in', user)
.then(response => {
const token = response.body.token; // figure out where the token is in response
cy.setCookie(token); // figure out where the app want's the token
})
It's also difficult to tell from the question what URL you need to cy.visit() in the bypass code, but there's only a couple of them so try both permutations.

Cypress test - Do not intercept api request

I need to test some pages on a project and this project do some APIs call to external services.
I need to make sure that these calls are made and check if my page change accordingly to the response.
This is my test:
describe('A logged in user', () =>{
it('can see his subscriptions', () => {
...... some checks .......
cy.intercept('https://example.com/api/v2/user-panel/get-subscription').as('userSubscription');
cy.wait('#userSubscription', { timeout: 35000 }).then(() => {
cy.contains('some text');
});
});
});
When I run the code seems that it can't se the API call but the page content change correctly.
This is the cypress response:
Timed out retrying after 35000ms: cy.wait() timed out waiting 35000ms
for the 1st request to the route: userSubscription. No request ever
occurred.
I tried to increase the timeout, event if the page loads in 1 second, but the result is the same.
There is something am I missing?
Doing the cy.wait() right after the cy.intercept() is not going to work.
Whatever triggers the API calls (a cy.visit() or a .click()) must occur after the intercept has been set up, and it therefore is ready to catch the API call.
From the Network Requests docs
cy.intercept('/activities/*', { fixture: 'activities' }).as('getActivities')
cy.intercept('/messages/*', { fixture: 'messages' }).as('getMessages')
// visit the dashboard, which should make requests that match
// the two routes above
cy.visit('http://localhost:8888/dashboard')
// pass an array of Route Aliases that forces Cypress to wait
// until it sees a response for each request that matches
// each of these aliases
cy.wait(['#getActivities', '#getMessages'])
// these commands will not run until the wait command resolves above
cy.get('h1').should('contain', 'Dashboard')

Cypress cache - server session expired

Can Cypress clear browser cookies/cache before each test?
The problem I am experiencing is the first execution is ok, but the second fails due to the cache. I tried cy.clearCookies(), but it doesn't work.
During the second execution, I receive the message server session expired.
Though I think by default each it block starts with a clear cache. The following command may be useful for your purposes
cy.clearLocalStorage()
Doc here:
https://docs.cypress.io/api/commands/clearlocalstorage#Command-Log
You could possibly wrap this like so
before(function () {
cy.clearLocalStorage();
});
describe("Some useful description", () => {
// your 'it' blocks here
})
Alternatively, if you wanted to programmatically clear your cache after each test, try:
describe("Some useful description", () => {
afterEach(() => {
cy.clearLocalStorage()
});
// your 'it' blocks here
})

Can't intercept Cypress API call

I have stuck with Cypress fixtures. Can't intercept an XHR request with SSR and navigation routing.
cypress/integration/page.js:
const fetch = require("unfetch")
describe("/about", () => {
beforeEach(() => {
cy.visit("/", { // Visit home page to trigger SSR
onBeforeLoad (win) {
win.fetch = fetch // replace fetch with xhr implementation
},
})
})
it("Has a correct title", () => {
cy.server()
cy.fixture("about").then(about => {
// about object is correct here, like {title: "About+"}
cy.route("GET", "http://localhost:8080/api/documents/url", about) // Not sure where .route should be
cy.get(".main > :nth-child(1) > a").click() // Navigate to the /about page
cy.route("GET", "http://localhost:8080/api/documents/url", about) // Tried both ways
// This hits my server API without stubbing, getting {title: "About"}
cy.title().should("eq", "About+") // About != About+
})
})
})
cypress/fixtures/about.json:
{"title": "About+"}
I see an XHR request (type=xhr) in Dev Tools and it doesn't use the above about stub object but hits real API instead. Why? Double checked URL and method – 100% the same. Can it be that route is coupled to visit and ignores click-based routing?!
Rechecking this once again, I've found a solution. Let me share the details for everyone interested:
1) I use Next.js which is an excellent tool for SSR but it doesn't allow you to disable server-side rendering (yet) according to this and this issues.
2) You can use Cypress with SSR pages but, in this way, you're limited to testing real HTML. Which means you have to either couple tests to real data (not good in most cases) or stub the database itself (slow). In general, you want to stub HTTP requests.
3) Cypress can't stub fetch requests and mocking fetch with XHR-based implementation was trickier than I thought.
First you need to:
// cypress/integration/your-test.js
Cypress.on('window:before:load', (win) => {
delete win.fetch
})
Then:
// pages/your-page.js
Entry.getInitialProps = async function() {
window.fetch = require("unfetch").default
...
}
Other combinations of delete & update code lines I tried didn't yield positive results. For example, when I had window.fetch = line in the test file it didn't work and fetch.toString() gave "native code". Not sure why, no time to explore further.
Axios solves the above but I don't like to bloat my bundle with extra stuff. You can inject XHR-based fetch for tests only.
4) The most important missing piece. You need to wait for route.
it("Has a correct title", () => {
cy.visit("/")
cy.server()
cy.route("GET", "http://localhost:8080/api/documents/url/about", {title: "About+"}).as("about")
cy.get("[href='/about']").click()
cy.wait("#about") // !!!
cy.get("h1").contains("About+")
})

Resources