Rayrun
← Back to Discord Forum

File upload not working.

anirudh.ruhelaposted in #help-playwright
Open in Discord
anirudh.ruhela

I am uploading a xml,My application reads that xml and create a user. iT is working fine when i am uplaoding the xml manually but, I am getting error when i am uploading the file from automation(playwright ). I have tried both the ways input file as well as file chooser.

Reason of failing is on uploading from automation an api call is not going. Can anyone suggest any other way of uploading the file

FileChooser fileChooser = FrameworkConfig.LocalPage.waitForFileChooser(() -> { //page.getByLabel("Upload file").click(); CommonUtility.click(element, 30000);

});
    //fileChooser.setFiles(Paths.get(filePath));
    fileChooser.element().setInputFiles(Paths.get(filePath));

This thread is trying to answer question "Why is file upload not working when done from automation using Playwright and how can it be fixed?"

4 replies

You might have omitted it from the snippet, but it looks like there might be a step missing. Generally, file uploads consist of:

  • click the file chooser
  • provide the filepath
  • click submit/send/whatever

For playwright, the whole process will have some extra steps, and look like this:

  • create your listeners ( fileChooser and network response)
  • click the file chooser
  • await the fileChooser event
  • set the path
  • click the submit button
  • await the network response event

I don't see the 'click to send' step in your code, and TS is my main language so I'm not sure what language idiosyncracies Java might have, but I'm guessing either that step is missing, or that your listeners are not present before you take the actions.

anirudh.ruhela

fileChooser.element().setInputFiles(Paths.get(filePath)); is the step where we are adding file

anirudh.ruhela

can you please provide your snippet

The typescript looks something like this:

test('example', async ({page}) => {
  const responsePromise = page.waitForResponse('**/api/fetch_data');
  const fileChooserPromise = page.waitForEvent('filechooser');
  await page.getByText('Select File').click();
  const fileChooser = await fileChooserPromise;
  await fileChooser.setFiles('myfile.pdf');
  await page.getByText('Upload').click();
  const response = await responsePromise;
  expect(await response.json()).toEqual({success: true});
});

My java is not great, but I imagine it looks something like this:

public class TestExample {
  public static void main(String[] args) {
    try (Playwright playwright = Playwright.create()) {
      Browser browser = playwright.chromium().launch();
      Page page = browser.newPage();
      Response responsePromise = page.waitForResponse("**/api/upload", () -> {
        // The callback lambda defines the scope of the code that is expected to trigger the request.
        page.onFileChooser(fileChooser -> {
          fileChooser.setFiles(Paths.get("myfile.pdf"));
        });
        page.click("text=Select File");
        page.click("text=Upload");
      });
      Map<String, Object> json = (Map<String, Object>) responsePromise.json();
      assertEquals(Map.of("success", true), json);
    }
  }
}

Answer

Uploading Files with Playwright's APIRequestContext.post()

If you're having trouble uploading a file using the standard methods in Playwright, there's an alternative approach you can try. You can simulate the file upload process by sending a POST request with the file content as the request body.

First, you need to read the content of the file you want to upload. You can use Node.js's fs library to do this. Once you have the file content, you can create a buffer object using Buffer.from().

Then, you can use Playwright's APIRequestContext.post() method to send an HTTP(S) POST request with the file content as part of the request body. This method will automatically populate request cookies from the context and update context cookies from the response.

Here's an example:

import { page } from '@playwright/test';
import fs from 'fs';

// Read and prepare your file content
const filePath = '/path/to/your/file.pdf';
const buffer = fs.readFileSync(filePath);

// Send POST request with form data
await page.context().post('https://ray.run/upload', {
  formData: {
    // Add any additional form fields if required
    field1: 'value1',
    field2: 'value2',
    // Specify your file field with its name, type, and content
    myFile: {
      name: 'file.pdf',
      mimeType: 'application/pdf',
      buffer,
    },
  },
});

In this example, we first read the contents of our target PDF file using fs.readFileSync(). Then we pass this buffer object along with any additional form fields in an object structure under formData parameter when making our POST request using APIRequestContext.post(). Make sure to provide the correct file name, MIME type, and buffer content.

This approach allows you to bypass the need for input file or file chooser elements and directly send the file content as part of an HTTP(S) request. This can be useful when the standard methods are not working due to API call issues.

Related Discord Threads

TwitterGitHubLinkedIn
AboutQuestionsDiscord ForumBrowser ExtensionTagsQA Jobs

Rayrun is a community for QA engineers. I am constantly looking for new ways to add value to people learning Playwright and other browser automation frameworks. If you have feedback, email luc@ray.run.