自定义对象格式化器

通过定义您自己的自定义对象格式化器,您可以自定义 Jasmine 在匹配器失败消息中描述您对象的的方式。自定义对象格式化器只是一个函数,如果它知道如何描述对象,则返回一个字符串,或者如果它不知道如何描述对象,则返回 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.

可以通过定义一个自定义对象格式化器来改善输出,该格式化器知道如何格式化单元格。如果不是单元格,则返回未定义。

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 + '>';
    }
}

然后,在 beforeEach 中注册自定义对象格式化器,以便 Jasmine 知道它。

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

现在 Jamsine 将在单元格出现在匹配器失败消息中的任何时候使用自定义对象格式化器

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
                };
            }
        }
    }
});