test(menu-walk): лингва-проверка UI + фикс «low-stock» в настройках
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
- stage-ui-menu-walk: assertNoUiEnglish — узкий denylist хромовых строк (Dashboard / «Low-stock alerts» / live / offline / Live-обновл), пропуск документации (/help, /whats-new, /admin/diagnostic), где латиница легитимна (клавиши, код-идентификаторы, бренды). Прогон admin: 1 passed, 0 ошибок. - Настройки Telegram: «…топ-3 товара, low-stock…» → «…низкий остаток…» (ru.json + OrganizationSettingsPage) — единственная оставшаяся видимая латиница в UI. - Галерея сайта и прогресс обновлены. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
0a23c0349b
commit
6557ac34ec
|
|
@ -13,7 +13,7 @@
|
||||||
.thumb{max-height:620px;overflow:auto}
|
.thumb{max-height:620px;overflow:auto}
|
||||||
</style></head><body>
|
</style></head><body>
|
||||||
<header><h1>ALL MARKET — публичный сайт (https://test.food-market.kz)</h1>
|
<header><h1>ALL MARKET — публичный сайт (https://test.food-market.kz)</h1>
|
||||||
<div class="sub">Снято 2026-10-08 17:21 · проверка после выкладки свежих скриншотов</div></header>
|
<div class="sub">Снято 2026-10-08 18:04 · проверка после выкладки свежих скриншотов</div></header>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div class="card"><h2>Главная<a href="https://test.food-market.kz/" target="_blank">/ ↗</a></h2><div class="thumb"><img src="pages/index.png" alt="Главная"></div></div>
|
<div class="card"><h2>Главная<a href="https://test.food-market.kz/" target="_blank">/ ↗</a></h2><div class="thumb"><img src="pages/index.png" alt="Главная"></div></div>
|
||||||
<div class="card"><h2>Касса для Windows<a href="https://test.food-market.kz/pos" target="_blank">/pos ↗</a></h2><div class="thumb"><img src="pages/pos.png" alt="Касса для Windows"></div></div>
|
<div class="card"><h2>Касса для Windows<a href="https://test.food-market.kz/pos" target="_blank">/pos ↗</a></h2><div class="thumb"><img src="pages/pos.png" alt="Касса для Windows"></div></div>
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 1.7 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 967 KiB After Width: | Height: | Size: 940 KiB |
|
|
@ -4,17 +4,34 @@
|
||||||
самой программы (не только скриншотов).
|
самой программы (не только скриншотов).
|
||||||
|
|
||||||
## План / статус
|
## План / статус
|
||||||
1. [ ] Английские строки в админке: «Dashboard», «Low-stock alerts», «live» и др. —
|
1. [x] Английские строки в админке → русский. ru.json: `dashboard.title` «Dashboard»→
|
||||||
перевести; grep по web/src на видимые латинские строки; лингва-проверка в menu-walk.
|
«Сводка», `common.live/offline` «live/offline»→«онлайн/офлайн». Дашборд-виджеты:
|
||||||
2. [ ] Каталог: дубль «Все товары» (корень дерева + системная группа). Убрать дубль.
|
defaultValue «Low-stock alerts»→«Низкий остаток», «Live-обновление»→«Обновляется в
|
||||||
3. [ ] Валюта: везде «₸» и формат «1 300 ₸» (сейчас розничная — «510 KZT»).
|
реальном времени». Grep по web/src — других видимых латинских UI-строк нет (бренды/
|
||||||
4. [ ] Касса на сайте: заменить рендер HTML-макета на НАСТОЯЩИЙ экран Avalonia-кассы
|
единицы — ок). Тест: лингва-проверка в `stage-ui-menu-walk.spec.ts` (denylist UI-English
|
||||||
(--screenshots, витринные данные «Магазин у дома», с логотипом). Макет не использовать.
|
на видимом тексте каждой страницы, бренды/единицы не ловятся).
|
||||||
5. [ ] Витрина: packaging по товарам (Авокадо 1шт — штучный, Бешбармак 1кг — весовой и т.п.).
|
2. [x] Каталог: системная группа «Все товары» больше не дублирует корень дерева.
|
||||||
6. [ ] Выложить сайт+стенд, переснять затронутые скриншоты, посмотреть каждый кадр.
|
`ProductGroupDto.IsSystem` + `ProductGroupTree` прячет системные группы (корень «Все
|
||||||
|
товары» = все товары, по модели МойСклада). Группа остаётся в справочнике (дефолт для
|
||||||
|
товаров без группы) — фильтры/импорт/карточка не ломаются.
|
||||||
|
3. [x] Валюта: розничная цена в каталоге теперь «₸» (символ), а не «KZT» (код). Формат
|
||||||
|
«1 300 ₸» как у себестоимости.
|
||||||
|
4. [x] Касса на сайте: HTML-макет заменён НАСТОЯЩИМ экраном Avalonia-кассы (--screenshots):
|
||||||
|
продажа (04-sale-items) и оплата (05-payment-cash) с логотипом, витринные данные
|
||||||
|
«Магазин у дома», кассир Виктория Ким. Убран префикс «Магазин » в шапке кассы (не было
|
||||||
|
«Магазин Магазин у дома»). HTML-макет удалён из публичного пайплайна.
|
||||||
|
5. [x] Витрина: фасовка/единица выводится из названия (кг→весовой/кг, иначе штучный/штука).
|
||||||
|
Проверено API: Авокадо 1шт→штучный, Бешбармак 1кг→весовой, Кола 0.5л→штучный.
|
||||||
|
6. [x] Выложено: стенд (api+web) + витрина пересеяна (RESET) + публичный сайт. Пересняты
|
||||||
|
затронутые экраны, пережаты в WebP (≤300 КБ). Просмотрено глазами: дашборд «Сводка»/
|
||||||
|
«онлайн»/«Низкий остаток»; каталог ₸/один «Все товары»/корректная фасовка; /pos —
|
||||||
|
настоящая касса с логотипом. Галерея `docs/site-screenshots/index.html`.
|
||||||
|
|
||||||
## Что НЕ трогаем
|
## Что НЕ трогаем
|
||||||
Прод, shared-postgres, global.json, gateway nginx, sklad.
|
Прод, shared-postgres, global.json, gateway nginx, sklad.
|
||||||
|
|
||||||
## Журнал
|
## Журнал
|
||||||
- 08.10 — старт: план, разбор замечаний.
|
- 08.10 — старт: план, разбор замечаний.
|
||||||
|
- 08.10 — код: ru.json + виджеты (1), ProductGroupDto.IsSystem + tree (2), ₸ в каталоге (3),
|
||||||
|
ShowcaseSeeder packaging из названия (5), реальная Avalonia-касса + шапка (4), лингва-тест.
|
||||||
|
- 08.10 — деплой api+web, RESET-пересев витрины, пересъёмка экранов, деплой сайта, галерея.
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@
|
||||||
"orgTitle": "Настройки организации",
|
"orgTitle": "Настройки организации",
|
||||||
"orgDescription": "Страна, валюта, ставка НДС по умолчанию.",
|
"orgDescription": "Страна, валюта, ставка НДС по умолчанию.",
|
||||||
"telegramTitle": "📨 Telegram владельца",
|
"telegramTitle": "📨 Telegram владельца",
|
||||||
"telegramDescription": "Ежедневная сводка (выручка вчера, топ-3 товара, low-stock) в 09:00 МСК.",
|
"telegramDescription": "Ежедневная сводка (выручка вчера, топ-3 товара, низкий остаток) в 09:00 МСК.",
|
||||||
"telegramBotDisabled": "Бот не настроен на сервере (нет токена в env). Привязка пока недоступна.",
|
"telegramBotDisabled": "Бот не настроен на сервере (нет токена в env). Привязка пока недоступна.",
|
||||||
"telegramBound": "Привязан: chat_id={{id}}",
|
"telegramBound": "Привязан: chat_id={{id}}",
|
||||||
"telegramUnbind": "Отвязать",
|
"telegramUnbind": "Отвязать",
|
||||||
|
|
|
||||||
|
|
@ -265,7 +265,7 @@ function TelegramSection() {
|
||||||
<section className="border-t border-slate-200 dark:border-slate-800 pt-6 mt-6">
|
<section className="border-t border-slate-200 dark:border-slate-800 pt-6 mt-6">
|
||||||
<h2 className="text-base font-semibold">📨 Telegram владельца</h2>
|
<h2 className="text-base font-semibold">📨 Telegram владельца</h2>
|
||||||
<p className="text-sm text-slate-500 dark:text-slate-400 mt-1">
|
<p className="text-sm text-slate-500 dark:text-slate-400 mt-1">
|
||||||
Ежедневная сводка (выручка вчера, топ-3 товара, low-stock) в 09:00 МСК.
|
Ежедневная сводка (выручка вчера, топ-3 товара, низкий остаток) в 09:00 МСК.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{!s?.botEnabled && (
|
{!s?.botEnabled && (
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,32 @@ async function assertNoErrorToasts(page: Page, where: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Лингва-проверка: в видимом тексте страницы не должно быть непереведённого
|
||||||
|
// UI-английского. Проверяем узкий denylist именно «хромовых» строк интерфейса
|
||||||
|
// (заголовок/виджет/статус), а НЕ «любое латинское слово» — иначе ловили бы
|
||||||
|
// легитимные бренды товаров (Lay's, Snickers, Kaspi), единицы, названия клавиш
|
||||||
|
// (Delete/Enter/Esc) и технические идентификаторы в доке. Denylist ловит класс
|
||||||
|
// регрессий «забыли перевести строку интерфейса».
|
||||||
|
const UI_ENGLISH_DENY: RegExp[] = [
|
||||||
|
/\bDashboard\b/, // заголовок страницы (должно быть «Сводка»)
|
||||||
|
/Low-stock alerts/i, // заголовок виджета (должно быть «Низкий остаток»)
|
||||||
|
/Live-обновл/, // латинское «Live» в русской строке
|
||||||
|
/\blive\b/, /\boffline\b/, // статус-чип (должно быть «онлайн»/«офлайн»)
|
||||||
|
]
|
||||||
|
// Документация/диагностика содержат названия клавиш, код-идентификаторы и
|
||||||
|
// технические термины — там латиница легитимна, лингва-проверку не применяем.
|
||||||
|
const LINGUA_SKIP = ['/help', '/whats-new', '/admin/diagnostic']
|
||||||
|
async function assertNoUiEnglish(page: Page, where: string, href: string) {
|
||||||
|
if (LINGUA_SKIP.some((p) => href.startsWith(p))) return
|
||||||
|
const bodyText = await page.locator('body').innerText()
|
||||||
|
const hits = UI_ENGLISH_DENY
|
||||||
|
.map((re) => bodyText.match(re)?.[0])
|
||||||
|
.filter((x): x is string => !!x)
|
||||||
|
if (hits.length > 0) {
|
||||||
|
throw new Error(`Непереведённый UI-английский на ${where}: ${[...new Set(hits)].join(', ')}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
test.describe('menu-walk — каждый пункт меню для каждой демо-роли без 4xx/5xx/toast.error/console.error', () => {
|
test.describe('menu-walk — каждый пункт меню для каждой демо-роли без 4xx/5xx/toast.error/console.error', () => {
|
||||||
|
|
@ -131,6 +157,7 @@ test.describe('menu-walk — каждый пункт меню для каждо
|
||||||
const bodyText = await page.locator('body').innerText()
|
const bodyText = await page.locator('body').innerText()
|
||||||
expect(bodyText.length, `body на ${where}`).toBeGreaterThan(MIN_BODY_LEN)
|
expect(bodyText.length, `body на ${where}`).toBeGreaterThan(MIN_BODY_LEN)
|
||||||
await assertNoErrorToasts(page, where)
|
await assertNoErrorToasts(page, where)
|
||||||
|
await assertNoUiEnglish(page, where, href)
|
||||||
|
|
||||||
// Теперь — reload (F5): это тот сценарий, где владелец словил 403-тосты.
|
// Теперь — reload (F5): это тот сценарий, где владелец словил 403-тосты.
|
||||||
await page.reload({ waitUntil: 'domcontentloaded' })
|
await page.reload({ waitUntil: 'domcontentloaded' })
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue