如何向Jest添加自定义消息?

Jur*_*osh 23 javascript unit-testing jestjs

图片跟随测试用例:

it('valid emails checks', () => {
  ['abc@y.com', 'a@b.nz'/*, ...*/].map(mail => {
    expect(isValid(mail)).toBe(true);
  });
});
Run Code Online (Sandbox Code Playgroud)

我想为每封电子邮件添加自动生成的消息,Email 'f@f.com' should be valid以便很容易找到失败的测试用例.

就像是:

// .map(email =>
expect(isValid(email), `Email ${email} should be valid`).toBe(true);
Run Code Online (Sandbox Code Playgroud)

Jest中有可能吗?

在Chai中可以使用第二个参数,就像expect(value, 'custom fail message').to.be...在Jasmine中看起来像是使用了.because子句.但是在Jest找不到解决方案.

Mon*_*dia 42

我在编写的一些代码中通过将it块放入forEach.

\n

通过这样做,我能够很好地近似您所描述的内容。

\n

优点:

\n
    \n
  • 出色的“本机”错误报告
  • \n
  • 将断言算作它自己的测试
  • \n
  • 无需插件。
  • \n
\n

使用我的方法,您的代码将如下所示:

\n
\n// you can\'t nest "it" blocks within each other,\n// so this needs to be inside a describe block. \ndescribe(\'valid emails checks\', () => {\n  [\'abc@y.com\', \'a@b.nz\'/*, ...*/].forEach(mail => {\n    // here is where the magic happens\n    it(`accepts ${mail} as a valid email`, () => {\n      expect(isValid(mail)).toBe(true);\n    })\n  });\n});\n
Run Code Online (Sandbox Code Playgroud)\n

然后错误就会像这样出现。

\n

注意这些有多好!

\n
 FAIL  path/to/your.test.js\n  \xe2\x97\x8f valid emails checks \xe2\x80\xba accepts abc@y.com as a valid email\n\n    expect(received).toBe(expected)\n\n    Expected: "abc@y.com"\n    Received: "xyz@y.com"\n\n      19 |    // here is where the magic happens\n      20 |    it(`accepts ${mail} as a valid email`, () => {\n    > 21 |      expect(isValid(mail)).toBe(true);\n                                       ^\n      22 |    })\n
Run Code Online (Sandbox Code Playgroud)\n

  • 我记得 Ruby 中也有类似的功能,而且很高兴发现 Jest 也支持它。 (2认同)
  • 预期和收到的邮件是如何变成电子邮件的?预期不应该是“真实的”吗? (2认同)
  • 您的解决方案是乔什·凯利的解决方案,但语法不合适。请改用 it.each(yourArray)(至少自 2020 年初起有效)。 (2认同)

Mic*_*ngo 15

我认为不可能提供这样的信息.但是你可以定义自己的匹配器.

例如,您可以创建一个toBeValid(validator)匹配器:

expect.extend({
  toBeValid(received, validator) {
    if (validator(received)) {
      return {
        message: () => `Email ${received} should NOT be valid`,
        pass: true
      };
    } else {
      return {
        message: () => `Email ${received} should be valid`,
        pass: false
      };
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

然后你像这样使用它:

expect(mail).toBeValid(isValid);
Run Code Online (Sandbox Code Playgroud)

注意:toBeValid为两种情况(成功和失败)返回一条消息,因为它允许您使用.not.根据您是否希望它通过验证,测试将失败并显示相应的消息.

expect(mail).toBeValid(isValid);
// pass === true: Test passes
// pass === false: Failure: Email ... should be valid

expect(mail).not.toBeValid(isValid);
// pass === true: Failure: Email ... should NOT be valid
// pass === false: Test passes
Run Code Online (Sandbox Code Playgroud)

  • 伙计,我不会否定你的答案,但我不敢相信笑话匹配器中缺少这个。这是一个基本概念。 (2认同)

Jos*_*ley 15

虽然这不是通用的解决方案,但对于需要自定义异常消息来区分循环中项目的常见情况,您可以改用 Jest 的test.each

例如,您的示例代码:

it('valid emails checks', () => {
  ['abc@y.com', 'a@b.nz'/*, ...*/].map(mail => {
    expect(isValid(mail)).toBe(true);
  });
});
Run Code Online (Sandbox Code Playgroud)

反而可以变成

test.each(
    ['abc@y.com', 'a@b.nz'/*, ...*/],
    'checks that email %s is valid',
    mail => {
        expect(isValid(mail)).toBe(true);
    }
);
Run Code Online (Sandbox Code Playgroud)


Mik*_*ikk 12

您可以使用try-catch:

try {
    expect(methodThatReturnsBoolean(inputValue)).toBeTruthy();
}
catch (e) {
    throw new Error(`Something went wrong with value ${JSON.stringify(inputValue)}`, e);
}
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案是一个坏主意,当测试失败时,你无法做出任何改变,因为返回为 false 或“methodThatReturnsBoolean”引发了异常。 (7认同)

小智 9

您可以尝试以下一种方法:https : //github.com/mattphillips/jest-expect-message

test('returns 2 when adding 1 and 1', () => {
  expect(1 + 1, 'Woah this should be 2!').toBe(3);
});
Run Code Online (Sandbox Code Playgroud)

  • 要使用打字稿,请确保还安装相应的类型`npm i jest-expect-message @types/jest-expect-message` (7认同)
  • 不适用于笑话 27+。不过,有一个[未解决的问题](https://github.com/mattphillips/jest-expect-message/pull/40)。 (4认同)
  • 这是一种非常干净的方法,应该优先用于尝试和捕获解决方案。 (2认同)
  • 我正在使用这个库与打字稿,它工作完美 (2认同)
  • @Marc 确保您已遵循“jest-expect-message”的[设置](https://github.com/mattphillips/jest-expect-message#setup)说明。Jest 需要配置为使用该模块。 (2认同)

Ily*_*ich 9

添加自定义错误消息的另一种方法是使用以下fail()方法:

it('valid emails checks', (done) => {
  ['abc@y.com', 'a@b.nz'/*, ...*/].map(mail => {
    if (!isValid(mail)) {
      done.fail(`Email '${mail}' should be valid`)
    } else {
      done()
    }
  })
})
Run Code Online (Sandbox Code Playgroud)


Zar*_*old 5

只是不得不自己处理这个问题,我想我可能会对其进行 PR:但这可以与您想要的任何内容配合使用。基本上,您创建了一个自定义方法,允许柯里化函数将自定义消息作为第三个参数。

重要的是要记住,expect 将设置您的第一个参数(expect(akaThisThing)作为自定义函数的第一个参数的那个。

对于通用的 Jest Message 扩展器,它可以适合您已经能够使用的任何 Jest 匹配,然后添加一点繁荣:

expect.extend({
  toEqualMessage(received, expected, custom) {
    let pass = true;
    let message = '';
    try {
      // use the method from Jest that you want to extend
      // in a try block
      expect(received).toEqual(expected);
    } catch (e) {
      pass = false;
      message = `${e}\nCustom Message: ${custom}`;
    }
    return {
      pass,
      message: () => message,
      expected,
      received
    };
  }
});

declare global {
  // eslint-disable-next-line @typescript-eslint/no-namespace
  namespace jest {
    // eslint-disable-next-line @typescript-eslint/naming-convention
    interface Matchers<R> {
      toEqualMessage(a: unknown, b: string): R;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

将显示如下:

    Error: expect(received).toEqual(expected) // deep equality

    Expected: 26
    Received: 13
    Custom Message: Sad Message Indicating failure :(
Run Code Online (Sandbox Code Playgroud)

对于 expect(actualObject).toBe() 内部的具体外观,以防有助于您的用例:

expect.extend({
  toEqualMessage(received, expected, custom) {
    let pass = true;
    let message = '';
    try {
      // use the method from Jest that you want to extend
      // in a try block
      expect(received).toEqual(expected);
    } catch (e) {
      pass = false;
      message = `${e}\nCustom Message: ${custom}`;
    }
    return {
      pass,
      message: () => message,
      expected,
      received
    };
  }
});

declare global {
  // eslint-disable-next-line @typescript-eslint/no-namespace
  namespace jest {
    // eslint-disable-next-line @typescript-eslint/naming-convention
    interface Matchers<R> {
      toEqualMessage(a: unknown, b: string): R;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

    Error: expect(received).toEqual(expected) // deep equality

    Expected: 26
    Received: 13
    Custom Message: Sad Message Indicating failure :(
Run Code Online (Sandbox Code Playgroud)