Що несе адреса
Два останні кандидати з аудиту PWA. Обидва стосуються адреси сторінки, і обидва виявилися справжніми вадами. Граф переставав стежити за адресою, якщо його відкривали з пошкодженим фрагментом. А сторінка джерел губила вибраний порядок, коли читач перемикав мову.
Що лишалося
У звіті аудиту PWA від 26 вересня, серед неперевіреного, стояли ще два кандидати, описані одним рядком: граф із пошкодженим або порожнім фрагментом адреси і порядок джерел після перемикання мови. «6 в 1» доручив обидва одному чату з умовою: спершу браузерний тест, який падає на нинішньому коді, і лише тоді виправлення. Якщо тест не падає, кандидата закрито.
Граф і фрагмент
Сторінка /graph/ тримає відкритий запис у фрагменті адреси, #evt-…, щоб картину можна було передати посиланням. Скрипт сторінки декодує фрагмент через decodeURIComponent під час завантаження і на кожну його зміну. Ця функція кидає помилку на обірваній послідовності відсоткового кодування, як-от #%E0%A4%A чи просто #%. Під час завантаження помилка зупиняла скрипт саме перед рядком, який ставить слухача зміни фрагмента. Кнопки груп і малюнок на ту мить уже працювали, тож на око сторінка була ціла. Але вона більше не відкривала запис, коли фрагмент змінювався, а в консолі лишалася необроблена помилка.
Тест перебирає сім фрагментів: дві обірвані послідовності, порожній #, неіснуючий id, id із пробілом, кирилицю і неопублікований запис, якщо такий є в даних. Для кожного він відкриває сторінку в новому документі й перевіряє, що нічого не вибрано. Потім дає правильний фрагмент і чекає, що запис відкриється. Наостанок знову дає поганий фрагмент, уже на живій сторінці. На старому коді тест упав на першому ж фрагменті: правильний фрагмент після нього нічого не відкрив. Решта випадків і без виправлення нічого не ламали: декодування проходить, а запису з таким id на сторінці немає.
Тепер фрагмент, який не декодується, нічого не називає, так само як невідомий id. Одне лишилося як було. Якщо запис відкрито, а фрагмент змінюється на такий, що нічого не називає, запис лишається відкритим. Так і має бути, бо посилання-пропуск на початку кожної сторінки теж міняє фрагмент, на #content, і воно не повинно закривати запис.
Джерела й мова
На сторінці джерел картки можна впорядкувати за абеткою або за кількістю записів, і порядок живе в адресі як ?order=records. Перемикач мов на сторінках-покажчиках переносить лише шлях. Так задумано, бо запит там нічого не означав. Сторінка джерел стала винятком, коли отримала власний перемикач порядку, а перемикач мов про це не дізнався. Читач, який упорядкував картки за записами й перейшов на іншу мову, діставав абетку.
Гіпотеза в завданні була трохи інша: що посилання мов копіюють запит один раз, під час завантаження, і тому несуть застарілий. Так поводиться перемикач мов на сторінці запису, але покажчики його не вмикають, тож на джерелах посилання не несли запиту взагалі. Тому зворотний випадок і до виправлення був правильний: сторінку відкрито з ?order=records, читач повертає абетку, перемикає мову й бачить абетку.
Тест натискає «За кількістю записів», перемикає мову й чекає /en/sources/?order=records із ранжованим списком. Потім повертає абетку й перемикає мову назад. На старому коді адреса після першого перемикання була /en/sources/. Тепер скрипт порядку сам пише в посилання мов той порядок, який показує: під час завантаження і після кожного натискання.
Перевірки
Обидва нові тести падали на f123bfa і проходять після виправлення. graph.spec.ts і atlas.spec.ts повністю в Chromium дали 99 з 99. verify:code пройшов. Verify на main (прогін 36311268446) і збірка Vercel зелені. На продакшні я відкрив /en/graph/ з #%E0%A4%A і змінив фрагмент на id запису: запис відкрився. На /uk/sources/?order=records посилання мов несли порядок, а після натискання «За абеткою» вже ні.
Перший варіант тесту на графі завантажував сторінку сім разів разом із малюнком. На раннері CI це тривало 25 секунд, а на наступному прогоні (36311774702) — 32, понад ліміт у 30, і тест упав. Вади сторінки за цим не було, лише ціна тесту. Тепер він завантажує сторінку без WebGL, тим самим шляхом, яким іде браузер без нього: фрагмент читається однаково з малюнком і без. У CI тест іде 2,3 секунди (прогін 36312364940), а на старому коді й далі падає з тієї самої причини.
Що не перевірено
Перевірено лише в Chromium; Safari, Firefox і мобільні браузери не перевірялися. Як інші браузери подають у location.hash обірвану послідовність, я не дивився. Виправлення від цього не залежить: воно ловить помилку, хоч би що прийшло.
Запис зроблено 27 вересня 2026 р.
Коміти, про які цей запис
962a2bd851a05d