How to enter Immersive Reader on Microsoft Edge through Selenium? - selenium

On a high level, does anyone know how to enter the Immersive Reader mode on Microsoft Edge when it is available for a given webpage through Selenium?
My aim is to load up a page, enter Immersive Reader, and save the page's source code to disk. I'm firing up Edge through Docker and I'm pragmatically connecting to it via a Node.js script.
I've tried driver.actions().sendKeys(KEY.F9), but that doesn't work since I'm targeting the browser and not a DOM element.
Many thanks for all your help.

New
Just run
driver.get('read://' + url)
and the site is loaded in immersive reader mode if available.
Old
To interact with the UI you have to use pyautogui (pip install pyautogui) and then run this code while the browser window is on focus/active:
import pyautogui
pyautogui.press('F9')
It is also useful for example to save a pdf by interacting with the popup window appearing when pressing CTRL+S.

Here's a bit of code for anyone else who might stumble across this:
Credits to #sound wave for helping me get there!
const { Builder } = require('selenium-webdriver');
const fs = require('fs');
(async () => {
const driver = await new Builder().forBrowser('MicrosoftEdge').usingServer('http://localhost:4444').build();
await driver.get('read://https://www.bbc.co.uk/news/entertainment-arts-64302120'); // this URL needs to be Immersive Reader supported
await driver.switchTo().frame(0);
const pagesource = await driver.getPageSource();
fs.writeFile('test.html', pagesource, err => {
if (err) {
console.log(err);
}
});
const title = (await driver.getTitle()).trim();
console.log(title);
await driver.quit();
})().catch((e) => console.error(e));

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");

webdriverio - download pdfs in chrome

I am new to using webdriverio, and attempting to automatically download a pdf file. The file opens in the browser and I cannot figure out how to download it - ideally to a folder specified on my local machine. I see some old forum posts which possibly suggest using chromedriver, however, due to minimal code snippets provided, I cannot understand if it's the correct approach though. Here is what I have this far (although the last two lines do not work):
const LoginPage = require('../pageobjects/login.page');
describe('Payroll Download Application', () => {
it('Login Fail Page', async () => {
await LoginPage.open();
await LoginPage.login();
await $("a[href='PayCycleReports']").click()
await $('a=Payroll Summary').click()
const handles = await browser.getWindowHandles()
await browser.switchToWindow(handles[1])
const elem = await $("#viewer").shadow$("#toolbar").shadow$("#downloads").shadow$("#downloads").shadow$("#download")
await elem.click()
});
});
Any help to figure it out would be greatly appreciated. Thanks :)
This can be done with browser.execute.
It will be necessary to select the element through JS and add the 'download' attribute to it. If you click on an element with the 'download' attribute, the pdf will not open but will be downloaded.
Example:
await browser.execute(function(){
document
.querySelector("#node-32 > div > div > div > ul:nth-child(4) > li:nth-child(1) > a")
.setAttribute("download", "download")
},
);
If you need a different selector (not CSS) you can use getElementById , getElementsByName, getElementsByTagName, getElementsByClassName, getElementByXPathand others.

How do I deal with a page loading in a secondary browser tab when I run Protractor tests headless (Chrome)?

When this code clicks a “Print”-icon, a PDF-file will be generated and displayed in a new browser-tab. I want to switch to this tab, wait until the PDF has finished loading there, check a part of the URL and then close that secondary tab.
it( "should open document as PDF-file in new browser-tab", async () => {
const mUrl = "TherapyReportForm/Export";
await mTherapyReportView.btnPrintform.click();
await browser.getAllWindowHandles().then(async (handles) => {
//if there is a secondary browser-tab open...
if (handles.length > 1) {
//...click on it
await browser.driver.switchTo().window(handles[1]);
}
});
//confirm that the url of the secondary tab matches the print-url pattern
await browser.sleep( 18000 );
expect( await browser.getCurrentUrl() ).toContain( mUrl );
await browser.getAllWindowHandles().then( async (handles) => {
//if there are multiple browser-tabs open
if (handles.length > 1) {
//close the secondary and move back to first
await browser.driver.close();
await browser.driver.switchTo().window( handles[0] );
}
} );
} );
The test above works reliably, unless I run it in chromes headless-mode, then the test-run breaks at line
expect(await browser.getCurrentUrl()).toContain(mUrl);
console output
The console output proves that it switches to the secondary tab, but apparently never tries to load the url. Since it fails to close this secondary tab the entire suite will break at that point.
What am I doing wrong?
Here is a thing... downloading functionality is not available in headless chrome. That's for sure. What I'm going to talk about below, I'm a little bit uncertain if that's the case
There is no such thing as 'open' pdf file in browser. The reason is that behind scene the browser actually downloads it (maybe temporarily). This is why you'll never be able to do that in headless
But that's rather a shot in the dark

TestCafe: Testing a Page Opening a PDF in a New Tab

Part of the web application I am testing is to click a button, which normally opens a PDF in a new tab. This enables the user to go forward in the application. The PDF can be ignored.
Currently, my strategy is to click the button and then navigate back using ClientFunction. TestCafe successfully opens the PDF when the button is clicked, but it is opened in the same tab and the test is then stuck. Navigating back changes the URL, but the PDF is still displayed.
const goBack = ClientFunction(() => window.history.back())
await this.t.click(this.button)
await this.t.wait(10000)
await goBack()
Is TestCafe currently able to bypass this issue, as I don't need to actually do anything with the PDF?
TestCafe allows testing html pages, but not PDF files. So, you can check the generated link to the PDF file as a string without actually following this link. For example:
const overrideWindowOpen = ClientFunction(() => {
window.open = function (url) {
window.__lastWindowOpenUrl = url;
};
});
const getResultUrl = ClientFunction(() => window.__lastWindowOpenUrl);
await overrideWindowOpen();
await t
.click(this.button)
.expect(getResultUrl()).eql('http://example.com/path/to/PDF/93023813-0984-1');
See also: Multiple Browser Windows

Detox: Testing a React-Native spinner with a stop button

Was wondering if anyone has had a similar issue.
In the app I'm working with, we have a spinner showing downloading content with a stop button in the middle. When the user taps the spinner/stop button, the download is meant to cancel. For reference the spinner/stop button looks like this on iOS:
I'm trying to write an e2e test for this functionality using Detox. It doesn't work using automatic synchronisation as the animation (and the download) keeps the thread running. I've tried using device.disableSynchronization() but I haven't had any success.
Here's my e2e test for reference:
it('should start and then cancel a download from the <My Learning> screen', async() => {
// setup
await device.reloadReactNative()
await expect(element(by.id('feed_screen'))).toBeVisible()
await element(by.id('LearningPlan_Tab')).tap()
await expect(element(by.id('learning-plan-screen'))).toBeVisible()
// Tap the download icon, it will turn into a spinner
await element(by.id('offline_download_c2a')).atIndex(1).tap()
// Alert box appears with Cancel/Download options
await expect(element(by.label('Download')).atIndex(1)).toBeVisible()
await element(by.label('Download')).atIndex(1).tap()
// Ideally this would work, but it doesn't (the above alert box doesn't dismiss properly)
await device.disableSynchronization()
await waitFor(element(by.id('download_spinner_c2a')).atIndex(0)).toBeVisible().withTimeout(5000)
await element(by.id('download_spinner_c2a')).atIndex(0).tap()
await device.enableSynchronization()
await element(by.label('Cancel download')).tap()
await expect(element(by.id('offline_download_c2a')).atIndex(1)).toBeVisible()
})
When this test runs the app still seems to wait for the download to finish. Does anyone know any suggestions on the best way to test this, or if it's even possible?
I've found a way to make it work, though it seems quite flaky:
it('should start and then cancel a download from the <My Learning> screen', async () => {
//...
await device.disableSynchronization()
// This timeout seems to help
await waitFor(element(by.id('download_spinner_c2a')).atIndex(0)).toBeVisible().withTimeout(10000)
await element(by.id('download_spinner_c2a')).atIndex(0).tap()
await device.enableSynchronization()
await element(by.label('Cancel download')).tap()
await expect(element(by.id('offline_download_c2a')).atIndex(1)).toBeVisible()
})