Автопроверка 44/44 на ширинах 320/375/390/402 × главная/pricing/signup — скриншоты k4-*.png и скрипт site-fixes-verify-4.mjs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
76 lines
5 KiB
JavaScript
76 lines
5 KiB
JavaScript
// Круг 4: проверка, что «сумма + ₸ + /мес» нигде не разрывается по строкам.
|
||
// Ширины из прогона владельца в Safari: 320, 375, 390, 402.
|
||
import { chromium } from '@playwright/test'
|
||
import { mkdirSync } from 'node:fs'
|
||
import { resolve } from 'node:path'
|
||
|
||
const BASE = process.env.SITE_URL ?? 'https://test.food-market.kz'
|
||
const OUT = resolve('/home/nns/food-market', 'docs/site-fixes-2026-10-11')
|
||
mkdirSync(OUT, { recursive: true })
|
||
const WIDTHS = [320, 375, 390, 402]
|
||
const results = []
|
||
const ok = (n, c, d = '') => { results.push({ n, c: !!c, d }); console.log(`${c ? '✓' : '✗'} ${n} ${d}`) }
|
||
|
||
// высота одной строки: text-xs ~16px, text-3xl ~36px, text-sm ~20px. Один ряд => ниже порога.
|
||
const oneLine = (box, max) => box && box.height > 0 && box.height <= max
|
||
|
||
const b = await chromium.launch({ args: ['--ignore-certificate-errors'] })
|
||
|
||
for (const w of WIDTHS) {
|
||
const ctx = await b.newContext({
|
||
viewport: { width: w, height: 900 }, deviceScaleFactor: 2,
|
||
ignoreHTTPSErrors: true, isMobile: true, hasTouch: true,
|
||
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
|
||
})
|
||
const p = await ctx.newPage()
|
||
|
||
// нет горизонтальной прокрутки
|
||
const noHScroll = async (label) => {
|
||
const over = await p.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth)
|
||
ok(`${label}@${w}: нет горизонтальной прокрутки`, over <= 1, `overflow=${over}`)
|
||
}
|
||
|
||
// ---- Главная ----
|
||
await p.goto(`${BASE}/`, { waitUntil: 'networkidle' }); await p.waitForTimeout(400)
|
||
// hero-строка: span с «5 000 ₸/мес»
|
||
const hero = await p.locator('p:has-text("Подписка от") span').first().boundingBox().catch(() => null)
|
||
ok(`home@${w}: hero «5 000 ₸/мес» одной строкой`, oneLine(hero, 24), hero ? `h=${Math.round(hero.height)}` : 'нет')
|
||
// карточки тарифов: nowrap-спаны внутри цен
|
||
const startCard = await p.locator('section:has(h2:has-text("Простые тарифы")) p.text-3xl').first().boundingBox().catch(() => null)
|
||
ok(`home@${w}: карточка «Старт» цена одной строкой`, oneLine(startCard, 48), startCard ? `h=${Math.round(startCard.height)}` : 'нет')
|
||
await p.screenshot({ path: resolve(OUT, `k4-home-${w}.png`), fullPage: true })
|
||
await noHScroll('home')
|
||
|
||
// ---- /pricing ----
|
||
await p.goto(`${BASE}/pricing`, { waitUntil: 'networkidle' }); await p.waitForTimeout(600)
|
||
const prBuilder = await p.locator('#configurator .font-extrabold').first().boundingBox().catch(() => null)
|
||
ok(`pricing@${w}: сумма конструктора одной строкой`, oneLine(prBuilder, 48), prBuilder ? `h=${Math.round(prBuilder.height)}` : 'нет')
|
||
await p.screenshot({ path: resolve(OUT, `k4-pricing-${w}.png`), fullPage: true })
|
||
await noHScroll('pricing')
|
||
|
||
// ---- /signup?plan=start ----
|
||
await p.goto(`${BASE}/signup?plan=start`, { waitUntil: 'networkidle' }); await p.waitForTimeout(600)
|
||
const tileStart = await p.locator('label:has-text("Старт") .whitespace-nowrap').first().boundingBox().catch(() => null)
|
||
ok(`signup-start@${w}: плитка «Старт» цена одной строкой`, oneLine(tileStart, 24), tileStart ? `h=${Math.round(tileStart.height)}` : 'нет')
|
||
await p.screenshot({ path: resolve(OUT, `k4-signup-start-${w}.png`), fullPage: true })
|
||
await noHScroll('signup-start')
|
||
|
||
// ---- /signup после конфигуратора «Бизнес» (14 000 ₸/мес) ----
|
||
await p.goto(`${BASE}/signup?plan=business&shops=3&cashes=1&warehouses=1&employees=5`, { waitUntil: 'networkidle' }); await p.waitForTimeout(700)
|
||
const sumBiz = await p.locator('span.font-bold.whitespace-nowrap').first().boundingBox().catch(() => null)
|
||
ok(`signup-biz@${w}: итог «14 000 ₸/мес» одной строкой`, oneLine(sumBiz, 24), sumBiz ? `h=${Math.round(sumBiz.height)}` : 'нет')
|
||
const tileBiz = await p.locator('label:has-text("Бизнес") .whitespace-nowrap').first().boundingBox().catch(() => null)
|
||
ok(`signup-biz@${w}: плитка «Бизнес» цена одной строкой`, oneLine(tileBiz, 24), tileBiz ? `h=${Math.round(tileBiz.height)}` : 'нет')
|
||
// проверим, что текст действительно «14 000 ₸/мес»
|
||
const bizTxt = await p.locator('span.font-bold.whitespace-nowrap').first().innerText().catch(() => '')
|
||
ok(`signup-biz@${w}: сумма = 14 000 ₸/мес`, /14[\s ]000[\s ]₸.?\/.?мес/.test(bizTxt), JSON.stringify(bizTxt))
|
||
await p.screenshot({ path: resolve(OUT, `k4-signup-biz-${w}.png`), fullPage: true })
|
||
await noHScroll('signup-biz')
|
||
|
||
await ctx.close()
|
||
}
|
||
await b.close()
|
||
const pass = results.filter(r => r.c).length
|
||
console.log(`\n[site-verify-4] ${pass}/${results.length} passed → ${OUT}`)
|
||
process.exit(pass === results.length ? 0 : 1)
|