9

Consider this code:

import {
    Component,
    OnInit,
    Renderer,
    OnDestroy
  } from '@angular/core';

  import { TranslateService } from 'ng2-translate/ng2-translate';

  export class AppComponent implements OnInit, OnDestroy {

  constructor( private translate: TranslateService, renderer: Renderer ) {
    this.globalKeyListenFunc = renderer.listenGlobal('document', 'keydown', (event) => {
      if (event.keyCode === 18) { // ALT-Key
        event.preventDefault();
      }
    });
    ...
  }

How can I test such a component with a jasmine test?

I tried following test:

describe('App', () => {
  let injector: Injector;
  let backend: MockBackend;
  let connection: MockConnection;
  let translate: TranslateService;
  let renderer: Renderer;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpModule, TranslateModule.forRoot()],
      providers: [
        AppComponent,
        {provide: XHRBackend, useClass: MockBackend},
        Renderer
      ]
    });
    injector = getTestBed();
    backend = injector.get(XHRBackend);
    translate = injector.get(TranslateService);
    renderer= injector.get(Renderer);
    backend.connections.subscribe((c: MockConnection) => connection = c);

  });


  it('should have fore languages', inject([ AppComponent ], (app: AppComponent) => {
    app.ngOnInit();
    expect(app.supportedLanguages.length).toBe(4);
  }));

The error I get:

TypeError: undefined is not a constructor (evaluating 'renderer.listenGlobal') in config/spec-bundle.js

It seams that the Renderer instance has not the same behavior as in a real browser environment. As usual in a CI environment, I am using the PhantomJS browser to execute the test.

Mat Ro
  • 103
  • 1
  • 7
  • What do you want to test? – Günter Zöchbauer Oct 22 '16 at 20:45
  • I only like to write a simple test for the component. I am able to mock the TranslateService but I am not able to inject any kind of Renderer. I did not found any example how the create a instance of a Renderer in a jasmine test. – Mat Ro Oct 22 '16 at 21:49
  • Doesn't look like there is anything special required in https://angular.io/docs/ts/latest/guide/testing.html#!#attribute-directive – Günter Zöchbauer Oct 22 '16 at 21:55
  • I need an example how to get a instance of an Renderer (@angular/core) class or a mock to inject it to the constructor. If it is so simple pleas show me how to get in an jasmine test a Renderer instance of the proper type... – Mat Ro Oct 23 '16 at 09:28
  • I don't get what the problem is. Do you get an error message with your above code? What about ` it('test renderer', inject([Renderer], (renderer: Renderer) => { `? – Günter Zöchbauer Oct 23 '16 at 10:27
  • Show at the code. Perhaps it is more clear what I like to do: code is to long see next Answer... – Mat Ro Oct 23 '16 at 12:14
  • I think you need to add `AppComponent` to `declarations` in `TestBed.configureTestingModule(...)` and remove `Renderer` and `AppComponent` from `providers`. – Günter Zöchbauer Oct 24 '16 at 04:39

1 Answers1

0

This should be working with Angular 6+

In your component.spec.ts

let renderer2: Renderer2;
...
beforeEach(async( () => {
   TestBed.configureTestingModule({
      ...
      providers: [Renderer2]
   }).compileComponents();
}));

beforeEach(() => {
   fixture = TestBed.createComponent(YourComponent);
   // grab the renderer
   renderer2 = fixture.componentRef.injector.get<Renderer2>(Renderer2 as Type<Renderer2>);
   // and spy on it
   spyOn(renderer2, 'addClass').and.callThrough();
   // or replace
   spyOn(renderer2, 'addClass').and.callFake(..);
   // etc
});

it('should call renderer', () => {
    expect(renderer2.addClass).toHaveBeenCalledWith(jasmine.any(Object), 'css-class');
});
General Grievance
  • 4,555
  • 31
  • 31
  • 45
GKA
  • 1,230
  • 1
  • 15
  • 15
  • 2
    It does not work if you are testing a directive. you cannot use fixture create component – Laura Liparulo Nov 27 '18 at 15:44
  • @LauraLiparulo the question was about a component. To test the directive you just follow the pattern for testing directives: create a dummy host component that uses your directive. You can get the Renderer2 instance the same way. – GKA Dec 27 '18 at 19:30