Playwright's set_input_files() function doesn't work properly in python
I'm writing tests for my Django project using playwright and StaticLiveServerTestCase. In one test I need to choose two files using input[type=file] field and send them to the server.
file_input = page.locator('input[type="file"]')
file_input.set_input_files(["Input1.xlsx", "Input2.xlsx"])
But Playwright sending only first file and my test fails. I've tried to watch does input field has only one file, but it has both of them inside after choosing
file_info = page.evaluate("""
element => {
const files = Array.from(element.files);
return files.map(file => ({
name: file.name,
size: file.size,
type: file.type
}));
}
""", file_input.element_handle())
print("Files that JS sees:", file_info)
That is the output:
Files that JS sees: [{'name': 'Input1.xlsx', 'size': 5853, 'type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}, {'name': 'Input2.xlsx', 'size': 5851, 'type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}]
And Playwright outs only the first:
input_value = file_input.input_value()
print("Playwright's version:", input_value)
Playwright's version: C:\fakepath\Input1.xlsx
If you'll ask me I've tried absolute path for files and I've tried to change browsers.
Django version 5.1.6 Playwright version 1.51.0
The first thing to say is, you need to compare apples to apples. In your page.evaluate
you are accessing the files
property but in file_input.input_value()
you are accessing the value
property.
These are different properties of the HTMLInputElement
So, instead of file_input.input_value()
you need something like file_input.get_property('files')
, but unfortunately that's missing from the Playwright API (AFAIK).
The only way I could do it was to use the deprecated element handle API, here is my test in Javascript (sorry I haven't used python for a long time).
I'm using the page provided by MDN to run my test.
The evaluate()
method is limited to returning simple values, but the input.files
property returns a FileList object that can't be returned intact, so we must extract the data we need to assert within the evaluate function.
test('file upload', async ({ page }) => {
await page.goto('https://mdn.github.io/learning-area/html/forms/file-examples/simple-file.html');
const fileInput = page.locator('input[type="file"]');
await fileInput.setInputFiles(['./fixtures/Input1.xlsx', './fixtures/Input2.xlsx']);
// for reference, this is the input value
await expect(fileInput).toHaveValue('C:\\fakepath\\Input1.xlsx');
// evaluate the input files property
const inputHandle = await page.waitForSelector('input[type="file"]');
const file0 = await inputHandle.evaluate(input => {
return (input as HTMLInputElement).files!.item(0)!.name;
});
expect(file0).toBe('Input1.xlsx');
const file1 = await inputHandle.evaluate(input => {
return (input as HTMLInputElement).files!.item(1)!.name;
});
expect(file1).toBe('Input2.xlsx')
})
This test succeeds, which means there are actually two files attached to the <input>
.
The problem was on the server side. I forgot to create user for testing 'cause test system creates empty database, that's why I had only one file in the storage.