我想知道是否有更好的方法在特定的Jest测试中禁用控制台错误(即在每次测试之前/之后恢复原始控制台)。

以下是我目前的方法:

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

有没有更干净的方式来完成同样的事情?我想避免spyOn,但mockRestore似乎只与它一起工作。


当前回答

另一种方法是使用process.env.NODE_ENV。通过这种方式,在运行测试时可以选择性地选择显示(或不显示)什么:

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

or

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

这将需要将这个配置放在package.json中:

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

注意,这种方法不是原始问题的直接解决方案,但只要有可能用上述条件包装console.log,就会给出预期的结果。

其他回答

如果你只是想做一个特定的测试:

beforeEach(() => {
  jest.spyOn(console, 'warn').mockImplementation(() => {});
});

由于每个测试文件都在自己的线程中运行,因此如果您想在一个文件中禁用所有测试,则不需要恢复它。出于同样的原因,你也可以只写

console.log = jest.fn()
expect(console.log).toHaveBeenCalled();

这里是你可能会用到的所有台词。你可以把它们放在测试中:

jest.spyOn(console, 'warn').mockImplementation(() => {});
console.warn("You won't see me!")
expect(console.warn).toHaveBeenCalled();
console.warn.mockRestore();

奇怪的是,上面的答案(除了Raja的精彩答案,但我想分享其他失败的奇怪方式,以及如何清除mock,这样其他人就不会浪费我的时间)似乎成功地创建了mock,但没有抑制到控制台的日志记录。

Both

const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});

and

global console = {
   warn: jest.fn().mockImplementation(() => {});
}

成功安装模拟(我可以使用expect(console.warn). tobecalledtimes(1)并且它通过),但它仍然输出警告,即使模拟实现似乎应该替换默认值(这是在jsdom环境中)。

最终,我找到了一个解决问题的黑客,并将以下内容放在配置中SetupFiles加载的文件中(注意,我发现有时是全局的。$不为我工作时,把jquery到全局上下文中,所以我只是设置我所有的全局在我的设置)。

const consoleWarn = jest.spyOn(console, 'warn').mockImplementation(() => {});
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
const consoleDebug = jest.spyOn(console, 'debug').mockImplementation(() => {});
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});


Object.defineProperty(global, 'console', {value: {
                                            warn: consoleWarn,
                                            log: consoleLog,
                                            debug: consoleDebug,
                                            error: consoleError}});

它感觉很难看,然后我不得不把如下代码放在每个测试文件中,因为beforeEach没有在SetupFiles引用的文件中定义(也许你可以把两者都放在SetupFilesAfterEnv中,但我没有尝试过)。

beforeEach(() => {
  console.warn.mockClear();
});

对我来说,一个更清晰/干净的方式(读者需要很少的笑话API知识来理解发生了什么),就是手动做mockRestore所做的事情:

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

// at end of test
console.log = consoleLog;