Accessing SalesForce with Cypress.IO - cypress

I am attempting to access SalesForce through Cypress but as soon as I sign in the test stops and SalesForce takes over the entire browser.I am able to visit my SalesForce Sandbox page but I cannot get a test to progress beyond there.
Where the test ends
Here is my code to access SalesForce:
///<reference types="Cypress"/>
describe("Visit SalesForce with Request", function()
{
it("Visits SalesForce", function()
{
const url = "https://test.lightning.force.com";
const username = "user#compnamy.com.ecommerce";
const password = "password";
cy.request(`${url}/?un=${username}&pw=${password}`)
.then(() =>
{
cy.visit(url);
// Sign in to SalesForce
cy.get('#wrap').find('input').eq(2).click();
// Does not execute beyond this point
cy.reload();
cy.log("Hello, world!");
});
});
});
Any advice on how to get Cypress tests to with the SalesForce would be greatly appreciated.

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.

Window object is undefined after deploy to netlify

I want to build an email verification. After the user registers, the user gets an email and clicks on it for verification purposes. The email-link invokes a netlify lambda function (api end point). Inside the link is a jwt token, which I decode on the backend. I used
window.location.href
for it and sliced the part I needed and decoded it. On localhost, it works fine, however, if I deploy it to netlify, I get an
window is undefined
error. I read that you have to check for
typeof window !== 'undefined'
However, if I add that to my lambda function I don't get any console.log statements.
exports.handler = async (event, context, callback) => {
if (typeof window !== 'undefined') {
let url = window.location.href
let index = url.indexOf("=");
let token = url.slice(index+1)
console.log(token, 'token here')
const decoded = jwt.verify(token, process.env.SECRET);
console.log('confirm registration route triggered',decoded)
if (decoded) {
const { email } = decoded;
console.log(decoded, 'decoded here')
User.findOneAndUpdate({email: email}, {verified: true },(...e)=>{
console.log(e)
});
} else {
console.log('could not update user')
//redirect user to page with message about email confirmation link expiration
//and proposal to register again
}
console.log('confirm registration got invoked')
}
return {
statusCode: 400,
body: "Oops"
}
};
I read that the function first runs on the server when deployed and afterwards on the client. Seems like it does not run on my client, as I invoke the api-endpoint directly? I'm quite a beginner when it comes to API-Endpoints, thanks for reading!
In case you have the same issue when deploying to netlify, you have to run
event.queryStringParameters
which gives you access to the query parts of your url.

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+")
})

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