feedback 1

This commit is contained in:
Max Schmitt 2024-06-06 23:27:13 +02:00
parent cfa92b479d
commit 4f72d983a7
7 changed files with 38 additions and 25 deletions

View file

@ -953,7 +953,7 @@ When all steps combined have not finished during the specified [`option: timeout
Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then they Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then they
are resolved relative to the current working directory. For empty array, clears the selected files. are resolved relative to the current working directory. For empty array, clears the selected files.
In order to upload a directory (`[webkitdirectory]`) pass the path to the directory. For inputs with a `[webkitdirectory]` attribute, only a single directory path is supported.
This method expects [ElementHandle] to point to an This method expects [ElementHandle] to point to an
[input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). However, if the element is inside the `<label>` element that has an associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), targets the control instead. [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). However, if the element is inside the `<label>` element that has an associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), targets the control instead.

View file

@ -2164,7 +2164,7 @@ When all steps combined have not finished during the specified [`option: timeout
* since: v1.14 * since: v1.14
Upload file or multiple files into `<input type=file>`. Upload file or multiple files into `<input type=file>`.
In order to upload a directory (`[webkitdirectory]`) pass the path to the directory. For inputs with a `[webkitdirectory]` attribute, only a single directory path is supported.
**Usage** **Usage**

View file

@ -3927,7 +3927,7 @@ An object containing additional HTTP headers to be sent with every request. All
Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then they Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then they
are resolved relative to the current working directory. For empty array, clears the selected files. are resolved relative to the current working directory. For empty array, clears the selected files.
In order to upload a directory (`[webkitdirectory]`) pass the path to the directory. For inputs with a `[webkitdirectory]` attribute, only a single directory path is supported.
This method expects [`param: selector`] to point to an This method expects [`param: selector`] to point to an
[input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). However, if the element is inside the `<label>` element that has an associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), targets the control instead. [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). However, if the element is inside the `<label>` element that has an associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), targets the control instead.

View file

@ -262,9 +262,9 @@ export async function convertInputFiles(files: string | FilePayload | string[] |
if (items.some(item => typeof item === 'string')) { if (items.some(item => typeof item === 'string')) {
if (!items.every(item => typeof item === 'string')) if (!items.every(item => typeof item === 'string'))
throw new Error('File paths cannot be mixed with buffers'); throw new Error('File paths cannot be mixed with buffers');
const directoryCount = (await Promise.all(items.map(async item => (await fs.promises.stat(item as string)).isDirectory()))).filter(Boolean).length; const itemFileType = (await Promise.all(items.map(async item => (await fs.promises.stat(item as string)).isDirectory() ? 'directory' : 'file')));
if (directoryCount > 1) if (new Set(itemFileType).size > 1 || itemFileType.filter(type => type === 'directory').length > 1)
throw new Error('Only one directory can be uploaded at a time'); throw new Error('File paths must be all files or a single directory');
if (context._connection.isRemote()) { if (context._connection.isRemote()) {
let streams: channels.WritableStreamChannel[] | undefined; let streams: channels.WritableStreamChannel[] | undefined;

View file

@ -648,8 +648,8 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
fs.promises.access(localPath, fs.constants.F_OK) fs.promises.access(localPath, fs.constants.F_OK)
))); )));
const isDirectoryUpload = localPaths.length === 1 ? (await fs.promises.stat(localPaths[0])).isDirectory() : false; const isDirectoryUpload = localPaths.length === 1 ? (await fs.promises.stat(localPaths[0])).isDirectory() : false;
const waitForChangeEvent = isDirectoryUpload ? this.evaluateInUtility(([_, node]) => new Promise<any>(fulfil => { const waitForChangeEvent = isDirectoryUpload ? this.evaluateInUtility(([_, node]) => new Promise<any>(fulfill => {
node.addEventListener('change', fulfil, { once: true }); node.addEventListener('change', fulfill, { once: true });
}), undefined) : Promise.resolve(); }), undefined) : Promise.resolve();
await this._page._delegate.setInputFilePaths(retargeted, localPaths); await this._page._delegate.setInputFilePaths(retargeted, localPaths);
await waitForChangeEvent; await waitForChangeEvent;

View file

@ -4055,8 +4055,8 @@ export interface Page {
* instead. Read more about [locators](https://playwright.dev/docs/locators). * instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then * Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then
* they are resolved relative to the current working directory. For empty array, clears the selected files. In order * they are resolved relative to the current working directory. For empty array, clears the selected files. For inputs
* to upload a directory (`[webkitdirectory]`) pass the path to the directory. * with a `[webkitdirectory]` attribute, only a single directory path is supported.
* *
* This method expects `selector` to point to an * This method expects `selector` to point to an
* [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). However, if the element is inside * [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). However, if the element is inside
@ -10580,8 +10580,8 @@ export interface ElementHandle<T=Node> extends JSHandle<T> {
* instead. Read more about [locators](https://playwright.dev/docs/locators). * instead. Read more about [locators](https://playwright.dev/docs/locators).
* *
* Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then * Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then
* they are resolved relative to the current working directory. For empty array, clears the selected files. In order * they are resolved relative to the current working directory. For empty array, clears the selected files. For inputs
* to upload a directory (`[webkitdirectory]`) pass the path to the directory. * with a `[webkitdirectory]` attribute, only a single directory path is supported.
* *
* This method expects {@link ElementHandle} to point to an * This method expects {@link ElementHandle} to point to an
* [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). However, if the element is inside * [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). However, if the element is inside
@ -12788,8 +12788,8 @@ export interface Locator {
}): Promise<void>; }): Promise<void>;
/** /**
* Upload file or multiple files into `<input type=file>`. In order to upload a directory (`[webkitdirectory]`) pass * Upload file or multiple files into `<input type=file>`. For inputs with a `[webkitdirectory]` attribute, only a
* the path to the directory. * single directory path is supported.
* *
* **Usage** * **Usage**
* *

View file

@ -37,20 +37,17 @@ it('should upload the file', async ({ page, server, asset }) => {
}, input)).toBe('contents of the file'); }, input)).toBe('contents of the file');
}); });
async function createTestDirectoryStructure() {
const baseDir = path.join(it.info().outputDir, 'file-upload-test');
await fs.promises.mkdir(baseDir, { recursive: true });
await fs.promises.writeFile(path.join(baseDir, 'file1.txt'), 'file1 content');
await fs.promises.writeFile(path.join(baseDir, 'file2'), 'file2 content');
await fs.promises.mkdir(path.join(baseDir, 'sub-dir'));
await fs.promises.writeFile(path.join(baseDir, 'sub-dir', 'really.txt'), 'sub-dir file content');
return baseDir;
}
it('should upload a folder', async ({ page, server, browserName, headless, browserMajorVersion }) => { it('should upload a folder', async ({ page, server, browserName, headless, browserMajorVersion }) => {
await page.goto(server.PREFIX + '/input/folderupload.html'); await page.goto(server.PREFIX + '/input/folderupload.html');
const input = await page.$('input'); const input = await page.$('input');
const dir = await createTestDirectoryStructure(); const dir = path.join(it.info().outputDir, 'file-upload-test');
{
await fs.promises.mkdir(dir, { recursive: true });
await fs.promises.writeFile(path.join(dir, 'file1.txt'), 'file1 content');
await fs.promises.writeFile(path.join(dir, 'file2'), 'file2 content');
await fs.promises.mkdir(path.join(dir, 'sub-dir'));
await fs.promises.writeFile(path.join(dir, 'sub-dir', 'really.txt'), 'sub-dir file content');
}
await input.setInputFiles(dir); await input.setInputFiles(dir);
expect(new Set(await page.evaluate(e => [...e.files].map(f => f.webkitRelativePath), input))).toEqual(new Set([ expect(new Set(await page.evaluate(e => [...e.files].map(f => f.webkitRelativePath), input))).toEqual(new Set([
// https://issues.chromium.org/issues/345393164 // https://issues.chromium.org/issues/345393164
@ -70,6 +67,22 @@ it('should upload a folder', async ({ page, server, browserName, headless, brows
} }
}); });
it('should upload a folder and throw for multiple directories', async ({ page, server, browserName, headless, browserMajorVersion }) => {
await page.goto(server.PREFIX + '/input/folderupload.html');
const input = await page.$('input');
const dir = path.join(it.info().outputDir, 'file-upload-test');
{
await fs.promises.mkdir(path.join(dir, 'folder1'), { recursive: true });
await fs.promises.writeFile(path.join(dir, 'folder1', 'file1.txt'), 'file1 content');
await fs.promises.mkdir(path.join(dir, 'folder2'), { recursive: true });
await fs.promises.writeFile(path.join(dir, 'folder2', 'file2.txt'), 'file2 content');
}
await expect(input.setInputFiles([
path.join(dir, 'folder1'),
path.join(dir, 'folder2'),
])).rejects.toThrow('File paths must be all files or a single directory');
});
it('should upload a file after popup', async ({ page, server, asset }) => { it('should upload a file after popup', async ({ page, server, asset }) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/29923' }); it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/29923' });
await page.goto(server.PREFIX + '/input/fileupload.html'); await page.goto(server.PREFIX + '/input/fileupload.html');