Files
wiki/tasks/ui-testing/tests/template.js
2026-05-04 12:20:17 +03:00

142 lines
5.8 KiB
JavaScript

#!/usr/bin/env node
/**
* template.js — шаблон теста для нового проекта
*
* Использование:
* CHROME_BIN=/usr/bin/chromium-browser node template.js
* TEST_URL=https://example.com node template.js
*/
const puppeteer = require('puppeteer-core');
const fs = require('fs');
const path = require('path');
// ─── Конфиг ───────────────────────────────────────────────────────────────────
const CONFIG = {
url: process.env.TEST_URL || 'https://example.com',
chromeBin: process.env.CHROME_BIN || '/usr/bin/chromium-browser',
screenshotsDir: process.env.SCREENSHOTS_DIR || '/tmp/ui-test-screenshots',
resultsFile: process.env.RESULTS_FILE || '/tmp/ui-test-results.json',
viewportDesktop: { width: 1280, height: 800 },
viewportMobile: { width: 375, height: 667 },
defaultTimeout: 15000,
};
// ─── Результаты ───────────────────────────────────────────────────────────────
const results = [];
function pass(id, note) {
results.push({ id, status: 'PASS', note });
console.log(`${id}: ${note}`);
}
function fail(id, note, screenshotPath) {
results.push({ id, status: 'FAIL', note, screenshot: screenshotPath });
console.log(`${id}: ${note}`);
}
function blocked(id, note) {
results.push({ id, status: 'BLOCKED', note });
console.log(`⚠️ ${id}: ${note}`);
}
// ─── Хелперы ──────────────────────────────────────────────────────────────────
async function screenshot(page, name) {
const filePath = path.join(CONFIG.screenshotsDir, `${name}.png`);
await page.screenshot({ path: filePath, fullPage: false });
console.log(` 📸 ${name}.png`);
return filePath;
}
async function waitAndClick(page, selector, timeout = CONFIG.defaultTimeout) {
await page.waitForSelector(selector, { timeout });
await page.click(selector);
}
async function getText(page, selector) {
return page.$eval(selector, el => el.textContent.trim()).catch(() => null);
}
async function isVisible(page, selector) {
return page.$eval(selector, el => {
const style = getComputedStyle(el);
return style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0';
}).catch(() => false);
}
async function sleep(ms) {
return new Promise(r => setTimeout(r, ms));
}
// ─── Тесты ────────────────────────────────────────────────────────────────────
async function runTests(page) {
// TC-TEMPLATE-01: страница загружается
await page.goto(CONFIG.url, { waitUntil: 'networkidle2', timeout: 30000 });
await sleep(2000);
const snap1 = await screenshot(page, 'TC-01-initial');
const title = await page.title();
title ? pass('TC-TEMPLATE-01', `title: "${title}"`) : fail('TC-TEMPLATE-01', 'страница не загрузилась', snap1);
// TC-TEMPLATE-02: пример проверки элемента
const header = await page.$('h1, header');
header ? pass('TC-TEMPLATE-02', 'заголовок найден') : fail('TC-TEMPLATE-02', 'заголовок не найден');
// Добавляй свои тест-кейсы здесь...
}
// ─── Главная функция ──────────────────────────────────────────────────────────
(async () => {
fs.mkdirSync(CONFIG.screenshotsDir, { recursive: true });
console.log(`\n🧪 UI Tests`);
console.log(` URL: ${CONFIG.url}`);
console.log(` Chrome: ${CONFIG.chromeBin}`);
console.log(` Screenshots: ${CONFIG.screenshotsDir}\n`);
const browser = await puppeteer.launch({
executablePath: CONFIG.chromeBin,
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu'],
});
try {
const page = await browser.newPage();
await page.setViewport(CONFIG.viewportDesktop);
// Desktop тесты
await runTests(page);
// Mobile тесты
await page.setViewport(CONFIG.viewportMobile);
await page.goto(CONFIG.url, { waitUntil: 'networkidle2', timeout: 20000 });
await sleep(1500);
await screenshot(page, 'TC-MOBILE-initial');
pass('TC-MOBILE', 'мобильный вид загружен');
} finally {
await browser.close();
}
// ─── Итог ─────────────────────────────────────────────────────────────────
const passed = results.filter(r => r.status === 'PASS').length;
const failed = results.filter(r => r.status === 'FAIL').length;
const blockedN = results.filter(r => r.status === 'BLOCKED').length;
console.log('\n═══════════════════════════════');
console.log(`ИТОГО: ✅ ${passed} / ❌ ${failed} / ⚠️ ${blockedN}`);
if (failed > 0) {
console.log('\nFAILED:');
results.filter(r => r.status === 'FAIL').forEach(r =>
console.log(`${r.id}: ${r.note}${r.screenshot ? `${r.screenshot}` : ''}`)
);
}
fs.writeFileSync(CONFIG.resultsFile, JSON.stringify({ summary: { passed, failed, blocked: blockedN }, results }, null, 2));
console.log(`\nРезультаты: ${CONFIG.resultsFile}`);
console.log(`Скриншоты: ${CONFIG.screenshotsDir}/`);
process.exit(failed > 0 ? 1 : 0);
})();