如何将自定义消息添加到 Jest 期望?
Posted
技术标签:
【中文标题】如何将自定义消息添加到 Jest 期望?【英文标题】:How to add custom message to Jest expect? 【发布时间】:2018-01-03 00:33:51 【问题描述】:图片如下测试用例:
it('valid emails checks', () =>
['abc@y.com', 'a@b.nz'/*, ...*/].map(mail =>
expect(isValid(mail)).toBe(true);
);
);
我想为每封电子邮件添加自动生成的消息,例如 Email 'f@f.com' should be valid
,以便轻松找到失败的测试用例。
类似:
// .map(email =>
expect(isValid(email), `Email $email should be valid`).toBe(true);
Jest有可能吗?
在 Chai 中可以使用 expect(value, 'custom fail message').to.be...
之类的第二个参数,而在 Jasmine 中似乎可以使用 .because
子句。但在 Jest 中找不到解决方案。
【问题讨论】:
【参考方案1】:你试试这个扩展 jest 的库: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);
);
【讨论】:
这是一种非常干净的方法,应该优先于尝试和捕获解决方案。 这似乎与 TS 不准确 我正在使用这个库和打字稿,它完美地工作 @Marc 确保您已按照Setup 的jest-expect-message
说明进行操作。 Jest 需要配置为使用该模块。
不适用于 jest 27+。不过有一个open issue。【参考方案2】:
我认为不可能提供这样的信息。但是你可以定义自己的matcher。
例如,您可以创建一个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
;
);
然后你像这样使用它:
expect(mail).toBeValid(isValid);
注意: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
【讨论】:
非常感谢,一个问题 - 在某个文件中使用它时,它是该测试文件的本地文件,对吗?如果我想在某个全局范围内使用该功能,我应该使用beforeAll
吗?
我不完全确定它是否仅适用于文件,但如果它在整个测试运行期间都可用,它可能取决于首先执行哪个文件以及何时并行运行测试,这成为问题。但是您可以做的是,将toBeValid
函数导出到帮助文件中,然后将其导入并在您需要的任何地方使用expect.extend( toBeValid )
注册。
伙计,我不会敲你的答案,但我不敢相信开玩笑的匹配器缺少这个。这是一个基本概念。【参考方案3】:
你可以使用try-catch:
try
expect(methodThatReturnsBoolean(inputValue)).toBeTruthy();
catch (e)
throw new Error(`Something went wrong with value $JSON.stringify(inputValue)`, e);
【讨论】:
这个解决方案是个坏主意,当测试失败时,您无法做出改变,因为返回为 false 或methodThatReturnsBoolean
抛出异常。
@dave008,是的,这两种情况都没有通过测试,但是错误消息非常容易解释并且取决于出了什么问题。
@Marc 你的代码一定有问题——在示例中,expect
函数只有一个参数/值。【参考方案4】:
虽然这不是一个通用的解决方案,但是对于想要自定义异常消息来区分循环中的项目的常见情况,您可以改用 Jest 的test.each。
例如,您的示例代码:
it('valid emails checks', () =>
['abc@y.com', 'a@b.nz'/*, ...*/].map(mail =>
expect(isValid(mail)).toBe(true);
);
);
可以改为
test.each(
['abc@y.com', 'a@b.nz'/*, ...*/],
'checks that email %s is valid',
mail =>
expect(isValid(mail)).toBe(true);
);
【讨论】:
【参考方案5】:2021年答案
我在为Mintbean 编写的一些代码中做到了这一点,将我的it
块放在forEach
中。
通过这样做,我能够很好地近似您所描述的内容。
优点:
出色的“本机”错误报告 将断言计为自己的测试 无需插件。下面是你的代码在我的方法中的样子:
// you can't nest "it" blocks within each other,
// so this needs to be inside a describe block.
describe('valid emails checks', () =>
['abc@y.com', 'a@b.nz'/*, ...*/].forEach(mail =>
// here is where the magic happens
it(`accepts $mail as a valid email`, () =>
expect(isValid(mail)).toBe(true);
)
);
);
然后错误会像这样显示。
注意这些有多好!
FAIL path/to/your.test.js
● valid emails checks › accepts abc@y.com as a valid email
expect(received).toBe(expected)
Expected: "abc@y.com"
Received: "xyz@y.com"
19 | // here is where the magic happens
20 | it(`accepts $mail as a valid email`, () =>
> 21 | expect(isValid(mail)).toBe(true);
^
22 | )
【讨论】:
我记得在 Ruby 中也有类似的东西,很高兴发现 Jest 也支持它。 我发现这个结构非常强大,奇怪的是这个答案被忽视了:) expected和received是怎么变成email的?预期不应该是“真实的”吗?【参考方案6】:我只需要自己处理这个问题,我想我可能会对其进行公关:但这可以适用于您想要的任何东西。基本上,您创建一个自定义方法,允许 curried 函数将自定义消息作为第三个参数。
请务必记住,expect 将设置您的第一个参数(进入 expect(akaThisThing)
的参数作为您自定义函数的第一个参数。
对于一个通用的 Jest 消息扩展器,它可以适合您已经能够使用的任何 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;
会显示如下:
Error: expect(received).toEqual(expected) // deep equality
Expected: 26
Received: 13
Custom Message: Sad Message Indicating failure :(
具体查看 expect(actualObject).toBe() 以防万一有助于您的用例:
import diff from 'jest-diff'
expect.extend(
toBeMessage (received, expected, msg)
const pass = expected === received
const message = pass
? () => `$this.utils.matcherHint('.not.toBe')\n\n` +
`Expected value to not be (using ===):\n` +
` $this.utils.printExpected(expected)\n` +
`Received:\n` +
` $this.utils.printReceived(received)`
: () =>
const diffString = diff(expected, received,
expand: this.expand
)
return `$this.utils.matcherHint('.toBe')\n\n` +
`Expected value to be (using ===):\n` +
` $this.utils.printExpected(expected)\n` +
`Received:\n` +
` $this.utils.printReceived(received)` +
`$(diffString ? `\n\nDifference:\n\n$diffString` : '')\n` +
`$(msg ? `Custom:\n $msg` : '')`
return actual: received, message, pass
)
// usage:
expect(myThing).toBeMessage(expectedArray, ' was not actually the expected array :(')
【讨论】:
干得好;我为我的 Create-React-App 创建的应用程序将它添加到我的 setupTests.js 中,它解决了我所有的麻烦......【参考方案7】:另一种添加自定义错误消息的方法是使用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()
)
)
【讨论】:
【参考方案8】:我最终只是用逻辑测试条件,然后将fail()
与字符串模板一起使用。
即
it('key should not be found in object', () =>
for (const key in object)
if (Object.prototype.hasOwnProperty.call(object, key))
const element = object[key];
if (element["someKeyName"] === false)
if (someCheckerSet.includes(key) === false)
fail(`$key was not found in someCheckerSet.`)
【讨论】:
【参考方案9】:扩展@Zargold's answer:
如需更多选项,如下方
comment
,请参阅MatcherHintOptions doc
// custom matcher - omit expected
expect.extend(
toBeAccessible(received)
if (pass) return pass ;
return
pass,
message: () =>
`$this.utils.matcherHint('toBeAccessible', 'received', '',
comment: 'visible to screen readers',
)\n
Expected: $this.utils.printExpected(true)
Received: $this.utils.printReceived(false)`,
;
// custom matcher - include expected
expect.extend(
toBeAccessible(received)
if (pass) return pass ;
return
pass,
message: () =>
`$this.utils.matcherHint('toBeAccessible', 'received', 'expected', // <--
comment: 'visible to screen readers',
)\n
Expected: $this.utils.printExpected(true)
Received: $this.utils.printReceived(false)`,
;
【讨论】:
【参考方案10】:你可以使用这个:(你可以在测试中定义它)
expect.extend(
ToBeMatch(expect, toBe, Msg) //Msg is the message you pass as parameter
const pass = expect === toBe;
if(pass)//pass = true its ok
return
pass: pass,
message: () => 'No ERRORS ',
;
else//not pass
return
pass: pass,
message: () => 'Error in Field '+Msg + ' expect ' + ' ('+expect+') ' + 'recived '+'('+toBe+')',
;
, );
并像这样使用它
let z = 'TheMassageYouWantWhenErrror';
expect(first.name).ToBeMatch(second.name,z);
【讨论】:
【参考方案11】:您可以重写expect
断言以使用toThrow()
或not.toThrow()
。然后使用您的自定义文本引发错误。 jest
将在输出中包含自定义文本。
// Closure which returns function which may throw
function isValid (email)
return () =>
// replace with a real test!
if (email !== 'some@example.com')
throw new Error(`Email $email not valid`)
expect(isValid(email)).not.toThrow()
【讨论】:
【参考方案12】:我通常使用类似的东西
it('all numbers should be in the 0-60 or 180-360 range', async () =>
const numbers = [0, 30, 180, 120];
for (const number of numbers)
if ((number >= 0 && number <= 60) || (number >= 180 && number <= 360))
console.log('All good');
else
expect(number).toBe('number between 0-60 or 180-360');
);
产生:
【讨论】:
以上是关于如何将自定义消息添加到 Jest 期望?的主要内容,如果未能解决你的问题,请参考以下文章
使用stanza.io将自定义属性添加到不在服务器上的存档表中存储消息的消息
将自定义消息头添加到从 Windows Mobile 6 客户端使用的 WCF 服务