2017-12-06 2 views
1

을 실패합니다 :사용 @ViewChild : 구성 요소의 {읽어하여 elementRef은} 단위 테스트 나는 다음과 같습니다 아이 컴퍼넌트가 내 구성 요소에서

내 부모 구성 요소에서
<child-component #childComponent></childComponent> 

그때 사용하여이 하위 구성 요소에 액세스를 @ ViewChild 및 read 매개 변수를 사용하여 구성 요소 참조가 아닌 ElementRef를 가져옵니다. 나는 내가 필요한 nativeElement에서 몇 가지 속성을 얻을 수 있도록 ElementRef가 필요합니다. 그래서 다음과 같이이다 :

@Component({ 
    selector: 'child-component', 
    template: '' 
}) 
class ChildComponentMockComponent { 
    private nativeElement = { 
    get offsetLeft() { 
     return 600 
    } 
    }; 
} 

beforeEach(async(() => TestBed.configureTestingModule({ 
    imports: [ ... ], 
    declarations: [ ParentComponent, ChildComponentMockComponent ], 
    providers: [ ... ], 
    schemas: [ NO_ERRORS_SCHEMA ] 
}).compileComponents())); 

it('should have the correct position, based on position of child-component',() => { 
    spyOn(component, 'someMethod'); 
    expect(component.someMethod).toHaveBeenCalled(); 
    expect(component.position).toBe('left'); 
}); 

그래서 테스트 구성 요소를 컴파일하고 :

export class ParentComponent { 
    @ViewChild('childComponent', { read: ElementRef }) public childComponent: ElementRef; 
    public position: string; 

    // some way down the code 
    private someMethod() { 
    if (this.childComponent.nativeElement.offsetLeft > 500) { 
     this.position = 'left'; 
    } else { 
     this.position = 'right'; 
    } 
    } 
} 

그래서이 그러나 나는 테스트를 작성하고 하위 구성 요소를 조롱, 다음과 같이하고, 응용 프로그램 작동 조롱 된 하위 구성 요소 값을 적절한 값으로 사용하고 this.position 값을 계산 한 다음 테스트에서 주장합니다.

그러나 { read: ElementRef } 매개 변수가 설정되면 모의은 선언 배열에 추가 되더라도 TestBed에서 완전히 무시됩니다. { read: ElementRef }을 제거하면 모의이 테스트에 사용되며 통과됩니다. 그러나 이제는 요소 참조가 아닌 nativeElement 속성이있는 구성 요소 참조가 나타나므로 응용 프로그램이 작동하지 않습니다.

내 응용 프로그램에서 ElementRef를 얻고 내 테스트에서 모의 ​​구성 요소를 사용하려면 어떻게해야합니까?

+0

당신이 내가 당신이 그것을 – Aravind

+0

안녕 @Aravind를 해결하는 데 도움이 될 수 있도록 작성한 테스트 케이스를 추가 할 수 있으며,이 건물은 실제로 시험에 사용 모호한 것에 대해 미안하지 않습니다. 그러나 테스트는 적절한 것 대신 조롱 된 하위 구성 요소를 사용하여 구성 요소를 컴파일 한 다음 구성 요소의 응용 프로그램 코드에서 다른 것 대신 모의 객체에서 설정 한 값을 사용합니다. app 코드는 하위 구성 요소의 위치를 ​​기반으로 변수를 설정합니다 (true/false). 그런 다음 테스트에서 주장합니다. 상당히 혼란 스럽지만 원래 게시물에 조금 더 자세히 설명했습니다. –

+0

elementRef를 읽을 때 component 인스턴스를 사용하지 않으므로 컴포넌트 인스턴스에서 'nativeElement' 속성을 선언하는 이유는 무엇입니까? 'elementRef'를 조롱하고 싶니? –

답변

0

저는 앱의 아키텍처를 변경하여이 문제를 해결했습니다. 이제 자식 구성 요소는 자신의 offsetLeft 속성을 찾은 다음 출력 EventEmitter에 배치하여 부모 구성 요소를 선택합니다.

export class ChildComponent implements AfterViewInit { 
    @Output() offsetPosition: EventEmitter<number> = new EventEmitter<number>(); 

    constructor(private el: ElementRef) {} 

    public ngAfterViewInit() { 
    this.offsetPosition.emit(this.el.nativeElement.offsetLeft); 
    } 
} 

export class ParentComponent implements AfterViewInit { 
    public childComponentOffset: number; 

    public ngAfterViewInit() { 
    setTimeout(() => { 
     // this.childComponentOffset is available 
     // needs to be in setTimeout to prevent ExpressionChangedAfterItHasBeenCheckedError 
     // more info: https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4 
    } 
    } 

    public getChildComponentOffset(position: number): void { 
    this.childComponentOffset = position; 
    } 
} 

그리고 다음 HTML에서, 당신은 출력 변수와 메소드를 사용하여 하위 구성 요소 정의 : 다음 하위 구성 요소하여 elementRef을 조롱하고 공급자로 사용, 테스트에서

<child-component (offsetPosition)="getChildComponentOffset($event)"></child-component> 

을 .

const mockElementRef: any = { 
    get offsetLeft() { 
    return position; 
    } 
}; 

beforeEach(async(() => TestBed.configureTestingModule({ 
    imports: [ ... ], 
    declarations: [ ParentComponent ], 
    providers: [ 
    { provide: ElementRef, useValue: mockElementRef } 
    ], 
    schemas: [ NO_ERRORS_SCHEMA ] 
}).compileComponents())); 

it('should have the correct position, based on position of child-component', (done) => { 
    component.getChildComponentOffset(600); 
    setTimeout(() => expect(component.position).toBe('left')); 
    done(); 
});