Jasmine spyOn: el método no existe en la función anónima de jQuery

He buscado la respuesta a este problema en SO y otros foros. No encontré la solución.

Estoy encontrando un problema donde Jasmine no puede encontrar una función dentro de un bloque de código jQuery, ya sea que el código Jasmine esté dentro de la función jQuery o no.

$(function() { function foo(param1, param2) { // some code } describe("Foo function", function () { spyOn(window, 'foo'); foo(1, 2); it("Should be found by Jasmine", function(){ expect(window.foo).toHaveBeenCalled(); }); }); }); Error: foo() method does not exist 

También he probado spyOn($, 'foo') , spyOn($.fn, 'foo') y otros.

Además, el siguiente código tampoco funciona.

 $(function() { function foo(param1, param2) { // some code } }); describe("Foo function", function () { spyOn(window, 'foo'); foo(1, 2); it("Should be found by Jasmine", function(){ expect(window.foo).toHaveBeenCalled(); }); }); 

Entonces, ¿cómo se puede hacer que funcionen estos dos bloques de código (es decir, donde el código Jasmine está dentro de la función jQuery y dónde está fuera de la función jQuery)?

Odio responder mi propia pregunta, pero prefiero eso que otras personas que no aprenden de mis errores.

Hay 2 temas aquí:

  1. Jasmine necesita un objeto contenedor.
  2. No puede acceder a funciones / variable fuera del scope de una función JS

1 – Los espías Jasmine necesitan usar un objeto contenedor, y si no se puede encontrar uno, solo necesitas hacerlo tú mismo. Así funciona el siguiente código:

 // Using Jasmine inside of a jQuery anon function $(function () { function foo() { // Some code } describe("Foo function", function () { it("Should be findable by Jasmine", function () { var Thing = {} Thing.foo = foo; spyOn(Thing, 'foo'); Thing.foo(2) expect(Thing.foo).toHaveBeenCalled(); }); }); }); 

2 – Si tiene el bloque de describe fuera de la función jQuery anon, no podrá acceder a ningún valor desde el bloque de jQuery, por lo que el segundo ejemplo de código anterior no funcionará, no importa lo que haga.

No estoy seguro de por qué necesitarías espías para funciones “privadas”. Puedes hacer la siguiente Demo .

 $(function(){ function foo() { return 'foo'; }; function baz() { return foo(); } describe('foo', function() { //create a spy and define it to change foo foo = jasmine.createSpy().andCallFake(foo); it('should be a function', function() { expect(typeof foo).toBe('function'); }); var result = baz(); //call function you want to test it('should be called', function() { expect(foo).toHaveBeenCalled(); //check if foo was called by baz }); //additional check for return since .andCallThrough won't work it('should return foo', function() { expect(result).toBe('foo'); }) }); }); 

Parece que solo necesitas configurar tu función jQuery de manera diferente. Tratar…

 (function ($) { $.fn.foo = function (param1, param2) { // some code }; }(jQuery)); 

y luego tu guión de jasmine se verá como …

 describe("Foo function", function () { var test = spyOn($.fn, 'foo'); $.fn.foo(1,2); it("Should be found by Jasmine", function(){ expect(test).toHaveBeenCalled(); expect(test).toHaveBeenCalledWith(1,2); }); });