Playwright Testing
chongdashu/vibejam-starter-pack
Plan, implement, and debug frontend tests: unit/integration/E2E/visual/a11y.
Test Radix NG primitives across every layer and pick the RIGHT one for a change: Vitest unit (zoneless), jest-axe a11y, Playwright browser regression (apps/visual-regression), SSR…
$ npx skills add radix-ng/primitives --skill testing -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install radix-ng/primitives testing --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/radix-ng/primitives.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/testing .claude/skills/testing && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "testing" agent skill from https://github.com/radix-ng/primitives/tree/main/.claude/skills/testing into .claude/skills/testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "testing", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/radix-ng/primitives/tree/main/.claude/skills/testingType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add radix-ng/primitives --skill testing -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install radix-ng/primitives testing --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/radix-ng/primitives.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/testing .agents/skills/testing && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "testing" agent skill from https://github.com/radix-ng/primitives/tree/main/.claude/skills/testing into .agents/skills/testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "testing", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add radix-ng/primitives --skill testing -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install radix-ng/primitives testing --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/radix-ng/primitives.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/testing .cursor/skills/testing && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "testing" agent skill from https://github.com/radix-ng/primitives/tree/main/.claude/skills/testing into .cursor/skills/testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "testing", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/radix-ng/primitives.git --path .claude/skills/testing--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add radix-ng/primitives --skill testing -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install radix-ng/primitives testing --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/radix-ng/primitives.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/testing .gemini/skills/testing && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "testing" agent skill from https://github.com/radix-ng/primitives/tree/main/.claude/skills/testing into .gemini/skills/testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "testing", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install radix-ng/primitives testingInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add radix-ng/primitives --skill testing -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/radix-ng/primitives.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/testing .github/skills/testing && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "testing" agent skill from https://github.com/radix-ng/primitives/tree/main/.claude/skills/testing into .github/skills/testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "testing", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add radix-ng/primitives --skill testing -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install radix-ng/primitives testing --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/radix-ng/primitives.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/testing .opencode/skills/testing && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "testing" agent skill from https://github.com/radix-ng/primitives/tree/main/.claude/skills/testing into .opencode/skills/testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "testing", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
testingTest Radix NG primitives across every layer and pick the RIGHT one for a change: Vitest unit (zoneless), jest-axe a11y, Playwright browser regression (apps/visual-regression), SSR…
Testing is an agent skill from radix-ng/primitives. Test Radix NG primitives across every layer and pick the RIGHT one for a change: Vitest unit (zoneless), jest-axe a11y, Playwright browser regression (apps/visual-regression), SSR (apps/radix-ssr-testing), and perf benches (apps/radix-perf-testing). Enforces the rule that layout / positioning / part-visibility / opens-without-error fixes need a browser test — jsdom can't see them. Use when: writing/fixing/adding a test, "напиши тест", "добавь тест", "почему баг не поймали", "покрой тестом", "write a test", "add a…
Its SKILL.md is about 3.3k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Testing & QA, covering Unit testing, Accessibility and Design systems. It works with Vitest, Playwright and Jest. The repository describes itself as: Headless, signals-first UI primitives for Angular. Accessible. Customizable. The licence is MIT.
4 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit eed2a31. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
pnpmnxFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use pnpm, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Testing loads about 3.3k tokens when it runs. Until then it costs about 167 tokens; SKILL.md has 943 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from radix-ng/primitives at commit eed2a31, republished under its MIT licence (© radix-ng). 943 words, ~3,282 tokens.
.claude/skills/testing/SKILL.md (or your agent's skills folder).First pick the layer, then write the test. Most bugs in this library are caught by Vitest unit
tests — but the suite runs in jsdom, which has no real layout (no box sizes, offsetHeight /
scroll metrics, flexbox resolution, getComputedStyle geometry, or floating-ui positioning), and
never opens an overlay the way a user does. Those gaps have their own layers. Match the change to the
layer below before writing anything.
| The change you made / bug you fixed | Add / run the test here |
|---|---|
| Directive logic, state, signals, inputs/outputs, keyboard handlers, value/selection model | Unit — packages/primitives/<name>/__tests__/*.spec.ts |
ARIA roles / aria-* / label associations | Unit + jest-axe in the same spec |
Layout / flex / overflow / scroll, part visibility ([hidden]), sizing, z-index | Browser — apps/visual-regression/tests/<name>.behavior.spec.ts (jsdom is blind) |
Overlay positioning (side/align/collision), *rdxXxxPortal teleport target, anatomy nesting | Browser — behavior.spec.ts (+ overlays.visual.spec.ts for the open-state look) |
A bug that throws only on open/interaction — NG0201 (missing provider), NG0951 (required query) | Browser — behavior.spec.ts with pageerror/console listeners |
| Pixel-level visual / styling regression | Browser — *.visual.spec.ts screenshot baseline |
SSR render, hydration (ngh), SSR-stable ids, platform guards | SSR — apps/radix-ssr-testing/src/ssr-rendering.spec.ts (+ keep the page current) |
| Render/update performance of a primitive | Perf — apps/radix-perf-testing/src/tests/<name>.bench.ts |
The rule that bit us: a select restructure made
rdxSelectList(inlineflex:1) a direct flex child of the popup; its inline flex overrode the demo's fixed viewport height, so the viewport grew to fit all items, never overflowed, and both scroll buttons stayed[hidden]. Every unit test stayed green — jsdom has no flexbox. A layout / positioning / visibility / opens-without-error fix is not proven until a browserbehavior.spec.tscovers it.
packages/primitives/<name>/__tests__/<name>-<role>.spec.tspnpm primitives:test · single file: nx run primitives:test --testFile packages/primitives/<name>/__tests__/<file>.spec.ts@testing-library/angular. Setup packages/primitives/test-setup.ts sets provideZonelessChangeDetection, loads @testing-library/jest-dom/vitest + the jest-axe matcher, and does not load zone.js — the suite is zone-free.vi.fn, vi.spyOn, vi.mock, vi.importActual), never Jest globals. xdescribe/xit map to .skip.Zoneless gotchas (these are the common failures):
fakeAsync / tick / waitForAsync are unavailable. Instead:setTimeout-based delays → vi.useFakeTimers() + vi.advanceTimersByTime(n)await fixture.whenStable()await new Promise((r) => setTimeout(r))fixture.detectChanges() throws NG0100 — call fixture.changeDetectorRef.markForCheck() first. Signal writes (input.set, model.set, componentRef.setInput) don't need it.a11y in the same spec (matcher is pre-registered):
import { axe } from 'jest-axe';
// …after rendering / opening:
expect(await axe(container)).toHaveNoViolations();References to copy: drawer/__tests__/drawer.spec.ts, form/__tests__/form-a11y.spec.ts.
Standard-backed test names. When a spec verifies an accessibility behavior, prefix the it(...)
title with the standard it backs: [APG <Pattern>] and/or [WCAG <x.y.z>], APG before WCAG, no
lowercasing — e.g. it('[APG Dialog][WCAG 4.1.2] links the trigger and popup with accessible ids and roles', …). Tag only specs that map cleanly to a criterion (roles/labels, keyboard, focus
trap/restore, axe), not plumbing. This mirrors each primitive's Accessibility-table rows so the suite
reads as a traceability matrix (full convention: storybook-story skill). Reference:
dialog/__tests__/dialog.spec.ts.
apps/visual-regression (Playwright over the built Storybook)This is the layer for everything jsdom can't see. Two spec kinds live in apps/visual-regression/tests/:
<name>.behavior.spec.ts — DOM/behavior, not pixelsOpen the story via its real interaction, then assert. Prefer auto-retrying web-first assertions
(expect(locator).toBeVisible()) over fixed waitForTimeout so async open/positioning settles
deterministically.
import { expect, Page, test } from '@playwright/test';
async function gotoStory(page: Page, storyId: string) {
await page.goto(`/iframe.html?id=${storyId}&viewMode=story`);
await page.waitForSelector('#storybook-root', { state: 'attached' });
}
test('scroll viewport overflows and buttons toggle', async ({ page }) => {
await gotoStory(page, 'primitives-select--with-scroll');
await page.locator('[rdxSelectTrigger]').first().click();
const up = page.locator('[rdxSelectScrollUpButton]');
const down = page.locator('[rdxSelectScrollDownButton]');
const list = page.locator('[rdxSelectList]');
await expect(down).toBeVisible(); // parts use the [hidden] attribute
await expect(up).toBeHidden();
const m = await list.evaluate((el) => ({ sh: el.scrollHeight, ch: el.clientHeight }));
expect(m.ch).toBeLessThan(m.sh); // a REAL overflow, not full-content expansion
await list.evaluate((el) => el.scrollBy(0, 200));
await expect(up).toBeVisible();
});Catch open-time runtime errors (NG0201 / NG0951) — attach listeners before navigating:
const errors: string[] = [];
page.on('pageerror', (e) => errors.push(e.message));
page.on('console', (m) => m.type() === 'error' && errors.push(m.text()));
await gotoStory(page, 'primitives-select--aligned-position');
await page.locator('[rdxSelectTrigger]').first().click();
await expect(page.locator('[rdxSelectPopup]')).toBeVisible();
expect(errors).toEqual([]);Story id derivation: lowercase the CSF title, replace / with -, append --, then the
kebab-cased export name. Example: title Primitives/Select + export WithScroll →
primitives-select--with-scroll.
<name>.visual.spec.ts — screenshot diffingtoHaveScreenshot with animations: 'disabled' (asserts the settled state, not mid-motion).
Baselines committed under tests/*-snapshots/, suffixed per project+platform (…-chromium-darwin.png).
stories.visual.spec.ts auto-shoots every story; overlays.visual.spec.ts covers open-state
positioning. Opt a story out of the auto sweep with the !visual CSF tag.
pnpm test-visual # CI path: build Storybook → serve :4400 → run every spec
pnpm test-visual:update # regenerate screenshot baselines after an INTENTIONAL visual change
pnpm test-visual:report # open the HTML actual/expected/diff report
# Local fast loop — reuse a running dev server, no full build:
pnpm storybook:primitives # keep on :4400
pnpm exec playwright test -c apps/visual-regression/playwright.config.ts <name>.behaviorplaywright.config.ts sets reuseExistingServer: !CI, so a running :4400 dev Storybook is reused;
iframe URLs resolve the same as the built site. test-results/ + playwright-report/ are gitignored;
specs and *-snapshots/ baselines are committed. For a quick one-off investigation you can also write
a throwaway Playwright script against :4400 (import { chromium } from 'playwright', run from repo
root) — but land the finding as a committed behavior.spec.ts, don't leave the script.
apps/radix-ssr-testingnx run radix-ssr-testing:test (Vitest; still passWithNoTests).src/ssr-rendering.spec.ts renders primitive pages via renderApplication (@angular/platform-server) and asserts: server render doesn't throw, markup is present, hydration annotations (ngh) are emitted, ids are SSR-stable. Needs import '@angular/compiler'; at the top (platform-server is partially compiled → JIT fallback).test/build, so its pages aren't type-checked there. When you change a primitive's public API, update the matching page under src/app/components/<name>/page.ts — drift only surfaces through this spec (the select page once drifted onto a removed API).apps/radix-perf-testingpnpm primitives:bench (Vitest browser mode — real Chromium, real layout).apps/radix-perf-testing/src/tests/<name>.bench.ts. Copy select.bench.ts / checkbox.bench.ts.docs/adr/0009, and apps/radix-storybook/docs/guides/performance.docs.mdx (Guides/Performance). Keep a bench's anatomy in sync with the primitive (the select bench reproduces the real template).| Symptom | Cause & fix |
|---|---|
NG0100 (ExpressionChanged) after fixture.detectChanges() | Plain (non-signal) field write didn't dirty the view → fixture.changeDetectorRef.markForCheck() first |
NG0951 (required child query has no value) | contentChild.required(X) found nothing — the template/anatomy no longer renders X; fix wiring, not the query |
NG0201 (no provider for X) only when opening | A directive injects a provider that the restructure moved to a descendant; read it off the child instead |
fakeAsync/tick "is not a function" | Suite is zoneless → use vi.useFakeTimers() / whenStable() / a macrotask (see §1) |
| Unit test green but the bug is layout/visibility/positioning | jsdom blind spot → it needs a browser behavior.spec.ts (§2), not a unit test |
| Screenshot diff after an intentional visual change | pnpm test-visual:update to re-baseline (review the diff first) |
pnpm primitives:test # unit (all)
nx run primitives:test --testFile <path> # unit (one file)
pnpm test-visual / :update / :report # browser regression (build+run / re-baseline / report)
nx run radix-ssr-testing:test # SSR
pnpm primitives:bench # perfCLAUDE.md → ## Tests — quick-reference for all layers (kept in sync with this skill)..claude/skills/project-knowledge/references/patterns.md → ## Testing — zoneless conventions + the browser-regression subsection in depth.Guides/Performance (benches), Guides/Server-Side Rendering (SSR), Overview/Accessibility (a11y patterns).apps/visual-regression/README.md — baselines, platform suffixes, CI Docker note.© radix-ng, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/testing of radix-ng/primitives.
Open the folder on GitHubat commit eed2a31
Testing next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Testing this skillradix-ng/primitives | 274 | — | ~3.3k | Automated safety check: Pass | MIT | |
| Playwright Testingchongdashu/vibejam-starter-pack | 149 | — | ~2.2k | Automated safety check: Pass | None | |
| Playwright Testingchongdashu/vibejam-starter-pack | 149 | — | ~2.1k | Automated safety check: Pass | None | |
| Web Testing with Playwright and Vitestwithkynam/vibecode-pro-max-kit | 1.1k | — | ~892 | Automated safety check: Pass | Apache-2.0 | |
| React Testingaffaan-m/ECC | 275k | 1 repos | ~3.3k | Automated safety check: Pass | MIT | |
| Test CommanderEliasOulkadi/shokunin | 114 | — | ~3k | Automated safety check: Notes | MIT |
chongdashu/vibejam-starter-pack
Plan, implement, and debug frontend tests: unit/integration/E2E/visual/a11y.
chongdashu/vibejam-starter-pack
Plan, implement, and debug frontend tests: unit/integration/E2E/visual/a11y.
withkynam/vibecode-pro-max-kit
Covers web testing from unit to E2E, load, visual, accessibility and security checks, with Playwright, Vitest and k6 guides plus a Playwright setup script.
affaan-m/ECC
React component testing with React Testing Library, Vitest/Jest, MSW for network mocking, accessibility assertions with axe, and the decision boundary between component tests and Playwright/Cypress…
EliasOulkadi/shokunin
Generate unit, integration, E2E, and visual regression tests following the Testing Trophy methodology (80% integration).
petrkindlmann/qa-skills
Migrate a test suite from one framework to another, incrementally and without losing coverage.
radix-ng/primitives
Build correct, accessible UI with @radix-ng/primitives — the signals-first, headless Angular primitive library.
radix-ng/primitives
Index of every documented @radix-ng/primitives example. An agent skill from radix-ng/primitives.
radix-ng/primitives
A skill your agent uses when you need information about this project's architecture, tech stack, coding patterns, data model, deployment setup, git workflow, or UX guidelines.
radix-ng/primitives
Write or update Storybook stories and docs MDX for a Radix NG primitive following project conventions.
radix-ng/primitives
Maintain project documentation in .claude/skills/project-knowledge/: audit, edit, check consistency, track status.
radix-ng/primitives
Angular framework reference for building this signals-first, headless directive library.
Works with
Categories
Test Radix NG primitives across every layer and pick the RIGHT one for a change: Vitest unit (zoneless), jest-axe a11y, Playwright browser regression (apps/visual-regression), SSR…. Testing is an agent skill from radix-ng/primitives. Test Radix NG primitives across every layer and pick the RIGHT one for a change: Vitest unit (zoneless), jest-axe a11y, Playwright browser regression (apps/visual-regression), SSR (apps/radix-ssr-testing), and perf benches (apps/radix-perf-testing).
Testing fits situations like: : writing/fixing/adding a test; Почему баг не поймали; add a regression test; choosing a test type.
Run `npx skills add radix-ng/primitives --skill testing -a claude-code`. Or copy the skill folder (.claude/skills/testing in radix-ng/primitives) into .claude/skills/testing in your project. Claude Code loads it when a task matches its description.
Run `npx skills add radix-ng/primitives --skill testing -a codex`. Or copy the skill folder (.claude/skills/testing in radix-ng/primitives) into .agents/skills/testing in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add radix-ng/primitives --skill testing -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/testing, .gemini/skills/testing, .github/skills/testing and .opencode/skills/testing in your project.
Going by SKILL.md and its folder, Testing needs the command-line tools its instructions call (pnpm and nx).
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Testing is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.3k tokens (SKILL.md is roughly 13k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Testing: Playwright Testing (chongdashu/vibejam-starter-pack, 149 stars), Playwright Testing (chongdashu/vibejam-starter-pack, 149 stars), Web Testing with Playwright and Vitest (withkynam/vibecode-pro-max-kit, 1.1k stars) and React Testing (affaan-m/ECC, 275k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
radix-ng (a GitHub organization) maintains it in radix-ng/primitives, which has 274 GitHub stars. The repository holds 7 skills in this directory. The repository was last updated on September 28, 2026.
Source: radix-ng/primitives on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.