120 votes

Quelle est la différence entre '.toMatchObject' et 'objectContaining' ?

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, y a-t-il une différence entre eux ? y a-t-il un impact sur les performances entre eux ?

176voto

jonathanconway Points 8307

D'après la documentation et mes propres expériences pour le confirmer, la différence réside dans la gestion des objets imbriqués dans les props transmis en tant qu'attente.

Si l'objet d'attente a une propriété, contenant un objet, qui contient certains mais pas tous des propriétés dans la propriété équivalente de l'objet réel, alors :

  • toMatchObject passe toujours, comme vu dans les docs .

  • expect.objectContaining échouera (sauf si vous déclarez 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)
    }
  });

32 votes

"Il n'y a que deux choses difficiles en informatique : l'invalidation du cache et le fait de nommer les choses".

0 votes

Mise à jour du lien vers les docs : jestjs.io/docs/expect#tomatchobjectobject

0 votes

Excellente réponse. Les noms de ces matchers sont à l'opposé de ce que je pensais initialement qu'ils seraient.

11voto

David Points 218

Je pense que expect.objectContaining ( et d'autres apparieurs comme lui ) peuvent être utilisés à la place des valeurs littérales à l'intérieur de l'"objet" que vous passez aux autres comparateurs.

Cet exemple est tiré 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),
  }));
});

Donc, bien qu'ils semblent faire la même chose dans votre exemple, la expect.* sont également utiles de cette autre manière.

8voto

und0 Points 6

Même sans les différences fonctionnelles entre les deux constructions, voici un exemple qui montre pourquoi expect.objectContaining - bien que longue et encombrante 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.-à-d. avec des champs autres que le simple "id")

[
  {id: 'some-id', other: 'fields'},
  {id: 'some-other-id', even: 'more-fields'}
]

todavía expect.objectContaining permet de mettre en œuvre la comparaison de la manière la plus simple qui soit (c'est-à-dire en se basant strictement sur l'identifiant) ; toMatchObject ne peut pas du tout être utilisé ici. Ainsi, alors que toMatchObject est courte et facile à lire, la construction la plus longue des deux est plus générique et permet une plus grande flexibilité puisqu'elle peut être utilisée de manières différentes. toMatchObject() ne peut pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X