Timeout while file download - testing

In my Fixture, I have an action that will start to download a file with browser. This worked very fine until the server will respond directly.
.expect(fs.existsSync(downloadsFolder()+'/export.xml')).ok()
But now I have some file the server need to create, and so a waiting time will occur. I tried to expand the function:
.expect(fs.existsSync(downloadsFolder()+'/export.xml')).ok('War wohl nicht erfolgreich',{ timeout: 300000 })
But the result is the same with a first tryout. I did some research and found:
async function CheckFileExistsWithTimeDelay(t, timeDelay, fileNameAndPath) {
for (var i = 0; i < timeDelay; i++) {
console.log('Waited for a total of ' + i.toString() + ' microseconds');
await t.wait(1);
if (fs.existsSync(fileNameAndPath)) {
// break;
return;
}
}
};
This also does not work. I think the watch file function blocks the Fs and so the browser cannot download the file (write the file). Also, this does not work:
async function waitForFile (path) {
for (let i = 0; i < 300; i++) {
if (fs.existsSync(path))
return true;
await t.wait(1000);
}
return fs.existsSync(path);
}
await t.expect(await waitForFile(downloadsFolder()+'/export.xml')).ok("War wohl nicht erfolgreich", { timeout: 300000 });
It looks like that the file download will fail until testcafe is waiting some time. If the file is downloaded directly everything is fine.
Is there any good example to wait for a downloaded file without blocking the fs?
It was requested so I add it here: The line where testcafe will get the command to download)
await t
.click(Selector('button').withText('Aktionen'))
.click(Selector('a').withText('Xml Exportieren'));
As I wrote. Immediately download works perfect. Until the download is delayed it fails. It looks like that some hook is hanging on the file and so chrome cannot download.
NEW INFO 1
The server will response exact 38,7 seconds after the download link was clicked. After I do this with testcafe I will get inside the browser window
If I use a real case, it means I will click on the link on the physical website the file is downloaded well after the 38 seconds. No error.
NEW INFO 2
I also tried to add a long .wait(150000) to the fixture and then check if the file exists. The browser tried to download the file in the background while waiting inside .wait(150000) loop. And also this is failed.
So I think it is proof that it is a Testcafe issue and not a node issue.

Here is the another example of how to wait for a downloaded file in test:
import { Selector } from 'testcafe';
import fs from 'fs';
const waitForFileDownloaded = (filePath, timeDelay) => new Promise(resolve => {
let i = 1;
const intervalId = setInterval(() => {
if (fs.existsSync(filePath)) {
clearInterval(intervalId);
resolve(true);
}
i++;
if (i > timeDelay) {
clearInterval(intervalId);
resolve(false);
}
}, 1000);
});
fixture `Downloading`
.page `https://github.com/DevExpress/testcafe`;
test('Test', async t => {
await t
.click(Selector('a').withText('218 releases'))
.click(Selector('a').withText('Source code'))
.expect(await waitForFileDownloaded('c:\\Users\\username\\Downloads\\testcafe-1.6.0.zip', 60)).ok();
});
Also could you please clarify if the downloading process is started after TestCafe clicked on the link (for example, using only await t.wait() with a big timeout)?

Related

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 returning Success on timeout

I have a page that is in break now, my backend is correcting it, but my test still returning success.
When I click to open the page, it is loading forever, doesn't open the page, and my "expect" was suppose to return an error, as it didn't find the "#btnStopService".
import 'testcafe';
import { Selector, ClientFunction } from 'testcafe';
fixture('Compass - Main page')
.page('http://localhost:3000/')
.beforeEach(async t => {
//login
t.ctx.username = 'admin';
t.ctx.password = 'admin';
await t.typeText(Selector('input').withAttribute('name','username'), t.ctx.username, {
paste: true,
replace: true,
});
await t.typeText(Selector('input').withAttribute('name','password'), t.ctx.password, {
paste: true,
replace: true,
});
await t.click(Selector('button').withAttribute('tabindex','0'));
})
.afterEach(async t => {
//logout
await t.click(Selector('#logoutBtn'));
});
test('Check if Services / Site Health page is loading... *** NOT WORKING ***', async t => {
await t.click(Selector('a').withExactText('Services'));
await t.click(Selector('a').withAttribute('href','#objectstore/sites/health'));
await t.expect(Selector('#btnStopService')).ok();
});
I am running it with:
testcafe edge .\test_spec.ts --selector-timeout 6000
The return I got is:
PS C:\ThinkOn\Compass_Test\Test1> testcafe edge .\test_spec.ts --selector-timeout 6000
Using locally installed version of TestCafe.
Running tests in:
- Microsoft Edge 17.17133 / Windows 10
Compass - Main page
√ Check if Services / Site Health page is loading... *** NOT WORKING ***
1 passed (23s)
PS C:\ThinkOn\Compass_Test\Test1>
Thanks all!!!
You need to add in an assertion option:
await t.expect(Selector('#btnStopService').exists).ok();

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

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

Pdf2json integrated with Protactor

Has someone integrated pdf2json npm package with Protractor? I have been able to create a standalone node application to convert a PDF to json.
What I'm trying to do now is to add pdf2json to protractor.config.js and be able to use it in my test specs.
I managed to make it work myself so I thought to post what I did just in case someone needs the same.
Add the following to the Protractor config file
// PDF Parser
var PDFParser = require("pdf2json");
global.pdfParser = new PDFParser();
In the spec, we just need to wait for the async call to load the PDF to finish - note the done() (see Jasmine Async Support). The spec would look like:
var fs = require('fs');
describe('PDF Parser', function() {
it ("The spec", function(done){
// Capture the error
pdfParser.on("pdfParser_dataError", errData => {
console.error(errData);
done();
});
// Transform to json
pdfParser.on("pdfParser_dataReady", pdfData => {
fs.writeFile("path/to/save/json/file", JSON.stringify(pdfData));
done();
});
// This is an async call. We have to wait for it, so we use done in the 'it'
pdfParser.loadPDF("path/to/pdf/file");
});
});