Skip to content
Back to skills

Testing

ASecurity

Where a test goes (tests/ vs integration-tests/<game>), which npm script runs it and how the nine GitHub Actions jobs map to them. Use when adding, moving or running tests, or editing .github/workflows/ci.yml.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
toolsgoswifttestinggit

Works with

  • cli

Security analysis

A100/100

Scanned November 7, 2026

npx -y skills add DeniSpasovski/mini-games --skill testing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Testing?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Testing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/denispasovski-testing/badge)](https://www.skillsdirectory.com/skills/denispasovski-testing)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: testing
description: Where a test goes (tests/ vs integration-tests/<game>), which npm script runs it and how the nine GitHub Actions jobs map to them. Use when adding, moving or running tests, or editing .github/workflows/ci.yml.
---

# Testing layout

Regular tests are fast (the whole `tests/` folder runs in about a minute); integration tests are slow playtests.

| Kind                                                       | Folder                      | Script                            |
| ---------------------------------------------------------- | --------------------------- | --------------------------------- |
| Unit / data / content checks for rally                     | `tests/rally/`              | `npm run test:rally`              |
| Unit / data / content checks for hole                      | `tests/hole/`               | `npm run test:hole`               |
| Unit / data / content checks for kaboom                    | `tests/kaboom/`             | `npm run test:kaboom`             |
| Portal / shared (analytics, consent, dom, site config ...) | `tests/*.test.ts`           | `npm run test:shared`             |
| Rally playtests                                            | `integration-tests/rally/`  | `npm run test:integration:rally`  |
| Hole playtests                                             | `integration-tests/hole/`   | `npm run test:integration:hole`   |
| Kaboom bot playtests                                       | `integration-tests/kaboom/` | `npm run test:integration:kaboom` |
| Browser smoke (each game's pages, console + WebGL)         | `scripts/smoke.mjs`         | `npm run test:smoke`              |

`npm run test` = every regular test (no integration); `npm run test:integration` = every playtest.

## Which folder?

Decide by what the test does, not only how long it takes. It is an **integration test** when it plays the game
end to end: a full stage with the autopilot, a car x tyre x set-up matrix, a bot playing a whole map, movers simulated
over time. It is a **regular test** when it checks one unit, a data table, a generator's output or a map's content.
Rough guide: over ~10 s for one file after the suite is warm, or minutes of simulated play, goes to `integration-tests/<game>/`.
Split a mixed file: keep the quick checks in `tests/`, move the playtest into its own file. Shared helpers (`handling-harness.ts`)
stay next to the tests that use them. A new game gets its own `tests/<id>/`, `integration-tests/<id>/` and CI jobs.

## CI (`.github/workflows/ci.yml`)

Runs on pull requests and on pushes to `main`, nine jobs (`changes` picks the integration tests, the other eight run in parallel): rally tests, rally integration tests, hole tests, kaboom tests, kaboom integration tests,
hole integration tests, a shared job (type check + lint + `test:shared`) and the browser smoke test (dev server + headless
Chrome on the SwiftShader GPU). A new script or folder needs a CI step in the same change, otherwise it silently never runs.

**Browser smoke** (`npm run test:smoke`, against `npm run dev:noreload`: HMR reloads from other sessions cause false failures;
`--base <url>`, `--stage`, `--car`, `--games rally,hole`, `--dist dist` for a build): drives a rally stage on autopilot, then loads
the rally, Hole Island and Kaboom play / tool pages in a fresh profile, and fails on any console error, exception, WebGL error
or failed same-origin request. `--profile <dir>` (or `SMOKE_PROFILE`) reuses a profile folder. Run it before calling rendering,
shader, loading or viewer work done. CI runs only the affected games' pages and skips it when none is affected (`smoke`
output of `scripts/ci-affected.mjs`).

Integration jobs are selective: `scripts/ci-affected.mjs` (job `changes`) runs only the test files whose import closure contains a
changed file (relative imports and `new URL()` workers, incl. imported assets such as `*.webp` and `*.data.ts`); a game with
none is skipped. Package / test / ts config, workflows or that script run all; pushes to `main` run all; docs run none.
Rally drive tests (those reaching `World`: `stage-<map>`, `car-matrix`, `tyres`, `gearing`, `replay`) ignore scenery: they run only
for physics / autopilot, a car folder, shared road / terrain code, the harness or the road files of a map they import (lists with
reasons in the script header). On a PR they drive one car per drive type (`REPRESENTATIVE_CARS`: Fabia, Zastava, M3 GT2) plus the
changed cars (`rally_cars` -> `RALLY_CARS`); physics / autopilot = every car. The `car-matrix` worst-tyre hills run only for the
changed cars (every map) and map roads (representative cars): `rally_hill_cars` / `rally_hill_maps` -> `RALLY_HILL_*`. Pushes to
`main` and local runs drive every car everywhere. A playtest file per map lets the maps run side by side (rstest runs files in parallel). Run the matching script before pushing; after touching physics or a map also
run `npm run test:integration:rally`.

## Gotchas

- rstest path filters are substrings: `rstest tests/rally` would also match `integration-tests/rally`, so the regular scripts
  pass `--exclude 'integration-tests/**'`. Session worktrees (`.claude/**`) are excluded in `rstest.config.ts`, but a CLI
  `--exclude` replaces that list: a script or command that passes one adds `--exclude '.claude/**'` too.
- Relative imports are `../../src/...` in both folders (same depth).
- Update the doc / skill links when you move a test (`grep -rn "<test-file>" --include=*.md .`).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.