Jest: Melhor maneira de desativar o console em testes de unidade

103

Eu me pergunto se há uma maneira melhor de desabilitar os erros do console dentro de um teste Jest específico (ou seja, restaurar o console original antes / depois de cada teste).

Aqui está minha abordagem atual:

describe("Some description", () => {
  let consoleSpy;

  beforeEach(() => {
    if (typeof consoleSpy === "function") {
      consoleSpy.mockRestore();
    }
  });

  test("Some test that should not output errors to jest console", () => {
    expect.assertions(2);

    consoleSpy = jest.spyOn(console, "error").mockImplementation();

    // some function that uses console error
    expect(someFunction).toBe("X");
    expect(consoleSpy).toHaveBeenCalled();
  });

  test("Test that has console available", () => {
    // shows up during jest watch test, just as intended
    console.error("test");
  });
});

Existe uma maneira mais limpa de realizar a mesma coisa? Eu gostaria de evitar spyOn, mas mockRestoresó parece funcionar com isso .

Obrigado!

Apidcloud
fonte

Respostas:

136

Para determinado arquivo de especificações, o de Andreas é bom o suficiente. A configuração abaixo irá suprimir as console.logdeclarações de todos os conjuntos de testes,

jest --silent

(ou)

Para personalizar warn, info and debugvocê pode usar a configuração abaixo

__tests __ / setup.js ou jest-preload.js configurado emsetupFilesAfterEnv

global.console = {
  log: jest.fn(), // console.log are ignored in tests

  // Keep native behaviour for other methods, use those to print out things in your own tests, not `console.log`
  error: console.error,
  warn: console.warn,
  info: console.info,
  debug: console.debug,
};

jest.config.js

module.exports = {
    verbose: true,
    setupTestFrameworkScriptFile: "<rootDir>/__tests__/setup.js",
};

Jest v24.x Nota: setupTestFrameworkScriptFile foi preterido em favor de setupFilesAfterEnv.

module.exports = {
    verbose: true,
    setupFilesAfterEnv: ["<rootDir>/__tests__/setup.js"],
};
Raja Jaganathan
fonte
2
Oi! setupTestFrameworkScriptFilefoi preterido e substituído por setupFilesAfterEnv.
elhoucine
1
Mocking global.consoleé realmente uma maneira simples de fazer e pode ser feito por meio de qualquer configuração setupFilesAfterEnv . Cuidado para simular todos os métodos nativos do consoleobjeto ou você pode encontrar outros erros inesperados.
Vadorequest
53

Como cada arquivo de teste é executado em seu próprio thread, não há necessidade de restaurá-lo se você quiser desativá-lo para todos os testes em um arquivo. Pelo mesmo motivo, você também pode simplesmente escrever

console.log = jest.fn()
expect(console.log).toHaveBeenCalled();
Andreas Köberle
fonte
1
Obrigado pela informação sobre esse assunto. Faz sentido :) Eu estava procurando uma maneira de fazer isso apenas dentro de um teste específico, sem ter que restaurá-lo (inicialmente pensei que era o comportamento padrão), mas acho que antes Cada um resolve.
Apidcloud
51

Se você quiser fazer isso apenas para um teste específico:

beforeEach(() => {
  jest.spyOn(console, 'warn').mockImplementation(() => {});
});
Constantin
fonte
1
isto é brilhante!
sheriff_paul
21

Descobri que a resposta acima re: suprimir console.logem todos os conjuntos de testes gerava erros quando quaisquer outros consolemétodos (por exemplo warn, error) eram chamados, pois estava substituindo todo o consoleobjeto global .

Essa abordagem um tanto semelhante funcionou para mim com Jest 22+:

package.json

"jest": {
  "setupFiles": [...],
  "setupTestFrameworkScriptFile": "<rootDir>/jest/setup.js",
  ...
}

jest / setup.js

jest.spyOn(global.console, 'log').mockImplementation(() => jest.fn());

Usando este método, apenas console.logé simulado e outros consolemétodos não são afetados.

nickb
fonte
7

Para mim, uma maneira mais clara / limpa (o leitor precisa de pouco conhecimento da API jest para entender o que está acontecendo) é fazer manualmente o que o mockRestore faz:

// at start of test you want to suppress
const consoleLog = console.log;
console.log = jest.fn();

// at end of test
console.log = consoleLog;
Michael Liquori
fonte
1
Você também precisa cobrir console.info, console.error, console.warn, etc.
Michael Oryl
1
@ michael-liquori por que você precisa reiniciar o console.log? Acho que depois de cada descrição as simulações são liberadas
Jhonatan
2
@Jhonatan Não acho que fique claro depois de cada descrição, embora não tenha testado isso recentemente para ter certeza. De acordo com jest docs há um clearMockse resetMocksconfiguração de opção, mas ambos padrão para false, e nem de quem realmente restaurar a implementação inicial, mesmo se estiver definida para true. E, considerando que esta é uma opção de configuração que pode ser alterada em algum momento, acho que é uma prática recomendada limpar manualmente para garantir que seus testes não causem problemas no futuro.
Michael Liquori
0

Outra abordagem é usar process.env.NODE_ENV. Desta forma, pode-se escolher seletivamente o que mostrar (ou não) durante a execução dos testes:

if (process.env.NODE_ENV === 'development') {
  console.log('Show output only while in "development" mode');
} else if (process.env.NODE_ENV === 'test') {
  console.log('Show output only while in "test" mode');
}

ou

const logDev = msg => {
  if (process.env.NODE_ENV === 'development') {
    console.log(msg);
  }
}
logDev('Show output only while in "development" mode');

Isso exigirá que esta configuração seja colocada em package.json:

"jest": {
  "globals": {
    "NODE_ENV": "test"
  }
}

Observe que esta abordagem não é uma solução direta para a questão original, mas dá o resultado esperado, desde que se tenha a possibilidade de envolver o console.logcom a condição mencionada.

Wallace Sidhrée
fonte
1
O autor da pergunta é como desabilitar console.log no teste. Esta solução não é a ideal.
Erick
Para copy-pasters: substitua ===por de !==acordo com suas necessidades. Uso essa abordagem há anos e ela funciona perfeitamente, mas faço ajustes de acordo com minhas necessidades.
Wallace Sidhrée
Não responde à pergunta real.
Michael Oryl
Esta é uma solução hacky e não personalizável. E se desativar apenas para um teste específico e não o outro?
Jhonatan