Miomir Dancevic
Miomir Dancevic

Reputation: 6852

Unit test WebGL2RenderingContext angular jasmine

I have some guard like this guard.ts that just show error if webGl is disabled

import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';

import { NotificationService } from '../notification.service';

@Injectable()
export class WebGlGuard implements CanActivate {
  text: string;
  title: string;
  webGl: WebGL2RenderingContext;

  constructor(
    private translate: TranslateService,
    private notificationService: NotificationService) { }

  canActivate(): boolean {
    this.webGl = document.createElement('canvas').getContext('webgl2');
    this.translate.get('Notification.Status.NoWebGl').subscribe((message: string) => {
      this.title = this.translate.instant(message);
      this.text = this.translate.instant('Notification.Message.NoWebGl');
      if (!this.webGl) {
        this.notificationService.error(this.text, this.title);
      }
    });
    return true;
  }
}

And I need to unit test that guard.spec.ts like this

import { TestBed, async } from '@angular/core/testing';
import { TranslateService } from '@ngx-translate/core';
import {
  testingModule
} from '../utils/mocks';
import { WebGlGuard } from './web-gl.guard';
import { NotificationService } from '../notification.service';

let webGlGuard: WebGlGuard;
let notificationService: NotificationService;
let translateService: TranslateService;
// let spy: jasmine.Spy;

describe('WebGlGuard', () => {
  beforeEach(async(() => {
    const imports = testingModule.imports();

    TestBed.configureTestingModule({
      imports: [
        imports
      ],
      providers: [
        WebGlGuard,
        WebGL2RenderingContext,
        NotificationService,
        TranslateService
      ]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    webGlGuard = TestBed.inject(WebGlGuard);
    notificationService = TestBed.inject(NotificationService);
    translateService = TestBed.inject(TranslateService);
  });

  it('should show notification message if Web Gl is disabled', () => {
    // GIVEN
    const notification = spyOn(notificationService, 'error').and.callThrough();
    const translate = spyOn(translateService, 'get').and.callThrough();
    webGlGuard.webGl = null;
    // WHEN
    webGlGuard.canActivate();
    // THEN
    expect(translate).toHaveBeenCalled();
    expect(notification).toHaveBeenCalledTimes(1);
  });

  it('should show notification message if Web Gl is not disabled', () => {
    // GIVEN
    const notification = spyOn(notificationService, 'error').and.callThrough();
    const translate = spyOn(translateService, 'get').and.callThrough();
    webGlGuard.webGl = new WebGL2RenderingContext();
    // WHEN
    // THEN
    webGlGuard.canActivate();
    expect(translate).toHaveBeenCalled();
    expect(notification).toHaveBeenCalledTimes(0);
  });
});

But all test fails liek this Expected spy error to have been called once. It was called 0 times. and the second like this TypeError: Illegal constructor

Does somebody knows how to unit test webGl guard, thanks

Upvotes: 0

Views: 206

Answers (1)

AliF50
AliF50

Reputation: 18809

Your guard will always be returning true and the whole point of a guard is to allow and not allow access. I think you can move this code into a service and run it from there.

Check out the comments in both snippets, it should help I think.

import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';

import { NotificationService } from '../notification.service';

@Injectable()
export class WebGlGuard implements CanActivate {
  text: string;
  title: string;
  webGl: WebGL2RenderingContext;

  constructor(
    private translate: TranslateService,
    private notificationService: NotificationService) { 
   // !! move this line into the constructor so we can change it after
   // this guard is constructed in the unit test !!
   this.webGl = document.createElement('canvas').getContext('webgl2');
}

  canActivate(): boolean {
    this.translate.get('Notification.Status.NoWebGl').subscribe((message: string) => {
      this.title = this.translate.instant(message);
      this.text = this.translate.instant('Notification.Message.NoWebGl');
      if (!this.webGl) {
        this.notificationService.error(this.text, this.title);
      }
    });
    return true;
  }
}
import { TestBed, async } from '@angular/core/testing';
import { TranslateService } from '@ngx-translate/core';
import {
  testingModule
} from '../utils/mocks';
import { WebGlGuard } from './web-gl.guard';
import { NotificationService } from '../notification.service';

let webGlGuard: WebGlGuard;
let notificationService: NotificationService;
let translateService: TranslateService;
// let spy: jasmine.Spy;

describe('WebGlGuard', () => {
  beforeEach(async(() => {
    const imports = testingModule.imports();

    TestBed.configureTestingModule({
      imports: [
        imports
      ],
      providers: [
        WebGlGuard,
        WebGL2RenderingContext,
        NotificationService,
        TranslateService
      ]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    webGlGuard = TestBed.inject(WebGlGuard);
    notificationService = TestBed.inject(NotificationService);
    translateService = TestBed.inject(TranslateService);
  });

  it('should show notification message if Web Gl is disabled', () => {
    // GIVEN
    // !! Don't call through, we don't need it
    const notification = spyOn(notificationService, 'error');
    // !! Change this line
const translate = spyOn(translateService, 'get').and.returnValue(of('Hello world'));    
   webGlGuard.webGl = null;
    // WHEN
    webGlGuard.canActivate();
    // THEN
    expect(translate).toHaveBeenCalled();
    expect(notification).toHaveBeenCalledTimes(1);
  });

  it('should show notification message if Web Gl is not disabled', () => {
    // GIVEN
    // !! Don't call through, we don't need it
    const notification = spyOn(notificationService, 'error');
   // !! Change this line
    const translate = spyOn(translateService, 'get').and.returnValue(of('Hello world'));
    webGlGuard.webGl = new WebGL2RenderingContext();
    // WHEN
    // THEN
    webGlGuard.canActivate();
    expect(translate).toHaveBeenCalled();
    expect(notification).toHaveBeenCalledTimes(0);
  });
});

I am not sure how to fix illegal constructor. I am thinking we can't do webGlGuard.webGl = null. Maybe try = undefined.

Upvotes: 0

Related Questions