如何模拟Node.js中的readline?

5

getUserInput在用户在CLI提示符中输入y时调用一个函数:

export const getUserInput = (fn: () => void) => {
  const { stdin, stdout } = process;
  const rl = readline.createInterface({ input: stdin, output: stdout });
  rl.question("Can you confirm? Y/N", (answer: string) => {
    if (answer.toLowerCase() === "y") {
      fn();
    }
    rl.close();
  });
};

我需要为getUserInput创建一个测试,模拟Node的readline。目前我已经尝试了以下方法,但都没有成功,出现了以下错误:
TypeError: rl.close is not a function

我的模拟实现是否正确,如果不正确该如何修复?

jest.mock("readline");
describe.only("program", () => {
    it.only("should execute a cb when user prompt in cli y", () => {
        const mock = jest.fn();
        getUserInput(mock);
        expect(mock).toHaveBeenCalled();
     });
 });

__mocks__/readline.ts(与node_module相邻的目录)

该文件是一个模拟readline模块的文件,用于测试和调试。
module.exports ={
  createInterface :jest.fn().mockReturnValue({
    question:jest.fn().mockImplementationOnce((_questionTest, cb)=> cb('y'))
  })
}

没问题!请在这里提供一个 [mcve];你是否调用了 jest.mock('readline')?在被测试的代码中它是如何导入的? - jonrsharpe
从我链接给你的文档中可以看到:"注意:为了正确模拟,Jest需要将jest.mock('moduleName')放置在与require/import语句相同的作用域中。" 不要把它放在规范内部。 - jonrsharpe
1
这个。实际上,你可以把它放在规范内部,但是你还需要重新导入使用模拟模块的模块。 - Estus Flask
1
显而易见的方法是不依赖全局的readline,并将readline作为参数接受(带有默认值),这样您就可以轻松地在测试中传递一个假的readline - Madara's Ghost
1个回答

3

我通过添加一个模拟的 close 函数来解决这个问题。

module.exports = {
  createInterface: jest.fn().mockReturnValue({
    question: jest.fn().mockImplementationOnce((_questionTest, cb) => cb("y")),
    close: jest.fn().mockImplementationOnce(() => undefined)
  })
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接