How do I login to salesforce by using cypress? - testing

I'm currently using cypress to do some testing. However, I have to do some tests with salesforce and it seems that I'm getting the following issue 'Whoops, there is no test to run.'
context('Salesforce', () => {
beforeEach(() => {
cy.request("https://test.salesforce.com/?un=username%40domain_name&pw=user_password&startURL=%2F001")
})
it('.click() - click on a DOM element', () => {
// load opportunity page
cy.visit('https://test.salesfroce.com/lightning/page/home')
// optional. let's the page load during the test runner
cy.wait(7000)
//cy.get('#username').type('username')
//cy.get('#password').type('password')
//cy.contains('Log In to Sandbox')
})
})
Does anyone know how to bypass the login page with cypress?

The problem that I had is that I was using a long password where extra characters didn't take into account. For this reason, I decided to change my password for something short, and now is working correctly.
This is the actual URL that you have to request and visit to make sure you can log in to your Salesforce account.
Take into consideration that cy.request is the link above & the cy.visit will be your dashboard URL.
"https://test.salesforce.com/?un=username%40domain_name&pw=user_password&startURL=%2F001

Related

Cypress uncaught:exception handler not working with Magic.link flow

I'm using Cypress to test a login flow that uses Magic.link auth on a mobile Web device, which is encountering the ResizeObserver loop limit exceeded error, as it tries to navigate the Google Auth forms. I've looked at numerous posts, and played around with my test, but it seems the handler is not working.
The recommended Google Authentication from the Cypress docs is insufficient, because with Magic, the flow is initiated by a call to magic.oauth.loginWithRedirect, hence I was hoping to drive the process via the UI directly.
You'll see I added a test to ensure the password input is visible. Now the exception is being thrown at that part of the test. If I remove that check the error occurs on the next step where I try to type the password.
describe('my auth flow', () => {
it('can auth with google', () => {
// click login button from my site
cy.get('button')
.contains('sign-in')
.click();
cy.origin('https://accounts.google.com', () => {
// enter email address
cy.get('input[type=email]')
.type('myuser#mydomain.com');
cy.get('button')
.find('span')
.contains('Next')
.click();
// wait for password page to show
cy.get('#password')
.should('exist')
.and('be.visible'); // error here...
// enter password
// error here if above visibility check removed
cy.get('#password input[type=password]')
.type('mypassword');
cy.get('button')
.find('span')
.contains('Next')
.click();
});
});
});
In support/commands.js, I've added the global error handler, which should handle all uncaught exceptions according to the documentation.
Cypress.on(
'uncaught:exception',
(err) => false
);
Magic does have a test mode, however I really don't want to bypass the login flow. Ideally I could exercise the login flow without hacks for testing.
The cy.origin() command is an isolated sandbox with different document and window to the primary domain.
Try adding the exception handler inside the origin command (presuming the error is happening while on the google domain).
cy.origin('https://accounts.google.com', () => {
Cypress.on('uncaught:exception', (err) => false)

cy.origin redirects user to a blank page

Scenario:
I am clicking a login button from my application served on localhost.
It redirects me to azure sso login through cy.origin
Authentication is performed fine.
User logs in successfully to the app.
But it redirects me to a blank page and hence rest of the IT blocks get failed.
The code attached below works fine but as soon as first IT block passes, upon the execution of second IT block page is set to about:blank so the test cases fail.
Question: What should be the workaround so that I can continue testing on application under test?
Second describe gets failed
Cypress.Commands.add('authenticate', () =>{
cy.visit('http://localhost:8080/')
cy.get('input[value="***"]').click();
cy.origin(`https://login.microsoftonline.com/`, () => {
cy.wait(3000)
cy.get('#i0116').type('username')
cy.get('#idSIButton9').click()
cy.wait(3000)
cy.get('#i0118').type('password')
cy.wait(2000)
cy.get('#idSIButton9').click()
cy.wait(2000)
cy.get('#idSIButton9').click();
})
cy.wait(6000)
cy.url().should('contain', 'Welcome')
})
According to the documentation, that behavior is by design
Take a look at cy.origin()
The cy.origin() command is currently experimental and can be enabled by setting the experimentalSessionAndOrigin flag to true in the Cypress config.
Enabling this flag does the following:
It adds the following new behaviors (that will be the default in a future major version release of Cypress) at the beginning of each test:
The page is cleared (by setting it to about:blank).
If by "Second describe gets failed" you mean the second test is not visiting the Welcome page, then just explicitly visit cy.visit('http://localhost:8080/') at the beginning of the second test.
This is the recommended approach when using cy.origin.
By the way, you should set http://localhost:8080/ as baseUrl in configuration, and use cy.visit('/') instead - from Cypress best practices.
Cypress.Commands.add("session_thing", (email, password) => {
cy.session([email, password], () => {
cy.visit('http://localhost:8080/AdminWebapp/Welcome.html')
cy.get('input[value="Log In With Office 365"]').click();
cy.origin(
`https://login.microsoftonline.com/`,
{ args: [email, password] },
([email, password]) => {
cy.wait(3000)
cy.get('#i0116').type(email)
cy.get('#idSIButton9').click()
cy.wait(3000)
cy.get('#i0118').type(password)
cy.wait(2000)
cy.get('#idSIButton9').click()
cy.wait(2000)
cy.get('#idSIButton9').click();
}
);
cy.url().should('contain', 'Welcome')
});
});
The desired behavior was achieved with above code. It restores the session in beforeEach hook. I am simply calling the cy.visit('/') in every IT block and perform the required actions which is kind of very fast with session feature.

Cypress doesn't work with an external login

I'm working on e2e test with cypress on my application.
In my case the login are manage by a external service.
When I want to enter in my application's home page (https://myApplication/home), the system redirects me in different superdomains to login.
At first cypress seems to be able to change the superdomain, but once arrived in external service page for the authentication, the system go in login error (as if we have already logged in, but incorrect).
This type of behavior does not happen outside the cypress .
Are there alternative solutions to manage external access in a cypress test or is it possible to manage it directly from cypress?
I added in my cypress.json the chromeWebSecurity:false and when I call the link for login, I added the failOnStatusCode: false,
but it still doesn't work.
Assuming this is caused by SameSite cookie blocking , then I've just been fighting the same issue. I resolved it by intercepting all requests, checking if they had a set-cookie header(s) and rewriting the SameSite attribute. There's probably a neater way to do it, as this does clutter up the cypress dashboard a little.
Sadly Zachary Costa's answer no longer works as Chrome 94 removed the SameSiteByDefaultCookies flag.
You can add this as a command for easy reuse:
In your commands file:
declare namespace Cypress {
interface Chainable<Subject> {
disableSameSiteCookieRestrictions(): void;
}
}
Cypress.Commands.add('disableSameSiteCookieRestrictions', () => {
cy.intercept('*', (req) => {
req.on('response', (res) => {
if (!res.headers['set-cookie']) {
return;
}
const disableSameSite = (headerContent: string): string => {
return headerContent.replace(/samesite=(lax|strict)/ig, 'samesite=none');
}
if (Array.isArray(res.headers['set-cookie'])) {
res.headers['set-cookie'] = res.headers['set-cookie'].map(disableSameSite);
} else {
res.headers['set-cookie'] = disableSameSite(res.headers['set-cookie']);
}
})
});
});
Usage:
it('should login using third party idp', () => {
cy.disableSameSiteCookieRestrictions();
//add test body here
});
or alteratively, run it before each test:
beforeEach(() => cy.disableSameSiteCookieRestrictions());
We were encountering a similar issue, where Cypress was redirecting us to the default "You are not logged in" page after getting through the login process. I'm not certain if that's EXACTLY the issue you were experiencing, but just in case, here's our solution. In our case, the issue was caused by Chrome's "Same Site Cookies" feature interacting poorly with Cypress, so we needed to disable it. In your plugins/index.js file, you would add the following code:
module.exports = (on, config) => {
on('before:browser:launch', (browser, launchOptions) => {
if (browser.name === 'chrome') {
launchOptions.args.push('--disable-features=SameSiteByDefaultCookies');
}
return launchOptions;
});
};
Note that if you already have launchOptions being set, you can just add this code onto it so it doesn't clash at all.
Hopefully, this works for you as well!
In the current version of cypress you can't go to another domain in the same test. This is due to the fact that cypress injects its test into the browser (they are working on this issue).
So one solution today is that you need to utilize cy.request to perform the login programmatically and inject the auth secret (jwt, cookie, localstorage, token or what you have) into the browser context yourself (for cookie this would be cy.setcookie).
Always make sure to checkout the plugins if there is already an abstraction for your login. Often this is openId or ntlm.

testcafe - CAS authentication

New to TestCafe. Got some simple example tests working easily. However, I wasn't able to find any examples of features that would seem to allow me to log in to my application via a CAS authentication page.
This code works to find the login button on the login page and click it.
fixture`VRT`
.page `http://myapp.com/login/`;
test('Find Login button', async t => {
const input = Selector('input.btn');
await t.click(input);
});
And this would work to type in the username and password on the login page:
test('Login using CAS', async t => {
await t
.expect("#username").exists
.typeText('#username', 'myuser')
.typeText('#password', '***')
.click('#submit');
});
But the problem is that there seems to be no way to continue from one test to another. So I can't go from the first test that opens the login page, to the next test that enters the credentials. It seems like, for TestCafe, every test has to specify its own page.
If I try to go to the CAS login page directly, by specifying it as the fixture "page", TestCafe fails to open the page, I think because the URL is extremely long.
Thanks for any suggestions.
Update:
So, using roles got me a bit further (thanks) but had to get through one more CAS page with an input button to click before getting to the page I wanted to test. Was able to add in another click to the role login:
import { Role } from 'testcafe';
import { Selector } from 'testcafe';
const finalLoginBtn = Selector('input.btn');
const myUserRole = Role('http://example.com/login', async t => {
await t
.click('input.btn')
.typeText('#username', 'my-username')
.typeText('#password', '*****')
.click('#submit')
.click(finalLoginBtn);
}, { preserveUrl: true });
fixture`VRT`
test("My User Page", async t => {
await t.navigateTo(`http://example.com`)
await t.useRole(myUserRole);
});
The TestCafe 'User Roles' functionality should suit your requirements. Please, refer to the following topic in the TestCafe documentation for details: https://devexpress.github.io/testcafe/documentation/test-api/authentication/user-roles.html

Using Cypress to Test an App That Relies on OAuth

I've inherited a Node.js web app that uses relies on OAuth. Whenever you visit a page the app ensures you've authenticated. Please note, there no Angular, React, Vue, etc here. Each page is straight up HTML.
I want to test this site using Cypress. My problem is, I'm stuck on the initial redirect from the auth provider. Cypress acknowledge OAuth is a challenge.
commands.js
Cypress.Commands.add('login', (credentials) => {
var settings = {
'clientId':'<id>',
'scope':'<scope-list>',
...
};
var body = `client_id=${settings.clientId}&scope=${settings.scope}...`;
var requestOptions = {
method: 'POST',
url: 'https://login.microsoftonline.com/...',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: body
}
cy.request(requestOptions);
});
Then, in my test, I have:
context('Home', () => {
it('Visits Successfully', () => {
cy.login();
cy.title().should('include', 'welcome');
});
});
In the test runner, I see the login POST request is occurring. I confirmed that an access token is being received using a console.log, however, my title is empty. It's like the redirect after OAuth isn't happening in Cypress. However, when I visit the site in the browser, the redirect is happening as expected.
What am I missing?
What you might be missing is confusing between the actual UI flow and the programmatic flow of doing OAuth with a 3rd party website.
What you would want to do is to complete the programmatic login and then send the required parameters to your OAuth callback URL for your app manually in the test code.
an example is given here (though it uses a different grant type it gives you an idea) https://auth0.com/blog/end-to-end-testing-with-cypress-and-auth0/#Writing-tests-using-Cypress-Login-Command
another issue on the cypress github that deals with a similar problem
https://github.com/cypress-io/cypress/issues/2085
this also might help:
https://github.com/cypress-io/cypress-example-recipes/blob/master/examples/logging-in__single-sign-on/cypress/integration/logging-in-single-sign-on-spec.js