Usando o Jasmine para espionar uma função sem um objeto

154

Eu sou novo no Jasmine e comecei a usá-lo. Eu tenho um arquivo js de biblioteca com muitas funções que não estão associadas a nenhum objeto (ou seja, são globais). Como faço para espionar essas funções?

Tentei usar a janela / documento como objeto, mas o espião não funcionou, mesmo que a função tenha sido chamada. Eu também tentei envolvê-lo em um objeto falso da seguinte maneira:

var fakeElement = {};
fakeElement.fakeMethod = myFunctionName;
spyOn(fakeElement, "fakeMethod");

e teste com

expect(fakeElement.fakeMethod).toHaveBeenCalled();

Isso também não funciona, pois o espião não funcionou

Chetter Hummin
fonte

Respostas:

155

Se você estiver definindo sua função:

function test() {};

Então, isso é equivalente a:

window.test = function() {}  /* (in the browser) */

Então spyOn(window, 'test')deve funcionar.

Caso contrário, você também deve ser capaz de:

test = jasmine.createSpy();

Se nenhum deles estiver funcionando, algo mais está acontecendo com sua configuração.

Não acho que sua fakeElementtécnica funcione por causa do que está acontecendo nos bastidores. O globalMethod original ainda aponta para o mesmo código. O que a espionagem faz é procurá-la, mas apenas no contexto de um objeto. Se você conseguir que seu código de teste chame o fakeElement, ele funcionaria, mas poderá renunciar ao fns global.

ndp
fonte
2
Funcionou! Acho que o erro que cometi anteriormente foi chamar o spyOn com method () em vez de method. Obrigado!
Chetter Hummin
3
Eu tive alguns problemas ao usar o spyOn (janela, 'teste') usando o chutzpah para executar os testes como parte de nossa automação devido ao fato de 'janela' não ser atribuída. O uso do jasmine.createSpy () contornou isso.
Henners
7
jasmine.createSpy () funcionou perfeitamente para mim. Obrigado!
Dplass
1
usado test = jasmine.createSpy();para espionar AngularJS $anchroScrollfuncionou perfeitamente
Edgar Martinez
1
Por alguma razão, não posso trabalhar de qualquer maneira, mas pode ser inteiramente possível que seja porque estou tentando simular uma função de janela existente; $window.open(url, '_blank');com a intenção de abrir uma nova guia (ou janela, dependendo da configuração do navegador). Como devo ter certeza de que está chamando essa função e verificando se está navegando para o URL certo, independentemente do navegador?
21915 CSS
71

Usuários do TypeScript:

Eu sei que o OP perguntou sobre javascript, mas para qualquer usuário TypeScript que se depare com isso que queira espionar uma função importada, eis o que você pode fazer.

No arquivo de teste, converta a importação da função a partir disso:

import {foo} from '../foo_functions';

x = foo(y);

Para isso:

import * as FooFunctions from '../foo_functions';

x = FooFunctions.foo(y);

Então você pode espionar FooFunctions.foo:)

spyOn(FooFunctions, 'foo').and.callFake(...);
// ...
expect(FooFunctions.foo).toHaveBeenCalled();
Alexander Taylor
fonte
3
Obrigado pela dica TypeScript. Deve ser igualmente o mesmo para ES6 / Babel, mas ainda não tentei.
Hgoebl 29/05
1
Parece que só funciona se chamar a função explicitamente com o alias FooFunctions . Eu tenho uma função bar () que é uma fábrica retornando baz () e quero testar se baz () chama foo (). Este método não parece funcionar nesse cenário.
Richard Matsen
4
Isso funcionará se o alias for colocado dentro de foo_functions export const FooFunctions = { bar, foo }; e a importação no teste se tornar import { FooFunctions } from '../foo_functions'. No entanto, o alias ainda precisa ser explicitamente usado na implementação privada de foo_functions para que o espião funcione. const result = FooFunctions.foo(params)// relatórios de espionagem chamar const result = foo(params)// espião relata nenhuma chamada
Richard Matsen
2
Trabalhou como um encanto! Obrigado, você me salvou muito tempo!
precisa saber é
1
Isso não está mais funcionando, tenho umError: <spyOn> : parseCookie is not declared writable or has no setter
Ling Vu
42

Há 2 alternativas que eu uso (para jasmim 2)

Este não é bem explícito, porque parece que a função é realmente falsa.

test = createSpy().and.callFake(test); 

O segundo mais detalhado, mais explícito e "mais limpo":

test = createSpy('testSpy', test).and.callThrough();

-> código fonte de jasmim para ver o segundo argumento

IxDay
fonte
Isso faz um pouco mais de sentido e o separa o suficiente para duplicar com sucesso. +1 de mim. Obrigado, C§
CSS
9

Uma maneira muito simples:

import * as myFunctionContainer from 'whatever-lib';

const fooSpy = spyOn(myFunctionContainer, 'myFunc');
FlavorScape
fonte
1
import * as saveAsFunctions from 'file-saver';
..........
....... 
let saveAs;
            beforeEach(() => {
                saveAs = jasmine.createSpy('saveAs');
            })
            it('should generate the excel on sample request details page', () => {
                spyOn(saveAsFunctions, 'saveAs').and.callFake(saveAs);
                expect(saveAsFunctions.saveAs).toHaveBeenCalled();
            })

Isso funcionou para mim.

Sushil
fonte
4
Por favor, adicione explicações à sua resposta, o código por si só não é útil para a pessoa que faz a pergunta se ela não consegue entender o que está acontecendo.
chevybow
0

Minha resposta difere um pouco do @FlavorScape, pois eu tinha uma única função (exportação padrão) no módulo importado, fiz o seguinte:

import * as functionToTest from 'whatever-lib';

const fooSpy = spyOn(functionToTest, 'default');
IonicBurger
fonte