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

# Python CLI for Playwright

> Upload reports, cache metadata, and rerun failed Playwright tests with testdino.

<Callout icon="book-open" color="#3B82F6">
  **What you'll learn**

  * Three commands: `upload`, `cache`, and `last-failed`
  * Upload options for HTML, images, videos, traces, and full bundles
  * How to cache metadata and rerun only failed tests
</Callout>

`testdino` is the TestDino Python CLI for Playwright. It uploads pytest-based Playwright reports, caches test metadata, and retrieves failed tests for selective reruns.

## Prerequisites

* Python `>= 3.9`
* `pytest` with `pytest-playwright`
* `pytest-playwright-json` (generates the required JSON report)
* `pytest-html` (generates HTML report)
* TestDino API token ([generate one](/guides/generate-api-keys))
* Git initialized repository (for commit and branch metadata)
* pytest configured with JSON and HTML reporter flags:

```bash theme={null}
pytest \
  --playwright-json=test-results/report.json \
  --html=test-results/index.html \
  --self-contained-html
```

## Installation

```bash theme={null}
pip install pytest-playwright-json pytest-html testdino
```

## Quick Start

<Steps>
  <Step title="Run tests with JSON output">
    ```bash theme={null}
    pytest \
      --playwright-json=test-results/report.json \
      --html=test-results/index.html \
      --self-contained-html
    ```
  </Step>

  <Step title="Upload the report">
    ```bash theme={null}
    testdino upload ./test-results --token="$TESTDINO_TOKEN"
    ```
  </Step>

  <Step title="Cache metadata for reruns">
    ```bash theme={null}
    testdino cache --working-dir test-results --token="$TESTDINO_TOKEN"
    ```
  </Step>
</Steps>

<Note>The upload command requires a JSON report. Always run pytest with the `--playwright-json` flag.</Note>

## Commands

### `upload`

Upload Playwright test reports and artifacts to TestDino.

```bash theme={null}
testdino upload <report-directory> --token="$TESTDINO_TOKEN"
```

**Upload flags:**

| Flag                 | Description                                             |
| :------------------- | :------------------------------------------------------ |
| `--upload-images`    | Upload screenshots                                      |
| `--upload-videos`    | Upload video recordings                                 |
| `--upload-html`      | Upload HTML reports                                     |
| `--upload-traces`    | Upload trace files                                      |
| `--upload-files`     | Upload file attachments (`.md`, `.pdf`, `.txt`, `.log`) |
| `--upload-full-json` | Upload all attachments                                  |

```bash theme={null}
# Upload with all artifacts
testdino upload ./test-results --token="$TESTDINO_TOKEN" --upload-full-json

# Upload with specific artifacts
testdino upload ./test-results --token="$TESTDINO_TOKEN" --upload-images --upload-videos

# Upload with environment tag
testdino upload ./test-results --token="$TESTDINO_TOKEN" --environment="staging"
```

### `cache`

Store test execution metadata after a run. Powers the `last-failed` command.

```bash theme={null}
testdino cache --working-dir test-results --token="$TESTDINO_TOKEN"
```

| Option                 | Description                       | Default           |
| :--------------------- | :-------------------------------- | :---------------- |
| `--working-dir <path>` | Directory containing test results | Current directory |
| `--cache-id <value>`   | Custom cache ID override          | Auto-detected     |

### `last-failed`

Retrieve cached test failures for reruns. Outputs test identifiers that pass directly to pytest.

```bash theme={null}
# Print failed tests
testdino last-failed --token="$TESTDINO_TOKEN"

# Rerun only failed tests
pytest $(testdino last-failed --token="$TESTDINO_TOKEN")

# Failed tests for a specific shard
testdino last-failed --shard="2/5" --token="$TESTDINO_TOKEN"
```

| Option                  | Description                       | Default       |
| :---------------------- | :-------------------------------- | :------------ |
| `--branch <value>`      | Branch name override              | Auto-detected |
| `--commit <value>`      | Commit hash override              | Auto-detected |
| `--shard <value>`       | Shard specification (e.g., `2/5`) | None          |
| `--environment <value>` | Environment name for filtering    | None          |
| `--cache-id <value>`    | Custom cache ID override          | Auto-detected |

### Global Options

These options apply to all commands.

| Option                | Description                   |
| :-------------------- | :---------------------------- |
| `-t, --token <value>` | TestDino API token (required) |
| `-v, --verbose`       | Enable verbose logging        |

## Configuration

Set environment variables to avoid passing flags with each command.

| Variable              | Description             |
| :-------------------- | :---------------------- |
| `TESTDINO_TOKEN`      | Authentication token    |
| `TESTDINO_TARGET_ENV` | Default environment tag |

```bash theme={null}
export TESTDINO_TOKEN="your-api-token"
export TESTDINO_TARGET_ENV="staging"
```

## CI/CD Integration

<Tabs>
  <Tab title="GitHub Actions">
    ```yaml .github/workflows/test.yml theme={null}
    name: Playwright Tests
    on: [push, pull_request]

    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
            with:
              fetch-depth: 0
          - uses: actions/setup-python@v5
            with:
              python-version: '3.11'

          - name: Install dependencies
            run: |
              pip install pytest pytest-playwright pytest-playwright-json pytest-html testdino
              playwright install chromium --with-deps

          - name: Run tests
            run: |
              pytest \
                --playwright-json=test-results/report.json \
                --html=test-results/index.html \
                --self-contained-html

          - name: Cache metadata
            if: always()
            run: testdino cache --working-dir test-results --token="${{ secrets.TESTDINO_TOKEN }}"

          - name: Upload reports
            if: always()
            env:
              TESTDINO_TOKEN: ${{ secrets.TESTDINO_TOKEN }}
            run: testdino upload ./test-results --token="${{ secrets.TESTDINO_TOKEN }}" --upload-full-json
    ```
  </Tab>

  <Tab title="GitHub Actions (Sharded)">
    ```yaml .github/workflows/test-sharded.yml theme={null}
    name: Playwright Tests (Sharded)
    on: [push, pull_request]

    jobs:
      test:
        runs-on: ubuntu-latest
        strategy:
          fail-fast: false
          matrix:
            shardIndex: [1, 2, 3, 4]
            shardTotal: [4]
        steps:
          - uses: actions/checkout@v4
            with:
              fetch-depth: 0
          - uses: actions/setup-python@v5
            with:
              python-version: '3.11'

          - name: Install dependencies
            run: |
              pip install pytest pytest-playwright pytest-playwright-json pytest-html testdino
              playwright install chromium --with-deps

          - name: Run tests
            shell: bash
            env:
              TESTDINO_TOKEN: ${{ secrets.TESTDINO_TOKEN }}
            run: |
              mkdir -p test-results

              if [[ "${{ github.run_attempt }}" -gt 1 ]]; then
                testdino last-failed \
                  --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} \
                  --token="$TESTDINO_TOKEN" > last-failed-flags.txt
                FAILED_TESTS="$(cat last-failed-flags.txt | tail -1)"

                if [[ -z "$FAILED_TESTS" ]]; then
                  echo "No failed tests found. Exiting."
                  exit 0
                fi

                eval "pytest $FAILED_TESTS \
                  --playwright-json=test-results/report.json \
                  --html=test-results/index.html \
                  --self-contained-html -v" || true
                exit 0
              fi

              pytest \
                --playwright-json=test-results/report.json \
                --html=test-results/index.html \
                --self-contained-html -v || true

          - name: Cache metadata
            if: always()
            run: testdino cache --working-dir test-results --token="${{ secrets.TESTDINO_TOKEN }}"

          - name: Upload reports
            if: always()
            run: testdino upload ./test-results --token="${{ secrets.TESTDINO_TOKEN }}" --upload-full-json
    ```
  </Tab>

  <Tab title="GitLab CI">
    ```yaml .gitlab-ci.yml theme={null}
    image: python:3.11

    stages:
      - test

    playwright-tests:
      stage: test
      script:
        - pip install pytest pytest-playwright pytest-playwright-json pytest-html testdino
        - playwright install chromium --with-deps
        - pytest --playwright-json=test-results/report.json --html=test-results/index.html --self-contained-html
        - testdino upload ./test-results --token="$TESTDINO_TOKEN" --upload-full-json
      when: always
    ```
  </Tab>

  <Tab title="Jenkins">
    ```groovy Jenkinsfile theme={null}
    pipeline {
        agent any

        environment {
            TESTDINO_TOKEN = credentials('testdino-token')
        }

        stages {
            stage('Test') {
                steps {
                    sh 'pip install pytest pytest-playwright pytest-playwright-json pytest-html testdino'
                    sh 'playwright install chromium --with-deps'
                    sh 'pytest --playwright-json=test-results/report.json --html=test-results/index.html --self-contained-html'
                    sh 'testdino upload ./test-results --token="$TESTDINO_TOKEN" --upload-full-json'
                }
            }
        }
    }
    ```
  </Tab>
</Tabs>

## Related

<CardGroup cols={2}>
  <Card title="View Test Runs" icon="play" href="/platform/playwright-test-runs">
    Explore test results in the platform
  </Card>

  <Card title="CI Optimization" icon="gauge-high" href="/guides/playwright-ci-optimization">
    Optimize your CI pipeline
  </Card>

  <Card title="Node.js CLI" icon="node-js" href="/cli/testdino-playwright-nodejs">
    Use TestDino with Playwright for Node.js
  </Card>

  <Card title="Generate API Keys" icon="key" href="/guides/generate-api-keys">
    Create and manage API tokens
  </Card>
</CardGroup>
