Angular 4/5 Render2茉莉花测试

问题描述 投票:1回答:2

我有一个接口,意图根据输入参数对象操作DOM元素。我想先写单元测试。我们的想法是使用Angular中提供的Render2。

export interface ModifyDomTree {
    modify(data: SomeData) : ElementRef;
}

这是实现(不知道这将如何出现),但为它编写测试。

export class ModifyDomTreeImpl implements ModifyDomTree {
   constructor(private render: Renderer2) {
   }
   modify(data: SomeData) : ElementRef{
        return null;
   }
}

在测试中我不想使用Renderer2的模拟我想使用Angular将使用的实际Renderer2。如何在测试中注入或实例化实际的Angular Render2?

规范将是

describe('ModifyDomTreeImpl', () => {
let data: SomeData;
let modifyDomTree: ModifyDomTree;

beforeEach(() => {
    //let render: Renderer2 = mock(Renderer2); ?? How Do I inject the real Angular thing here
    modifyDomTree = new ModifyDomTreeImpl(render);
});

it('should convert a data into a text node', () => {
   data = mock(SomeData);
   when(data.value).thenReturn('Groot!!');
   const result: ElementRef = modifyDomTree.convert(data);
   expect(result).toBeDefined();
   expect(result).not.toBeNull();
   expect(result.nativeElement).toBeDefined();
   expect(result.nativeElement).toBeDefined();
   expect(result.nativeElement.childNodes).toBeDefined();
   expect(result.nativeElement.childNodes.length).toEqual(1);
   expect(result.nativeElement.childNodes.length[0]).toEqual('text');
   expect(result.nativeElement.childNodes.length[0].data).toEqual('Groot!!');
  });
});
angular typescript angular5
2个回答
0
投票

用角度声音直接操作DOM元素是一个非常糟糕的主意。我首先尝试理解我真正想要实现的目标,并且如果有更好的方法来实现它,那么动态修改dom。角度的基础是直接避免DOM操作

我理解这可能不容易理解......所以,你必须考虑实现中的组件。在这种情况下,您有一些案例和一些适合这些案例的组件(或者有一些选项)。 div / css中提供了所有选项。但是仅在需要时启用/可见(模板中的ngIf条件)。想想你已经实现了所有可用的选项,只有自定义。在这种情况下,这并不禁止实现DOM操作(通过角度)仅用于在页面创建/或服务更新时创建不同类型的组件:

例:

import { Component, OnInit , ComponentFactoryResolver, ViewContainerRef, ViewChild} from '@angular/core';

import { NicolabelComponent } from './nicolabel/nicolabel.component';


@Component({
  selector: 'app-nicoview',
  templateUrl: '
  <button (click)="addNicoLabel()">Add </button>
  <div #mydiv style="width:100px;height:200px">;
  </div>
',
  styles: []
})
export class NicoviewComponent implements OnInit {
  @ViewChild('mydiv', {read: ViewContainerRef}) mydiv;

  labels: NicolabelComponent[] = [];

  ngOnInit() {

  }
 // `ViewContainerRef` from the component itself
  constructor(private viewContainerRef:ViewContainerRef, private componentFactoryResolver: ComponentFactoryResolver) {}

labelClicked(label)
{
console.log("click : ");
console.log(label.text);
}

  addNicoLabel()
  {
  console.log("clicked");
  // to be created dynamicalaly this component must be declared in app.module.ts as an entryComponents
  let factory = this.componentFactoryResolver.resolveComponentFactory(NicolabelComponent);
  let created_component = this.mydiv.createComponent(factory);
//  this.labels.push(created_component );

  }
}

0
投票

这应该与Angular 6+一起使用

在component.spec.ts中,使用提供程序注入渲染器。然后,您可以检索并监视它以确认测试。

let renderer2: Renderer2;
...
beforeEach(async( () => {
   TestBed.configureTestingModule({
      ...
      providers: [Renderer2] // This is the angular renderer
   }).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');
});
© www.soinside.com 2019 - 2024. All rights reserved.