diff --git a/src/JSHandle.ts b/src/JSHandle.ts index fea9f49108b..f433eb46e59 100644 --- a/src/JSHandle.ts +++ b/src/JSHandle.ts @@ -291,7 +291,24 @@ export class ElementHandle extends JSHandle { // the cost unnecessarily. // eslint-disable-next-line @typescript-eslint/no-var-requires const path = require('path'); - const files = filePaths.map(filePath => path.resolve(filePath)); + // eslint-disable-next-line @typescript-eslint/no-var-requires + const fs = require('fs'); + // eslint-disable-next-line @typescript-eslint/no-var-requires + const {promisify} = require('util'); + const access = promisify(fs.access); + + // Locate all files and confirm that they exist. + const files = await Promise.all(filePaths.map(async filePath => { + const resolvedPath: string = path.resolve(filePath); + try { + await access(resolvedPath, fs.constants.R_OK); + } catch (error) { + if (error.code === 'ENOENT') + throw new Error(`${filePath} does not exist or is not readable`); + } + + return resolvedPath; + })); const {objectId} = this._remoteObject; const {node} = await this._client.send('DOM.describeNode', {objectId}); const {backendNodeId} = node; diff --git a/test/input.spec.js b/test/input.spec.js index e1aef5e7b38..6291cc97436 100644 --- a/test/input.spec.js +++ b/test/input.spec.js @@ -184,6 +184,18 @@ describe('input tests', function() { ]).catch(e => error = e); expect(error).not.toBe(null); }); + it('should fail for non-existent files', async() => { + const {page} = getTestState(); + + await page.setContent(``); + const [chooser] = await Promise.all([ + page.waitForFileChooser(), + page.click('input'), + ]); + let error = null; + await chooser.accept(['file-does-not-exist.txt']).catch(e => error = e); + expect(error).not.toBe(null); + }); it('should fail when accepting file chooser twice', async() => { const {page} = getTestState();