# TestDino CLI (tdpw)

[![npm version](https://badge.fury.io/js/tdpw.svg)](https://www.npmjs.com/package/tdpw)
[![Node.js](https://img.shields.io/node/v/tdpw.svg)](https://nodejs.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**TestDino CLI** - Upload Playwright test reports and manage test metadata for the TestDino
platform.

## Quick Start

```bash
# Upload test reports
npx tdpw upload ./playwright-report --token="your-api-token"

# Upload with run tags for categorization
npx tdpw upload ./playwright-report --token="your-api-token" --tag="regression,smoke"

# Cache test metadata for intelligent reruns
npx tdpw cache --token="your-api-token"

# Get previously failed tests
npx tdpw last-failed --token="your-api-token"
```

## Installation

### Using npx (Recommended)

```bash
npx tdpw <command> --token="your-token"
```

### Global Installation

```bash
npm install -g tdpw
tdpw <command> --token="your-token"
```

### Project Dependency

```bash
npm install --save-dev tdpw
```

## Commands

### Upload

Upload Playwright test reports to TestDino.

```bash
# Basic upload
npx tdpw upload ./playwright-report --token="your-token"

# Upload with all attachments (images, videos, traces)
npx tdpw upload ./playwright-report --token="your-token" --upload-full-json

# Upload with environment tag
npx tdpw upload ./playwright-report --token="your-token" --environment="staging"

# Upload with run tags for categorization and filtering
npx tdpw upload ./playwright-report --token="your-token" --tag="regression,smoke,v1.2.3"
```

**Options:**

| Option                  | Description                                         | Default   |
| ----------------------- | --------------------------------------------------- | --------- |
| `<report-directory>`    | Directory containing Playwright reports             | Required  |
| `-t, --token <value>`   | TestDino API token                                  | Required  |
| `--environment <value>` | Target environment tag (staging, production, qa)    | `unknown` |
| `--tag <values>`        | Comma-separated run tags for categorization (max 5) | None      |
| `--upload-images`       | Upload image attachments                            | `false`   |
| `--upload-videos`       | Upload video attachments                            | `false`   |
| `--upload-html`         | Upload HTML reports                                 | `false`   |
| `--upload-traces`       | Upload trace files                                  | `false`   |
| `--upload-files`        | Upload file attachments (.md, .pdf, .txt, .log)     | `false`   |
| `--upload-full-json`    | Upload all attachments                              | `false`   |
| `--json`                | Output results as JSON to stdout (for CI/CD)        | `false`   |
| `-v, --verbose`         | Enable verbose logging                              | `false`   |

#### JSON Output (CI/CD Integration)

Use `--json` to get machine-readable output for CI/CD pipelines. When active, all human-readable
output goes to stderr and only a JSON object is written to stdout.

```bash
# Capture test run ID and URL
RESULT=$(npx tdpw upload ./playwright-report --token="$TESTDINO_TOKEN" --json)
TEST_RUN_ID=$(echo "$RESULT" | jq -r '.data.testRunId')
URL=$(echo "$RESULT" | jq -r '.data.url')

# Post results to a GitHub PR comment
gh pr comment --body "TestDino results: $URL"
```

**Success output:**

```json
{
  "success": true,
  "data": { "testRunId": "test_run_abc123", "url": "https://app.testdino.com/..." }
}
```

**Error output:**

```json
{
  "success": false,
  "error": { "code": "AUTH_ERROR", "message": "Invalid API key or unauthorized access" }
}
```

**Empty-run output** (report contains zero tests — no upload is performed, exit code `0`):

```json
{
  "success": true,
  "data": { "skipped": true, "reason": "empty-run" }
}
```

#### Empty Runs

When the Playwright report contains zero tests (e.g. no tests matched a grep filter), `upload`
prints a warning and exits with code `0` without contacting the server. This keeps CI pipelines
green for no-op runs instead of creating empty test runs in TestDino.

### Cache

Store test execution metadata after Playwright runs for intelligent reruns.

```bash
# Basic usage
npx tdpw cache --token="your-token"

# With custom working directory
npx tdpw cache --working-dir ./test-results --token="your-token"
```

**Options:**

| Option                 | Description                        | Default           |
| ---------------------- | ---------------------------------- | ----------------- |
| `--working-dir <path>` | Directory to scan for test results | Current directory |
| `--cache-id <value>`   | Custom cache ID override           | Auto-detected     |
| `-t, --token <value>`  | TestDino API token                 | Required          |
| `-v, --verbose`        | Enable verbose logging             | `false`           |

### Last Failed

Retrieve previously failed tests for selective reruns.

```bash
# Get failed test files
npx tdpw last-failed --token="your-token"

# Run only failed tests with Playwright
npx playwright test $(npx tdpw last-failed --token="your-token")
```

**Options:**

| Option                | Description                 | Default       |
| --------------------- | --------------------------- | ------------- |
| `--cache-id <value>`  | Custom cache ID override    | Auto-detected |
| `--branch <value>`    | Custom branch name override | Auto-detected |
| `--commit <value>`    | Custom commit hash override | Auto-detected |
| `-t, --token <value>` | TestDino API token          | Required      |
| `-v, --verbose`       | Enable verbose logging      | `false`       |

## Environment Variables

```bash
export TESTDINO_TOKEN="your-api-token"
export TESTDINO_TARGET_ENV="staging"                # Optional: Test run target environment
export TESTDINO_RUN_TAGS="regression,smoke"         # Optional: Comma-separated run tags
```

## Run Tags

Run tags allow you to categorize and filter test runs in TestDino. Unlike test case tags (defined
with `@tag` annotations in your test files), run tags are applied to the entire test run via the
CLI.

### Use Cases

- **Test Types**: `--tag="smoke,regression,e2e"`
- **Release Versions**: `--tag="v1.2.3,release-candidate"`
- **CI Triggers**: `--tag="nightly,scheduled,manual"`
- **Feature Branches**: `--tag="feature-auth,sprint-42"`

### Tag Format

Tags must contain only letters, numbers, hyphens, underscores, and dots:

- Valid: `regression`, `v1.2.3`, `feature-test`, `nightly_run`
- Invalid: `my tag`, `test@123`, `tag#1`

### Tag Limits

- Maximum of **5 tags** per test run
- If more than 5 tags are provided, only the first 5 will be used (with a warning)

### Analytics

Run tags appear in the TestDino Analytics dashboard under the **Tags** tab, where you can:

- View test execution trends filtered by run tags
- Compare pass/fail/flaky rates across different tags
- See the relationship between run tags and test case tags

## CI/CD Integration

### GitHub Actions

```yaml
name: Playwright Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright
        run: npx playwright install --with-deps

      - name: Run tests
        run: npx playwright test

      - name: Upload and capture results (JSON mode)
        if: always()
        run: |
          RESULT=$(npx tdpw upload ./playwright-report --token="${{ secrets.TESTDINO_TOKEN }}" --json)
          URL=$(echo "$RESULT" | jq -r '.data.url')
          echo "TESTDINO_URL=$URL" >> $GITHUB_ENV

      - name: Comment on PR
        if: always() && github.event_name == 'pull_request'
        run: gh pr comment ${{ github.event.number }} --body "TestDino results: ${{ env.TESTDINO_URL }}"
```

### GitLab CI

```yaml
playwright-tests:
  image: node:18
  script:
    - npm ci
    - npx playwright install --with-deps
    - npx playwright test
    - npx tdpw upload ./playwright-report --token="$TESTDINO_TOKEN"
  when: always
```

### Jenkins

```groovy
pipeline {
    agent any
    environment {
        TESTDINO_TOKEN = credentials('testdino-token')
    }
    stages {
        stage('Test') {
            steps {
                sh 'npm ci'
                sh 'npx playwright install --with-deps'
                sh 'npx playwright test'
                sh 'npx tdpw upload ./playwright-report --token="$TESTDINO_TOKEN"'
            }
        }
    }
}
```

### Bitbucket Pipelines

```yaml
image: node:18

pipelines:
  default:
    - step:
        name: Playwright tests
        script:
          - npm ci
          - npx playwright install --with-deps
          - npx playwright test || true
          - npx tdpw upload ./playwright-report --token="$TESTDINO_TOKEN"
```

## Authentication

### Getting Your Token

1. Sign up at [TestDino](https://app.testdino.com)
2. Navigate to **Project** > **Settings** > **API Tokens**
3. Generate a new token
4. Store it securely in your CI/CD secrets

### Security Best Practices

- Never commit tokens to version control
- Use environment variables or CI/CD secrets
- Rotate tokens regularly

## Example Workflows

### Basic Upload

```bash
# Run tests and upload results
npx playwright test
npx tdpw upload ./playwright-report --token="$TESTDINO_TOKEN" --upload-full-json

# Upload with run tags for better organization
npx tdpw upload ./playwright-report --token="$TESTDINO_TOKEN" --tag="nightly,regression" --upload-full-json
```

### Intelligent Test Reruns

```bash
# First run: execute all tests and cache metadata
npx playwright test
npx tdpw cache --token="$TESTDINO_TOKEN"

# Subsequent runs: execute only previously failed tests
npx playwright test $(npx tdpw last-failed --token="$TESTDINO_TOKEN")
```

### Complete CI Workflow

```bash
#!/bin/bash
# Run all tests
npx playwright test
TEST_EXIT_CODE=$?

# Cache test metadata
npx tdpw cache --token="$TESTDINO_TOKEN"

# Upload reports
npx tdpw upload ./playwright-report --token="$TESTDINO_TOKEN" --upload-full-json

# Rerun failed tests if any
if [ $TEST_EXIT_CODE -ne 0 ]; then
  FAILED=$(npx tdpw last-failed --token="$TESTDINO_TOKEN")
  if [ -n "$FAILED" ]; then
    npx playwright test $FAILED
  fi
fi
```

## Support

- **Documentation**: [docs.testdino.com](https://docs.testdino.com)
- **Issues**: [GitHub Issues](https://github.com/testdino-inc/testdino-cli/issues)
- **Email**: support@testdino.com

---

**Made with ❤️ by the [TestDino](https://testdino.com) team**
