Your Selenium upload tests must run against a local browser and a remote browser with its own filesystem - how would you design for both?
answer
- One invariant covers both environments
- The difference belongs at session creation
- Transfer is not free
- Assert on what the app shows
- LocalFileDetector on the remote branch only
basics
~20 sHold one invariant: the file must exist where the browser can read it. Keep the test bodies identical, and put the difference in session creation, where a remote driver gets a LocalFileDetector and a local driver keeps the default.
solid answer
~50 sThere is a single rule to satisfy - the remote end verifies the named file exists on the browser's own filesystem before it attaches anything. Locally that is free; remotely it is not, so the remote branch of session creation installs `new LocalFileDetector()` via `setFileDetector` and everything else stays identical. Keep the difference there rather than in tests, because the detector is a driver property copied onto elements as they are found. Then budget the transfer honestly: each resolved path costs one zipped, base64-encoded HTTP upload, base64 inflates bytes by about a third, and the remote copy lives in a session-scoped temporary directory. Choose the smallest fixture that still exercises the behaviour, keep one deliberately large file for the size-limit case, and assert on the filename the application shows rather than on the path you sent.
go deeper
Recall the invariant: the browser must be able to read the file. Knowing that a remote browser needs the file transferred, and that Selenium has a detector for it, is what is expected here.
Explain why the local case needs nothing and the remote case needs a LocalFileDetector, and describe the extra upload command it introduces before the send-keys call.
Show you keep the environment difference out of test bodies and can name the sharp edges: all-or-nothing path resolution, directories not resolving, and the remote copy's path being unusable for assertions.
Own the trade-offs: how large a fixture may be before you stop shipping it on every run, what a pre-placed file costs in hidden coupling, and where in the harness the decision lives so it stays visible.
## The invariant everything else hangs off There is exactly one rule that both environments have to satisfy: **when Element Send Keys runs, the named file must exist on the filesystem the browser process can read.** The remote end verifies existence before it sets the element's selected files, and it returns `invalid argument` when the check fails. Every design decision below is only a way of making that one sentence true. - Against a **local** browser, it is true for free: the runner and the browser share a disk, so an absolute path to your fixture is already valid. - Against a **remote** browser, it is false by default, because `RemoteWebDriver` starts with a `UselessFileDetector` and simply forwards the characters you typed. ## The two ways to make it true | Approach | How the file gets there | What it costs | |---|---|---| | `LocalFileDetector` on the remote driver | the client zips, base64-encodes and posts the file to `POST /session/{sessionId}/se/file`; the remote end unzips it and returns its own path | an extra HTTP command per file, plus the encoded bytes on the wire | | The file is already beside the browser | nothing at runtime; the test sends the path it knows the browser has | the path becomes an environment contract the test cannot verify | The first approach keeps the test self-contained and is what almost every suite should do. The second is only worth it for a fixture too large to ship on every run, and it trades a runtime cost for a coupling that breaks silently when the environment changes. ## Where the detector setting belongs Set it once where the remote session is created, not inside individual tests. It is a property of the *driver*, propagated to each `RemoteWebElement` as elements are found, so a test that finds an element before the detector is set gets the old behaviour on that element. Leave the local driver on its default: a local browser needs no transfer, and the do-nothing detector is what keeps ordinary `sendKeys` calls from being interpreted as paths. ## Budgeting the transfer The upload is a real HTTP request carrying a zipped, base64-encoded copy of the file, and base64 inflates bytes by roughly a third. That has consequences worth deciding on deliberately: 1. **One command per path.** A `multiple` input given four paths costs four uploads before a single character of send-keys text is produced. 2. **Choose the smallest fixture that still exercises the behaviour.** A 20 KB leaf photo proves the plant finder attaches, previews and posts an image just as well as a 25 MB one. 3. **Keep the genuinely large file to the one case that needs it** - the test for the app's own size limit - rather than paying for it in every upload test. 4. **Expect the copy to persist for the session.** The remote end writes the unzipped file into a temporary directory tied to the session, so a suite that uploads on every test leaves that directory growing until the session ends. ## The sharp edges to design around - **All-or-nothing resolution.** If any newline-separated segment does not resolve to an existing local file, the client uploads none of them and sends the raw string through. A helper should therefore assert that each fixture exists before it calls `sendKeys`, so the failure names the missing fixture instead of surfacing as a confusing `invalid argument`. - **Only regular files resolve.** A directory is ignored by `LocalFileDetector`, so "upload this folder" is not a thing the detector can express. - **`strictFileInteractability` interacts with all of this.** Left at its default `false`, a hidden input accepts the path in both environments; set to `true`, the same test starts failing wherever the uploader is styled - so it is a per-session decision, not a per-environment one. - **The path you send is not the path the browser sees.** Any assertion that echoes the uploaded path back is asserting on a remote temporary directory, so assert on the **filename** the application displays instead. ## What good looks like A single upload helper that takes a fixture path, resolves it to an absolute path, asserts it exists, and calls `sendKeys` on the located `input`. The environment difference lives entirely in session creation - one `setFileDetector(new LocalFileDetector())` on the remote branch - and the tests themselves never mention it. When the plant-finder suite moves from a developer's laptop to a remote browser, nothing in the test bodies changes, and the only thing you re-examine is the size of the fixtures you are now shipping over HTTP on every run.
- When would you not ship the fixture through the detector at all?When the file is large enough that shipping it on every run dominates the test, and the environment can guarantee a copy beside the browser. That trade buys speed and pays for it with a hidden contract: the test now depends on an environment fact it cannot verify, and it breaks silently when that environment changes. Reserve it for the rare oversized fixture.
- Your upload helper fails with invalid argument and no useful message. How do you make that diagnosable?Assert the fixture exists and resolve it to an absolute path inside the helper, before sendKeys. The client only uploads when every newline-separated path resolves locally, so a bad path degrades into a raw string and surfaces as a remote invalid argument. A local existence check turns that into a failure naming the missing fixture.
- How does strictFileInteractability factor into a cross-environment plan?It is orthogonal to where the file lives - it decides whether a hidden file input is rejected as unreachable, and it applies per session in both environments. Leave it at its default false for suites that use uploads as a step, and treat any decision to enable it as a separate policy about testing the control's reachability, not as an environment concern.
saying these in an interview costs you the question
- Branching inside test bodies on local versus remote
- Treating the upload transfer as free at any fixture size
- Asserting on the path sent rather than the filename displayed
- Setting the file detector after elements are already found
- Assuming a pre-placed fixture stays valid as environments change