Utiliser Jasmine pour espionner une fonction sans objet

154

Je suis nouveau sur Jasmine et je viens de commencer à l'utiliser. J'ai un fichier de bibliothèque js avec beaucoup de fonctions qui ne sont associées à aucun objet (c'est-à-dire globales). Comment espionner ces fonctions?

J'ai essayé d'utiliser window / document comme objet, mais l'espion ne fonctionnait pas même si la fonction était appelée. J'ai également essayé de l'envelopper dans un faux objet comme suit:

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

et tester avec

expect(fakeElement.fakeMethod).toHaveBeenCalled();

Cela ne fonctionne pas non plus car l'espion n'a pas fonctionné

Chetter Hummin
la source

Réponses:

155

Si vous définissez votre fonction:

function test() {};

Ensuite, cela équivaut à:

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

Donc spyOn(window, 'test')devrait fonctionner.

Si ce n'est pas le cas, vous devriez également pouvoir:

test = jasmine.createSpy();

Si aucun de ceux-ci ne fonctionne, il se passe autre chose avec votre configuration.

Je ne pense pas que votre fakeElementtechnique fonctionne à cause de ce qui se passe dans les coulisses. Le globalMethod d'origine pointe toujours vers le même code. Ce que fait l'espionnage, c'est le proxy, mais uniquement dans le contexte d'un objet. Si vous pouvez faire appeler votre code de test via le fakeElement, cela fonctionnerait, mais vous pourrez alors abandonner les fns globales.

ndp
la source
2
Ça a marché! Je pense que l'erreur que je faisais plus tôt était que j'appelais le spyOn avec method () au lieu de method. Merci!
Chetter Hummin
3
J'ai eu quelques problèmes en utilisant spyOn (window, 'test') en utilisant chutzpah pour exécuter les tests dans le cadre de notre automatisation car 'window' n'était pas assigné. L'utilisation de jasmine.createSpy () a contourné ce problème.
Henners
7
jasmine.createSpy () a parfaitement fonctionné pour moi. Merci!
dplass
1
utilisé test = jasmine.createSpy();pour espionner angularJs $anchroScrollfonctionnait parfaitement
Edgar Martinez
1
Pour une raison quelconque, je ne peux pas travailler dans les deux sens, mais il est peut-être tout à fait possible que ce soit parce que j'essaie de simuler une fonction de fenêtre existante; $window.open(url, '_blank');avec l'intention d'ouvrir un nouvel onglet (ou une fenêtre selon la configuration du navigateur). Comment dois-je m'assurer qu'il appelle cette fonction et vérifier qu'elle navigue vers la bonne URL quel que soit le navigateur?
CSS
71

Utilisateurs de TypeScript:

Je sais que l'OP a posé des questions sur javascript, mais pour tous les utilisateurs de TypeScript qui rencontrent ce problème et qui souhaitent espionner une fonction importée, voici ce que vous pouvez faire.

Dans le fichier de test, convertissez l'importation de la fonction à partir de ceci:

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

x = foo(y);

Pour ça:

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

x = FooFunctions.foo(y);

Ensuite, vous pouvez espionner FooFunctions.foo:)

spyOn(FooFunctions, 'foo').and.callFake(...);
// ...
expect(FooFunctions.foo).toHaveBeenCalled();
Alexander Taylor
la source
3
Merci pour l'astuce TypeScript. Cela devrait être pareil pour ES6 / Babel, mais je ne l'ai pas essayé.
hgoebl
1
Il semble que cela ne fonctionne que si vous appelez la fonction explicitement avec l'alias FooFunctions . J'ai une fonction bar () qui est une usine retournant baz () et je veux tester que baz () appelle foo (). Cette méthode ne semble pas fonctionner dans ce scénario.
Richard Matsen
4
Cela fonctionnera si l'alias est pris dans foo_functions export const FooFunctions = { bar, foo }; et que l'importation dans le test devient import { FooFunctions } from '../foo_functions'. Cependant, l'alias doit toujours être utilisé explicitement dans l'implémentation privée de foo_functions pour que l'espion fonctionne. const result = FooFunctions.foo(params)// espion rapporte un appel const result = foo(params)// espion rapporte aucun appel
Richard Matsen
2
A travaillé comme un charme! Merci, tu m'as fait gagner beaucoup de temps!
SrAxi
1
Cela ne fonctionne plus obtenu unError: <spyOn> : parseCookie is not declared writable or has no setter
Ling Vu
42

Il y a 2 alternatives que j'utilise (pour jasmin 2)

Celui-ci n'est pas tout à fait explicite car il semble que la fonction soit en fait un faux.

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

La seconde plus verbeuse, plus explicite et "plus propre":

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

-> code source jasmine pour voir le deuxième argument

IxDay
la source
Cela a un peu plus de sens et éclate assez loin pour se reproduire avec succès. +1 de moi. Merci, C§
CSS
9

Une manière très simple:

import * as myFunctionContainer from 'whatever-lib';

const fooSpy = spyOn(myFunctionContainer, 'myFunc');
FlavourScape
la source
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();
            })

Cela a fonctionné pour moi.

Sushil
la source
4
Veuillez ajouter une explication à votre réponse, le code en lui-même n'est pas très utile pour la personne qui pose la question si elle ne comprend pas ce qui se passe.
chevybow
0

Ma réponse diffère légèrement de @FlavorScape en ce que j'avais une seule fonction (exportation par défaut) dans le module importé, j'ai fait ce qui suit:

import * as functionToTest from 'whatever-lib';

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