Can't provide mock for Renderer during component tests

See original GitHub issue

I’m submitting a … (check one with “x”)

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

I Have a component which uses the Renderer via dependency injection. In my component test I provide Renderer mock instead of the real one. When running the test, the real Renderer is being injected instead of my mock (DebugDomRenderer).

Expected behavior

Renderer mock should be injected during the component test instead of the real one.

Minimal reproduction of the problem with instructions

  1. Use the Renderer in component via DI:
import { Component, ElementRef, Renderer } from '@angular/core';

  @Component({
    selector: 'app-main',
    templateUrl: './main.component.html',
    styleUrls: ['./main.component.less']
  }) export class MainComponent {
    @Input() globalInputRef: ElementRef;
    constructor(private renderer:Renderer) {
    }
    setColor() {
      this.renderer.setElementStyle(this.globalInputRef.nativeElement, 'backgroundColor', 'yellow');
    }
  }
  1. Create renderer mock with spies, inject it on tests:
describe('Main component tests', () => {
    let fixture: ComponentFixture<MainComponent>,
        component: MainComponent;

    const rendererMock = jasmine.createSpyObj('rendererMock', ['setElementStyle']); 

    beforeEach(done => {
        TestBed.configureTestingModule({
            declarations: [MainComponent],
            schemas: [NO_ERRORS_SCHEMA]
        }).overrideComponent(MainComponent, {
            set: {
                providers: [
                                     {provide: Renderer, useValue: rendererMock}
                                   ]
            }
        });

        TestBed.compileComponents().then(() => {
            fixture = TestBed.createComponent(MainComponent);
            component = fixture.componentInstance;
            done();
        });
    });

    it('should inject renderer mock', () => {
         component.globalInputRef = {nativeElement: 'nativeElement'};
         component.setColor();
        expect(rendererMock.setElementStyle).toHaveBeenCalled();
    });
});

Karma fails because it tries to call real functions from the real Renderer (DebugDomRenderer).

Workaround: Inject the Injector, and use it to inject the Renderer: in MainComponent class:

constructor(injector:Injector) {
   this.renderer = injector.get(Renderer);
}

What is the motivation / use case for changing the behavior?

Isolating my component from outer services/modules during tests.

Please tell us about your environment:

OS: macOS Sierra 10.12.1 IDE: WebStorm npm: v4.1.1

  • Angular version: 2.1.0
  • Browser: all
  • Language: TypeScript 2.0.7

  • Node (for AoT issues): node --version = v6.9.2

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

4reactions
nabilnaffarcommented, Mar 21, 2017

@DzmitryShylovich Thanks for the quick respond! I ended up creating my own custom renderer with spies for tests.

let rendererMock = jasmine.createSpyObj('rendererMock', ['selectRootElement',
        'createElement',
        'createViewRoot',
        'createText',
        'setElementProperty',
        'setElementAttribute',
        'setText',
        'setBindingDebugInfo',
        'createTemplateAnchor',
        'projectNodes',
        'attachViewAfter',
        'detachView',
        'destroyView',
        'listen',
        'listenGlobal',
        'setElementClass',
        'setElementStyle',
        'invokeElementMethod',
        'animate']);

    let rootRendererMock =  {
        renderComponent: () => {
            return rendererMock;
        }
    };

    TestBed.configureTestingModule({
            declarations: [MainComponent],
            schemas: [NO_ERRORS_SCHEMA],
            providers: [
                { provide: RootRenderer, useValue: rootRendererMock }
            ]
        });

3reactions
gkamperiscommented, Aug 31, 2018

The above did not work for me on Angular v6.

Instead of mocking the renderer try to hijack it…

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');
});
Read more comments on GitHub >

github_iconTop Results From Across the Web

Testing React components - Apollo GraphQL Docs
The MockedProvider component enables you to define mock responses for individual queries that are executed in your test. This means your test doesn't...
Read more >
Jest Mock React Component ONLY in some tests
the component you want to mock in one of tests. Use jest. ... import React from 'react' import { render } from '@testing-library/react' ......
Read more >
How To Mock A React Component In Jest | Rob Marshall
To mock a React component within Jest you should use the `jest.mock` function. The file that exports the specific component is mocked and ......
Read more >
Advanced React Component Mocks with Jest and ... - Eric Cobb
The answer is to use jest to set up up your mock, then before you run your tests, change the implementation of your...
Read more >
How To Mock A React Component In Jest - Chak Shun Yu
Testing is one of the most important aspects to React development. Without tests, you can't have confidence that your code will work as...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found