Pesquisa de site

javascript - Como verificar múltiplos argumentos em múltiplas chamadas para spies do jest?


Eu tenho a seguinte função em um componente React:

onUploadStart(file, xhr, formData) {
  formData.append('filename', file.name);
  formData.append('mimeType', file.type);
}

Este é o meu teste que pelo menos faz com que o espião seja chamado:

const formData = { append: jest.fn() };
const file = { name: 'someFileName', type: 'someMimeType' };
eventHandlers.onUploadStart(file, null, formData);

expect(formData.append).toHaveBeenCalledWith(
  ['mimeType', 'someMimeType'],
  ['fileName', 'someFileName']
);

No entanto, a afirmação não está funcionando:

Expected mock function to have been called with:
 [["mimeType", "someMimeType"], ["fileName", "someFileName"]]
But it was called with:
  ["mimeType", "someMimeType"], ["filename", "someFileName"]

Qual é a maneira correta de usar toHaveBeenCalledWith?

Resposta #1

Eu consegui simular várias chamadas e verificar os argumentos desta maneira:

expect(mockFn.mock.calls).toEqual([
  [arg1, arg2, ...], // First call
  [arg1, arg2, ...]  // Second call
]);

onde mockFn é o nome da sua função mockada.

Resposta #2

Desde o Jest 23.0 existe .toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....) https://jestjs.io/docs/expect#tohavebeennthcalledwithnthcall-arg1-arg2-

Também sob o pseudônimo: .nthCalledWith(nthCall, arg1, arg2, ...)

Se você tiver uma função mock, pode usar .toHaveBeenNthCalledWith para testar com quais argumentos ela foi chamada pela enésima vez. Por exemplo, digamos que você tenha uma função drinkEach(drink, Array<flavor>) que aplica f a diversos sabores, e você quer garantir que, quando chamá-la, o primeiro sabor com o qual ela opera seja 'limão' e o segundo seja 'polvo'. Você pode escrever:

test('drinkEach drinks each drink', () => {
  const drink = jest.fn();
  drinkEach(drink, ['lemon', 'octopus']);
  expect(drink).toHaveBeenNthCalledWith(1, 'lemon');
  expect(drink).toHaveBeenNthCalledWith(2, 'octopus');
});

Nota: o n-ésimo argumento deve ser um número inteiro positivo começando a partir de 1.

Resposta #3

Você também pode testar toHaveBeenCalledWith e testar várias vezes para cada combinação de parâmetros esperada.

Um exemplo é que a API do plugin Google Analytics usa a mesma chamada de função com diferentes combinações de parâmetros.

function requireGoogleAnalyticsPlugins() {
  ...
  ga('create', 'UA-XXXXX-Y', 'auto');
  ga('require', 'localHitSender', {path: '/log', debug: true});
  ga('send', 'pageview');
}

Para testar isso, o exemplo abaixo verifica que ga foi chamado três vezes com as várias combinações de parâmetros.

describe("requireGoogleAnalyticsPlugins", () => {
  it("requires plugins", () => {
    requireGoogleAnalyticsPlugins();
    expect(GoogleAnalytics.ga.toHaveBeenCalledTimes(3);
    expect(GoogleAnalytics.ga).toHaveBeenCalledWith('create', 'UA-XXXXX-Y', 'auto');
    expect(GoogleAnalytics.ga).toHaveBeenCalledWith('require', 'localHitSender', {path: '/log', debug: true});
    expect(GoogleAnalytics.ga).toHaveBeenCalledWith('send', 'pageview');
  });
});

No caso do OP, você poderia testar isso com

expect(formData.append).toHaveBeenCalledWith('mimeType', 'someMimeType');
expect(formData.append).toHaveBeenCalledWith('fileName', 'someFileName');

Resposta #4

A assinatura é .toHaveBeenCalledWith(arg1, arg2, ...), onde arg1, arg2, ... significa em uma chamada única (veja).

Se você quiser testar várias chamadas, basta expect várias vezes.

Infelizmente, ainda não encontrei um método para testar a ordem de várias chamadas.

Resposta #5

Você também pode criar um array dos argumentos esperados por chamada e percorrê-lo:

const expectedArgs = ['a', 'b', 'c', 'd']
expectedArgs.forEach((arg, index) => 
    expect(myFunc).toHaveBeenNthCalledWith(index + 1, arg))

Esta solução considera a ordem das chamadas. Se você não se importar com a ordem, pode usar toHaveBeenCalledWith sem o índice.

Artigos relacionados