Usando Jasmine para espiar una función sin un objeto

154

Soy nuevo en Jasmine y acabo de comenzar a usarlo. Tengo un archivo js de biblioteca con muchas funciones que no están asociadas con ningún objeto (es decir, son globales). ¿Cómo hago para espiar estas funciones?

Intenté usar window / document como objeto, pero el espía no funcionó aunque se llamó a la función. También intenté envolverlo en un objeto falso de la siguiente manera:

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

y prueba con

expect(fakeElement.fakeMethod).toHaveBeenCalled();

Esto tampoco funciona ya que el espía no funcionó

Chetter Hummin
fuente

Respuestas:

155

Si está definiendo su función:

function test() {};

Entonces, esto es equivalente a:

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

Entonces spyOn(window, 'test')debería funcionar.

Si eso no es así, también debería ser capaz de:

test = jasmine.createSpy();

Si ninguno de esos está funcionando, algo más está sucediendo con su configuración.

No creo que tu fakeElementtécnica funcione debido a lo que sucede detrás de escena. El globalMethod original todavía apunta al mismo código. Lo que hace el espionaje es su representación, pero solo en el contexto de un objeto. Si puede obtener su código de prueba para llamar a través de fakeElement, funcionaría, pero entonces podría renunciar a los archivos globales.

ndp
fuente
2
¡Funcionó! Creo que el error que estaba cometiendo anteriormente fue que estaba llamando a spyOn con method () en lugar de method. ¡Gracias!
Chetter Hummin
3
He tenido algunos problemas al usar spyOn (ventana, 'prueba') usando chutzpah para ejecutar las pruebas como parte de nuestra automatización debido a que no se ha asignado 'ventana'. El uso de jasmine.createSpy () solucionó esto.
Henners
77
jasmine.createSpy () funcionó perfectamente para mí. ¡Gracias!
dplass
1
solía test = jasmine.createSpy();espiar angularJs $anchroScrollfuncionó perfectamente
Edgar Martinez
1
Por alguna razón, no puedo obtener ninguna de las dos formas de trabajar, pero es muy posible que sea porque estoy tratando de simular una función de ventana existente; $window.open(url, '_blank');con la intención de abrir una nueva pestaña (o ventana dependiendo de la configuración del navegador). ¿Cómo debo hacer para asegurarme de que está llamando a esta función y verificar que está navegando a la URL correcta independientemente del navegador?
CSS
71

Usuarios de TypeScript:

Sé que el OP preguntó sobre javascript, pero para cualquier usuario de TypeScript que se encuentre con esto y quiera espiar una función importada, esto es lo que puede hacer.

En el archivo de prueba, convierta la importación de la función a partir de esto:

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

x = foo(y);

A esto:

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

x = FooFunctions.foo(y);

Entonces puedes espiar FooFunctions.foo:)

spyOn(FooFunctions, 'foo').and.callFake(...);
// ...
expect(FooFunctions.foo).toHaveBeenCalled();
Alexander Taylor
fuente
3
Gracias por la sugerencia de TypeScript. Debería ser igual para ES6 / Babel, pero no lo he probado.
hgoebl
1
Parece que solo funciona si se llama a la función explícitamente con el alias FooFunctions . Tengo una barra de función () que es una fábrica que devuelve baz () y quiero probar que baz () llama a foo (). Este método no parece funcionar en ese escenario.
Richard Matsen
44
Esto funcionará si el alias se toma dentro de foo_functions export const FooFunctions = { bar, foo }; y la importación en la prueba se convierte import { FooFunctions } from '../foo_functions'. Sin embargo, el alias aún debe usarse explícitamente dentro de la implementación privada de foo_functions para que el espía funcione. const result = FooFunctions.foo(params)// informes de espionaje llaman const result = foo(params)// espía reporta ninguna llamada
Richard Matsen
2
¡Trabajado como un encanto! ¡Gracias, me has ahorrado mucho tiempo!
SrAxi
1
Esto ya no funciona tiene unError: <spyOn> : parseCookie is not declared writable or has no setter
Ling Vu
42

Hay 2 alternativas que uso (para jazmín 2)

Este no es del todo explícito porque parece que la función es realmente falsa.

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

El segundo más detallado, más explícito y "más limpio":

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

-> código fuente de jazmín para ver el segundo argumento

IxDay
fuente
Esto tiene un poco más de sentido y lo separa lo suficiente como para duplicarlo con éxito. +1 de mi parte Gracias, C§
CSS
9

Una forma muy simple:

import * as myFunctionContainer from 'whatever-lib';

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

Esto funcionó para mí.

Sushil
fuente
44
Agregue una explicación a su respuesta, el código por sí solo no es tan útil para la persona que hace la pregunta si no puede entender lo que está sucediendo.
chevybow
0

Mi respuesta difiere ligeramente de @FlavorScape en que tenía una sola función (exportación predeterminada) en el módulo importado, hice lo siguiente:

import * as functionToTest from 'whatever-lib';

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