In one of our component, we use Renderer2 to add and remove some css classes/styles to the body element. To achieve that, we simply do something like:
this.renderer.setStyle(document.body, 'padding-left', '10px');
this.renderer.addClass(document.body, 'modal-container--opened');
As soon as we run the tests, we encounter errors:
Cannot read property 'add' of undefined
Cannot set property 'padding-left' of undefined
So it seems angular testBed doesn't create any body element.
In our test configuration, how to create a mocked body element? So we can run our tests against that element and see if style/class was properly applied by renderer.
It also seems mocking the Renderer2 is not possible.
We tried to create a spy:
let renderer: jasmine.SpyObj<Renderer2>;
renderer = jasmine.createSpyObj('renderer', ['addClass', 'removeClass', 'setStyle']);
then in TestBed.configureTestingModule (also tested in overrideProviders without more success):
{ provide: Renderer2, useValue: renderer }
But Angular ignores completely this override.
How to be able to test our component behavior, acting on document.body?
To run your tests using the Angular CLI, you use the ng test command in your terminal. As a result, Karma will open up the default browser and run all the tests written with the aid of Jasmine and will display the outcome of those tests.
A mock component in Angular tests can be created by MockComponent function. The mock component respects the interface of its original component, but all its methods are dummies. To create a mock component, simply pass its class into MockComponent function.
The Angular fixture provides the component's element directly through the fixture. nativeElement . content_copy const bannerElement: HTMLElement = fixture.
Mocking is the act of creating something that looks like the dependency but is something we control in our test. There are a few methods we can use to create mocks.
Instead of mocking the renderer try to hijack it. 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');
});
Other approach would be, mocking service:
let renderer: MockRenderer;
class MockRenderer {
addClass(document: string, cssClass: string): boolean {
return true;
}
}
beforeEach(async( () => {
TestBed.configureTestingModule({
...
providers: [{
provide: Renderer2,
useClass: MockRenderer
}]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(YourComponent);
renderer = fixture.debugElement.injector.get(Renderer2);
});
}));
...
it('should call render', () => {
spyOn(renderer, 'addClass');
...
expect(renderer.addClass).toHaveBeenCalledWith(jasmine.any(Object), 'css-class');
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With