Jest: Lepszy sposób na wyłączenie konsoli w testach jednostkowych

91

Zastanawiam się, czy istnieje lepszy sposób niepełnosprawnymi błędów konsoli wewnątrz w konkretnym teście żartem (czyli przywrócić oryginalną konsolę przed / po każdej próbie).

Oto moje obecne podejście:

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");
  });
});

Czy istnieje czystszy sposób na osiągnięcie tego samego? Chciałbym tego uniknąć spyOn, ale mockRestorewydaje mi się, że to działa .

Dzięki!

Apidcloud
źródło

Odpowiedzi:

125

Dla konkretnego pliku specyfikacji Andreas jest wystarczająco dobry. Poniższa konfiguracja pominie console.loginstrukcje dla wszystkich zestawów testów,

jest --silent

(lub)

Aby dostosować warn, info and debug, możesz użyć poniższej konfiguracji

__tests __ / setup.js lub jest-preload.js skonfigurowane wsetupFilesAfterEnv

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 Uwaga: plik setupTestFrameworkScriptFile jest przestarzały i zastępuje go setupFilesAfterEnv.

module.exports = {
    verbose: true,
    setupFilesAfterEnv: ["<rootDir>/__tests__/setup.js"],
};
Raja Jaganathan
źródło
2
Cześć! setupTestFrameworkScriptFilejest przestarzały na korzyść setupFilesAfterEnv.
elhoucine
1
Mockowanie global.consolejest rzeczywiście prostym sposobem i można je wykonać za pomocą dowolnego skonfigurowanego setupFilesAfterEnv . Uważaj, aby kpić ze wszystkich natywnych metod consoleobiektu, bo możesz napotkać inne nieoczekiwane błędy.
Vadorequest
49

Ponieważ każdy plik testowy działa we własnym wątku, nie ma potrzeby jego przywracania, jeśli chcesz go wyłączyć dla wszystkich testów w jednym pliku. Z tego samego powodu możesz też po prostu pisać

console.log = jest.fn()
expect(console.log).toHaveBeenCalled();
Andreas Köberle
źródło
1
Dziękuję za informację w tej sprawie. To ma sens :) Szukałem sposobu, aby to zrobić tylko w ramach konkretnego testu bez konieczności przywracania go (początkowo myślałem, że to zachowanie domyślne), ale chyba wcześniej każdy załatwia sprawę.
Apidcloud
46

Jeśli chcesz to zrobić tylko dla konkretnego testu:

beforeEach(() => {
  jest.spyOn(console, 'warn').mockImplementation(() => {});
});
Constantin
źródło
1
To jest genialne!
sheriff_paul
20

Okazało się, że odpowiedź powyżej re: tłumienie console.logwe wszystkich zestawów testów wyrzucił błędy gdy wszelkie inne consolemetody (np warn, error) były nazywane, ponieważ został zastępując całą globalną consoleobiekt.

To nieco podobne podejście zadziałało u mnie w przypadku Jest 22+:

package.json

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

jest / setup.js

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

Korzystanie z tej metody console.logjest tylko wyszydzane, a inne consolemetody pozostają niezmienione.

nickb
źródło
6

Dla mnie bardziej przejrzystym sposobem (czytelnik potrzebuje niewielkiej wiedzy na temat API jest, aby zrozumieć, co się dzieje), jest ręczne zrobienie tego, co robi mockRestore:

// 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
źródło
1
Musisz także zakryć console.info, console.error, console.warn, itp.
Michael Oryl
1
@ michael-liquori dlaczego musisz zrestartować console.log? Myślę, że po każdym opisie kpiny są usuwane
Jhonatan,
2
@Jhonatan Nie sądzę, żeby było to jasne po każdym opisie, chociaż ostatnio nie testowałem tego, aby mieć pewność. Według żartem docs jest clearMocksi resetMockskonfiguracja opcji, ale oboje domyślnie false, a żadna z tych faktycznie przywrócić początkową realizację nawet jeśli jest ustawiony na true. Biorąc pod uwagę, że jest to opcja konfiguracji, którą można zmienić w pewnym momencie, myślę, że najlepszą praktyką jest ręczne czyszczenie, aby upewnić się, że testy nie spowodują problemów w przyszłości.
Michael Liquori
-1

Innym podejściem jest użycie process.env.NODE_ENV. W ten sposób można wybiórczo wybrać, co wyświetlać (a czego nie) podczas uruchamiania testów:

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');
}

lub

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

Będzie to wymagało umieszczenia tej konfiguracji na package.json:

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

Zwróć uwagę, że takie podejście nie jest bezpośrednim rozwiązaniem pierwotnego pytania, ale daje oczekiwany rezultat, o ile ma się możliwość objęcia console.logwspomnianego warunku.

Wallace Sidhrée
źródło
1
Autor pytania, jak wyłączyć console.log podczas testowania. To rozwiązanie nie jest optymalne.
Erick
Dla kopiowaniem pasters tam zamienić ===się !==w zależności od potrzeb. Stosuję to podejście od lat i działa bezbłędnie, ale dostosowuję się do moich potrzeb.
Wallace Sidhrée
Nie odpowiada na właściwe pytanie.
Michael Oryl
To hackerskie rozwiązanie, którego nie można dostosowywać. Co się stanie, jeśli wyłącz tylko dla konkretnego testu, a nie dla drugiego?
Jhonatan