Faking the date in an Electron app
Search for this and every answer is about changing your own code - mock the
Date object, use your test framework's fake timers. None of that helps
when what you have is a built application. This runs the application you already have.
Why injection does not reach it
This mode exists because of a specific failure. A Pomodoro timer built on Electron was
run under an x60 session and its countdown did not move at all. Taking the
application's bundle apart showed two independent reasons, and neither had a fix on the
native side:
- The countdown was not reading a clock. It was a counter incremented by
setInterval, running inside a Web Worker. There was no time call to intercept, because the application never asked what time it was. - That worker lives in a sandboxed renderer process, which is precisely the place a library injected from outside does not get into.
So the Windows-side mechanism cannot help here, and the answer is to speak to the application's own JavaScript engine instead.
What happens instead
The application is launched with a debugging port and a clean throwaway profile, and
its own time APIs are put on the session clock through the DevTools protocol -
Date.now, the new Date() constructor,
performance.now, setTimeout and setInterval.
The override is installed into every context the application opens, including its Web Workers - which is where the timer usually turns out to live, and the one place native injection was never going to reach.
Nothing about how you drive it changes. The same command, the same window, the same session panel with the two clocks and the verdict.
# Same command as for a native application - the mode is detected chrono run "%LOCALAPPDATA%\Programs\pomotroid\Pomotroid.exe" --at 2038-01-01T00:00:00 --mode x60
Two limits worth knowing before you start
The launch is invasive, and deliberately loud about it.
The application is started with a remote debugging port open and a fresh, isolated
profile under %TEMP% - it does not run against your real profile, and it
is not the copy already in your system tray. The profile is deleted when the session
ends, and if it could not be, the session summary says so rather than leaving it
quietly behind.
Passing your own --user-data-dir or --remote-debugging-port
through is refused rather than overridden, because the obvious accident - pointing the
session at your real browser profile - is not one worth allowing.
The session time zone follows the host.
In this mode the instant is faked, but the local-time getters are not, so an independent time zone is a native-mode feature only. That is a limitation of this version, not a decision.
One more thing that surprises people: an interval already scheduled keeps its
old rate when you change the speed mid-session. Date.now,
new Date() and performance.now react immediately, a running
setInterval does not, and the session warns about it rather than letting
you conclude the change did nothing.
How well tested is it
Experimental, and that word has a defined meaning here: it works on the targets it was built against, it has not been tested broadly, and the built-in audit is your source of truth rather than this page. It was verified by hand rather than by the automated suite, against a real Electron application on 64-bit Windows.
Coverage is reported per JavaScript context rather than per process, since that is the unit that exists here. An application sitting idle and never asking the time honestly produces undetermined - it did not read a clock, so nothing can be claimed about whether it would have seen the right one. What the verdicts mean →