🎉  Delighted to announce our  $10M Series A  round. Read the full story and next milestones here! Read More

E2E File Download

Websites might expose files for users to download and then access from their local machine. Common cases are downloading tickets, receipts and itineraries.

Steps

This example runs against our test webshop and proceeds to download a receipt for a previous purchase. It includes the following steps:

  1. Logging in to the website
  2. Navigating to the account page
  3. Downloading a linked file

We will check that the downloaded file is as expected by comparing it to a fixture file in our final assertion.

We can approach this scenario in different ways. One possibility is to perform the first two steps, then extract the href value and use it to retrieve the file with a GET request (performed with axios, for example).


const { chromium } = require('playwright')
const axios = require('axios')
const fs = require('fs')
const assert = require('chai').assert;

(async () => {
  const browser = await chromium.launch()
  const page = await browser.newPage()

  await page.goto('https://danube-webshop.herokuapp.com/')

  await page.click('#login')
  await page.type('#n-email', process.env.USER_EMAIL)
  await page.type('#n-password2', process.env.USER_PASSWORD)

  await page.click('#goto-signin-btn')

  await page.click('#account')

  await page.waitForSelector('#orders > ul > li:nth-child(1) > a')

  const downloadUrl = await page.$eval(
    '#orders > ul > li:nth-child(1) > a',
    (el) => el.href
  )

  const response = await axios.get(downloadUrl)
  const newFile = Buffer.from(response.data)

  const testFile = await fs.readFileSync('fixtures/testfile.pdf')

  assert(newFile.equals(testFile))

  await browser.close()
})()



const puppeteer = require('puppeteer')
const axios = require('axios')
const fs = require('fs')
const assert = require('chai').assert;

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()

  await page.goto('https://danube-webshop.herokuapp.com/')

  await page.setViewport({ width: 1200, height: 800 })

  await page.waitForSelector(' #login')
  await page.click('#login')

  await page.waitForSelector('#n-email')

  await page.type('#n-email', process.env.USER_EMAIL)
  await page.type('#n-password2', process.env.USER_PASSWORD)

  await page.waitForSelector('#goto-signin-btn')
  await page.click('#goto-signin-btn')

  await page.waitForSelector('#goto-signin-btn', { hidden: true })
  await page.click('#account')

  await page.waitForSelector('#orders > ul > li:nth-child(1) > a')
  const downloadUrl = await page.$eval(
    '#orders > ul > li:nth-child(1) > a',
    (el) => el.href
  )

  const response = await axios.get(downloadUrl)

  const newFile = Buffer.from(response.data)
  const testFile = await fs.readFileSync('fixtures/testfile.pdf')

  assert(newFile.equals(testFile))

  await browser.close()
})()


We could also click the link directly and wait for the download event, then proceed with the comparison. Waiting for the download event is currently supported by Playwright, but not by Puppeteer.

Note that in this case, we need to enable downloads in the browser context before proceeding.


const { chromium } = require('playwright')
const fs = require('fs')
const assert = require('chai').assert;

(async () => {
  const browser = await chromium.launch()
  const context = await browser.newContext({ acceptDownloads: true })
  const page = await context.newPage()

  await page.goto('https://danube-webshop.herokuapp.com/')

  await page.click('#login')
  await page.type('#n-email', process.env.USER_EMAIL)
  await page.type('#n-password2', process.env.USER_PASSWORD)

  await page.click('#goto-signin-btn')

  await page.click('#account')

  await page.waitForSelector('#orders > ul > li:nth-child(1) > a')

  const [download] = await Promise.all([
    page.waitForEvent('download'),
    page.click('#orders > ul > li:nth-child(1) > a')
  ])

  const path = await download.path()

  const newFile = await fs.readFileSync(path)
  const testFile = await fs.readFileSync('fixtures/testfile.pdf')

  assert(newFile.equals(testFile))

  await browser.close()
})()


Both examples can be run as follows:

USER_EMAIL=user@email.com USER_PASSWORD=supersecure1 node file-download.js
SET USER_EMAIL=user@email.com
SET USER_PASSWORD=supersecure1
node file-download.js

Takeaways

  1. Use environment variables to inject secrets.
  2. Compare the expected file with the newly downloaded one.
  3. There is more than one way to download a file within our script.

Further reading

  1. Playwright’s documentation on downloading files.