使用不可变数据结构时,Jest模拟函数参数不匹配

问题描述:

当试图使用Jest的.toHaveBeenCalledWith()方法测试传递给该函数的参数时,如果使用ImmutableJS库处理不可变数据结构,则测试失败。测试失败,类似这样的消息:使用不可变数据结构时,Jest模拟函数参数不匹配

Expected mock function to have been called with: 
    [{"foo": true, "bar": "baz"}] 
But it was called with: 
    [{"foo": true, "bar": "baz"}] 

测试类似于这样:

const expectedArgs = Map({ 
    foo: true, 
    bar: 'baz' 
}); 

const foo = jest.fn(); 
bar(); 
expect(foo).toHaveBeenCalledWith(expectedArgs); 

而类似这样的功能:

const bar =() => { 
    const baz = Map({}); 
    const bazModified = baz.set('foo', true).set('bar', 'baz'); 
    foo(bazModified); 
} 

我意识到,如果我以这种方式传递参数一切正常:

const bar =() => { 
    const baz = Map({ 
    foo: true, 
    bar: 'baz' 
    }); 
    foo(baz); 
} 

问题是,这是我的函数的逻辑大大简化,我不得不使用.set来构造对象。有没有人知道为什么.set方法无法正确评估?

所以你的测试失败了,因为toHaveBeenCalledWith只有在实体的实例完全相同时才会通过。它类似于以下,这也将失败:

const expectedArgs = Map({ 
    foo: true, 
    bar: 'baz' 
}); 

const input = Map({ 
    foo: false, 
    bar: 'baz' 
}); 

const result = input.set('foo', true); 

expect(result).toBe(expectedArgs); 

此,在另一方面,没有工作:

expect(result).toEqual(expectedArgs); 

由于执行了深刻的相等。

因为baz.set('foo', true)将始终返回一个新的实例(这是使用不可变数据的要点),所以您无法测试与toHaveBeenCalledWith的相等性。

我不认为有一种方式让toHaveBeenCalledWith表现得像toEqual,所以我猜要走的路是手动测试与toEqual模拟电话:

const expectedArgs = Map({ 
    foo: true, 
    bar: 'baz' 
}); 

const foo = jest.fn(); 
bar(); 
// foo.mock.calls[0][0] returns the first argument of the first call to foo 
expect(foo.mock.calls[0][0]).toEqual(expectedArgs); 

参见toBe的文件, 和mock calls