> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qawolf.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Upload files

> Upload files to QA Wolf and use them in your test flows.

<Check>
  Make sure you have:

  * Your `QAWOLF_API_KEY` — available under **Workspace Name → Workspace Settings → Integrations → API Access**
</Check>

## Supported file types

### App executables

The build under test.

* **Mobile apps** (`.apk`, `.aab`, `.ipa`) — use a static filename based on the environment (e.g., `app-staging.ipa`) so tests always reference the latest build. See [Mobile build testing](/Fastlane) for how to automate this as part of your build process.
* **Linux desktop apps** (`.deb`) — use a static filename based on the environment, the same convention as mobile app builds.

### Data files

Used inside a test flow, not the app itself.

* **ZIP archives** (`.zip`) — bundle multiple assets for a single upload. Make sure the contents match the structure your tests expect.
* **CSV files** (`.csv`) — test data inputs. Use a consistent filename so flows always pick up the latest version.
* **PDF files** (`.pdf`) — for test flows that involve document handling or validation.

## Upload a file

QA Wolf accepts file uploads via a two-step signed URL process.

<Steps>
  <Step title="Generate a signed URL">
    ```bash theme={null}
    curl "https://app.qawolf.com/api/v0/run-inputs-executables-signed-urls?file=$DESTINATION_FILE_PATH" \
      -H "Authorization: Bearer $QAWOLF_API_KEY"
    ```

    Returns a `signedUrl` for the next step, plus `fileLocation` and `playgroundFileLocation` — the paths you'll use to reference the file afterward.
  </Step>

  <Step title="Upload the file">
    ```bash theme={null}
    curl -X PUT \
      --header "Content-Type: application/octet-stream" \
      --data-binary @some_file.zip \
      $SIGNED_URL
    ```
  </Step>
</Steps>

See [v0/run-inputs-executables-signed-urls](/run-inputs-executables-signed-urls) for the full request/response reference, including error codes.

## Use an uploaded file in a flow

### Mobile apps

QA Wolf resolves an uploaded build automatically through `RUN_INPUT_PATH` — omit `app` in your launch call and provide only the package/bundle ID:

```typescript theme={null}
import { flow, launch } from "@qawolf/flows/android";

export default flow("Open uploaded build", "Android - Pixel", async () => {
  const { driver } = await launch({
    appPackage: "com.example.android",
  });
});
```

See [App resolution](/libraries/flows/api-reference/android#app-resolution) (or the [iOS equivalent](/libraries/flows/api-reference/ios#app-resolution)) for the full resolution order and how to reference a specific path or URL instead.

### Web file upload

Use Playwright's `filechooser` event to intercept the file dialog and set the uploaded file programmatically.

```javascript theme={null}
const fileName = `${process.env.TEAM_STORAGE_DIR}/fileNameHere`;

page.once(
  "filechooser",
  (chooser) => void chooser.setFiles(fileName).catch(console.error)
);

await page.getByText("Upload file").click();
```

<Warning>
  Use `page.once` rather than `page.on`. `page.once` registers a one-time event listener that automatically unregisters after the first use. Using `page.on` adds a persistent listener that may interfere with subsequent file uploads in the same flow.
</Warning>

### PDF viewing

Use the internal PDF viewer to open an uploaded PDF file in a flow.

```javascript theme={null}
const invoicePath = `${process.env.TEAM_STORAGE_DIR}/invoices/invoice-1.pdf`;

const pdfPage = await context.newPage();
await pdfPage.goto("http://pdf-viewer.psc.qaw.internal");

pdfPage.once(
  "filechooser",
  (chooser) => void chooser.setFiles(invoicePath).catch(console.error)
);

await pdfPage.waitForTimeout(4000);
await pdfPage.click("#openFile");
```
