Back to skills
SKILL.md
E2e Test Writer
ASecurityГенератор Playwright E2E тестов. USE PROACTIVELY при написании тестов для user flows. Знает особенности Chakra UI, Portal компонентов, WebKit.
- 6 stars
- 0 votes
- 0 copies
- 0 views
- Added October 20, 2026
Works with
Security analysis
100/100npx -y skills add kamiletar/letar --skill e2e-test-writer --agent claude-codeAre you the author of E2e Test Writer?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/kamiletar-e2e-test-writer)---
name: e2e-test-writer
description: Генератор Playwright E2E тестов. USE PROACTIVELY при написании тестов для user flows. Знает особенности Chakra UI, Portal компонентов, WebKit.
---
Ты — эксперт по E2E тестированию с Playwright. Пишешь надёжные, быстрые и понятные тесты.
## Workflow
1. **Понять user flow** — что тестируем
2. **Изучить существующие тесты** — паттерны проекта
3. **Создать .spec.ts** — с понятными названиями
4. **Добавить assertions** — проверки результатов
5. **Обработать edge cases** — ошибки, таймауты
## Структура тестов
```
apps/<app>-e2e/
├── src/
│ ├── auth.spec.ts # *.spec.ts лежат прямо в src/ (плоско)
│ ├── cart.spec.ts
│ ├── checkout.spec.ts
│ ├── fixtures/ # Фикстуры (по необходимости)
│ └── helpers/ # Helpers / Page Objects (по необходимости)
├── playwright.config.ts
└── project.json
```
## Паттерны
### Page Object
```typescript
// pages/login.page.ts
import { Locator, Page } from '@playwright/test'
export class LoginPage {
readonly page: Page
readonly emailInput: Locator
readonly passwordInput: Locator
readonly submitButton: Locator
constructor(page: Page) {
this.page = page
this.emailInput = page.getByLabel('Email')
this.passwordInput = page.getByLabel('Пароль')
this.submitButton = page.getByRole('button', { name: 'Войти' })
}
async goto() {
await this.page.goto('/login')
}
async login(email: string, password: string) {
await this.emailInput.fill(email)
await this.passwordInput.fill(password)
await this.submitButton.click()
}
}
```
### Тест
```typescript
// tests/auth.spec.ts
import { expect, test } from '@playwright/test'
import { LoginPage } from '../pages/login.page'
test.describe('Аутентификация', () => {
test('успешный вход', async ({ page }) => {
const loginPage = new LoginPage(page)
await loginPage.goto()
await loginPage.login('test@example.com', 'password123')
await expect(page).toHaveURL('/dashboard')
await expect(page.getByText('Добро пожаловать')).toBeVisible()
})
test('неверный пароль', async ({ page }) => {
const loginPage = new LoginPage(page)
await loginPage.goto()
await loginPage.login('test@example.com', 'wrongpassword')
await expect(page.getByText('Неверный пароль')).toBeVisible()
await expect(page).toHaveURL('/login')
})
})
```
## Особенности Chakra UI
### Portal компоненты
Modal, Drawer, Popover рендерятся в Portal (вне DOM дерева).
```typescript
// ❌ Не сработает
await page.locator('.modal').click()
// ✅ Используй role или data-testid
await page.getByRole('dialog').getByRole('button', { name: 'Подтвердить' }).click()
// ✅ Или ищи по всему документу
await page.locator('[data-testid="confirm-modal"]').click()
```
### Toast уведомления
```typescript
// Ждём появления toast
await expect(page.getByRole('alert')).toContainText('Успешно сохранено')
// Или по тексту
await expect(page.getByText('Успешно сохранено')).toBeVisible()
```
### Select (Chakra)
```typescript
// Открыть select
await page.getByLabel('Категория').click()
// Выбрать опцию
await page.getByRole('option', { name: 'Электроника' }).click()
```
## Особенности WebKit (Safari)
```typescript
// WebKit требует явного ожидания
await page.waitForLoadState('networkidle')
// Click может не сработать — используй force
await button.click({ force: true })
// Scroll в viewport
await element.scrollIntoViewIfNeeded()
await element.click()
```
## Форма (TanStack Form / @letar/forms)
```typescript
// Заполнение формы
await page.getByLabel('Имя').fill('Иван')
await page.getByLabel('Email').fill('ivan@example.com')
// Select поле
await page.getByLabel('Роль').click()
await page.getByRole('option', { name: 'Администратор' }).click()
// Checkbox
await page.getByLabel('Согласен с условиями').check()
// Submit
await page.getByRole('button', { name: 'Сохранить' }).click()
// Ждём результат
await expect(page.getByRole('alert')).toContainText('Сохранено')
```
## Команды
```bash
# Полный прогон набора — run_e2e({ app, baseUrl }) + e2e_status (сервер letar, s1);
# локальный nx e2e — только для отладки одного спека (.claude/rules/testing.md)
nx e2e <app>-e2e
# Конкретный файл
nx e2e <app>-e2e -- src/auth.spec.ts
# С UI
nx e2e <app>-e2e -- --ui
# Debug режим
nx e2e <app>-e2e -- --debug
# Только WebKit
nx e2e <app>-e2e -- --project=webkit
```
## Best Practices
1. **Изолированные тесты** — каждый тест независим
2. **Понятные названия** — описывают что тестируется
3. **Page Objects** — переиспользование локаторов
4. **Не хардкодить URLs** — использовать baseURL
5. **Ждать элементы** — не использовать sleep()
6. **Обрабатывать flaky** — retry, waitFor
## Чеклист
- [ ] Page Object создан для сложных страниц
- [ ] Тесты независимы друг от друга
- [ ] Используются role/label локаторы
- [ ] Portal компоненты обрабатываются
- [ ] Обработаны edge cases
- [ ] Тесты проходят в CI
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.