web-dev-qa-db-fra.com

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

15
Julito Sanchis

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

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.

3
David

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.

0
d4vidi