diff --git a/src/common/JSHandle.ts b/src/common/JSHandle.ts index 59c9a17ef409d..1e143c4a7cb7a 100644 --- a/src/common/JSHandle.ts +++ b/src/common/JSHandle.ts @@ -801,9 +801,12 @@ export class ElementHandle< /** * This method expects `elementHandle` to point to an * {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input | input element}. + * * @param filePaths - Sets the value of the file input to these paths. - * If some of the `filePaths` are relative paths, then they are resolved - * relative to the {@link https://nodejs.org/api/process.html#process_process_cwd | current working directory} + * If a path is relative, then it is resolved against the + * {@link https://nodejs.org/api/process.html#process_process_cwd | current working directory}. + * Note for locals script connecting to remote chrome environments, + * paths must be absolute. */ async uploadFile(...filePaths: string[]): Promise { const isMultiple = await this.evaluate<(element: Element) => boolean>( @@ -829,21 +832,14 @@ export class ElementHandle< avoid paying the cost unnecessarily. */ const path = await import('path'); - const fs = await import('fs'); // 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 fs.promises.access(resolvedPath, fs.constants.R_OK); - } catch (error) { - if (error && (error as NodeJS.ErrnoException).code === 'ENOENT') - throw new Error(`${filePath} does not exist or is not readable`); - } - - return resolvedPath; - }) - ); + const files = filePaths.map((filePath) => { + if (path.isAbsolute(filePath)) { + return filePath; + } else { + return path.resolve(filePath); + } + }); const { objectId } = this._remoteObject; const { node } = await this._client.send('DOM.describeNode', { objectId }); const { backendNodeId } = node; diff --git a/test/input.spec.ts b/test/input.spec.ts index 9244356333a34..2b03d8f3f15c4 100644 --- a/test/input.spec.ts +++ b/test/input.spec.ts @@ -235,7 +235,7 @@ describe('input tests', function () { .catch((error_) => (error = error_)); expect(error).not.toBe(null); }); - it('should fail for non-existent files', async () => { + it('should succeed even for non-existent files', async () => { const { page } = getTestState(); await page.setContent(``); @@ -243,11 +243,29 @@ describe('input tests', function () { page.waitForFileChooser(), page.click('input'), ]); - let error = null; + let error: Error | undefined; await chooser .accept(['file-does-not-exist.txt']) .catch((error_) => (error = error_)); - expect(error).not.toBe(null); + expect(error).toBeUndefined(); + }); + it('should error on read of non-existent files', async () => { + const { page } = getTestState(); + + await page.setContent(``); + page + .waitForFileChooser() + .then((chooser) => chooser.accept(['file-does-not-exist.txt'])); + expect( + await page.$eval('input', async (picker: HTMLInputElement) => { + picker.click(); + await new Promise((x) => (picker.oninput = x)); + const reader = new FileReader(); + const promise = new Promise((fulfill) => (reader.onerror = fulfill)); + reader.readAsText(picker.files[0]); + return promise.then(() => false); + }) + ).toBeFalsy(); }); it('should fail when accepting file chooser twice', async () => { const { page } = getTestState();