Автотесты: ревью ИИ-кода без случайных ожиданий
Выбираем устойчивые локаторы, ожидаем наблюдаемое состояние и понимаем границы DOM-упражнения.
- Заменить произвольные паузы ожиданием состояния.
- Проверить локаторы, await, изоляцию и доказательства.
- Не выдавать DOM-пример за проверку сервера.
Смысл теста важнее его синтаксиса
Модель предложила кликнуть .button-primary, подождать 3000 мс и считать любой зелёный текст успехом. Код может пройти, не проверив публикацию нужной задачи. CSS-класс описывает реализацию, пауза угадывает скорость, а цвет не задаёт бизнес-результат. Начните ревью с вопроса: какое утверждение должен доказать сценарий и какие наблюдения его подтверждают?
Для UI-действия выбирайте понятный пользователю локатор по роли и имени. Если продукт не даёт однозначного доступного атрибута, используйте согласованный test ID. Уточняйте текст или область поиска. Добавление first() после ошибки неоднозначности не доказывает, что выбран нужный элемент. Оно может скрыть проблему выбора.
Изолированное упражнение, которое можно запустить
import { test, expect } from '@playwright/test';
// A standalone DOM exercise: does NOT test the OrbitDesk server.
test('publication message follows the user action', async ({ page }) => {
await page.setContent(`
<main>
<label for="title">Название</label>
<input id="title" value="Учебная задача" />
<button type="button" id="publish">Опубликовать</button>
<p role="status" id="status">Черновик</p>
</main>
<script>
document.getElementById('publish').addEventListener('click', () => {
document.getElementById('status').textContent = 'Опубликовано';
});
</script>
`);
await expect(page.getByRole('status')).toHaveText('Черновик');
await page.getByRole('button', { name: 'Опубликовать', exact: true }).click();
await expect(page.getByRole('status')).toHaveText('Опубликовано');
await expect(page.getByLabel('Название', { exact: true })).toHaveValue('Учебная задача');
});
Что доказывает локальный пример
page.setContent создаёт маленькую изолированную страницу. Пример показывает изменение role=status и сохранность значения поля. Сеть и сервер здесь не участвуют. Успешный прогон подтверждает поведение этого DOM, но не сохранение в D1, право Бориса или надёжность настоящего OrbitDesk. Границу нужно прямо указать в отчёте.
В реальном end-to-end сценарии нужны контролируемые данные, вход определённого пользователя, переход к нужному объекту и проверка после операции. Подмена сети даёт UI-тест с фиксированным ответом, а не проверку интеграции. Если состояние после reload не получено с сервера, уведомление могло отражать только локальную переменную.
Ожидания должны проверять состояние
Playwright проверяет условия доступности элемента перед действием; assertions вроде toHaveText повторяются до таймаута. Фиксированная пауза не подтверждает готовность системы. Если ожидаемое состояние не наступило, нужен объяснимый провал, а не увеличение sleep до случайного значения. Асинхронные действия и web-first assertions должны ожидаться через await. Обычный синхронный expect(value).toBe(...) сам не повторяет получение значения; await перед isVisible() не превращает такую конструкцию в web-first assertion.
Данные также требуют изоляции. Второй тест, зависящий от задачи первого, не повторится отдельным запуском. Подготовьте собственную фикстуру для сценария и очищайте только его объекты. Не удаляйте реальные записи ради устранения нестабильности. Повторный запуск помогает исследовать причину, но retries не превращают необъяснённое падение в правильный тест.
Как задавать ревью помощнику
Передайте цель сценария, DOM-контракт, способ подготовки и код без секретов. Попросите отдельно оценить смысл, локаторы, ожидания, данные и диагностику. Затем проверьте предложенные методы по официальной документации: правдоподобное имя API может быть выдумано. В примере достаточно стандартных test, expect, setContent, getByRole и getByLabel.
При падении сохраните исходную ошибку и шаг, на котором она возникла. Не перегенерируйте весь тест до исчезновения симптома: так можно потерять проверяемое условие. Полезное изменение должно объяснять, что было ненадёжно и как подтверждается исправление. Если Playwright не установлен, статическое ревью всё равно возможно. Однако его результат нельзя назвать успешным запуском.
Как запустить скачанный DOM-пример
Для динамической проверки нужен отдельный локальный каталог, поддерживаемая Playwright версия Node.js и установленный браузер Chromium. Не выполняйте учебный файл в рабочем репозитории и не подставляйте производственные адреса. Пример сам создаёт минимальную HTML-страницу через page.setContent; сервер OrbitDesk ему не нужен.
Скопируйте dom-exercise.spec.ts из материалов курса в созданную папку. После запуска сравните фактический результат с тремя утверждениями в тесте. Успешный результат подтверждает только действие и состояние учебного DOM, а не серверные права, сохранение в БД или качество продукта целиком. Если установка или запуск недоступны, оставьте динамическую проверку Not run и отдельно запишите результат статического ревью.
Изолированный проект для практики
mkdir qa-orbit-dom-practice
cd qa-orbit-dom-practice
npm init -y
npm install --save-dev @playwright/test
npx playwright install chromium
# Скопируйте сюда скачанный dom-exercise.spec.ts
npx playwright test dom-exercise.spec.tsЗАДАЧА
Отревьюируй тест Playwright и предложи минимальное исправление.
КОНТЕКСТ
Проверяется пользовательское состояние; разделяй DOM, моки и реальный сервер.
ВХОДНЫЕ ДАННЫЕ
Базовая локальная страница и ожидаемое поведение:
import { test, expect } from '@playwright/test';
// A standalone DOM exercise: does NOT test the OrbitDesk server.
test('publication message follows the user action', async ({ page }) => {
await page.setContent(`
<main>
<label for="title">Название</label>
<input id="title" value="Учебная задача" />
<button type="button" id="publish">Опубликовать</button>
<p role="status" id="status">Черновик</p>
</main>
<script>
document.getElementById('publish').addEventListener('click', () => {
document.getElementById('status').textContent = 'Опубликовано';
});
</script>
`);
await expect(page.getByRole('status')).toHaveText('Черновик');
await page.getByRole('button', { name: 'Опубликовать', exact: true }).click();
await expect(page.getByRole('status')).toHaveText('Опубликовано');
await expect(page.getByLabel('Название', { exact: true })).toHaveValue('Учебная задача');
});
Ошибочная замена действий и проверок:
await page.locator(".button-primary").first().click(); await page.waitForTimeout(3000); expect(await page.getByText("Опубликовано").isVisible()).toBe(true);
ОГРАНИЧЕНИЯ
Не добавляй sleep. Не используй first или force для маскировки неоднозначности. Не выдумывай API и результаты запуска.
ОЖИДАЕМЫЙ ФОРМАТ
Проблема → влияние → исправление → способ проверки. Пределы покрытия отдельно.Используйте разрешённый ИИ-сервис. Не отправляйте рабочие секреты и персональные данные.
Источники и проверка фактов
Playwright — Best PracticesПроверка пользовательского поведения, изоляция тестов, локаторы и повторяемые web-first assertions.Playwright — Auto-waitingПроверки доступности элемента перед действием и повторяемые проверки ожидаемого состояния.Playwright — AssertionsОфициальная документация: повторяемые web-first assertions и отличие от обычных проверок значений.Playwright — установка и первый запускУстановка тестового пакета и браузеров; поддержку Node.js и системные требования сверяйте перед запуском.Авторский учебный материал · Редакция QA Orbit · версия 2026-10-28.1