Tilak Raj
Tilak Raj

Reputation: 145

Mock document.querySelectorAll() in angular test Case

I have following code in my method, which removes particular class from the fullcalendar events and do someother things after that.

 someMethod() {
   let events = document.querySelectorAll(`.calendar-event`);
   events.forEach((event) => {
     event.classList.remove('calendar-read-event');
   });
   //dosomething
  }

When running the test cases due to some reason the fullcalendar is not displayed and when i call this method i am getting error

'Cannot read property 'forEach' of undefined'

This is because calendar-event class is not loaded yet and i am getting no result for querySelectorAll() , Is there a way to spyon document.querySelectorAll() and return some value.

Something like this in beforeEach method:

spyOn(document, 'querySelectorAll').and.returnValue(NodeList);

Have tried this but its not stubbing the value and I am still getting 'Cannot read property 'forEach' of undefined' error

Upvotes: 2

Views: 12941

Answers (1)

Jason White
Jason White

Reputation: 5833

Instead of using the document directly, Angular has a token (DOCUMENT in @angular/common) to inject the document using DI.

import { DOCUMENT } from '@angular/common';

@Component({...}) // could be a service too!
export class MyComponent {
  constructor (@Inject(DOCUMENT) private document: Document) {}

  // Reference this.document instead of document.
  someMethod() {
    let events = this.document.querySelectorAll(`.calendar-event`);
    events.forEach((event) => {
      event.classList.remove('calendar-read-event');
    });
  }
}

Then in your test you can mock the document and provide it as a dependency. This way your test and the component will reference the same document instance.

import { DOCUMENT } from '@angular/common';

describe('MyComponent', () => {
  const mockDocument = jasmine.createSpyObject('Document', ['querySelectorAll'])

  beforeEach(() => {
    TestBed.configureTestingModule({
      // Your other stuff here
      providers: [{ provide: DOCUMENT, useValue: mockDocument }]
    });
  });

Note: The above code is untested and may not be 100% correct. It's meant to give you an idea as to how to approach the issue.

https://medium.com/ngconf/how-to-inject-document-in-angular-7d17804430b6

Upvotes: 4

Related Questions