Подмена даты в приложении на Electron
Поищите это, и каждый ответ будет о том, как менять собственный код: замокать объект
Date, использовать фальшивые таймеры своего тестового фреймворка. Ничто из этого не
помогает, когда у вас готовое собранное приложение. Эта программа запускает то приложение, которое у
вас уже есть.
Почему внедрение до него не достаёт
Этот режим существует из-за конкретной неудачи. Таймер Pomodoro на Electron запустили в сессии
x60, и его обратный отсчёт вообще не сдвинулся. Разбор пакета приложения показал две
независимые причины, и ни у одной не было решения на нативной стороне:
- Обратный отсчёт не читал часы. Это был счётчик, увеличиваемый
setInterval, работающий внутри Web Worker. Перехватывать было нечего: нет вызова времени, потому что приложение никогда не спрашивало, который час. - Этот worker живёт в изолированном процессе рендерера, то есть именно там, куда библиотека, внедрённая снаружи, не попадает.
Поэтому механизм на стороне Windows здесь не поможет, и ответ — обращаться вместо этого к собственному движку JavaScript приложения.
Что происходит вместо этого
Приложение запускается с портом отладки и чистым одноразовым профилем, а его собственные API
времени переводятся на часы сессии через протокол DevTools — Date.now, конструктор
new Date(), performance.now, setTimeout и
setInterval.
Подмена устанавливается в каждый контекст, который открывает приложение, включая его Web Worker — именно там обычно и оказывается таймер, и это единственное место, куда нативное внедрение никогда не достало бы.
В том, как вы им управляете, ничего не меняется. Та же команда, то же окно, та же панель сессии с двумя часами и вердиктом.
# Та же команда, что и для нативного приложения — режим определяется сам chrono run "%LOCALAPPDATA%\Programs\your-app\YourApp.exe" --at 2038-01-01T00:00:00 --mode x60
Два ограничения, о которых стоит знать до начала
Запуск навязчив, и это намеренно говорится вслух.
Приложение запускается с открытым портом удалённой отладки и новым изолированным профилем в
%TEMP% — оно не работает на вашем настоящем профиле и это не та копия, что уже
висит у вас в области уведомлений. Профиль удаляется по окончании сессии, а если это не удалось,
сводка сессии сообщает об этом, а не оставляет его тихо лежать.
Передача вашего собственного --user-data-dir или --remote-debugging-port
отклоняется, а не переопределяется, потому что очевидную оплошность — направить сессию на ваш
настоящий профиль браузера — допускать не стоит.
Страницы читают часовой пояс сессии.
Каждая страница и каждый воркер переводится на часовой пояс
сессии, фиксированное смещение без перехода на летнее время, и проверяет смещение,
которое читает, поэтому страница, прочитавшая другой пояс, попадает в отчёт. Два
ограничения: Intl называет этот пояс смещением вроде GMT+02:00, а
не городом, а главный процесс приложения Electron выполняет JavaScript в Node, куда сессия
не доходит, поэтому он остаётся на реальных часах - отчёт об этом говорит.
Ещё одно, что удивляет людей: интервал, уже поставленный в расписание, сохраняет прежний
темп, когда вы меняете скорость посреди сессии. Date.now,
new Date() и performance.now реагируют сразу, а работающий
setInterval — нет, и сессия предупреждает об этом, а не позволяет сделать вывод, что
изменение ничего не сделало.
Насколько хорошо это проверено
Экспериментально, и у этого слова здесь определённый смысл: оно работает на тех целях, под которые создавалось, не проверялось широко, а встроенный аудит — ваш источник истины, а не эта страница. Проверено вручную, а не автоматическим набором, на настоящем приложении Electron в 64-разрядной Windows.
Покрытие сообщается по контекстам JavaScript, а не по процессам, поскольку именно эта единица здесь существует. Приложение, которое простаивает и никогда не спрашивает время, честно даёт не определено — оно не читало часы, поэтому нельзя утверждать, увидело бы оно правильные. Что означают вердикты →