Practical Puppeteer: How to upload a file programatically
Tags: puppeteer, uploadfile, javascript, automation
Published: 2019-12-19 04:43:59

Hi everybody! Today I will share about how to upload file using Puppeteer. If you don't know about Puppeteer yet, here is the brief explanation.

> Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. Puppeteer runs headless by default, but can be configured to run full (non-headless) Chrome or Chromium. Go to https://pptr.dev for more details.

During automation using Puppeteer sometimes we want to simulate upload a file and now I will show it with real scenario.

The scenario is we will upload a file to website called Easyupload.io at https://easyupload.io. We can upload a file without need for login and they will by default keep the file for 7 days and they will give us the URL of uploaded file. Quite simple and perfect sample.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/zli7xiohdxbunj5wnb5m.png) *Easyupload.io, the website for our scenario*

Let's start.

## Preparation

Install Puppeteer

```
npm i puppeteer
```

The API to upload file is `elementHandle.uploadFile(...filePaths)`. We will prepare the file to upload called `test_to_upload.jpg` and pass to `uploadFile` method.

## The code

```js
const puppeteer = require('puppeteer');

(async () => {
	// set some options (set headless to false so we can see 
	// this automated browsing experience)
	let launchOptions = { headless: false, args: ['--start-maximized'] };
	
	const browser = await puppeteer.launch(launchOptions);
	const page = await browser.newPage();

	// set viewport and user agent (just in case for nice viewing)
	await page.setViewport({width: 1366, height: 768});
	await page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36');

	// go to the target web
	await page.goto('https://easyupload.io/');

	// get the selector input type=file (for upload file)
	await page.waitForSelector('input[type=file]');
	await page.waitFor(1000);

	// get the ElementHandle of the selector above
	const inputUploadHandle = await page.$('input[type=file]');

	// prepare file to upload, I'm using test_to_upload.jpg file on same directory as this script
	// Photo by Ave Calvar Martinez from Pexels https://www.pexels.com/photo/lighthouse-3361704/
	let fileToUpload = 'test_to_upload.jpg';
	
	// Sets the value of the file input to fileToUpload
	inputUploadHandle.uploadFile(fileToUpload);

	// doing click on button to trigger upload file
	await page.waitForSelector('#upload');
	await page.evaluate(() => document.getElementById('upload').click());

	// wait for selector that contains the uploaded file URL
	await page.waitForSelector('#upload-link');
	await page.waitFor(5000);

	// get the download URL
	let downloadUrl = await page.evaluate(() => {
		return document.getElementById('upload-link').value;
	});

	// display the result on console
	console.log({'file': fileToUpload,
                 'download_url': downloadUrl});

	// close the browser
	await browser.close();
})();
```

The code is full of comment, I hope you can understand. I set the `headless` option to `false` so we can see the browser in action.

In the code I also put some `page.waitFor()` to avoid race condition during scraping this scenario.

## Run it

```
node upload_file.js
```

If everyting OK it will	display the result in console similar like below.

```
{
  file: 'test_to_upload.jpg',
  download_url: 'https://easyupload.io/ffbvzk'
}
```

You can go to the `download_url` above and you will get your uploaded image. It means our upload automation with Puppeteer works perfectly. I have test it using headless mode and headful mode, all are working well.

That's it. Thank you and I hope you enjoy it.

Source code of this sample is available at GitHub https://github.com/sonyarianto/upload-file-with-puppeteer.git.

## Reference
- https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#elementhandleuploadfilefilepaths
- https://pptr.dev
- https://easyupload.io

# Credits
- test_to_upload.jpg is taken from photo by Ave Calvar Martinez from Pexels https://www.pexels.com/photo/lighthouse-3361704/
- Cover image is taken from photo by Brett Stone from Pexels https://www.pexels.com/photo/photo-of-a-person-using-a-gray-laptop-computer-2874782/