J'ai écrit le test suivant:
it('Can decrement the current step', function () {
expect(reducer(TestState, { type: 'GOTO_PREVIOUS_STEP' })).toMatchObject({ currentStep: 4 });
});
it('Can decrement the current step v2', function () {
expect(reducer(TestState, { type: 'GOTO_PREVIOUS_STEP' })).toEqual(expect.objectContaining({ currentStep: 4 }));
});
les deux semblent passer le test, est-ce qu'il y a une différence entre eux? Y a-t-il un impact sur les performances entre eux?
En regardant les documents et mes propres expériences pour le confirmer, la différence réside dans le traitement des objets imbriqués dans les accessoires transmis comme une attente.
Si l'objet d'attente a une propriété, contenant un objet, contenant une partie mais pas la totalité des propriétés de la propriété équivalente de l'objet réel, alors:
toMatchObject passera toujours, comme on le voit dans la documentation .
expect.objectContaining va échouer (à moins que vous ne déclariez cette propriété dans l'objet expectation lui-même avec expect.objectContaining ())
Exemples (testés en Jest):
// objectContaining, with nested object, containing full props/values
// PASSES
expect({ position: { x: 0, y: 0 } }).toEqual(expect.objectContaining({
position: {
x: expect.any(Number),
y: expect.any(Number)
}
}));
// objectContaining, with nested object, containing partial props/values
// FAILS
expect({ position: { x: 0, y: 0 } }).toEqual(expect.objectContaining({
position: {
x: expect.any(Number)
}
}));
// objectContaining, with nested object, also declared with objectContaining, containing partial props/values
// PASSES
expect({ position: { x: 0, y: 0 } }).toEqual(expect.objectContaining({
position: expect.objectContaining({
x: expect.any(Number)
})
}));
// toMatchObject, with nested object, containing full props/values
// PASSES
expect({ position: { x: 0, y: 0 } }).toMatchObject({
position: {
x: expect.any(Number),
y: expect.any(Number)
}
});
// toMatchObject, with nested object, containing partial props/values
// PASSES
expect({ position: { x: 0, y: 0 } }).toMatchObject({
position: {
x: expect.any(Number)
}
});
Ma pensée est que expect.objectContaining (et d'autres correspondants similaires) peut être utilisé à la place des valeurs littérales à l'intérieur de "l'objet" que vous passez à d'autres correspondants.
Cet exemple provient de la documentation:
test('onPress gets called with the right thing', () => {
const onPress = jest.fn();
simulatePresses(onPress);
expect(onPress).toBeCalledWith(expect.objectContaining({
x: expect.any(Number),
y: expect.any(Number),
}));
});
Ainsi, bien qu'ils semblent faire la même chose dans votre exemple, les attendus. * Sont également utiles de cette autre manière.
Même sans différences fonctionnelles entre les deux constructions, voici un exemple de la raison pour laquelle expect.objectContaining
- bien que long et fastidieux par rapport à toMatchObject
, peut être utile:
describe('list of X', () => {
it('should contain an element with a specific ID', () => {
const listOfItems = uut.getItems();
expect(listOfItems).toContainEqual(expect.objectContaining({id: 'some-id'}));
});
});
Même si listOfItems
contient des éléments en tant que tels (c'est-à-dire avec des champs autres que le "id") -
[
{id: 'some-id', other: 'fields'},
{id: 'some-other-id', even: 'more-fields'}
]
toujours expect.objectContaining
permet un moyen simple d’implémenter la comparaison comme on peut s’y attendre (c’est-à-dire basé strictement sur l’id); toMatchObject
ne peut pas être utilisé ici. Ainsi, alors que toMatchObject
est court et lisible, la construction plus longue des deux est plus générique et permet une plus grande souplesse, car elle peut être utilisée de manière que toMatchObject()
ne peut pas.