如果控制台错误计数增加,则 Jest 测试套件失败

Fail jest test suite if console error count increases

如果引入更多控制台错误,我们希望构建失败。例如,假设 console.error 在整个测试套件中被调用了 30 次。如果引入另一个错误,这将增加到 31,这是我们不希望的。有什么办法可以避免这种情况吗?

对于一个测试套件,可以使用:

  const spy = jest.spyOn(console, "error");
  let count = 0;

  afterEach(() => {
    count += spy.mock.calls.length;
  });

  afterAll(() => {
    if (count > 2) {
      throw Error(`oops error count: ${count}`);
    }
  });

但最好在全局范围内定义它。

我们用稍微不同的方式解决了这个问题:

// src/utils/testUtils
let consoleErrorSpy;

export const spyOnConsoleError = () => {
  consoleErrorSpy = jest.spyOn(console, "error");
};

/**
 * We are using this to prevent the console errors from increasing.
 * These are our preferences in order of priority:
 * 1. Don't call this method
 * 2. Call this method at the end of a specific test (eg. for an error that can't be solved)
 * 3. Call this method in `afterEach` (eg. for an async error that can't be solved)
 */
export const catchConsoleErrors = ({ silenced = [] } = {}) => {
  const alwaysSilencedErrors = [
    '<bug from a 3rd party library>'
  ];
  const forbiddenCalls = [];
  const silencedCalls = [];

  for (const call of consoleErrorSpy.mock.calls) {
    if (
      new RegExp([...alwaysSilencedErrors, ...silenced].join("|")).test(call)
    ) {
      silencedCalls.push(call);
    } else {
      forbiddenCalls.push(call);
    }
  }

  for (const silencedCall of silencedCalls) {
    // eslint-disable-next-line no-console
    console.log("SILENCED\n---\n" + silencedCall.join(",") + "\n---");
  }

  expect(forbiddenCalls).toHaveLength(0);

  // We clear the mock here so nothing happens if the method is called again for the same test,
  // which is the case when this method is called in a specific test (file)
  // as it is also called in `afterEach` in setUpTests.js
  consoleErrorSpy.mockClear();
};

// some test file
afterEach(() => {
  catchConsoleErrors({
    silenced: [
      "Warning: Can't perform a React state update on an unmounted component.*"
    ]
  });
});

// src/setupTests.js
spyOnConsoleError();

afterEach(() => {
  catchConsoleErrors();
});