Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload a file with puppeteer in Jest

I am using Jest and have puppeteer set up as in this repository, which is linked to from the Jest documentation.

I am trying to write some automated smoke tests on a WordPress website using puppeteer. One of the tests attempts to upload an image to the WordPress Media Library.

This is the test:

it('Create test media', async () => {
  // go to Media > Add New
  await page.goto(`${env.WP_HOME}/wp/wp-admin/media-new.php`)
  const display = await page.evaluate(() => {
    const el = document.querySelector('#html-upload-ui')
    return window.getComputedStyle(el).display
  })
  if (display !== 'block') {
    // ensure we use "built-in uploader" as it has `input[type=file]`
    await page.click('.upload-flash-bypass > a')
  }
  const input = await page.$('#async-upload')
  await input.uploadFile(testMedia.path)
})

The file input field's value is populated as expected (I know this because if I save out a screenshot after the call to uploadFile it shows the path of the file in the input), and the form is submitted, however when I go to view the media library there are no items.

I have tried the following amendments to the uploadFile part of the test, to no avail:

// 1. attempt to give time for the upload to complete
await input.uploadFile(testMedia.path)
await page.waitFor(5000)

// 2. attempt to wait until there is no network activity
await Promise.all([
  input.uploadFile(testMedia.path),
  page.waitForNavigation({waitUntil: 'networkidle0'})  
])

// 3. attempt to submit form manually (programmatic)
input.uploadFile(testMedia.path)
page.evaluate(() => document.querySelector('#file-form').submit())
await page.waitFor(5000) // or w/ `waitForNavigation()`

// 4. attempt to submit form manually (by interaction)
input.uploadFile(testMedia.path)
page.click('#html-upload')
await page.waitFor(5000) // or w/ `waitForNavigation()`
like image 432
sdgluck Avatar asked Feb 28 '18 15:02

sdgluck


1 Answers

The problem is that file uploading doesn't work when connecting to a Browser instance via WebSocket as in jest-puppeteer-example. (GitHub issue here: #2120.)

So instead of doing that just use puppeteer.launch() directly when setting up your test suite (instead of via the custom "Jest Node environment"):

let browser
  , page

beforeAll(async () => {
  // get a page via puppeteer
  browser = await puppeteer.launch({headless: false})
  page = await browser.newPage()
})

afterAll(async () => {
  await browser.close()
})

You also then have to manually submit the form on the page, as in my experience uploadFile() doesn't do this. So in your case, for the WordPress Media Library single file upload form, the test would become:

it('Create test media', async () => {
  // go to Media > Add New
  await page.goto(`${env.WP_HOME}/wp/wp-admin/media-new.php`)
  const display = await page.evaluate(() => {
    const el = document.querySelector('#html-upload-ui')
    return window.getComputedStyle(el).display
  })
  if (display !== 'block') {
    // ensure we use the built-in uploader as it has an `input[type=file]`
    await page.click('.upload-flash-bypass > a')
  }
  const input = await page.$('#async-upload')
  await input.uploadFile(testMedia.path)
  // now manually submit the form and wait for network activity to stop
  await page.click('#html-upload')
  await page.waitForNavigation({waitUntil: 'networkidle0'})
})
like image 128
sdgluck Avatar answered Oct 23 '22 05:10

sdgluck