playwright-ai-auto-debug
Version:
Automatic Playwright test debugging with AI assistance + UI Test Coverage Analysis
284 lines (234 loc) • 12 kB
JavaScript
// DemoProject/tests/detailed-coverage.spec.js
import { test, expect } from '@playwright/test';
import { DetailedCoverageTracker } from '../lib/detailedCoverageTracker.js';
import { MockMCPIntegration } from '../lib/mockMCPIntegration.js';
/**
* 🎯 Демонстрация детального покрытия UI элементов
* Показывает какие именно элементы покрыты тестами, а какие нет
*/
let coverageTracker;
let mcpIntegration;
test.beforeAll(async () => {
// Инициализация детального трекера покрытия
coverageTracker = new DetailedCoverageTracker({
outputDir: 'detailed-coverage',
trackingEnabled: true,
includeSelectors: true,
includeScreenshots: true
});
mcpIntegration = new MockMCPIntegration();
// Начало сессии детального покрытия
coverageTracker.startSession('detailed-demo-session');
console.log('🎬 Начата сессия детального покрытия UI элементов');
});
test.afterAll(async () => {
if (coverageTracker) {
// Генерация и сохранение детальных отчетов
const reports = await coverageTracker.saveDetailedReports();
console.log('\n📊 === ДЕТАЛЬНЫЕ ОТЧЕТЫ ПОКРЫТИЯ ===');
console.log(`JSON отчет: ${reports.json}`);
console.log(`HTML отчет: ${reports.html}`);
console.log(`Дерево покрытия: ${reports.tree}`);
// Показать краткую сводку
const summary = coverageTracker.generateDetailedCoverageReport();
console.log('\n📈 === СВОДКА ПОКРЫТИЯ ===');
console.log(`Всего элементов: ${summary.summary.totalElements}`);
console.log(`Покрыто: ${summary.summary.coveredElements}`);
console.log(`Не покрыто: ${summary.summary.uncoveredElements}`);
console.log(`Покрытие: ${summary.summary.coveragePercentage}%`);
// Показать непокрытые критичные элементы
const uncoveredCritical = summary.detailedElements.critical.filter(el => !el.covered);
if (uncoveredCritical.length > 0) {
console.log('\n🔴 === НЕПОКРЫТЫЕ КРИТИЧНЫЕ ЭЛЕМЕНТЫ ===');
uncoveredCritical.forEach(el => {
console.log(`❌ ${el.type}: "${el.text}" (${el.selector})`);
});
}
}
});
test.describe('Детальное покрытие UI элементов', () => {
test('Анализ главной страницы с детальным трекингом', async ({ page }) => {
console.log('\n🔍 === АНАЛИЗ ГЛАВНОЙ СТРАНИЦЫ ===');
// Переход на страницу
await page.goto('https://playwright.dev');
await page.waitForLoadState('networkidle');
// Получение MCP snapshot
const mcpSnapshot = await mcpIntegration.getMCPSnapshot(page);
console.log('📸 MCP snapshot получен');
// Регистрация всех элементов страницы
const elements = coverageTracker.registerPageElements(
'playwright-homepage',
mcpSnapshot,
'homepage-analysis'
);
console.log(`📋 Найдено ${elements.length} элементов на странице`);
// Показать дерево элементов в консоли
console.log('\n🌳 === ДЕРЕВО ЭЛЕМЕНТОВ ===');
const tree = coverageTracker.generateCoverageTree('playwright-homepage');
printTreeToConsole(tree.tree, 0);
// Взаимодействие с некоторыми элементами для демонстрации покрытия
console.log('\n🎯 === ВЗАИМОДЕЙСТВИЯ ===');
// Поиск и клик по кнопке "Get started"
try {
const getStartedButton = page.locator('text="Get started"').first();
if (await getStartedButton.isVisible()) {
await getStartedButton.click();
console.log('✅ Кликнули по кнопке "Get started"');
// Отметка элемента как покрытого
coverageTracker.markElementCovered(
{ type: 'button', text: 'Get started' },
'homepage-analysis',
'click'
);
}
} catch (error) {
console.log('❌ Кнопка "Get started" не найдена');
}
// Возврат на главную
await page.goto('https://playwright.dev');
await page.waitForLoadState('networkidle');
// Поиск и клик по ссылке "Docs"
try {
const docsLink = page.locator('text="Docs"').first();
if (await docsLink.isVisible()) {
await docsLink.hover();
console.log('✅ Навели на ссылку "Docs"');
coverageTracker.markElementCovered(
{ type: 'link', text: 'Docs' },
'homepage-analysis',
'hover'
);
}
} catch (error) {
console.log('❌ Ссылка "Docs" не найдена');
}
// Поиск поля поиска
try {
const searchInput = page.locator('input[placeholder*="Search"], [role="searchbox"]').first();
if (await searchInput.isVisible()) {
await searchInput.fill('testing');
console.log('✅ Ввели текст в поле поиска');
coverageTracker.markElementCovered(
{ type: 'input', text: 'Search' },
'homepage-analysis',
'fill'
);
}
} catch (error) {
console.log('❌ Поле поиска не найдено');
}
expect(elements.length).toBeGreaterThan(0);
});
test('Анализ страницы документации', async ({ page }) => {
console.log('\n📚 === АНАЛИЗ СТРАНИЦЫ ДОКУМЕНТАЦИИ ===');
await page.goto('https://playwright.dev/docs/intro');
await page.waitForLoadState('networkidle');
// Получение snapshot для страницы документации
const mcpSnapshot = await mcpIntegration.getMCPSnapshot(page);
// Регистрация элементов
const elements = coverageTracker.registerPageElements(
'playwright-docs',
mcpSnapshot,
'docs-analysis'
);
console.log(`📋 Найдено ${elements.length} элементов на странице документации`);
// Взаимодействие с навигацией
try {
const nextButton = page.locator('text="Next"').first();
if (await nextButton.isVisible()) {
await nextButton.click();
console.log('✅ Кликнули по кнопке "Next"');
coverageTracker.markElementCovered(
{ type: 'button', text: 'Next' },
'docs-analysis',
'click'
);
}
} catch (error) {
console.log('❌ Кнопка "Next" не найдена');
}
expect(elements.length).toBeGreaterThan(0);
});
test('Генерация итогового отчета покрытия', async ({ page }) => {
console.log('\n📊 === ГЕНЕРАЦИЯ ИТОГОВОГО ОТЧЕТА ===');
// Убедимся что есть данные - если нет, добавим тестовые
if (coverageTracker.coverageData.allElements.size === 0) {
// Добавим тестовые данные для демонстрации
const mockSnapshot = `- button: "Test button"
- link: "Test link"
- input: "Test input"`;
coverageTracker.registerPageElements('test-page', mockSnapshot, 'test-case');
coverageTracker.markElementCovered(
{ type: 'button', text: 'Test button' },
'test-case',
'click'
);
}
// Получение детального отчета
const report = coverageTracker.generateDetailedCoverageReport();
console.log('\n📈 === СТАТИСТИКА ===');
console.log(`Всего элементов: ${report.summary.totalElements}`);
console.log(`Покрыто тестами: ${report.summary.coveredElements}`);
console.log(`Не покрыто: ${report.summary.uncoveredElements}`);
console.log(`Процент покрытия: ${report.summary.coveragePercentage}%`);
console.log(`Взаимодействий: ${report.summary.interactionsCount}`);
// Покрытие по типам элементов
console.log('\n📊 === ПОКРЫТИЕ ПО ТИПАМ ===');
Object.entries(report.coverageByType).forEach(([type, coverage]) => {
const icon = coverage.percentage === 100 ? '✅' : coverage.percentage > 50 ? '⚠️' : '❌';
console.log(`${icon} ${type}: ${coverage.covered}/${coverage.total} (${coverage.percentage}%)`);
});
// Покрытие по страницам
console.log('\n🌐 === ПОКРЫТИЕ ПО СТРАНИЦАМ ===');
Object.entries(report.coverageByPage).forEach(([page, coverage]) => {
const icon = coverage.percentage === 100 ? '✅' : coverage.percentage > 50 ? '⚠️' : '❌';
console.log(`${icon} ${page}: ${coverage.covered}/${coverage.total} (${coverage.percentage}%)`);
});
// Критичные элементы
console.log('\n🔴 === КРИТИЧНЫЕ ЭЛЕМЕНТЫ ===');
console.log(`Всего критичных: ${report.criticalCoverage.total}`);
console.log(`Покрыто: ${report.criticalCoverage.covered}`);
console.log(`Не покрыто: ${report.criticalCoverage.uncovered}`);
console.log(`Процент: ${report.criticalCoverage.percentage}%`);
// Список непокрытых элементов
console.log('\n❌ === НЕПОКРЫТЫЕ ЭЛЕМЕНТЫ ===');
report.detailedElements.uncovered.slice(0, 10).forEach(element => {
const criticalMark = element.critical ? '🔴' : '';
const interactiveMark = element.interactable ? '🎯' : '';
console.log(`${criticalMark}${interactiveMark} ${element.type}: "${element.text}" (${element.selector})`);
});
if (report.detailedElements.uncovered.length > 10) {
console.log(`... и еще ${report.detailedElements.uncovered.length - 10} элементов`);
}
// Рекомендации
console.log('\n💡 === РЕКОМЕНДАЦИИ ===');
report.recommendations.forEach(rec => {
const priorityIcon = rec.priority === 'HIGH' ? '🔴' : rec.priority === 'MEDIUM' ? '🟡' : '🟢';
console.log(`${priorityIcon} [${rec.priority}] ${rec.category}: ${rec.message}`);
console.log(` Действие: ${rec.action}`);
if (rec.elements.length > 0) {
console.log(` Элементы: ${rec.elements.join(', ')}`);
}
});
// Проверки
expect(report.summary.totalElements).toBeGreaterThan(0);
expect(report.summary.coveragePercentage).toBeGreaterThanOrEqual(0);
expect(report.summary.coveragePercentage).toBeLessThanOrEqual(100);
});
});
/**
* Вспомогательная функция для вывода дерева в консоль
*/
function printTreeToConsole(nodes, level = 0) {
nodes.forEach(node => {
const indent = ' '.repeat(level);
const coverageIcon = node.covered ? '✅' : '❌';
const criticalIcon = node.critical ? '🔴' : '';
const interactableIcon = node.interactable ? '🎯' : '';
const testsInfo = node.coverage.tests.length > 0 ? ` (${node.coverage.tests.length} тестов)` : '';
console.log(`${indent}${coverageIcon}${criticalIcon}${interactableIcon} ${node.type}: "${node.text}"${testsInfo}`);
if (node.children && node.children.length > 0) {
printTreeToConsole(node.children, level + 1);
}
});
}