4

I want to write a fixture to simulate the export file and make sure a file is downloaded from browser actions. any example?

NA

Vladimir A.
  • 2,202
  • 2
  • 10
  • 28
GM.
  • 141
  • 1
  • 6

4 Answers4

6

There's not a fancy way check if the download has finished, TestCafe is somewhat limited in its ability to control the download ability in the browser.

import fs from 'fs';

const fileName = 'junk.txt';
const downloadLocation = 'C:\\Wherever\\Downloads\\';
const fileDLUrlBase = 'https://example.com/downloads/';
fixture('download test fixture');
test('download test', async t => {
  await t.navigateTo(fileDLUrlBase + fileName);
  await t.wait(30000);
  // Wait 30 seconds
  await t.expect(fs.fileExistsSync(downloadLocation + fileName));
});

You could convert that to a loop that checks, say, every 5 seconds for 60 seconds, if you wanted.

David Sampson
  • 727
  • 3
  • 15
  • Thanks! To add on, you may want to use a plugin like [downloads-folder](https://www.npmjs.com/package/downloads-folder) so you don't have to hardcode the download location. – Jia Jian Goi Jun 16 '20 at 18:31
  • You can inspect how to test file download in TestCafe using [this](https://github.com/DevExpress/testcafe-examples/tree/master/examples/check-downloaded-file-name-and-content) runnable example. – mlosev Oct 14 '20 at 08:10
  • 1
    Yes but that only works if the download is coming from a server, because it relies on intercepting HTTP. If you already have the data in the browser and are downloading from there, then you need this type of solution because there is no HTTP request to intercept. – philw Sep 11 '21 at 15:11
4
  // Wait 15*1000 ms or less
  async function waitForFile (path) {
     for (let i = 0; i < 15; i++) {
        if (fs.existsSync(path))
           return true;
  
        await t.wait(1000);
     }
  
     return fs.existsSync(path);
  }
  
  await t.expect(await waitForFile(/*path*/)).ok();

See also: Check the Downloaded File Name and Content

Alex Skorkin
  • 4,264
  • 3
  • 25
  • 47
Vladimir A.
  • 2,202
  • 2
  • 10
  • 28
1

Since the question is vague i.e. we don't know whether OP's exported file is:

  • from a remote URL, or
  • or a data URI

I'm adding on my answer for the latter, as I recently had a similar question. Instead of a remote URL download, I wanted to test for download of a data URI, but I couldn't find an answer so I'm posting my answer in case anyone has the same question.

Here's the download button with a data URI:

<a
  download="file.txt"
  target="_black"
  href="data:text/plain;,generated text data that will force download on click"
  id="btn-download">
  Download
</a>

And a snippet of my test (in TypeScript):

  const DownloadButton = Selector("#btn-download");

  // Simulate a file download
  const fileName = await DownloadLink.getAttribute("download");
  const filePath = `${downloadsFolder()}\\${fileName}`; // Used the downloads-folder package
  await t.click(DownloadButton);
  // Using Vladimir's answer to check for file download every x seconds
  await t.expect(await waitForFile(filePath)).eql(true);

  // We expect the contents of the input to match the downloaded file
  await t.expect(JSON.parse(readFileSync(filePath, "utf8"))).eql(TestDocument2);

  // Clean up
  await unlinkSync(filePath); // Or you can use the afterEach hook to do cleanups

Point is, if your downloaded file is via an anchor href, you cannot use the navigateTo solution posted above for security reasons, and you will get the Not allowed to navigate top frame to data URL error.

In the last months a new security update for Google Chrome was published that practically removed the possibility to open base64 URIs in the browser directly with JavaScript.

Jia Jian Goi
  • 1,415
  • 3
  • 20
  • 31
0

this works for me

await t 
    .click(this.downloadPdfImage) // selector -- downloadPdfImage file name that get downloaded
    .wait(1000)
await t.expect(fs.existsSync(this.downloadLocation + this.fileNamePdf)).ok(); //assertion to verify
surender pal
  • 447
  • 6
  • 15