2017-08-17 55 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) 
})