カスタムオブジェクトフォーマッター

独自のオブジェクトフォーマッターを定義して、オブジェクトを比較器の失敗メッセージでどのように記述するかをカスタマイズできます。カスタムオブジェクトフォーマッターは、オブジェクトの記述方法を知っている場合は文字列を返したり、知らない場合は undefined を返すだけの関数です。

たとえば、細胞が expectedcorrectValue プロパティを持つオブジェクトとしてモデル化される数独ゲームに関するこのテストを見てみましょう

it('compares some cells', function() {
    const expectedCells = [
        {correctValue: 4, entry: null},
        {correctValue: 1, entry: {pencil: true, numbers: [1, 2]}},
        {correctValue: 5, entry: {pencil: false, number: 3}}
    ];
    const actualCells = [
        {correctValue: 4, entry: null},
        {correctValue: 1, entry: {pencil: false, number: 2}},
        {correctValue: 5, entry: {pencil: false, number: 4}}
    ];

    expect(actualCells).toEqual(expectedCells);
});

この仕様は、次のメッセージで失敗します

Expected $[1].entry to have properties
    numbers: [ 1, 2 ]
Expected $[1].entry not to have properties
    number: 2
Expected $[1].entry.pencil = false to equal true.
Expected $[2].entry.number = 4 to equal 3.

セルのフォーマット方法を知るカスタムオブジェクトフォーマッターを定義することで、出力を改善できます。値がセルでない場合、undefined を返します。

function formatCell(val) {
    if (val.hasOwnProperty('entry') && val.hasOwnProperty('correctValue')) {
        const entries = val.entry.pencil
            ? 'pencil entries: ' + val.entry.numbers.join(',')
            : 'entry: ' + val.entry.number;

        return '<cell ' + entries + ', correct: ' + val.correctValue + '>';
    }
}

次に、Jasmine に認識させるために beforeEach にカスタムオブジェクトフォーマッターを登録します。

beforeEach(function() {
    jasmine.addCustomObjectFormatter(formatCell);
});

これで、セルが比較器の失敗メッセージに表示されるたびに、Jasmine はカスタムオブジェクトフォーマッターを使用します

Expected $[1] = <cell entry: 2, correct: 1> to equal <cell pencil entries: 1,2, correct: 1>.
Expected $[2] = <cell entry: 4, correct: 5> to equal <cell entry: 3, correct: 5>.

カスタムオブジェクトフォーマッターを使用するには、カスタム比較器MatchersUtil#pp を使用して失敗メッセージの期待値と実際の値を記述するか、Jasmine で message プロパティを指定せずに結果オブジェクトを返すことでメッセージを生成させる必要があります。

jasmine.addMatchers({
    // OK: Jasmine will format expected and actual correctly.
    toBeFoo: function (matchersUtil) {
        return {
            compare: function (actual, expected) {
                return {
                    pass: matchersUtil.equals(actual, expected)
                };
            }
        }
    },

    // OK: Uses pp to format expected and actual.
    toBeBar: function (matchersUtil) {
        return {
            compare: function (actual, expected) {
                return {
                    pass: matchersUtil.equals(actual, expected),
                    message: 'Expected ' + matchersUtil.pp(actual) + ' to be bar like ' + 
                        matchersUtil.pp(expected)
                };
            }
        }
    },

    // Won't use custom object formatters.
    toBeBaz: function (matchersUtil) {
        return {
            compare: function (actual, expected) {
                return {
                    pass: matchersUtil.equals(actual, expected),
                    message: 'Expected ' + actual + ' to be baz like ' + expected
                };
            }
        }
    }
});