본문으로 건너뛰기
cccskills
무료GitHub에 공개

e2e

Use when user asks to write, create, run, or debug Playwright e2e tests in the Gramax project. Triggers on keywords like e2e, playwright, test, spec, QA.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Gram-ax/gramax스타 616(GitHub 616 + cccskills 0)
연동 도구Playwright

실행 점수 미검증

설치 방법 보기

포함된 파일(1)

  • SKILL.md10.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Writing E2E Tests

Framework: Playwright + custom fixtures/POMs. All tests in e2e-pw/.

Workflow (MANDATORY)

The user is a QA tester who describes tests in human language. You translate intent into code. You decide ALL technical details (fixtures, POMs, locators).

1. Explore

Before anything else:

  • Check similar tests in e2e-pw/platforms/
  • Read relevant POMs for available methods
  • Read app UI components to understand elements, roles, text content

2. Clarify ambiguities

If the request has gaps, present a numbered questionnaire in a single message. The user answers by number. Only ask about behavior/expectations, never about implementation.

Must ask when: platform unclear, scope ambiguous, expected result vague, multiple UI paths exist, locale matters.

Example questionnaire:

Before I write the test, I need to clarify a few things:

1. Platform: web or docportal?
2. You said "create catalog" — verify it appears in the list only, or also that it opens?
3. Should the test check the modal content, or just that the action completes?

Skip questions only if the request is unambiguous with explicit steps and expected results.

3. Plan in Plan Mode

Use EnterPlanMode to create the test plan. The plan must translate user's words into technical steps:

Test: <name>
Platform: web / docportal
Fixture: editorTest / homeTest / catalogTest / baseTest
Test data: <files/catalogs to create>

Steps:
1. <action>
2. <action>

Assertions:
- <assertion 1>
- <assertion 2>

Wait for user approval, then exit plan mode and write the test.

Fixture Selection

Editor content/formatting     → editorTest
Home page / catalog list      → homeTest
Navigation inside a catalog   → catalogTest
Custom setup (web)            → baseTest
Docportal                     → baseTest (docportal)

Hierarchy (web)

baseTest            — web context, files, localStorage
  ├─ homeTest       — + homePage (HomePage)
  ├─ catalogTest    — + catalogPage (CatalogPage)
  │    └─ editorTest — + editor (ArticleEditorPom)
  └─ (direct use for custom setups)

Hierarchy (docportal)

baseTest — web context, API login/source setup

Running Tests

cd e2e-pw
# Build & start: web (6001) / docportal (6003)
bun run web:build && bun run web:start
bun run docportal:build && bun run docportal:start

# Run
bunx playwright test --project=web                    # all web
bunx playwright test --project=web basic.spec.ts      # single file
bunx playwright test --project=web -g "test name"     # by name
bun run ui                                            # interactive UI
bunx playwright test --project=docportal-prepare --project=docportal

Projects: web, web-enterprise, static (port 6002), docportal-prepare, docportal, docportal-enterprise.

Platforms

PlatformPortStateSetup
web6001Reset each test (isolated)files fixture via DOM
docportal6003PersistentAPI setup, docportal-prepare
static6002Static buildPre-built

Locators

Only getByRole and getByText. getByPlaceholder and getByLabel are fine where they read naturally — they resolve through accessible names too. getByTestId is a last resort. CSS and XPath selectors — locator(".foo"), locator("[data-qa=…]"), class names, tag chains, :nth-child — are not allowed, and neither is reaching for a data-* attribute as a hook.

When an element has no usable role or accessible name, the answer is to fix the component, not to work around it in the test. Give the button a real <button>, an aria-label, a visible text — whatever the element is actually missing. A test that reaches into markup is a test that breaks on the next restyle, and it hides an accessibility gap in the product.

Editing app code to make an element addressable is expected and welcome. It is not scope creep.

// GOOD — the element says what it is
page.getByRole("button", { name: "Save" }).click();
page.getByRole("menuitemradio", { name: "master" }).click();
page.getByText("Article Title").click();

// LAST RESORT — only when the element genuinely cannot carry a role or a name
page.getByTestId("add-catalog").click();

// NOT ALLOWED — fix the component instead
page.locator(".btn-primary > span").click();
page.locator(".right-extensions i").first().click();
page.locator("[data-qa='qa-publish-tab']").click();

If you find yourself writing a comment that explains which CSS class the app happens to render, stop: that is the moment to add the role or the label to the component.

Fixing the component: use the real element, not an ARIA patch

Making an element addressable means giving it the right tag, not decorating the wrong one.

// GOOD
<button type="button" aria-label={t("git.branch.actions")} onClick={…}>

// BAD — a div wearing a button costume
<div role="button" tabIndex={0} aria-label={…} onClick={…}>

role="button" plus tabIndex={0} on a <div> or <span> reproduces by hand what <button> gives for free — keyboard activation, focus order, Enter/Space handling — and it always reproduces some of it wrong. Use <button type="button">; type is required, or the button submits any form it lands in.

Never silence an a11y lint. biome-ignore lint/a11y/* is not an accepted way out: that rule firing is the review telling you the element is wrong. If a semantic element genuinely does not fit — an existing click target would nest, a styled wrapper would break — change the surrounding markup so it does, or say plainly in the MR why it cannot be done. Do not commit the suppression.

Suppressions in general are a smell here. The only one currently accepted in e2e-pw is lint/correctness/noEmptyPattern on fixture signatures, because Playwright requires the async ({}, use) form to detect fixture dependencies and biome has no way to know that.

Test Examples

Editor:

import { editorTest } from "@web/fixtures/editor.fixture";
editorTest("does something", async ({ editor }) => {
  await editor.setMarkdown("Hello(*)");
  await editor.press("ControlOrMeta+B");
  await editor.type("bold");
  await editor.assertMarkdownContains("**bold**");
});

Home/catalog:

import { homeTest } from "@web/fixtures/home.fixture";
homeTest.use({ files: { "my-catalog": { "article.md": "# Hello", "doc-root.yml": "title: My Catalog\n" } } });
homeTest("shows catalog", async ({ homePage }) => {
  await homePage.workspace.assertHasCatalogs(["my-catalog"]);
});

Docportal:

import { baseTest as test } from "@docportal/fixtures/base.fixture";
test.use({ source: "env", user: "env" });
test("navigates", async ({ basePage }) => {
  const page = basePage.raw;
  await page.getByRole("button", { name: "Catalog" }).click();
  await basePage.waitForLoad();
});

Fixtures

Test data setup

files — inline file tree (primary method):

homeTest.use({ files: { "catalog": { "art.md": "# Title", "doc-root.yml": "title: Cat\n" } } });

Keys = dirs/files, strings = content, objects = subdirs, number[] = binary.

dir — load from filesystem: catalogTest.use({ dir: new URL("./test-catalog", import.meta.url) });

zip — upload and extract ZIP file.

Options (web)

files, zip, dir, source ("env" | SourceData), isolated (true), isReadOnly (false), experimentalFeatures (string[]), startUrl ("/").

Editor extras: initMd (string), firstEnter (true).

Options (docportal)

source, user ("env" | AuthCredentials), isolated (true), startUrl ("/").

Serial mode

test.describe.configure({ mode: "serial" }) — when tests depend on each other.

Step grouping

await test.step("label", async () => { ... }) — for better reporting.

POMs

BaseSharedPage (shared-pom/page.ts): goto(path), waitForLoad(), waitForUrl(url), assertUrl(url), assertNoModal(), navigate(path) (pushState), copyFileToClipboard(path), raw (Page), modal (Locator).

HomePage (web/pom/home.page.ts): topBar (TopMenu: getAddCatalog(), getSwitchWorkspace(), getSwitchUiLanguage(), getSwitchTheme()), workspace (WorkspacePom).

CatalogPage (web/pom/catalog.page.ts): currentArticleContent(markdownOnly?), getCatalogActions(), getCatalogProperties(), getNavTreeState(catalogName).

ArticleEditorPom (web/pom/editor.pom.ts): setMarkdown(md, opts?), markdown(), type(text), press(keys), focus(), pasteHtml(html), pasteText(text), forceSave(), clickToolbar(button), hoverToolbar(button), assertMarkdown(expected, opts?), assertMarkdownContains(expected), assertMarkdownValid(), bottom().

WorkspacePom: assertHasCatalogs(names[]), assertCurrentWorkspace(config), assertWorkspaces(configs[]).

CatalogPom (web/pom/catalog.pom.ts): props().

Theme (shared-pom/theme.ts): assertHasTheme(theme), assertThemeChanged(), switch(locator?).

Atoms (shared-pom/atoms/)

Dropdown: open(), close(), isOpen(), getItems(), findItemByTitle(title), assertHasItem(item), assertHasItems(items[]), assertTriggerVisible(), assertContentVisible(), assertContentHidden().

DropdownItem: click(), hover(), assertVisible(), assertHidden(). Props: title, description, hasSubContent.

Button: click(), hover(), text(), assertVisible(), assertHasText(text).

Select (extends Dropdown): uses select-content/select-item test IDs.

Editor Specifics

(*) in setMarkdown = cursor position. Keys: space-separated, modifiers with + (ControlOrMeta+B).

Toolbar buttons: bold, italic, strikethrough, heading-2/3/4, bullet-list, ordered-list, task-list, code, table, note, diagrams, pencil-ruler.

md template tag (@utils/utils) removes indentation from template literals.

Conventions

  1. One behavior per test
  2. Use POMs, not raw locators
  3. getByRole/getByText only — no CSS, no XPath, no data-* hooks. Missing role or name means the component gets fixed; getByTestId is the last resort, not the default
  4. waitForLoad() after navigation
  5. serial only when order matters
  6. files fixture for test data, not manual setup
  7. Files: <feature>.spec.ts, group in describe blocks
  8. Do not modify test infrastructure (fixtures, POMs, utils, config) without asking. Only *.spec.ts files can be created/edited freely.
  9. For examining playwright's trace files use playwright skill

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

biome

무료

Use when user asks to lint with Biome, check lint warnings introduced in an MR/branch, run `lint:ref`, or read/triage large Biome diagnostic output in the Gramax project. Triggers on keywords like biome, lint, lint:ref, warnings, lint gate.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Gram-ax/gramax6162026년 10월 6일 업데이트

ci

무료

Use when running headless inside a GitLab CI job in the Gramax repo (the `ai` job). Establishes environment — repo checked out, glab/gh authenticated, what tools exist, how to read/post on GitLab, how to diagnose failed pipeline jobs. Triggers on "ci", "running in CI", "headless CI job", "ты в CI", "запущен в пайплайне".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Gram-ax/gramax6162026년 10월 6일 업데이트

Use when CI jobs are red on a Gramax branch and need diagnosing/fixing — failed pipeline, broken build/tests, flaky jobs, a job that has been red for a while, "почини пайплайн", "почини все пайплайны", "сломанные джобы", "failed CI jobs", "pipeline red", "fix the pipeline".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Gram-ax/gramax6162026년 10월 6일 업데이트

Use when creating, rewriting, OR reviewing a GitLab Merge Request in the Gramax product repo (`gramax/` → `gitlab.ics-it.ru/ics/doc-reader`). Triggers on "mr", "напиши описание MR", "опиши MR", "создай MR", "мерж реквест", "ревью MR", "проверь MR", "посмотри MR", "review MR", "review merge request", "code review for MR", "write MR description", "draft MR", "create merge request". Also pre-empts generic `/requesting-code-review`, `/code-review`, `/review` flows when target is a Gramax GitLab MR — team-convention checks (description, board link, `## Notes`) must run BEFORE code review.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Gram-ax/gramax6162026년 10월 6일 업데이트

Use when the user wants to inspect a Playwright `trace.zip` (actions, screenshots, console errors, network). Triggers on "examine trace", "explore trace", "open trace.zip", "look at the playwright trace", "что в trace.zip", "посмотри трейс", or any message attaching a `*.zip` path that looks like a Playwright trace (e.g. `trace-*.zip`, `trace.zip`).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Gram-ax/gramax6162026년 10월 6일 업데이트

Gram-ax의 스킬 모두 보기

이 스킬의 문제 신고