JavaScript - приставка консоли в Jest / mock "не вызывалась" - PullRequest
0 голосов
/ 19 ноября 2018

Я пытаюсь смоделировать console.info, который, как я знаю, будет вызываться при запуске импортированной функции. Функция полностью состоит из одного fetch, который, когда не работает в рабочей среде, сообщает о запросе и ответе, используя console.info.

На вопрос Шутка. Как смоделировать консоль, когда она используется сторонней библиотекой? , самый популярный ответ предлагает перезаписать global.console, поэтому я использую jest.spyOn, чтобы попробовать это:

import * as ourModule from "../src/ourModule";

test("Thing", () => {
    // Tested function requires this. Including it here in case it's causing
    // something quirky that readers of this question may know about
    global.fetch = require("jest-fetch-mock");

    const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
        () => { console.error("mockInfo") }
    );

    ourModule.functionBeingTested("test");
    expect(mockInfo).toHaveBeenCalled();
}

Как и ожидалось, вывод содержит экземпляр «mockInfo». Однако затем выполнить проверку с помощью toHaveBeenCalled() не удалось.

expect(jest.fn()).toHaveBeenCalled()

Expected mock function to have been called, but it was not called.

  40 |
  41 |     ourModule.functionBeingTested("test");
> 42 |     expect(mockInfo).toHaveBeenCalled();
     |                      ^
  43 | 

  at Object.toHaveBeenCalled (__tests__/basic.test.js:42:22)

console.error __tests__/basic.test.js:38
  mockInfo

Я пытался переместить spyOn до загрузки модуля, как это предлагается в одном из комментариев к ответу, без различий в результате. Что мне здесь не хватает?

Вот эта функция:

function functionBeingTested(value) {
    const fetchData = {
        something: value
    };

    fetch("https://example.com/api", {
        method: "POST",
        mode:   "cors",
        body:   JSON.stringify(fetchData),
    })
        .then( response => {
            if (response.ok) {
                if (MODE != "production") {
                    console.info(fetchData);
                    console.info(response);
                }
            } else {
                console.error(`${response.status}: ${response.statusText}`);
            }
        })
        .catch( error => {
            console.error(error);
        });
}

1 Ответ

0 голосов
/ 19 ноября 2018

Выпуск

console.info вызывается в обратном вызове Promise, который не был выполнен к моменту возврата ourModule.functionBeingTested и запускается expect.

Решение

Перед запуском expect.

убедитесь, что обратный вызов Promise, вызывающий console.info, выполнен.

Самый простой способ сделать это - вернуть Promise из ourModule.functionBeingTested:

function functionBeingTested(value) {
  const fetchData = {
    something: value
  };

  return fetch("https://example.com/api", {  // return the Promise
    method: "POST",
    mode: "cors",
    body: JSON.stringify(fetchData),
  })
    .then(response => {
      if (response.ok) {
        if (MODE != "production") {
          console.info(fetchData);
          console.info(response);
        }
      } else {
        console.error(`${response.status}: ${response.statusText}`);
      }
    })
    .catch(error => {
      console.error(error);
    });
}

... и дождитесь его разрешения, прежде чем утверждать:

test("Thing", async () => {  // use an async test function...
  // Tested function requires this. Including it here in case it's causing
  // something quirky that readers of this question may know about
  global.fetch = require("jest-fetch-mock");

  const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
      () => { console.error("mockInfo") }
  );

  await ourModule.functionBeingTested("test");  // ...and wait for the Promise to resolve
  expect(mockInfo).toHaveBeenCalled();  // SUCCESS
});
...