I've been trying to find what events or responses to listen for to know that a file has finished uploading, but didn't find anything useful. The below is the best I've come up with and it's working for me so far in my situation:
// Get the input
let selector = `input[type=file]`;
let file_input_handle = await page.waitForSelector( selector );
// This comes before the upload starts
// Notice `await` is missing. Don't wait for this to finish now.
// This will be working in the background so we can use it later.
let disabled_selector = `${ selector }[disabled]`;
let wait_for_disabled = page.waitForSelector( disabled_selector );
// Upload
await handle.uploadFile(...paths);
// Stop to wait for the input to be disabled. If it already happened by now
// then this will be done already and it won't wait.
await wait_for_disabled;
// Now DO use `await` to wait for the input to be enabled again.
// On the webpage I'm working with, that means the files are done uploading.
let enabled_selector = `${ selector }:not([disabled])`;
await page.waitForSelector( enabled_selector );
// Do the next thing, like submitting the form
console.log( `Done uploading!` );
Edit:
As I said, this is specific to my case. We're using the https://github.com/kartik-v/bootstrap-fileinput library that disables the input while the upload is happening.
Also, as per @ggorlen's suggestion, I've made an example. I'll put the code here, but you can see it at https://jsfiddle.net/tgfp4x6h/3/. I wasn't sure puppeteer would work in jsfiddle and I wasn't sure how to store files on there to load, so I decided to just use my own promises as examples.
That means you have to upload files by hand to see it at work. You'll be able to see the background change colors from red through to green as the process happens. Open the browser console to see logs of the action happening. Make sure to upload a bunch of images or something so that it takes long enough for you to see the changes happen.
<!-- bootstrap 5.x or 4.x is supported. You can also use the bootstrap css 3.3.x versions -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" crossorigin="anonymous">
<!-- default icons used in the plugin are from Bootstrap 5.x icon library (which can be enabled by loading CSS below) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.min.css" crossorigin="anonymous">
<!-- alternatively you can use the font awesome icon library if using with `fas` theme (or Bootstrap 4.x) by uncommenting below. -->
<!-- link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" crossorigin="anonymous" -->
<!-- the fileinput plugin styling CSS file -->
<link href="https://cdn.jsdelivr.net/gh/kartik-v/bootstrap-fileinput@5.2.2/css/fileinput.min.css" media="all" rel="stylesheet" type="text/css" />
<!-- if using RTL (Right-To-Left) orientation, load the RTL CSS file after fileinput.css by uncommenting below -->
<!-- link href="https://cdn.jsdelivr.net/gh/kartik-v/bootstrap-fileinput@5.2.2/css/fileinput-rtl.min.css" media="all" rel="stylesheet" type="text/css" /-->
<!-- the jQuery Library -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js" crossorigin="anonymous"></script>
<!-- piexif.min.js is needed for auto orienting image files OR when restoring exif data in resized images and when you
wish to resize images before upload. This must be loaded before fileinput.min.js -->
<script src="https://cdn.jsdelivr.net/gh/kartik-v/bootstrap-fileinput@5.2.2/js/plugins/piexif.min.js" type="text/javascript"></script>
<!-- sortable.min.js is only needed if you wish to sort / rearrange files in initial preview.
This must be loaded before fileinput.min.js -->
<script src="https://cdn.jsdelivr.net/gh/kartik-v/bootstrap-fileinput@5.2.2/js/plugins/sortable.min.js" type="text/javascript"></script>
<!-- bootstrap.bundle.min.js below is needed if you wish to zoom and preview file content in a detail modal
dialog. bootstrap 5.x or 4.x is supported. You can also use the bootstrap js 3.3.x versions. -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<!-- the main fileinput plugin script JS file -->
<script src="https://cdn.jsdelivr.net/gh/kartik-v/bootstrap-fileinput@5.2.2/js/fileinput.min.js"></script>
<!-- following theme script is needed to use the Font Awesome 5.x theme (`fas`). Uncomment if needed. -->
<!-- script src="https://cdn.jsdelivr.net/gh/kartik-v/bootstrap-fileinput@5.2.2/themes/fas/theme.min.js"></script -->
<!-- optionally if you need translation for your language then include the locale file as mentioned below (replace LANG.js with your language locale) -->
<script src="https://cdn.jsdelivr.net/gh/kartik-v/bootstrap-fileinput@5.2.2/js/locales/LANG.js"></script>
<input id="input_id" name="file_data" type="file" multiple>
<script>
$(document).ready(function() {
// initialize with defaults
$("#input_id").fileinput();
// with plugin options
$("#input_id").fileinput({'uploadUrl': '/path/to/your-upload-api', 'previewFileType': 'any'});
});
</script>
// Bootstrap input from https://github.com/kartik-v/bootstrap-fileinput
let waitForDisabled = function (resolve, reject) {
console.log('waiting for disabled');
let disabled_node = document.querySelector('input#input_id[disabled]');
if ( disabled_node ) {
// If node is found, finish
resolve()
console.log( disabled_node );
} else {
// otherwise, loop
setTimeout(function() {
waitForDisabled( resolve, reject );
}, 100);
}
}
let waitForEnabled = function (resolve, reject) {
console.log('waiting for enabled');
let enabled_node = document.querySelector('input#input_id:not([disabled])');
if ( enabled_node ) {
// If node is found, finish
resolve()
console.log( enabled_node );
} else {
// otherwise, loop
setTimeout(function() {
waitForEnabled( resolve, reject );
}, 100);
}
}
let uploadFile = function ( resolve, reject ) {
// This would be uploading the file, but you should do it by hand
resolve();
};
let wait_for_it = async function () {
let waiting_for_disabled = new Promise( waitForDisabled );
await new Promise( uploadFile );
await waiting_for_disabled;
await new Promise( waitForEnabled );
console.log( 'Done uploading!' );
}
wait_for_it();