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.
- Host: GitHub
- URL: https://github.com/get-skipper/skipper
- Owner: get-skipper
- License: mit
- Created: 2026-03-15T08:33:30.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-04-09T06:23:10.000Z (3 months ago)
- Last Synced: 2026-04-09T06:23:41.397Z (3 months ago)
- Language: TypeScript
- Homepage: https://get-skipper.github.io
- Size: 189 KB
- Stars: 2
- Watchers: 0
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
- awesome-cypress - skipper - Real-time test execution control via Google Spreadsheet, enabling instant toggle without code changes. (Uncategorized / Uncategorized)
- awesome-testing - skipper - Real-time test execution control via Google Spreadsheet, enabling instant toggle without code changes. (Software / Test Management)
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).