2017-12-06 1 views
1

In meiner Komponente zum Scheitern verurteilt ich eine untergeordnete Komponente habe, die wie folgt aussieht:Mit @ViewChild {lesen: ElementRef} der Komponente bewirkt, dass Unit-Test

<child-component #childComponent></childComponent> 

In meiner Elternkomponente ich dann dieses Kind zugreifen Komponente mit @ ViewChild und der read Parameter, um die ElementRef und nicht die Komponentenreferenz zu erhalten. Ich brauche das ElementRef, um sicherzustellen, dass ich einige Eigenschaften von nativeElement bekommen kann, die ich brauche. Es ist also wie folgt aus:

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

So dies für die Anwendung funktioniert, aber ich die Prüfungen schreibe und das Kind Komponente spöttisch, wie folgt aus:

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

so der Test die Komponente kompilieren, und Verwenden Sie die gemockten untergeordneten Komponentenwerte als den richtigen Wert, und berechnen Sie den Wert this.position, der dann im Test bestätigt wird.

Wenn jedoch der Parameter { read: ElementRef } festgelegt ist, wird der Mock vom TestBed vollständig ignoriert, obwohl er im Deklarationsarray hinzugefügt wird. Wenn ich { read: ElementRef } entferne, wird der Schein im Test verwendet und es passiert. Aber dann funktioniert meine Anwendung nicht, da sie jetzt die Komponentenreferenz erhält, bei der die nativeElement-Eigenschaft nicht existiert, und nicht die Elementreferenz.

Wie bekomme ich das ElementRef in meiner Anwendung und dann in meinem Test die Mock-Komponente?

+0

können Sie den Testfall hinzufügen, die Sie geschrieben haben, so kann ich Ihnen helfen, zu fixieren – Aravind

+0

Hallo @Aravind, wird die Eigenschaft nicht tatsächlich in dem Test, sorry für mehrdeutig verwendet. Aber der Test kompiliert die Komponente unter Verwendung der mocked child-Komponente anstelle der richtigen, und dann verwendet sie im Anwendungscode für die Komponente den Wert, den ich im Mock gesetzt habe, anstelle von irgendetwas anderem. Der App-Code setzt eine Variable (true/false) basierend auf der Position der Kindkomponente, die ich dann im Test bestätige. Es ist ziemlich verwirrend, aber ich habe meinem ursprünglichen Beitrag etwas mehr Details hinzugefügt. –

+0

Wenn Sie readElementRef verwenden, wird keine Komponenteninstanz verwendet. Warum deklarieren Sie also die Eigenschaft 'nativeElement' für die Komponenteninstanz? Möchtest du 'elementRef' vortäuschen? –

Antwort

0

Ich habe das durch Ändern der Architektur der App behoben. Die untergeordnete Komponente sucht nun nach ihrer eigenen Eigenschaft offsetLeft und legt sie dann in einem Ausgabe-EventEmitter ab, um die übergeordnete Komponente abzurufen.

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

Und dann in der HTML, Sie nur die untergeordnete Komponente mit Ausgangsgröße und Verfahren definieren:

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

Im Test habe ich dann ElementRef für das Kind Komponente verspotten und es als Anbieter verwenden .

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(); 
}); 
Verwandte Themen