Testing stripe.redirectToCheckout using selenium - selenium

The problem that I am experiencing is that when I click the checkout button on Stripe domain page (the selenium is losing the session ). I am using JWT tokens, so the question is how should I access localStorage to get the token and later on to pass it to the browser ( I am not sure that this will actually work, so if there is some other way please give me a hand ). I got this code before the execution of the test:
const { Before, After } = require('cucumber');
const { Builder } = require('selenium-webdriver');
const firefox = require('selenium-webdriver/firefox');
const config = require('../config');
let driver;
Before(async () => {
driver = await new Builder().forBrowser('firefox');
if (config.headlessBrowser === 'true') {
const screen = {
width: 1920,
height: 1200,
};
driver = driver
.setFirefoxOptions(new firefox.Options().headless().windowSize(screen));
}
driver = driver
.build();
driver.manage().window().maximize();
exports.driver = driver;
});
After(() => {
driver.quit();
});
And the tests for clicking the submit button and expected URL when redirected:
Then('I press stripe checkout button', {timeout: waitTime}, async () => {
await d.driver.findElement(By.className('SubmitButton')).click();
})
Then(/I should be redirected to "(.*)"/, {timeout: waitTime}, async (path) => {
await d.driver.wait(until.urlIs(config.url + path), waitTime);
});
I can see that it is trying to redirect me to the correct success URL, but unfortunately, it logs me out( I assume that is happening because the session is lost ).

Related

How to capture full page screenshot in Selenium 4 using Bidi API's?

I want to capture a full page screenshot in selenium 4 using Bidi API's/Chrome developer tools.
https://www.selenium.dev/documentation/webdriver/bidirectional/bidi_api/
A sample for generating console logs through Bidi apis. Want to capture the full page screenshot and store it in a local directory.
const { Builder } = require('selenium-webdriver');
(async () => {
try {
let driver = new Builder()
.forBrowser('chrome')
.build();
const cdpConnection = await driver.createCDPConnection('page');
await driver.onLogEvent(cdpConnection, function (event) {
console.log(event['args'][0]['value']);
});
await driver.executeScript('console.log("CDP connection established")');
await driver.quit();
} catch (e) {
console.log(e);
}
})()

logging in with cypress/puppeteer

I have an application that uses Okta to log in. I am trying to set up an automation test using Cypress with Puppeteer. The problem I am having is that when I launch puppeteer with {headless: true}, it doesn't fill in the login form. {headless: false} opens another browser window outside of Cypress and works as expected. It fills in the login form, logs in correctly, but I can't run any cypress tests in that window.
on('task', {
login({username, password}) {
return (async () => {
const browser = await puppeteer.launch({headless: false});
const page = await browser.newPage();
await page.goto(config.baseUrl);
await page.waitForNavigation();
await page.waitFor('#okta-signin-username');
await page.type('#okta-signin-username', username, {delay: 100});
await page.waitFor('#okta-signin-password');
await page.type('#okta-signin-password', password, {delay: 100});
await page.click('#okta-signin-submit');
await page.waitForNavigation();
return true;
};
});
Here's how it's being used:
it('my test', () => {
cy.visit('/');
cy.viewport(1280, 1024);
cy.login('username', 'password');
//tests go here
});
The above code opens Chromium and correctly logs in but then the tests fail. It doesn't log in with {headless: true}. Am I missing something here?
Any help would be appreciated.
Thanks

Can't log in through Facebook using Puppeteer - Error: Cookies required

This is my code to login using facebook to a website I'm automating:
const loginButton = await page.waitForXPath(
"//button[contains(#name, 'login')]"
);
const email = await page.waitForSelector("#email");
const pass = await page.waitForSelector("#pass");
await page.evaluate((text) => {
email.value = text;
}, "my email");
await page.evaluate((text) => {
pass.value = text;
}, "my password");
await loginButton.click();
Usually it works well, but once every 4 or 5 times, I get the following error after clicking the loginButton:
"Cookies required. Cookies are not enabled on your browser. Please enable cookies in your browser preferences to continue."
I changed from Chromium to Chrome to see if this would solve the issue, but it didn't work.
I also checked the cookies settings and they are enabled.
The problem was that the inputs were being filled to quickly and facebook was suspecting that I wasn't a real person. I solved it by introducing some delay between the login steps:
const loginButton = await page.waitForXPath(
"//button[contains(#name, 'login')]"
);
const email = await page.waitForSelector("#email");
const pass = await page.waitForSelector("#pass");
await page.waitFor(1000);
await page.evaluate((text) => {
email.value = text;
}, "casas.farach#yahoo.com");
await page.waitFor(1000);
await page.evaluate((text) => {
pass.value = text;
}, "789654123");
await page.waitFor(1000);
await loginButton.click();

How do I split my Jest + Puppeteer tests in multiple files?

I am writing automated tests using Jest & Puppeteer for a Front-end application written in Vue.js
So far I managed to write a set of tests, but they all reside in the same file:
import puppeteer from 'puppeteer';
import faker from 'faker';
let page;
let browser;
const width = 860;
const height = 1080;
const homepage = 'http://localhost:8001/brt/';
const timeout = 1000 * 16;
beforeAll(async () => {
browser = await puppeteer.launch({
headless: false, // set to false if you want to see tests running live
slowMo: 30, // ms amount Puppeteer operations are slowed down by
args: [`--window-size=${width},${height}`],
});
page = await browser.newPage();
await page.setViewport({ width, height });
});
afterAll(() => {
browser.close();
});
describe('Homepage buttons', () => {
test('Gallery Button', async () => {
// navigate to the login view
await page.goto(homepage);
await page.waitFor(1000 * 0.5); // without this, the test gets stuck :(
await page.waitForSelector('[data-testid="navBarLoginBtn"]');
await page.click('[data-testid="navBarLoginBtn"]'),
await page.waitForSelector('[data-testid="navBarGalleryBtn"]');
await page.click('[data-testid="navBarGalleryBtn"]'),
// test: check if we got to the gallery view (by checking nr of tutorials)
await page.waitForSelector('.card-header');
const srcResultNumber = await page.$$eval('.card-header', (headers) => headers.length);
expect(srcResultNumber).toBeGreaterThan(1);
}, timeout);
});
describe('Register', () => {
const btnLoginToRegister = '#btn-login-to-register';
const btnRegister = '#btn-register';
const btnToLogin = '#btn-goto-login';
test('Register failed attempt: empty fields', async () => {
// navigate to the register form page via the login button
await page.goto(homepage);
await page.waitForSelector(navLoginBtn);
await page.click(navLoginBtn);
await page.waitForSelector(btnLoginToRegister);
await page.click(btnLoginToRegister);
// test; checking for error messages
await page.waitForSelector(btnRegister);
await page.click(btnRegister);
const errNumber = await page.$$eval('#errMessage', (err) => err.length);
expect(errNumber).toEqual(3);
}, timeout);
test('Register failed: invalid char count, email format', async () => {
// fill inputs
await page.waitForSelector('#userInput');
await page.type('#userInput', 'a');
await page.waitForSelector('#emailInput');
await page.type('#emailInput', 'a');
await page.waitForSelector('#emailInput');
await page.type('#passInput', 'a');
await page.waitForSelector(btnRegister);
await page.click(btnRegister);
// test: check if we 3 errors (one for each row), from the front end validations
const err = await page.$$eval('#errMessage', (errors) => errors.length);
expect(err).toEqual(3);
}, timeout);
test('Register: success', async () => {
await page.click('#userInput', { clickCount: 3 });
await page.type('#userInput', name1);
await page.click('#emailInput', { clickCount: 3 });
await page.type('#emailInput', email1);
await page.click('#passInput', { clickCount: 3 });
await page.type('#passInput', password1);
await page.waitForSelector(btnRegister);
await page.click(btnRegister);
// test: check if go to login link appeared
await page.waitForSelector(btnToLogin);
await page.click(btnToLogin);
// await Promise.all([
// page.click(btnToLogin),
// page.waitForNavigation(),
// ]);
}, timeout);
test('Register failed: email already taken', async () => {
// navigate back to the register form
await page.waitForSelector(btnLoginToRegister);
await page.click(btnLoginToRegister);
await page.click('#userInput');
await page.type('#userInput', name2);
await page.click('#emailInput');
await page.type('#emailInput', email1); // <- existing email
await page.click('#passInput');
await page.type('#passInput', password2);
await page.click(btnRegister);
const err = await page.$eval('#errMessage', (e) => e.innerHTML);
expect(err).toEqual('Email already taken');
}, timeout);
});
I would like to be able to have a single test file that does the beforeAll and afterAll stuff, and each test suite: HomepageButtons, Register, etc. to reside in it's own test file. How would I be able to achieve this?
I've tried splitting tets into:
testsUtils.js that would contain the beforeAll and afterAll hooks and code but it doesn't guarantee that it runs when it needs: the beforeAll code to fire before all other test files and the afterAll code to fire after all the test files finished.
Sorry, I'd rather comment on your question, but I don't have reputation for that. Anyway, I think that you are looking for something like a "global beforeAll" and "global afterAll" hooks, right? Jest has it alread. It's called "globalSetup" and "globalTeardown".
Take a look at globalSetup. Excerpt:
This option allows the use of a custom global setup module which
exports an async function that is triggered once before all test
suites.
The Global Teardown one goes the same.
I think you'll have a headache trying to get a reference to the page or browser in globalSetup/globalTeardown and I confess that I never try this. Maybe the answer for that problem (if you have it) is on this page, under "Custom example without jest-puppeteer preset section.
Also there is a repo that tries to facilitate Jest + Puppeteer integration. Maybe you find it util: repo.
Good luck. :)

Running Chrome ignoring Cross-Origin Chrome policy

I'm trying to run Chrome using selenium webdriver without any security restrictions as part of an experiment.
Basically, I'm trying to access iframe context from different origin then my page.
Obviously, by default I'm getting the Cross-Origin exception - that's what I want to avoid and I know that I can achieve that using a browser extension, but I want to find alternatives.
Exception that I get when trying to access iframe context:
DOMException: Blocked a frame with origin "file://" from accessing a cross-origin frame.
I've tried to set any of suggested flags that I found online and official documentation when running Chrome/Chromium:
'--allow-file-access-from-files',
'--system-developer-mode',
'-–allow-file-access-from-files',
'--disable-features=IsolateOrigins',
'--disable-web-security',
'--user-data-dir=/home/chrome-dir',
'--disable-features=CrossSiteDocumentBlockingIfIsolating'
My html page:
<html>
<body>
<iframe width="560" height="315" src="https://www.youtube.com></iframe>
</body>
</html>
Script that I'm injecting:
for (let i = 0; i < window.frames.length; i++) {
try {
const frame = window.frames[i];
console.log(frame.name, frame.document);
} catch (e) {
console.log(e);
}
}
My webdriver code:
const { Builder, Capabilities } = require('selenium-webdriver');
const fs = require('fs');
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
function constructChromeOptions() {
const options = {
'args': [
'--allow-file-access-from-files',
'--system-developer-mode',
'--force-dev-mode-highlighting',
'-–allow-file-access-from-files',
'--disable-web-security',
'--user-data-dir=/home/chrome-dir',
]
};
return options;
}
function constructChromeCapabilities(packedExtensionPath) {
const chromeCapabilities = Capabilities.chrome();
const chromeOptions = constructChromeOptions(packedExtensionPath);
const capabilities = chromeCapabilities.set('chromeOptions', chromeOptions);
return capabilities;
}
(async function init() {
let driver = await new Builder()
.withCapabilities(constructChromeCapabilities())
.forBrowser('chrome')
.build();
await driver.get(`file:///${__dirname}/iframes.html`);
const js = fs.readFileSync('scripts/inject.bundle.js', 'utf8');
driver.executeScript(js);
}();