Files
octopus/ADJUSTMENT_VALUE_FIX_TESTING.md
Andrey Smakotin 8bec5823f3 docs: Добавить документацию по исправлению race condition при загрузке корректировки цены
Добавлены три документа:
1. FINAL_FIX_SUMMARY.md - Финальное резюме исправления
2. ADJUSTMENT_VALUE_FIX_TESTING.md - План тестирования и проверки
3. TECHNICAL_RACE_CONDITION_FIX.md - Глубокий технический анализ проблемы и решения

Документы включают:
- Описание проблемы и решения
- Пошаговый план тестирования (4 сценария)
- Анализ race condition на примере JS event loop
- Трёхуровневая защита от race condition
- Логирование для отладки
- Сравнение подходов синхронизации

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 20:29:06 +03:00

12 KiB
Raw Blame History

Тестирование исправления загрузки сохранённых значений корректировки цены

Дата исправления: 2025-11-02

Коммит: c7bf23c


Описание проблемы (которая была исправлена)

Проблема: Сохранённые значения корректировки цены не отображались на странице редактирования комплекта.

  • Отображались только в 1 из 10 случаев
  • Большую часть времени поля были пустыми
  • Когда отображались, то сразу затирались какой-то переинициализацией

URL для воспроизведения: http://grach.localhost:8000/products/kits/4/update/

Корневая причина:

  1. При загрузке значений в input-поля срабатывают события input и change
  2. Эти события вызывают calculateFinalPrice() и validateSingleAdjustment()
  3. Функция calculateFinalPrice() перезаписывает скрытые поля (id_price_adjustment_type, id_price_adjustment_value) со значениями по умолчанию
  4. Получается race condition: значения загружаются → события срабатывают → значения стираются

Что было исправлено

Решение: Два уровня защиты от перезаписи

Уровень 1: Флаг isLoadingAdjustmentValues

  • Подавляет события input и change во время загрузки значений
  • Код видит эти события, но пропускает обработку
  • Логирует в консоль: "Skipping event during adjustment value loading"

Уровень 2: Флаг isInitializing

  • Даже если событие обработается, calculateFinalPrice() не перезапишет скрытые поля
  • Проверка: if (!isInitializing) { adjustmentTypeInput.value = ...; }

Уровень 3: requestAnimationFrame

  • Гарантирует что isInitializing = false устанавливается в конце frame
  • Синхронизация с браузерным rendering cycle

Файлы изменены

productkit_edit.html (строки 435, 683-696, 912-935)

// Строка 435: Добавлен новый флаг
let isLoadingAdjustmentValues = false;

// Строки 683-696: Добавлена проверка в event listeners
input.addEventListener('input', () => {
    if (isLoadingAdjustmentValues) {
        console.log('Skipping event during adjustment value loading');
        return;
    }
    validateSingleAdjustment();
    calculateFinalPrice();
});

// Строки 912-935: Используется флаг во время загрузки значений
isLoadingAdjustmentValues = true;
console.log('isLoadingAdjustmentValues = true, suppressing input/change events');

// Загрузка значений
// ...

isLoadingAdjustmentValues = false;
console.log('isLoadingAdjustmentValues = false, events are enabled again');

Как тестировать исправление

Тестовые данные

Используются комплекты в тенанте "grach":

  • Kit #4: "Комплект Роза" с корректировкой increase_percent: 10.00
  • Kit #2: "Комплект белые розы" с корректировкой increase_amount: 5.00

Сценарий 1: Проверка отображения на странице редактирования (10 раз)

Цель: Убедиться что значение отображается ВСЕГДА, а не 1 раз из 10

Шаги:

  1. Открыть http://grach.localhost:8000/products/kits/4/update/
  2. Нажать Ctrl+F5 (очистить кэш и перезагрузить)
  3. Найти блок "НА СКОЛЬКО БЫЛА ИЗМЕНЕНА ЦЕНА"
  4. Должно отображаться: поле "Увеличить на %" с значением 10
  5. Повторить шаги 2-4 ещё 9 раз (всего 10 раз)

Ожидаемый результат: 10/10 раз значение 10 отображается в поле

Признаки успеха:

  • Поле не пустое
  • Значение = 10
  • Остальные 3 поля (Увеличить на сумму, Уменьшить на %, Уменьшить на сумму) - отключены (disabled)
  • Они помечены серым цветом (не активны)

Сценарий 2: Проверка логирования в консоли браузера

Цель: Убедиться что логирование показывает правильный порядок выполнения

Шаги:

  1. Открыть http://grach.localhost:8000/products/kits/4/update/
  2. Нажать F12 (открыть DevTools)
  3. Перейти на вкладку Console
  4. Нажать Ctrl+F5
  5. В консоли должны появиться логи (отсортировать по времени вверх):

Ожидаемые логи (в таком порядке):

Loading saved adjustment values: {type: 'increase_percent', value: 10}
isLoadingAdjustmentValues = true, suppressing input/change events
Loaded increase_percent: 10
isLoadingAdjustmentValues = false, events are enabled again
calculateFinalPrice: calculating...
[несколько логов о расчётах цен]
Initialization complete, isInitializing = false

Признаки успеха:

  • isLoadingAdjustmentValues = true появляется ДО загрузки значений
  • Loaded increase_percent: 10 показывает что значение загружено
  • isLoadingAdjustmentValues = false появляется ПОСЛЕ загрузки
  • Initialization complete появляется в конце
  • Нет ошибок в консоли (красных сообщений)

Сценарий 3: Проверка редактирования корректировки

Цель: Убедиться что можно изменить значение и оно сохраняется

Шаги:

  1. Открыть http://grach.localhost:8000/products/kits/4/update/
  2. В поле "Увеличить на %" изменить значение с 10 на 15
  3. Нажать кнопку "Сохранить"
  4. Открыть страницу редактирования снова (F5)
  5. Проверить что значение = 15

Ожидаемый результат:

  • Значение измененo на 15
  • Сохранилось в БД
  • При перезагрузке отображается 15

Сценарий 4: Проверка другого комплекта (с decrease_percent)

Цель: Убедиться что исправление работает для всех 4 типов корректировки

Шаги:

  1. Создать новый комплект
  2. Добавить товар
  3. В блоке "НА СКОЛЬКО БЫЛА ИЗМЕНЕНА ЦЕНА" выбрать "Уменьшить на %" и ввести 20
  4. Сохранить
  5. Открыть для редактирования
  6. Проверить что "Уменьшить на %" = 20
  7. Повторить 5 раз

Ожидаемый результат: 5/5 раз значение отображается правильно


Что смотреть в консоли браузера (для отладки)

F12 → Console → Filter (Фильтр)

Полезные логи:

// Загрузка сохранённых значений
"Loading saved adjustment values:"
"isLoadingAdjustmentValues = true"
"Loaded increase_percent: 10"
"isLoadingAdjustmentValues = false"

// События которые подавляются
"Skipping event during adjustment value loading"

// Инициализация завершена
"Initialization complete, isInitializing = false"

Если видите эти логи в консоли - значит исправление работает правильно.


Возможные проблемы и решения

Проблема: Значение всё ещё не отображается

Решение:

  1. Откройте консоль (F12)
  2. Проверьте логи - есть ли ошибки?
  3. Проверьте что комплект в БД имеет значение price_adjustment_value > 0
  4. Очистите браузерный кэш (Ctrl+Shift+Delete)
  5. Нажмите Ctrl+F5 на странице редактирования

Проблема: Логи не появляются

Решение:

  1. Проверьте что консоль не отфильтрована (нет активного фильтра)
  2. Нажмите Ctrl+F5 (hard refresh)
  3. Проверьте что в productkit_edit.html есть код с логами (смотрите коммит c7bf23c)

Проблема: Значение загружается но потом исчезает

Решение:

  1. Это была исходная проблема
  2. Если она всё ещё есть - значит исправление не развернулось
  3. Проверьте git статус: git log -1
  4. Должен быть коммит "c7bf23c fix: Улучшить загрузку сохранённых значений"
  5. Если коммита нет - обновите файл productkit_edit.html вручную

Результаты тестирования

Заполните после выполнения тестов:

Сценарий Попыток Успешных Результат
1. Отображение (10 раз) 10 __/10 /
2. Логирование 1 __/1 /
3. Редактирование 1 __/1 /
4. Другой тип коррекции 5 __/5 /

Итоговый результат: ПРОЙДЕНО / НЕ ПРОЙДЕНО


Архитектура исправления

Загрузка страницы редактирования
    ↓
1. DOMContentLoaded срабатывает
    ↓
2. Инициализация переменных
    - isInitializing = true
    - isLoadingAdjustmentValues = false
    - priceCache = {}
    ↓
3. Регистрация event listeners (с проверкой isLoadingAdjustmentValues)
    ↓
4. setTimeout 500ms → Загрузка сохранённых значений
    ↓
5a. Устанавливаем isLoadingAdjustmentValues = true
5b. Заполняем поля (input события ПОДАВЛЯЮТСЯ благодаря флагу)
5c. Вызываем validateSingleAdjustment()
5d. Устанавливаем isLoadingAdjustmentValues = false
    ↓
6. calculateFinalPrice() с isInitializing = true
   (не перезапишет скрытые поля даже если они обновятся)
    ↓
7. requestAnimationFrame × 2 → isInitializing = false
   (в конце frame cycle, после всех events)
    ↓
8. ГОТОВО: значения загружены, события обрабатываются, скрытые поля защищены

Заключение

Исправление использует трёхуровневую защиту:

  1. Подавление событий (isLoadingAdjustmentValues) во время загрузки
  2. Защита скрытых полей (isInitializing) от перезаписи
  3. Синхронизация с браузером (requestAnimationFrame) для надёжности

Это должно полностью исправить проблему с надёжностью загрузки сохранённых значений корректировки цены.

🎉 Готово к тестированию!