Rafael Camargo

Testando redirecionamento feito via window.location.href com Jest

Às vezes somos surpreendindos com o seguinte erro ao rodar nossos testes:

not implemented: navigation

Uma situação muito comum sob a qual este erro pode acontecer é quando a implementação altera o valor de window.location.href.

Se nenhuma situação como esta lhe vem à cabeça, pense no seguinte caso: ao clicar em um botão da sua aplicação, o usuário pode tanto ser redirecionado para outra view desta mesma aplicação — situação em que apenas o window.history é manipulado — quanto pode ser redirecionado para uma página externa. É quando a aplicação leva o usuário para a página externa alterando o valor de window.location.href, que o teste cai exatamente no erro comentado no início do post.

O jeito mais simples de evitar esse problema é estabelecendo uma fronteira entre o comportamento que está sob domínio da aplicação, e o comportamento que é responsabilidade do browser (carregar uma outra página a partir do novo valor atribuído ao window.location.href).

Diagrama exibindo uma fronteira, delimitada por um serviço chamado "window service", entre a aplicação e o browser
Fronteira estabelecida pelo Window Service

Essa fronteira pode ser estabelecida com a criação de um serviço que convenciono chamar de window service, dado que ele pode abrigar outros métodos que resolvem problemas similares ao da reatribuição do href. Especifico-o com a seguinte suite de testes:

// src/services/window.test.js
describe('Window Service', () => {
  it('should set window location href', () => {
    const { origin } = window.location;
    const newUrl = `${origin}/#my-custom-hash`;
    windowService.setHref(newUrl);
    expect(window.location.href).toEqual(newUrl);
  });
});

Como o objetivo desta suíte é garantir que o valor de window.location.href é de fato atualizado pelo browser quando eu o defino através do método setHref, temos toda a liberdade do mundo para definir um valor que não dispara qualquer navegação por parte do browser: /#my-custom-hash.

// src/services/window.js
const _public = {};

_public.setHref = href  => {
  window.location.href = href;
}

export default _public

Tendo agora a garantia de que chamando windowService.setHref usufruímos do mesmo resultado que atribuir diretamente um valor para window.location.href, podemos substituir a atribuição direta pelo método setHref na nossa implementação, e mocar o respectivo método nos testes:

describe('Conditional Button', () => {
  beforeEach(() => {
    windowService.setHref = jest.fn();
  });

  it('should redirect to help page if user does not satisfy some condition', () => {
    render (<ConditonalButton />);
    await screen.getByRole('button', { name: 'Go' });
    expect(windowService.setHref).toHaveBeenCalledWith(
      'https://some.support.page'
    );
  });
});

Saiba mais: Se esta dica te ajudou a testar o redirecionamento para uma página externa, você provavelmente vai gostar de saber como simular search params nos testes de um componente React.

Todo mês, uma boa dica de programação pro seu dia a dia.

Você pode ser notificado também por RSS