How to fix function has already been spied on error in Jasmine
Asked Answered
D

2

10

I have 3 tests, each testing various methods.

it('test function1', function() {
   spyOn(document, 'getElementById');
   // ... some code to test function1
   expect(document.getElementById).toHaveBeenCalled();

 });

it('test function2', function() {
   spyOn(document, 'getElementById');
   // ... some code to test function2
   expect(document.getElementById).toHaveBeenCalled();

 });

it('test function3', function() {
   spyOn(document, 'getElementById');
   // ... some code to test function3
   expect(document.getElementById).toHaveBeenCalled();    
 });

But when I run these tests I get the following error: getElementById has already been spied upon. Can someone explain why am I getting this error even when spies are in different test suites and how to fix it.

Duncan answered 13/5, 2019 at 18:50 Comment(3)
Why are you spying on and testing native JS/browser code? I think it's safe to expect that these functions will work when they are called.Quadruplet
Because test does not load the HTML file, so document.getElementById('').style etc in js file will throw error.Duncan
You should probably instead test for the existence of a certain element rather than testing that native browser code was called or not.Quadruplet
M
5

Once you spy on a method once, you cannot spy on it again. If all you want to do is check to see if it's been called in each test, just create the spy at the beginning of the test, and reset the calls in afterEach:

     spyOn(document, 'getElementById');

     afterEach(() => {
       document.getElementById.calls.reset();
     });

     it('test function1', function() {
       // ... some code to test function1
       expect(document.getElementById).toHaveBeenCalled();

     });

    it('test function2', function() {
       // ... some code to test function2
       expect(document.getElementById).toHaveBeenCalled();

     });

    it('test function3', function() {
       // ... some code to test function3
       expect(document.getElementById).toHaveBeenCalled();    
     });
Madalena answered 13/5, 2019 at 18:57 Comment(1)
Just to clarify, you can spy on a method of a single object only once.Incest
S
12

Its late to reply but, if someone is trying to spyon same function multiple times but with different return value you could use

it('test function', function() {
   // spy and return data
   spyOn(serviceName,'functionName').and.returnValue(data);
   expect(serviceName.functionName).toHaveBeenCalled();
   
   // spy and return newData
   serviceName.functionName = jasmine.createSpy().and.returnValue(newData);
   expect(serviceName.functionName).toHaveBeenCalled();
});
Stodder answered 12/4, 2022 at 11:41 Comment(1)
This does not work for a property getterSusi
M
5

Once you spy on a method once, you cannot spy on it again. If all you want to do is check to see if it's been called in each test, just create the spy at the beginning of the test, and reset the calls in afterEach:

     spyOn(document, 'getElementById');

     afterEach(() => {
       document.getElementById.calls.reset();
     });

     it('test function1', function() {
       // ... some code to test function1
       expect(document.getElementById).toHaveBeenCalled();

     });

    it('test function2', function() {
       // ... some code to test function2
       expect(document.getElementById).toHaveBeenCalled();

     });

    it('test function3', function() {
       // ... some code to test function3
       expect(document.getElementById).toHaveBeenCalled();    
     });
Madalena answered 13/5, 2019 at 18:57 Comment(1)
Just to clarify, you can spy on a method of a single object only once.Incest

© 2022 - 2024 — McMap. All rights reserved.