Chromium/chrome running headless: wait for page load when using --screenshot? - chromium

Trying to take a screenshot using headless Chrome but it executes --screenshot before the page is loaded. On MacOS running zsh, I'm invoking it like this:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome https://example.com/foo.html --screenshot=/Users/myhome/foo.png
Is there a way to wait until the page is loaded before the screenshot is taken?

The answer, it turns out, is that those command line options don't work well and have been supplanted by Puppeteer. Here's the script I created (hardcodes values for brevity).
Here's the complete code.
const puppeteer = require('puppeteer');
const sleep = (milliseconds) => {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
async function run () {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://twitter.com/gnuman1979/status/1239523796542992387');
await sleep(2000)
await page.screenshot({path: './foo.png'});
browser.close();
}
run();
Save as foo.js, then run using node:
$ node foo.js

Related

How to paste(using keyboard simulation) what's currently in clipboard on nextjs ubuntu ec2 instance using selenium?

I am trying to copy a text using a npm package called "copy-paste" and to paste the content using selenium keyboard simulation on nextjs ubuntu ec2 instance.
When I run below code from the local dev env, it works fine, but when I run it on ubuntu ec2 instance, it just sends "v" key instead of pasting the content in the clipboard.
I've tried all control, command, and meta key, but they all didn't work...
Plz help!
const { By, Key } = require("selenium-webdriver");
var ncp = require("copy-paste");
let resultElement = await driver.findElement(By.id("naver_id_login_anchor"));
await resultElement.click();
console.log("naver login button clicked");
await driver.sleep(3000);
const elem_id = await driver.findElement(By.id("id"));
await elem_id.click();
await driver.sleep(3000);
await ncp.copy(id, () => console.log("id copied"));
await driver.sleep(3000);
await driver
.actions()
.keyDown(Key.META)
.sendKeys("v")
.keyUp(Key.META)
.perform();
await driver.sleep(3000);
console.log(await elem_id.getAttribute("value"));
Try this:
el.sendKeys(Keys.CONTROL+ "v");

Playwright test works fine localy, but fails in pipeline

I am trying to run this code:
test('should login', async ({ page }) => {
await page.goto(localhost);
await page.fill('[name=username]', 'username');
await page.fill('[name=password]', 'password');
await page.click('[name=login]');
await page.waitForURL(`${localhost}/main`);
const currentUrl = await page.url();
expect(currentUrl).toBe(`${localhost}/main`);
});
When I run it with npx playwright test localy, the test passes; but, when run in CI/CD, it fails:
Timeout of 180000ms exceeded.
page.waitForURL: Navigation failed because page was closed!
=========================== logs ===========================
waiting for navigation to "http://localhost:3000/main" until "load"
============================================================
Any idea what causes this problem?
I would try logging all network requests to see what's going on there:
// Log and continue all network requests
page.route('**', (route, request) => {
console.log(request.url());
route.continue();
});
If it never gets beyond the goto(), perhaps try using the new playwright request fixture to see if it can even reach http://localhost:3000/main.
await page.request.get("http://localhost:3000/main", { ignoreHTTPSErrors: true });

Jest + Selenium: how do I do an operation before and after all tests inside a describe block is run?

I am trying to create a simple automated test to detect if the added element contains the text it is supposed to have. The test is run using node.js with jest command. I am using Selenium to automate the UI process and Jest to validate the UI's content.
I want to do the following.
Create variables that are accessible in all tests in the describe block before running any of the test
Close the Selenium-driven browser after all tests in the describe block is run
So far, I have this code.
const { Builder, By, until } = require('selenium-webdriver')
const url = 'http://127.0.0.1:3000'
describe('addUser', async() => {
afterAll(async() => {
await driver.quit()
}, 15000)
test('valid name and age should add a new element', async() => {
const driver = await new Builder().forBrowser('firefox').build()
await driver.get(url)
const nameField = await driver.wait(until.elementLocated(By.id('name')), 10000)
const ageField = await driver.wait(until.elementLocated(By.id('age')), 10000)
const btnAddUser = await driver.wait(until.elementLocated(By.id('btnAddUser')), 10000)
await nameField.click()
await nameField.sendKeys('Adam')
await ageField.click()
await ageField.sendKeys('39')
await btnAddUser.click()
const userItem = await driver.wait(until.elementLocated(By.css('.user-item')), 10000)
const userItemText = await userItem.getText()
expect(userItemText).toBe('Adam (39 years old)')
}, 10000)
})
The problems I am facing are the following.
I have to declare the driver, ask the driver to open a new page, and finding all the necessary elements every time I run a test. If possible, I would like to do these initialization steps inside a beforeAll function (by Jest) and store the variables somehow. Then, I can use driver, nameField, ageField, etc. in every test without having to declare them again. How would I do this while maintaining a clean code?
I will close the Selenium-driven browser after all tests inside the addUser describe block are run. So, I added driver.quit() inside afterAll (Jest) to close the browser. Unfortunately, this doesn't work; the browser doesn't close itself. How can I close the Selenium-operated browser after each describe block?
The test is working great, but how can I solve the two problems above?
driver variable is declared in test scope and is unavailable in afterAll. Even if it were declared in describe scope, a teardown would be performed only for the last driver because there can be multiple tests but afterAll is called after the last one.
Variables that need a teardown can be either redefined for each test:
let driver;
beforeEach(async () => {
driver = ...
});
afterEach(async () => {
await driver.quit()
});
Or reused for all tests:
let driver;
beforeAll(async () => {
driver = ...
});
afterAll(async () => {
await driver.quit()
});

Chromium won't load any websites and keeps crashing

All of the sudden my scripts aren't working anymore.
const puppeteer = require("puppeteer");
async function run() {
const browser = await puppeteer.launch({
headless: false
});
const page = await browser.newPage();
await page.goto("https://www.google.com");
// browser.close();
}
run();
When I run node index.js, Chromium launches, however, it is all white, then my mouse turns into the little rainbow spinning circle (Mac) and it crashes and I get the following error:
(node:37226) UnhandledPromiseRejectionWarning: Error: Navigation failed because browser has disconnected!
Thanks for any help!
I had the same problem on mac and solved it by adding '--no-sandbox' to the chrome args.
You can expose it as an env variable like so:
CHROME_ARGS=--no-sandbox
or add it to your browser.launch configuration:
const browser = await puppeteer.launch({
headless: false,
args: ['--no-sandbox']
});

Let Puppeteer wait for globalSetup to finish

I use Jest-Puppeteer to end2end test a webapplication. All tests run parallel with async functions. Now I find that the first test already runs before the globalSetup has finished and the data preperation is done (initializing client-settings etc.)
I've tried to timeout after the request, but that isn't working because now all requests have a timeout.
import puppeteer from "puppeteer";
import { getUrlByPath, post } from "../helper";
module.exports = async function globalSetup(globalConfig) {
await setupPuppeteer(globalConfig);
puppeteer.launch({args: ["--no-sandbox", "--disable-setuid-sandbox"]}).then(async browser => {
const page = await browser.newPage();
await post(
page,
getUrlByPath("somePath"),
"prepare_data_for_testing",
);
await browser.close();
});
};
Above code runs a globalConfig, after that it starts preparing the data for the testing environment.
Is there a way to make the test suites run AFTER this script returns the post with http 200: ok ?
I had to place await before puppeteer.launch and add require("expect-puppeteer"); at the top.