A standalone Playwright test that runs without AI (npm run test:ui), writes pinpoint observations to JSONL, and Claude renders a verdict based on the log.
When to use
- After deploying the feature to the database (
/db-load-xml→/db-update) - The feature affects the UI (forms, buttons, tabular sections)
When NOT to use
- A backend-only feature (a new MCP tool, BSL only without forms)
- Changes only in configuration/rights/subsystems without UI effects
Step 1 — Scaffold the infrastructure (one-time per project)
Check for package.json и playwright.config.js in the root of the target project.
If they are missing — create from templates:
package.json
{
"name": "<project-name>-tests",
"private": true,
"scripts": {
"test:ui": "npx playwright test",
"test:ui:headed": "npx playwright test --headed",
"test:ui:debug": "npx playwright test --debug"
},
"devDependencies": {
"@playwright/test": "^1.50.0"
}
}
playwright.config.js
const { defineConfig } = require('@playwright/test');
module.exports = defineConfig({
testDir: './tests/playwright',
timeout: 60000,
retries: 0,
use: {
// URL базы 1С — подставить из CLAUDE.md проекта
baseURL: 'http://localhost:8080',
// 1С веб-клиент: headless ненадёжен для некоторых действий
headless: true,
viewport: { width: 1280, height: 720 },
ignoreHTTPSErrors: true,
},
projects: [
{
name: '1c-ui',
use: { browserName: 'chromium' },
},
],
});
After creation:
cd <project-root> && npm install && npx playwright install chromium
Step 2 — Define checkpoints (UI checkpoints)
Before writing the test — determine what exactly is being checked. Sources:
openspec/changes/<feature>/design.md→ section## UI checkpoints- Form.xml of the feature → form elements, buttons, commands
- Common sense → after action X, what changes on the screen?
Checkpoint format:
<действие пользователя> → <ожидаемое наблюдение на экране>
Examples:
Нажать "Провести" → заголовок содержит "№" и дату
Заполнить Контрагент → поле "Договор" стало доступно
Добавить строку в ТЧ Товары → количество строк увеличилось на 1
If nothing changes visually after the action — the test cannot verify it. The UI needs to be improved (a message to the user, a status change, an indicator).
Step 3 — Generate spec.js
Create tests/playwright/<feature>.spec.js according to the pattern:
// tests/playwright/<feature>.spec.js
const { test, expect } = require('@playwright/test');
const fs = require('fs');
const path = require('path');
const LOG_FILE = path.join(__dirname, '<feature>.log.jsonl');
const BASE_URL = '<url-from-project-claude-md>';
// --- Logging helpers ---
function log(step, observation) {
const entry = {
ts: new Date().toISOString(),
step,
...observation,
};
fs.appendFileSync(LOG_FILE, JSON.stringify(entry) + '\n');
}
function clearLog() {
if (fs.existsSync(LOG_FILE)) fs.unlinkSync(LOG_FILE);
}
// --- 1C helpers ---
async function clipboardPaste(page, value) {
await page.evaluate((v) => navigator.clipboard.writeText(v), value);
await page.keyboard.press('Control+A');
await page.keyboard.press('Control+V');
}
async function checkFormClosed(page) {
const hasModal = await page.locator('.modalSurface').count() > 0;
const hasValidation = await page.locator('[title="Закрыть (Ctrl+Shift+Z)"]')
.filter({ visible: true }).count() > 0;
return { hasModal, hasValidation };
}
// --- Tests ---
test.describe('<Feature Name>', () => {
test.beforeAll(() => clearLog());
test('checkpoint: <description>', async ({ page }) => {
// Navigate
await page.goto(BASE_URL);
await page.waitForTimeout(2000); // 1C web client init
// Action
// ... (clipboard paste, DLB clicks, etc.)
// Observe — точечная проверка, НЕ полный DOM
const fieldValue = await page.locator('[id$="_FieldName"]').textContent();
const isVisible = await page.locator('[id$="_Element"]').isVisible();
log('checkpoint-name', {
fieldValue,
isVisible,
pass: fieldValue === 'expected',
});
expect(fieldValue).toBe('expected');
});
});
Rules for generating spec.js
- One test() per checkpoint — isolated verification
- JSONL log is mandatory — each
test()writeslog(step, observation) - Observations are pinpoint:
isVisible,textContent,count— NOT a full snapshot - 1C selectors: suffix
[id$="_FieldName_DLB"], NEVER hardcode the formform40_ - Input only via clipboard — standard
fill()/type()do not work in 1C - aria-label and button text — not CSS classes (unstable in 1C)
Analyzing Form.xml for generation
Read the feature's Form.xml (via Read or /form-info), extract:
- Element names → suffix selectors
[id$="_<ElementName>"] - Commands → buttons to click
- Form attributes → fields for value verification
- TabularSection → row count verification
Step 4 — Run the test
cd <project-root> && npm run test:ui 2>&1 || true
If there are Playwright setup errors (browser not installed):
npx playwright install chromium
Step 5 — Verdict
The AI reads two sources and issues an assessment:
1. Test JSONL log
cat tests/playwright/<feature>.log.jsonl
Each line is a JSON object with step, pass, and observation fields. Check: all pass: true?
2. 1C event log
{"name": "get_event_log", "arguments": {"count": 20}}
Check: are there any errors related to the feature after the test run?
Verdict format
UI-тест: ✅ PASS (N/N checkpoints)
- checkpoint-1: OK (field = "expected")
- checkpoint-2: OK (element visible)
Журнал 1С: нет ошибок
or
UI-тест: ❌ FAIL (N-1/N checkpoints)
- checkpoint-1: OK
- checkpoint-2: FAIL (expected "Проведён", got "Новый")
→ Воспроизвести через Playwright MCP, browser_snapshot на шаге 2
On FAIL
Do not repeat the test automatically. Reproduce the problematic step via Playwright MCP (browser_navigate → browser_snapshot) for diagnostics. browser_snapshot — a debugging tool, not the primary mechanism.
Full example (end-to-end)
1. /db-load-xml + /db-update (фича уже в базе)
2. Проверить tests/ инфраструктуру → scaffold если нет
3. Прочитать Form.xml → извлечь элементы
4. Определить checkpoints из design.md
5. Сгенерировать tests/playwright/payment-form.spec.js
6. npm run test:ui → читать .log.jsonl
7. get_event_log → проверить ошибки
8. Вердикт: PASS/FAIL + детали
Limitations
- Chromium only (the 1C web client is optimized for it)
headless: truemay not work for some 1C actions — switch toheadedviatest:ui:headed- The test verifies UI behavior, not business logic (for logic →
/1c-test-runner) - package.json and playwright.config.js live in the target project, not in this workspace
- Clipboard paste requires permissions — Chromium grants by default
Related skills
/1c-web-session— interactive work with 1C in the browser (for test debugging)/1c-test-runner— unit testing of business logic (server side)/form-info— analysis of Form.xml for extracting elements/db-load-xml+/db-update— deploy the feature before the test