使组件测试具有正文或模拟Renderer2

时间:2018-02-16 12:07:23

标签: angular jasmine

在我们的一个组件中,我们使用Renderer2向body元素添加和删除一些css类/样式。为此,我们只需执行以下操作:

this.renderer.setStyle(document.body, 'padding-left', '10px');
this.renderer.addClass(document.body, 'modal-container--opened');

一旦我们运行测试,我们就会遇到错误:

  

无法读取未定义

的属性'add'      

无法设置未定义

的属性'padding-left'

因此,似乎角度testBed不会创建任何body元素。

在我们的测试配置中,如何创建模拟的body元素?因此,我们可以针对该元素运行测试,并查看渲染器是否正确应用了样式/类。

似乎也无法模仿Renderer2。

我们试图创建一个间谍:

let renderer: jasmine.SpyObj<Renderer2>;
renderer = jasmine.createSpyObj('renderer', ['addClass', 'removeClass', 'setStyle']);

然后在TestBed.configureTestingModule中(也在overrideProviders进行了测试,但未获得更多成功):

{ provide: Renderer2, useValue: renderer }

但是Angular完全忽略了这种覆盖。

如何测试我们的组件行为,对document.body采取行动?

2 个答案:

答案 0 :(得分:4)

为什么删除答案? 它确切说明了如何实现所需的行为?

与其嘲笑渲染器,不如尝试劫持它……

这应该适用于Angular 6 +

在您的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');
});

答案 1 :(得分:2)

其他方法是模拟服务:

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');
});