// Круг 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)