An open API service indexing awesome lists of open source software.

https://github.com/get-skipper/skipper

Enable and disable tests directly from a Google Spreadsheet — no code changes required.
https://github.com/get-skipper/skipper

Last synced: 3 months ago
JSON representation

Enable and disable tests directly from a Google Spreadsheet — no code changes required.

Awesome Lists containing this project

README

          

# Skipper

Enable and disable tests directly from a Google Spreadsheet — no code changes required.

Skipper integrates with your existing test suite via a minimal config. Each test is identified by its file path + title. Set a `disabledUntil` date in the spreadsheet to skip a test until that date; leave it empty (or set a past date) to run it normally.

## Packages

| Package | Framework |
|---|---|
| [`@get-skipper/playwright`](packages/playwright/README.md) | Playwright |
| [`@get-skipper/jest`](packages/jest/README.md) | Jest |
| [`@get-skipper/vitest`](packages/vitest/README.md) | Vitest |
| [`@get-skipper/cypress`](packages/cypress/README.md) | Cypress |
| [`@get-skipper/nightwatch`](packages/nightwatch/README.md) | Nightwatch.js |

## How It Works

- **`read-only` mode** (default): Skipper reads the spreadsheet at the start of the test run and skips any test whose `disabledUntil` date is in the future.
- **`sync` mode** (`SKIPPER_MODE=sync`): Same as read-only, plus after the run Skipper reconciles the spreadsheet — adding rows for new tests and, when `SKIPPER_SYNC_ALLOW_DELETE=true`, removing rows for tests no longer in the suite.

## Spreadsheet Schema

Create a Google Spreadsheet with the following columns in the first row (header):

| `testId` | `disabledUntil` | `notes` |
|---|---|---|
| `tests/auth/login.spec.ts > login > should log in` | | |
| `tests/checkout/payment.spec.ts > payment > stripe` | `2026-04-01` | Flaky until fix |
| `tests/payments/refund.spec.ts > refund` | `2099-12-31` | Disabled indefinitely |

- **`testId`** — `{relative file path} > {describe blocks} > {test name}`, automatically generated by the plugin.
- **`disabledUntil`** — ISO 8601 date (e.g. `2026-04-01`). Empty or past date = test runs. Future date = test is skipped.
- **`notes`** — optional free-text field, ignored by the plugin.

## Configuration Reference

All Skipper plugins accept the same `SkipperConfig` object:

| Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `spreadsheetId` | `string` | ✅ | — | The Google Spreadsheet ID (from the URL) |
| `credentials` | object | ✅ | — | Service account credentials — see below |
| `sheetName` | `string` | | first tab | Name of the sheet tab to read/write |
| `referenceSheets` | `string[]` | | `[]` | Additional sheet tabs to read (read-only); merged with the primary sheet |
| `testIdColumn` | `string` | | `"testId"` | Column header for the test identifier |
| `disabledUntilColumn` | `string` | | `"disabledUntil"` | Column header for the disable date |

### Credentials

```ts
// Base64-encoded JSON (recommended for CI)
credentials: { credentialsBase64: process.env.GOOGLE_CREDS_B64! }

// Path to a local JSON file (recommended for local dev)
credentials: { credentialsFile: './service-account.json' }

// Raw service account object
credentials: { client_email: '...', private_key: '...' }
```

### `sheetName`

By default Skipper uses the first tab of the spreadsheet. Use `sheetName` to target a specific tab:

```ts
{
spreadsheetId: '...',
credentials: { credentialsBase64: '...' },
sheetName: 'E2E Tests', // reads and writes to this tab only
}
```

### `referenceSheets`

Additional sheet tabs to read (never written to). Useful for sharing a common list of disabled tests across multiple suites. When the same `testId` appears in more than one sheet, the most restrictive (latest future) `disabledUntil` wins:

```ts
{
spreadsheetId: '...',
credentials: { credentialsBase64: '...' },
sheetName: 'E2E Tests', // primary sheet (read + write in sync mode)
referenceSheets: ['Shared'], // additional sheets (read-only)
}
```

## Google Sheets Setup

### 1. Create a Google Cloud Project and enable the API

1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create a new project (or select an existing one)
3. Navigate to **APIs & Services → Library**
4. Search for **Google Sheets API** and enable it

### 2. Create a Service Account

1. Navigate to **APIs & Services → Credentials**
2. Click **Create Credentials → Service Account**
3. Give it a name (e.g. `skipper-bot`) and click **Done**
4. Click on the service account → **Keys** tab → **Add Key → Create new key → JSON**
5. Download the JSON file — keep it secret

### 3. Share the Spreadsheet

Open your Google Spreadsheet and share it with the service account email (found in the JSON file as `client_email`):

- **Viewer** role for `read-only` mode
- **Editor** role for `sync` mode

### 4. Prepare Credentials for CI

Convert the JSON file to a base64 string for use as a CI secret:

```bash
base64 -i service-account.json | tr -d '\n'
```

Save the output as a secret named `GOOGLE_CREDS_B64` in your CI environment (e.g. GitHub Actions secrets).

For local development, keep the JSON file and reference it via `credentialsFile`:

```ts
credentials: { credentialsFile: './service-account.json' }
```

### 5. Populate the Spreadsheet for the First Time

Run your test suite in sync mode once to auto-populate all test rows:

```bash
SKIPPER_MODE=sync SKIPPER_SPREADSHEET_ID= pnpm test
```

All tests will be added to the spreadsheet with an empty `disabledUntil` (enabled by default). You can then set dates in the spreadsheet to disable specific tests.

## Environment Variables

| Variable | Default | Description |
|---|---|---|
| `SKIPPER_MODE` | `read-only` | Set to `sync` to enable spreadsheet reconciliation after the test run |
| `SKIPPER_FAIL_OPEN` | `true` | When `true`, runs all tests if the API is unreachable and no valid cache exists. Set to `false` to crash instead |
| `SKIPPER_CACHE_TTL` | `300` | Seconds a local `.skipper-cache.json` is considered valid. Skipper writes this file after each successful fetch and reads it as a fallback on API failure |
| `SKIPPER_SYNC_ALLOW_DELETE` | `false` | When `false`, orphaned rows (tests removed from the suite) are only warned about. Set to `true` to delete them |
| `SKIPPER_DEBUG` | — | Set to any truthy value to enable verbose logging |

## Modes

### read-only (default)

No env var needed. Tests with a future `disabledUntil` are skipped.

```bash
SKIPPER_SPREADSHEET_ID= pnpm test
```

### sync (CI on merge to main)

```bash
SKIPPER_MODE=sync SKIPPER_SPREADSHEET_ID= pnpm test
```

After the run:
- New tests → added to the spreadsheet with empty `disabledUntil`
- Removed tests → warned (set `SKIPPER_SYNC_ALLOW_DELETE=true` to also delete them)

## CI Example (GitHub Actions)

```yaml
# .github/workflows/test.yml
name: Test

on:
pull_request:
push:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm

- run: pnpm install

- name: Test (read-only on PR)
if: github.event_name == 'pull_request'
env:
SKIPPER_SPREADSHEET_ID: ${{ secrets.SKIPPER_SPREADSHEET_ID }}
GOOGLE_CREDS_B64: ${{ secrets.GOOGLE_CREDS_B64 }}
run: pnpm test

- name: Test + sync (on merge to main)
if: github.ref == 'refs/heads/main'
env:
SKIPPER_MODE: sync
SKIPPER_SPREADSHEET_ID: ${{ secrets.SKIPPER_SPREADSHEET_ID }}
GOOGLE_CREDS_B64: ${{ secrets.GOOGLE_CREDS_B64 }}
run: pnpm test
```

## License

MIT — see [LICENSE](LICENSE).