TypeScript Test
| This documentation was generated with the assistance of AI. Please report any inaccuracies. |
Run a TypeScript/npm project’s unit test suite through whichever test runner it actually has configured —
Vitest, Jest, or the Angular CLI’s Vitest-backed ng test builder — scoping the run to whatever the caller
asked for and reporting a compact pass/fail summary parsed from the runner’s own JSON reporter. This is a
read-only reporting skill: it never fixes a failing test or modifies source/test code unless asked to as an
explicit follow-up.
Purpose
iru-typescript-test turns a loosely-specified request ("run everything", "just this file", "tests matching
this name") into the correct invocation for whichever runner a TypeScript project actually has wired, and
returns a concise pass/fail report instead of a raw console dump. It detects the runner and package manager
from the project’s own manifests rather than assuming one, and distinguishes a genuinely clean run from a
selector that silently matched nothing — a distinction that looks identical in a broken CI job if conflated.
When .ui-quality.yml says accessibility: none (opted out entirely) or off (rules apply, checks not run), accessibility checks are not applicable: they are skipped and reported as "accessibility: opted out" (none) or "accessibility checks off" (off) — never "unverified" and never a failure.
Plugin
Shipped by the iru-typescript plugin of the ai-catalog marketplace (install with /plugin install iru-typescript@ai-catalog; see Plugins).
Invocation
/iru-typescript-test
/iru-typescript-test <selector>
/iru-typescript-test e2e [<selector>]
/iru-typescript-test ui [<selector>]
/iru-typescript-test e2e
lock: held
configuration: <detox-configuration>
Inputs
| Argument | Required | Description | Default |
|---|---|---|---|
|
No |
A file path, a directory, or a |
None — omitting it runs the whole unit suite. |
|
No |
Leading keyword (NestJS, Next.js, React Native and Playwright-wired web UIs only) that picks the suite. |
|
|
No |
|
Not set — React Native |
|
No |
React Native |
Derived from |
The runner and its invocation are resolved as follows:
| Runner | Detected via | Full-suite command |
|---|---|---|
Vitest |
|
|
Jest |
|
|
Angular CLI ( |
|
|
If none of the three is found, the skill stops and reports "no test runner wired" rather than reporting a
misleadingly clean "0 tests". If ng test’s target has `options.runner explicitly set to "karma", the
skill’s Vitest-shaped commands don’t apply and it reports that instead of guessing at Karma’s CLI. The
package manager (npm/pnpm/yarn) is read from packageManager in package.json or the lockfile present, and
the runner’s binary is invoked directly (npx/pnpm exec/yarn) rather than through the project’s own
test npm script, since that script often omits flags the skill needs to forward predictably.
Selector scoping per runner:
| What the user wants | Vitest | Jest | ng test (Vitest runner) |
|---|---|---|---|
One file |
|
|
|
A directory |
|
|
|
Name pattern |
|
|
|
File/dir + name pattern |
|
|
|
An unmatched file/directory selector is a hard failure (non-zero exit) for all three runners; an unmatched
-t/--filter name pattern against files that do match is not a failure — every runner reports the matched
tests as skipped and exits 0.
NestJS, Next.js and React Native
@nestjs/core in dependencies marks a NestJS project, next a Next.js project, and react-native or expo a React
Native project; all still run on Vitest or Jest, detected as above, and the framework only changes which suite counts
as "unit", how failures are explained, and how e2e resolves:
-
NestJS — unit tests are
.spec.tsnext to the source and e2e tests aretest/.e2e-spec.ts, kept apart by two configs so the default run never picks up e2e files: ESM/Vitest (vitest.config.tsplusvitest.config.e2e.ts) or CommonJS/Jest (jest.config.tsplustest/jest-e2e.json). The e2e config path is read from the project’s owntest:e2escript; with no such script or config,e2eis reported as "NestJS e2e suite not wired". Relative.jsimports in the ESM flavor are correct and never reported. -
Next.js — unit/component tests run on Vitest (
vitest.config.mts) or Jest vianext/jest; e2e is Playwright (@playwright/testplusplaywright.config.*), which builds and starts the app, so it only runs on an explicite2eselector and never by default. Cypress-only projects are reported as "Cypress e2e present, not run". -
React Native — always Jest (never Vitest), with the toolchain resolved first:
expoindependenciesisexpo(even with prebuildandroid//ios/), otherwisemetro(bare CLI app). The preset is read from the Jest config:jest-expo(or a platform variant;jest-expo/universalmultiplies test counts per platform project and the report says so) for expo,@react-native/jest-presetor the legacyreact-nativepreset for metro. A preset contradicting the toolchain still runs but is flagged. Unit tests live intests/or beside the source;.maestro/ande2e/flows are never matched by the default run. Failures are reported by cause: an untranspiled ESM/Flow package needingtransformIgnorePatterns, a native module without a Jest mock, or React Native Testing Library 14’s un-awaitedrender.
React Native e2e picks Detox (.detoxrc.* plus the detox devDependency) or else Maestro (.maestro/ flows), runs it
through its own JUnit/JSON reporter, and reports "React Native e2e suite not wired" when neither exists. Preconditions
are checked in order (tool installed, a booted simulator/emulator, the repository lock, Metro answering on port 8081,
started and later stopped by the skill when it wasn’t running) and any miss is reported as "unverified (reason)", never
as a pass. Unlike NestJS/Next.js, whose callers take .integration-test.lock, React Native e2e acquires and
releases that lock itself unless lock: held is passed.
Web UI (React/Vite, Angular CLI, Ionic) — @playwright/test plus a playwright.config.* makes the project a web-ui one:
unit/component tests stay on the unit runner (jsdom/happy-dom runs never produce screenshots) and the browser UI tests
are Playwright, resolved through the e2e selector’s Playwright column and every config the project’s own scripts name
(for example a separate Playwright component-testing config). Cypress is reported as "present, not run".
UI runs
Every Playwright, Maestro or Detox e2e/ui run is also a UI run, wrapping the command with the catalog’s UI contract
(see Building user interfaces):
-
The settings are resolved at the repository root:
UI_SCREENSHOTS_DIR(absolute, from the environment) or.ui-screenshots/, and theaccessibility(enforce/report/off/none),directionsandthemeskeys of.ui-quality.yml(missing file or key meansenforce, left-to-right and right-to-left, light and dark). -
A full UI run (no file, directory, name or tag) clears the screenshot directory’s contents first, only when the path is
.ui-screenshotsor came fromUI_SCREENSHOTS_DIR; a scoped run adds to it. A missing.gitignoreentry is reported, never edited. -
The directory is exported to the runner. Playwright’s helper writes straight into it and the axe results come from
accessibility-scan-resultsattachments in the JSON report; Maestro getsUI_SCREENSHOTS_DIRandUI_THEME, with the device appearance recorded, switched through each theme forui-flowflows and restored on every exit path; Detox’s helper copies its screenshots in. Stray PNGs are moved into the<kind>/<Id>/layout. -
Every file name is validated against the contract’s naming pattern (malformed names and captures outside the configured matrix are listed), React Native accessibility is checked through
eslint-plugin-react-native-a11ylint counts, and the level is applied:enforcemakes violations a failed run,reportonly lists them,offskips the check.
An e2e selector on any other project is reported as unsupported and the skill stops. A failure caused by a missing
database, Docker/Testcontainers daemon, Playwright browsers, or a failed next build is reported as an environment
failure ("e2e not run/aborted: cause"), never as failing tests; the skill checks docker info first when the project
uses Testcontainers.
Outputs
-
A plain-text pass/fail summary in the conversation — never a written file.
-
Total, passed, and failed test counts parsed from each runner’s JSON reporter output (
--reporter=jsonfor Vitest,--jsonfor Jest,--reporters=jsonforng test), written to a scratch file and deleted after parsing. -
On failures: each failing test’s
fullNameand the first line of its assertion message — no stack traces, no passing-test noise. -
A selector that matched no files is reported plainly as "matched no test files", distinct from a genuinely clean 0-failure run; a name pattern that matched no individual tests is reported plainly as "0 of N tests matched the filter", distinct from "all passed".
-
For every UI run: the screenshot directory used (cleared or added to), screenshot counts per kind (
component/screen/flow) and distinct ids, strays collected, malformed names, captures outside the configured matrix, the.ui-quality.ymllevel applied, accessibility violations as a count plus rule ids, and for Maestro the themes switched through and confirmation that the original appearance was restored; a run that could not start is "UI run unverified" with the reason. -
For NestJS, Next.js and React Native, the report states which suite ran (unit or e2e), so a green unit run is never read as e2e coverage. Playwright runs are parsed from its own JSON reporter shape (
statsand nestedsuites[].specs[]). -
No source or test code is ever modified.
Execution flow
Dependencies
Invokes
None — iru-typescript-test is a leaf skill; it only runs Vitest/Jest/ng test commands and reports on their
output, it does not call any other skill in this catalog.
Invoked by
-
TypeScript Code One Task Group — Step 3.3, to run the scoped tests for the task group’s changes, via the
iru-gate-runneragent. -
TypeScript Generate All Tests — Step 6b (the
uiselector over generated UI specs) and Step 7, to run the full suite after generating tests, via theiru-gate-runneragent. -
NestJS Code One Task Group — Step 3.4, 3.6 and 3.9, unit tests, full unit suite and e2e run, via the
iru-gate-runneragent. -
Next.js Code One Task Group — Step 3.3, 3.5 and 3.8, unit suites and Playwright via the e2e selector, via the
iru-gate-runneragent. -
React Native Code One Task Group — Steps 3.3 and 3.5, scoped and full Jest unit runs, and Step 3.10, the Maestro/Detox
e2eselector withlock: held(the caller already owns the lock), via theiru-gate-runneragent.
Related agents
-
iru-gate-runner— both calling skills above invoke this skill from inside airu-gate-runnersub-agent they spawn, not inline.
Source
SKILL.md on GitHub — the file this page was generated from.