File Upload Using sendKeys() in Selenium Java

1. Introduction

File upload is one of the most common automation tasks in Selenium. Applications ask users to upload resumes, identity documents, profile pictures, product images, insurance proofs, bank statements, spreadsheets, CSV import files, ZIP archives, and many other types of files. Because file upload involves the local machine, beginners often assume it requires operating-system automation. In most web applications, it does not.

File Upload Using sendKeys in Selenium Java

Selenium provides a simple and reliable way to upload files when the application uses a standard HTML file input. The technique is to locate the <input type="file"> element and call sendKeys() with the absolute path of the file. Selenium then assigns that file path to the file input directly. This bypasses the native file picker dialog, which Selenium WebDriver is not designed to control.

This approach is the recommended industry-standard solution for file uploads in Selenium. It is faster, simpler, more stable, and more portable than trying to automate the operating system dialog with tools such as Robot, AutoIT, or platform-specific scripts. The key is understanding when sendKeys() applies, how to build file paths correctly, and how to verify that the upload really succeeded.

2. What Is File Upload?

File upload allows a user to select a file from the local machine and send it to a web application. A typical manual flow looks like this: the user clicks a Choose File button, selects a file such as resume.pdf, and then clicks Upload or Submit. The application reads the selected file and sends it to the server.

In HTML, the core element behind this behavior is a file input.

<input type="file" id="uploadFile">

This element is different from a normal text box. A user does not type text into it. The browser expects a file selection. Selenium handles this by sending the local file path to the file input.

3. Why sendKeys() Works for File Upload

For normal text boxes, sendKeys() simulates keyboard input. For file inputs, sendKeys() assigns the file path to the input element. The path must point to a real file on the machine where the browser is running.

C:\Users\Suresh\Documents\Resume.pdf

This avoids the operating system's file picker. Native file picker windows are outside the browser DOM, and Selenium WebDriver cannot reliably control them. By sending the path directly to the file input, Selenium stays inside the browser automation model and avoids OS-level fragility.

4. HTML File Input Example

<input
    type="file"
    id="uploadFile">

Locate it like any other WebElement:

WebElement upload =
        driver.findElement(By.id("uploadFile"));

The important condition is that the located element must be the actual file input. Calling sendKeys() on a styled button, label, span, or wrapper will not upload the file. Inspect the DOM and locate the real input[type='file'].

5. Basic File Upload

WebElement upload =
        driver.findElement(By.id("uploadFile"));

upload.sendKeys(
        "C:\\Files\\Resume.pdf"
);

After this command, the browser selects the file. Most applications then show the selected filename or enable an Upload button. Some applications upload immediately after selection, while others require a separate submit action.

6. Complete Example

WebDriver driver =
        new ChromeDriver();

driver.get("https://example.com/upload");

WebElement upload =
        driver.findElement(By.id("uploadFile"));

upload.sendKeys(
        "C:\\Files\\Resume.pdf"
);

driver.findElement(By.id("submit"))
      .click();

This is the complete flow for a simple upload form: open the page, locate the file input, send the file path, and submit the form.

7. Required Imports

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;

The required imports depend on the exact code style. Paths is useful for cross-platform paths, File is useful for checking existence, and WebDriverWait is useful for waiting until the file input or success message is available.

8. Why Hardcoded Paths Are a Problem

Hardcoded local paths are fragile. A path such as C:\Users\Suresh\Documents\Resume.pdf may work only on one developer's machine. It will fail on another laptop, a Linux CI server, a Docker container, or a cloud execution environment. This is why project-relative file paths are preferred.

Test files should be stored inside the project repository or test resources folder. The test can then build the absolute path at runtime. This makes the same code run on different machines without editing file paths.

9. Using Relative Project Paths

A typical test project may contain a folder like this:

Project
│
├── src
├── test-data
│      resume.pdf

The file path can be created from the project directory.

String filePath =
        System.getProperty("user.dir")
        + "\\test-data\\resume.pdf";

driver.findElement(By.id("uploadFile"))
      .sendKeys(filePath);

This is better than a hardcoded user folder path. However, the string still uses Windows-style separators. For better cross-platform support, use the Java Paths API.

10. Using java.nio.file.Path

Path file =
        Paths.get(
                "test-data",
                "resume.pdf"
        );

String filePath =
        file.toAbsolutePath()
            .toString();

driver.findElement(By.id("uploadFile"))
      .sendKeys(filePath);

This approach works better across Windows, Linux, and macOS because Java handles path separators. It is the recommended approach for CI/CD pipelines and cross-platform automation projects.

11. Verify File Exists Before Uploading

File file =
        new File(filePath);

Assert.assertTrue(
        file.exists(),
        "Upload file does not exist: " + filePath
);

This simple check prevents confusing upload failures. If the file is missing, the test fails early with a clear message. Without this check, Selenium may throw an InvalidArgumentException or the application may show a vague upload error.

12. Wait for Upload Control Before Uploading

WebDriverWait wait =
        new WebDriverWait(
                driver,
                Duration.ofSeconds(10)
        );

WebElement upload =
        wait.until(
                ExpectedConditions
                        .presenceOfElementLocated(
                                By.id("uploadFile")
                        )
        );

upload.sendKeys(filePath);

Presence is usually enough for a file input because sendKeys() can often work even when the input is hidden. If the application requires a visible file input, wait for visibility instead. Choose the wait condition based on the component behavior.

13. Verify Selected File Name

WebElement upload =
        driver.findElement(By.id("upload"));

upload.sendKeys(filePath);

System.out.println(
        upload.getAttribute("value")
);

Browsers often show a value like C:\fakepath\Resume.pdf. This is expected. Browsers hide the real local path for security reasons. Do not assert the complete original local path from the input value. If needed, assert the filename or the application's visible uploaded-file label.

14. Upload Image

driver.findElement(By.id("profileImage"))
      .sendKeys(
              "C:\\Images\\photo.jpg"
      );

Image upload is common for profile pictures, product images, identity proof images, and content management systems. After upload, verify preview image, filename, or success message.

15. Upload PDF

driver.findElement(By.id("document"))
      .sendKeys(
              "C:\\Documents\\report.pdf"
      );

PDF uploads are common in resume portals, banking applications, and document management systems. Validate that the application accepts the file type and displays the uploaded document state.

16. Upload Excel File

driver.findElement(By.id("excelUpload"))
      .sendKeys(
              "C:\\Reports\\Employees.xlsx"
      );

Excel uploads are often used for bulk import. The upload may be followed by parsing, validation, and preview screens. Wait for those results before asserting.

17. Upload CSV File

driver.findElement(By.id("csvUpload"))
      .sendKeys(
              "C:\\Reports\\Employees.csv"
      );

CSV uploads are common for data import features. Validate both upload success and import result. A file can upload successfully but still fail business validation.

18. Upload ZIP File

driver.findElement(By.id("zipUpload"))
      .sendKeys(
              "C:\\Backup\\project.zip"
      );

ZIP uploads may involve larger files and server-side scanning. Use explicit waits for completion messages or progress indicators.

19. Upload Multiple Files

Multiple file upload requires the HTML input to support the multiple attribute.

<input
    type="file"
    id="upload"
    multiple>

Send multiple absolute paths separated by newline characters.

String file1 =
        "C:\\Files\\A.pdf";

String file2 =
        "C:\\Files\\B.pdf";

driver.findElement(By.id("upload"))
      .sendKeys(file1 + "\n" + file2);

If the input does not support multiple files, only one file may be selected or the command may fail depending on the browser and application.

20. Upload File Using XPath

driver.findElement(
        By.xpath("//input[@type='file']")
).sendKeys(
        "C:\\Files\\photo.jpg"
);

XPath is useful when the file input does not have a stable ID. Still prefer stable IDs or data attributes if the application provides them.

21. Upload File Using CSS Selector

driver.findElement(
        By.cssSelector("input[type='file']")
).sendKeys(
        "C:\\Files\\document.docx"
);

CSS selectors are concise for locating file inputs. If the page has more than one file input, make the selector more specific.

22. Upload Hidden File Input

Many modern upload controls hide the actual file input and show a styled button or drag-and-drop area. The good news is that sendKeys() often still works on a hidden file input because Selenium assigns the file path directly.

driver.findElement(By.id("upload"))
      .sendKeys(filePath);

If this works, it is usually better than using Robot or clicking the native dialog. If the application blocks interaction with the hidden input, inspect the component and decide whether JavaScript visibility adjustment is appropriate.

23. Upload Hidden File Input Using JavaScript

WebElement upload =
        driver.findElement(By.id("hiddenUpload"));

JavascriptExecutor js =
        (JavascriptExecutor) driver;

js.executeScript(
        "arguments[0].style.display='block';",
        upload
);

upload.sendKeys(filePath);

This temporarily makes the input visible and then sends the file path. Use it only when necessary. If sendKeys() already works on the hidden input, changing CSS is not needed.

24. Upload After Clicking a Button

driver.findElement(By.id("uploadButton"))
      .click();

driver.findElement(By.id("uploadFile"))
      .sendKeys(filePath);

Some applications create or reveal the file input only after the user clicks an upload button. In that case, perform the click, wait for the file input to be present, and then send the path.

25. Upload Inside an iFrame

driver.switchTo().frame("uploadFrame");

driver.findElement(By.id("upload"))
      .sendKeys(filePath);

driver.switchTo().defaultContent();

File inputs inside frames require frame switching. sendKeys() does not remove the need to be in the correct frame context.

26. Upload and Click Submit

driver.findElement(By.id("upload"))
      .sendKeys(filePath);

driver.findElement(By.id("submit"))
      .click();

Some applications only select the file after sendKeys(). The actual upload happens after Submit. Always understand whether selection and upload are separate steps in the application.

27. Verify Upload Success Message

driver.findElement(By.id("upload"))
      .sendKeys(filePath);

driver.findElement(By.id("submit"))
      .click();

String message =
        driver.findElement(By.id("success"))
              .getText();

Assert.assertEquals(
        message,
        "File uploaded successfully."
);

This validates the user-visible result. A test should not stop at sending the file path. It should prove the application accepted the upload.

28. Wait for Upload Success

driver.findElement(By.id("upload"))
      .sendKeys(filePath);

driver.findElement(By.id("submit"))
      .click();

WebElement success =
        wait.until(
                ExpectedConditions
                        .visibilityOfElementLocated(
                                By.id("success")
                        )
        );

Upload may take time, especially for large files or server-side processing. Wait for the success state instead of immediately reading the message.

29. Upload Different Files Using a Loop

String[] files = {
        "C:\\Files\\one.pdf",
        "C:\\Files\\two.pdf",
        "C:\\Files\\three.pdf"
};

for (String file : files) {
    driver.findElement(By.id("upload"))
          .sendKeys(file);
}

This pattern is useful for data-driven tests. Be careful: some upload components replace the previous file when a new path is sent. Others append files. Verify the component behavior.

30. Upload Using Dynamic File Name

String fileName =
        "invoice.pdf";

String path =
        Paths.get(
                "test-data",
                fileName
        ).toAbsolutePath()
         .toString();

driver.findElement(By.id("upload"))
      .sendKeys(path);

This is useful when test data is selected by scenario. Keep file names meaningful and store files in predictable project folders.

31. Upload Using Page Object Model

public class UploadPage {

    private WebDriver driver;

    private By upload =
            By.id("uploadFile");

    public UploadPage(WebDriver driver) {
        this.driver = driver;
    }

    public void uploadFile(String path) {
        driver.findElement(upload)
              .sendKeys(path);
    }
}

Usage:

UploadPage page =
        new UploadPage(driver);

page.uploadFile(filePath);

Page Object Model keeps the test readable and hides locator details inside the page class.

32. Reusable Upload Utility

public static void uploadFile(
        WebDriver driver,
        By locator,
        String path) {

    driver.findElement(locator)
          .sendKeys(path);
}

Usage:

uploadFile(
        driver,
        By.id("uploadFile"),
        filePath
);

A utility method is useful when upload behavior is consistent across pages. If each page has different validation and success behavior, keep upload verification in page objects.

33. Stronger Upload Utility with File Check

public static void uploadFile(
        WebDriver driver,
        By locator,
        Path file) {

    String filePath =
            file.toAbsolutePath()
                .toString();

    Assert.assertTrue(
            file.toFile().exists(),
            "File not found: " + filePath
    );

    driver.findElement(locator)
          .sendKeys(filePath);
}

This version verifies the file before uploading. It makes failures easier to diagnose and supports project-relative paths cleanly.

34. Real Project Example: Resume Upload

String resume =
        Paths.get(
                "documents",
                "Resume.pdf"
        ).toAbsolutePath()
         .toString();

driver.findElement(By.id("resume"))
      .sendKeys(resume);

driver.findElement(By.id("submit"))
      .click();

Resume upload is common in job portals and HR systems. Verify the uploaded filename or confirmation message after submission.

35. Real Project Example: Profile Picture Upload

String image =
        Paths.get(
                "images",
                "profile.jpg"
        ).toAbsolutePath()
         .toString();

driver.findElement(By.id("profilePic"))
      .sendKeys(image);

Profile picture uploads often show a preview after selection. Wait for the preview or success state before asserting.

36. Real Project Example: Bulk CSV Import

String csv =
        Paths.get(
                "data",
                "Employees.csv"
        ).toAbsolutePath()
         .toString();

driver.findElement(By.id("csvUpload"))
      .sendKeys(csv);

driver.findElement(By.id("import"))
      .click();

CSV import usually has two stages: upload and processing. The upload may succeed while row validation fails. Test both stages if the scenario requires it.

37. Real Project Example: Document Management System

Document systems often require a file, document type, description, and submit action. Upload should be treated as part of a workflow, not as an isolated command.

documentTypeDropdown.selectByVisibleText("Contract");

driver.findElement(By.id("documentUpload"))
      .sendKeys(filePath);

driver.findElement(By.id("description"))
      .sendKeys("Signed contract");

driver.findElement(By.id("save"))
      .click();

After saving, verify that the document appears in the list with the expected name and type.

38. Real Project Example: Large File Upload

Large files may take longer to upload and process. Use waits based on progress indicators, completion messages, or uploaded file rows. Do not use a fixed sleep.

upload.sendKeys(largeFilePath);

wait.until(
        ExpectedConditions
                .invisibilityOfElementLocated(
                        By.id("uploadProgress")
                )
);

wait.until(
        ExpectedConditions
                .visibilityOfElementLocated(
                        By.id("uploadSuccess")
                )
);

This pattern handles slower environments better than hardcoded pauses.

39. Common Exceptions

InvalidArgumentException may occur when the file path is empty, malformed, or points to a file that does not exist. Verify the path before calling sendKeys(). ElementNotInteractableException may occur if the locator points to the wrong element, the input is disabled, or the component blocks interaction. NoSuchElementException means Selenium could not find the file input at all.

Do not solve every upload failure with Robot or JavaScript. First confirm that the locator targets the actual input[type='file'], the file exists, and the browser is in the correct frame or window.

40. sendKeys() vs Robot Class

sendKeys() is the best choice when the application exposes a standard HTML file input. It is reliable, fast, and cross-platform. Robot class interacts with the operating system keyboard and clipboard. It may be needed only when the application forces a native dialog that cannot be bypassed through an HTML file input.

Robot-based upload is more fragile because it depends on active windows, OS behavior, keyboard layout, timing, and environment. It also does not work cleanly in many headless or remote execution environments. Use Robot only when there is no standard file input to target.

41. File Upload in Remote or Grid Execution

In Selenium Grid or remote execution, the browser may run on a different machine from the test code. File upload can require special handling because the path must be available to the remote browser. Modern Selenium supports remote file upload mechanisms, but the framework setup matters.

If upload works locally but fails on Grid, check where the browser runs, where the file exists, and whether the remote driver supports file transfer. Store test files in the project and configure the framework so remote sessions can access them consistently.

42. File Upload in CI/CD

CI environments are usually Linux-based and do not have the same paths as a developer's Windows machine. Avoid paths like C:\Files\resume.pdf in CI-ready tests. Use project-relative files and Paths.get(...).toAbsolutePath(). Make sure test files are committed to the repository or created during the build.

Also consider cleanup. If the application stores uploaded files, test environments may accumulate data. Some test suites need teardown steps, API cleanup, or unique filenames to avoid collisions.

CI logs should print the resolved upload path when an upload fails. That small detail makes it much easier to distinguish between an application defect, a missing test file, a wrong working directory, and a path problem caused by the build agent.

43. Security Notes

Browsers intentionally display C:\fakepath\ for selected files. This protects the user's real local path. Tests should not depend on the complete visible path. Assert the filename or application confirmation instead.

Do not upload sensitive real documents into test environments. Use safe sample files with dummy content. For regulated applications, test data management matters as much as Selenium code. Keep uploaded samples harmless, predictable, and reviewable.

44. Validating File Type Restrictions

Many upload controls accept only certain file types. A resume field may accept PDF and DOCX. A profile image field may accept PNG and JPG. A data import field may accept only CSV or XLSX. A strong upload test should not only verify a successful upload; it should also verify that invalid file types are rejected when the requirement says they should be rejected.

The HTML input may include an accept attribute, but browser-side restrictions alone are not enough. The server should also validate file type. Selenium can upload an invalid file and verify the error message.

Path invalidFile =
        Paths.get(
                "test-data",
                "invalid-file.txt"
        );

driver.findElement(By.id("resume"))
      .sendKeys(
              invalidFile.toAbsolutePath()
                         .toString()
      );

driver.findElement(By.id("submit"))
      .click();

WebElement error =
        wait.until(
                ExpectedConditions
                        .visibilityOfElementLocated(
                                By.id("uploadError")
                        )
        );

This turns upload testing into a real validation scenario. It proves that the application handles unsupported files correctly instead of only proving that Selenium can select a file.

45. Validating File Size Restrictions

File size validation is another common upload requirement. Applications may reject files larger than 2 MB, 5 MB, or 10 MB. To test this reliably, keep sample files in the project with clear names such as small-profile.jpg, valid-resume.pdf, and large-upload.pdf. Do not depend on random files from a developer's machine.

A file size test should upload the boundary-related file and verify the application's response. If the application validates before submit, wait for the client-side error. If it validates after submit, wait for the server response. The important point is that the assertion should match the requirement.

Path largeFile =
        Paths.get(
                "test-data",
                "large-upload.pdf"
        );

upload.sendKeys(
        largeFile.toAbsolutePath()
                 .toString()
);

wait.until(
        ExpectedConditions
                .visibilityOfElementLocated(
                        By.id("fileSizeError")
                )
);

This style of testing is more valuable than simply uploading one valid file every time.

46. Verifying Preview After Upload

Image upload components often show a preview after the file is selected. In that case, the selected input value is not the best assertion. The visible preview is closer to what the user cares about. After sending the file path, wait for the preview image or thumbnail to appear.

profileImageUpload.sendKeys(imagePath);

WebElement preview =
        wait.until(
                ExpectedConditions
                        .visibilityOfElementLocated(
                                By.id("profilePreview")
                        )
        );

Assert.assertTrue(
        preview.isDisplayed()
);

For product image upload, also verify that the image appears in the product form or gallery. For document upload, verify the uploaded filename row. Assertions should validate user-facing application behavior, not just browser input state.

47. Handling Drag-and-Drop Upload Areas

Many modern applications show a drag-and-drop upload area. Even when the visible UI looks like a drop zone, there is often a hidden file input behind it. Inspect the DOM. If an input[type='file'] exists, use sendKeys() on that input. This is usually more reliable than trying to simulate native drag-and-drop with the operating system.

If the component truly supports only drag-and-drop and does not expose a usable file input, Selenium alone may not be enough. Some teams use JavaScript-based event simulation or API-level setup for those advanced cases. But first check for the hidden input. Most production upload widgets still use a real file input internally because browsers require it for file selection.

48. Upload Progress and Processing States

Some applications upload immediately after file selection. Others upload after submit. Some show a progress bar, then run server-side processing, then display a final success or validation result. A stable test should wait for the correct final state.

upload.sendKeys(filePath);

wait.until(
        ExpectedConditions
                .visibilityOfElementLocated(
                        By.id("uploadProgress")
                )
);

wait.until(
        ExpectedConditions
                .invisibilityOfElementLocated(
                        By.id("uploadProgress")
                )
);

wait.until(
        ExpectedConditions
                .visibilityOfElementLocated(
                        By.id("uploadedFileName")
                )
);

This pattern handles real upload timing better than a fixed sleep. It also makes failures clearer: the test can show whether upload never started, progress never finished, or the final filename never appeared.

49. Test Data Design for Uploads

Upload tests need intentional test data. A useful test-data folder may include valid and invalid examples: a valid PDF, valid image, valid CSV, unsupported TXT file, oversized file, empty file, corrupt file, and a file with special characters in the name. These files should be safe, small enough for the repository, and clearly named.

Good file names improve test readability. A file named valid-resume.pdf communicates intent better than file1.pdf. A file named unsupported-file-type.txt makes a negative test self-explanatory. Do not use personal documents, real customer data, or sensitive production files in automated upload tests.

50. Framework Design for Upload Utilities

A mature framework should centralize path building and upload behavior. Instead of every test manually constructing paths, create a helper that resolves files from a known test-data directory. This reduces duplication and makes CI execution easier.

public static String testDataFile(
        String fileName) {

    return Paths.get(
            "test-data",
            fileName
    ).toAbsolutePath()
     .toString();
}

Then page objects can call:

upload.sendKeys(
        testDataFile("valid-resume.pdf")
);

This keeps tests clean and prevents hardcoded machine paths from spreading through the codebase.

51. When sendKeys() Is Not Enough

There are cases where sendKeys() may not be enough. The locator may not point to a real file input. The file input may be created only after clicking a button. The input may be inside a shadow DOM or iframe. The browser may run remotely and need file transfer support. The application may use a non-standard component with no accessible file input.

In those cases, do not immediately jump to Robot. First inspect the DOM, find the real file input, switch frames if needed, wait until the input exists, and use a portable absolute path. If the application truly does not expose a file input, discuss testability with the development team or use an API-level setup for the file where appropriate.

Also separate file selection from upload completion. Selecting a file in the browser does not always mean the server has received and processed it. Some applications upload immediately; others wait for a submit button; others upload first and process later. The safest assertion is tied to the final business state: a success message, uploaded filename row, document ID, preview image, import summary, or downloadable file record. That final validation is what turns a file selection script into a meaningful upload test.

52. Common Beginner Mistakes

  • Trying to automate the native file picker when sendKeys() is enough.
  • Calling sendKeys() on a visible button instead of the real file input.
  • Hardcoding local machine paths.
  • Using relative paths incorrectly.
  • Forgetting to verify that the file exists before upload.
  • Forgetting to verify upload success after selection.
  • Ignoring frames that contain the file input.
  • Using Robot class unnecessarily.

53. Best Practices

  • Use sendKeys() whenever the application uses a standard <input type="file">.
  • Prefer project-relative paths for portability.
  • Use Paths.get(...).toAbsolutePath() for cross-platform path construction.
  • Store test files in a dedicated test-data or resources folder.
  • Verify that the file exists before uploading.
  • Wait for the upload input, success message, or uploaded filename.
  • For multiple uploads, separate paths with newline characters and confirm the input supports multiple.
  • Avoid OS-level automation unless the application does not expose a usable file input.

54. Debugging Checklist

  • Confirm the locator points to input[type='file'].
  • Confirm the file path is absolute.
  • Confirm the file exists on the machine running the browser.
  • Check whether the file input is inside an iframe.
  • Check whether the input is disabled.
  • Check whether the application requires a submit button after selection.
  • Check whether the selected file value shows C:\fakepath\, which is normal.
  • Verify the final upload result in the application UI.

55. Interview Perspective

A short interview answer is: file upload in Selenium is usually done by locating the HTML <input type="file"> element and calling sendKeys() with the absolute path of the file. This bypasses the native OS file picker and is the recommended approach for standard web file uploads.

A stronger real-time answer is: in projects, I store sample files inside the test resources or test-data folder, build absolute paths using System.getProperty("user.dir") or Paths.get(...).toAbsolutePath(), verify that the file exists, send the path to the file input, and then validate the upload result through a success message, uploaded filename, preview, or server-side result. I use Robot or OS automation only when the application does not expose a standard file input.

56. Key Takeaway

Whenever a web application provides a standard <input type="file">, sendKeys() is the simplest, fastest, and most reliable file upload solution in Selenium. The method accepts the file's absolute path and avoids the operating system file picker.

The quality of the upload test depends on more than the single sendKeys() line. Build portable file paths, verify that files exist, wait for the upload control and result, handle frames when needed, and assert the application outcome after the upload.

Use OS-level tools only as a last resort. For most real-world Selenium Java projects, clean file path management plus sendKeys() on input[type='file'] is the correct enterprise approach.