Chrono Mock
IdiomaPortuguês (Brasil)

Falsificando a data em um aplicativo Electron

Pesquise por isso e toda resposta é sobre mudar o seu próprio código - simular o objeto Date, usar os temporizadores falsos do seu framework de testes. Nada disso ajuda quando o que você tem é um aplicativo já compilado. Isto executa o aplicativo que você já tem.

Por que a injeção não chega até ele

Este modo existe por causa de uma falha específica. Um temporizador Pomodoro feito em Electron foi executado sob uma sessão x60 e a contagem regressiva dele não se mexeu. Desmontar o bundle do aplicativo mostrou duas razões independentes, e nenhuma tinha solução no lado nativo:

  • A contagem regressiva não lia nenhum relógio. Era um contador incrementado por setInterval, rodando dentro de um Web Worker. Não havia chamada de tempo para interceptar, porque o aplicativo nunca perguntava que horas eram.
  • Esse worker vive em um processo de renderização isolado, que é justamente o lugar em que uma biblioteca injetada de fora não entra.

Então o mecanismo do lado do Windows não pode ajudar aqui, e a resposta é falar com o próprio motor JavaScript do aplicativo.

O que acontece em vez disso

O aplicativo é iniciado com uma porta de depuração e um perfil limpo e descartável, e as próprias APIs de tempo dele são colocadas no relógio da sessão por meio do protocolo DevTools - Date.now, o construtor new Date(), performance.now, setTimeout e setInterval.

A substituição é instalada em todo contexto que o aplicativo abre, inclusive nos Web Workers - onde o temporizador costuma estar, e o único lugar que a injeção nativa nunca ia alcançar.

Nada muda na forma de operar. O mesmo comando, a mesma janela, o mesmo painel de sessão com os dois relógios e o veredito.

# O mesmo comando de um aplicativo nativo - o modo é detectado
chrono run "%LOCALAPPDATA%\Programs\your-app\YourApp.exe" --at 2038-01-01T00:00:00 --mode x60

Dois limites que vale conhecer antes de começar

A inicialização é invasiva, e deliberadamente barulhenta sobre isso.

O aplicativo é iniciado com uma porta de depuração remota aberta e um perfil novo e isolado em %TEMP% - ele não roda no seu perfil real, e não é a cópia que já está na sua bandeja do sistema. O perfil é apagado quando a sessão termina, e, se não puder ser, o resumo da sessão diz isso em vez de deixá-lo ali em silêncio.

Passar o seu próprio --user-data-dir ou --remote-debugging-port é recusado em vez de sobrescrito, porque o acidente óbvio - apontar a sessão para o seu perfil real do navegador - não é um que valha a pena permitir.

As páginas leem o fuso horário da sessão.

Cada página e cada worker é colocado no fuso horário da sessão, um deslocamento fixo sem horário de verão, e confere o deslocamento que lê, então uma página que leu outro fuso é reportada. Dois limites: o Intl nomeia esse fuso como um deslocamento, como GMT+02:00, e não como uma cidade, e o processo principal de um aplicativo Electron executa JavaScript no Node, que a sessão não alcança, então ele mantém o relógio real - o relatório diz isso.

Mais uma coisa que surpreende: um intervalo já agendado mantém o ritmo antigo quando você muda a velocidade no meio da sessão. Date.now, new Date() e performance.now reagem imediatamente, um setInterval em execução não, e a sessão avisa isso em vez de deixar você concluir que a mudança não fez nada.

Quão bem testado é

Experimental, e essa palavra tem aqui um significado definido: funciona nos alvos para os quais foi construído, não foi testado amplamente, e a auditoria integrada é a sua fonte da verdade, não esta página. Foi verificado manualmente e não pela suíte automatizada, em um aplicativo Electron real no Windows de 64 bits.

A cobertura é relatada por contexto JavaScript e não por processo, já que essa é a unidade que existe aqui. Um aplicativo parado que nunca pergunta a hora produz honestamente indeterminado - ele não leu nenhum relógio, então nada pode ser afirmado sobre se teria visto o certo. O que os vereditos significam →

Experimente