2017-08-17 56 views
2

我正在尝试在Jest中创建一个类似于stringMatching的自定义匹配器,但接受空值。但是,文档没有显示如何重用现有的匹配器。到目前为止,我有这样的事情:开玩笑的自定义匹配器

​​

我不知道这是这样做,因为我的时候我叫stringMatching匹配我不返回任何东西以正确的方式(这是建议here) 。当我尝试使用此匹配,我得到:expect.stringMatchingOrNull is not a function,即使这是在同一个测试案例声明:

expect(player).toMatchObject({ 
    playerName: expect.any(String), 
    rank: expect.stringMatchingOrNull(/^[AD]$/i) 
    [...] 
}); 

请,有人可以帮我显示正确的方式做到这一点?

我使用Jest 20.0.4和Node.js 7.8.0运行测试。

回答

2

有两种不同的方法与expect有关。当您拨打expect(value)时,您会收到一个包含匹配器的对象,您可以将它用于各种断言(例如,toBe(value),toMatchSnapshot())。其他类型的方法直接在expect上,这些方法基本上是辅助方法(expect.extend(matchers)就是其中之一)。

随着expect.extend(matchers)您添加第一种方法。这意味着它不能直接在expect上得到,因此你得到了错误。您需要按如下方式调用它:

expect(string).stringMatchingOrNull(regexp); 

但是,当您调用此函数时,将会发生另一个错误。

TypeError: expect(...).stringMatching is not a function 

这时候你正在尝试使用使用expect.stringMatching(regexp)作为匹配,但它是对expect辅助方法之一,它为您提供了将接受任何字符串值,将匹配一个伪值正则表达式。这使您可以使用它像这样:

expect(received).toEqual(expect.stringMatching(argument)); 
//  ^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
//  string     acts as a string 

当它失败这种说法只会扔,这意味着当它是成功的功能继续,什么都不会返回(undefined)和玩笑会抱怨说,你必须返回一个对象与pass和可选message

Unexpected return from a matcher function. 
Matcher functions should return an object in the following format: 
    {message?: string | function, pass: boolean} 
'undefined' was returned 

你需要考虑的最后一件事是在匹配器之前使用.not。当使用.not时,您还需要在自定义匹配器中创建的断言中使用.not,否则在错误通过时它会错误地失败。幸运的是,这是非常简单的,因为您可以访问this.isNot

expect.extend({ 
    stringMatchingOrNull(received, regexp) { 
     if (received === null) { 
      return { 
       pass: true, 
       message:() => 'String expected to be not null.' 
      }; 
     } 

     // `this.isNot` indicates whether the assertion was inverted with `.not` 
     // which needs to be respected, otherwise it fails incorrectly. 
     if (this.isNot) { 
      expect(received).not.toEqual(expect.stringMatching(regexp)); 
     } else { 
      expect(received).toEqual(expect.stringMatching(regexp)); 
     } 

     // This point is reached when the above assertion was successful. 
     // The test should therefore always pass, that means it needs to be 
     // `true` when used normally, and `false` when `.not` was used. 
     return { pass: !this.isNot } 
    } 
}); 

注意,message只所示,当断言没有得到正确的结果,所以最后return不需要的消息,因为它总是会通过。错误消息只能发生在上面。您可以通过running this example on repl.it查看所有可能的测试用例和产生的错误消息。

+0

糟糕!谢谢@迈克尔,我忘记写下这个匹配器的预期用法。我想用它作为'toMatchObject'匹配器内的一个辅助方法。我使用导致错误的代码段编辑了我的问题。从你的回答中,我认为使用'expect.extend'并不是正确的做法。有没有关于如何直接为'expect'编写helper函数的文档? – rober710

+2

我不认为有一种官方的方式来创建这种提供伪值的帮助方法。你可以尝试自己定义一个像['StringMatching'](https://github.com/facebook/jest/blob/64f8dbc541494327d2f375a515c3e04a7ff8ac6a/packages/jest-matchers/src/asymmetric_matchers.js#L209-L232)。无论哪种方式,值为'null'都表示有bug。如果你明确地将它设置为'null',你应该有单独的测试来覆盖这些场景,以确保它在你期望的时候只有'null'。测试一个值或'null'听起来就像你一起压缩多个测试。 –

0

我写了这个破解使用.toEqual内的.to...函数中的任何函数,包括用expect.extend添加的自定义函数。

class SatisfiesMatcher { 
    constructor(matcher, ...matcherArgs) { 
    this.matcher = matcher 
    this.matcherArgs = matcherArgs 
    } 
    asymmetricMatch(other) { 
    expect(other)[this.matcher](...this.matcherArgs) 
    return true 
    } 
} 
expect.expect = (...args) => new SatisfiesMatcher(...args) 

...

expect(anObject).toEqual({ 
    aSmallNumber: expect.expect('toBeLessThanOrEqual', 42) 
})