【问题标题】:Angular 5 unit testing: How to make change detection work properly?Angular 5 单元测试:如何使变更检测正常工作?
【发布时间】:2018-03-04 21:21:38
【问题描述】:

如何使单元测试中的变更检测正常工作? 从源代码来看,应该在微任务为空(包括事件任务?)后运行 changeDetection。

this._onMicrotaskEmptySubscription = ngZone.onMicrotaskEmpty.subscribe({
    next: () => {
        if (this._autoDetect) {
            // Do a change detection run with checkNoChanges set to true to check
            // there are no changes on the second run.
            this.detectChanges(true);
        }
    }
});

在这个简短的示例中,更改检测在 setTimeout 之后运行,但不是在手动单击元素之后运行。是否有适当的方法在事件调度后触发更改检测(在 fakeAsync 区域内,没有 fixture.detectChanges,因为在这种情况下更改检测与现实生活中的不同)?

import {
    fakeAsync, tick, ComponentFixture, TestBed, ComponentFixtureAutoDetect
} from '@angular/core/testing';
import {
    Component, QueryList, ViewChildren
} from '@angular/core';
import { By } from '@angular/platform-browser';
import { CommonModule } from '@angular/common';
describe('bug', () => {
    let host: Host;
    let fixture: ComponentFixture<Host>;
    @Component({
        selector: 'child',
        template: ``,
    })
    class Child {}
    @Component({
        template: `
            <ng-container *ngFor="let show of shows">
                <child *ngIf="show"></child>
            </ng-container>
            <button (click)="shows[1] = true">show</button>`
    })
    class Host {
        shows = [false, false];
        @ViewChildren(Child) children: QueryList<Child>;
        constructor() {
            setTimeout(() => this.shows[0] = true, 50);
        }
    }
    fit('test', fakeAsync(() => {
        TestBed.configureTestingModule({
            imports: [
                CommonModule,
            ],
            declarations: [
                Host, Child,
            ],
            providers: [{
                provide: ComponentFixtureAutoDetect,
                useValue: true,
            }]
        });
        fixture = TestBed.createComponent(Host);
        host = fixture.componentInstance;
        tick(10);
        expect(host.children.length).toEqual(0);
        tick(50);
        expect(host.children.length).toEqual(1);
        const button = fixture.debugElement.query(By.css('button'));
        button.triggerEventHandler('click', new Event('click'));
        tick(50);
        // fixture.detectChanges();
        expect(host.children.length).toEqual(2); // fails here
    }));
});

【问题讨论】:

    标签: angular angular5 angular2-testing angular2-changedetection


    【解决方案1】:

    我找到了我的问题的解决方案。 应该使用HTMLElement.dispatchEvent。 如何触发inputkeyup事件:

    const inputDe = this.de.query(By.css('input'));
    const inputEl = inputDe.nativeElement;
    inputEl.value = text;
    inputEl.focus(); // if it has matAutocompleteTrigger value accessor
    inputEl.dispatchEvent(new Event('input'));
    inputEl.dispatchEvent(new KeyboardEvent('keyup', {
          key: 'Enter',
    }));
    

    完整示例

    import {
        fakeAsync, tick, ComponentFixture, TestBed, ComponentFixtureAutoDetect
    } from '@angular/core/testing';
    import {
        Component, QueryList, ViewChildren
    } from '@angular/core';
    import { By } from '@angular/platform-browser';
    import { CommonModule } from '@angular/common';
    fdescribe('bug', () => {
        let host: Host;
        let fixture: ComponentFixture<Host>;
        @Component({
            selector: 'child',
            template: ``,
        })
        class Child {}
        @Component({
            template: `
                <ng-container *ngFor="let show of shows">
                    <child *ngIf="show"></child>
                </ng-container>
                <button (click)="shows[1] = true">show</button>`
        })
        class Host {
            shows = [false, false];
            @ViewChildren(Child) children: QueryList<Child>;
            constructor() {
                setTimeout(() => this.shows[0] = true, 50);
            }
        }
        it('test', fakeAsync(() => {
            TestBed.configureTestingModule({
                imports: [
                    CommonModule,
                ],
                declarations: [
                    Host, Child,
                ],
                providers: [{
                    provide: ComponentFixtureAutoDetect,
                    useValue: true,
                }]
            });
            fixture = TestBed.createComponent(Host);
            host = fixture.componentInstance;
            tick(10);
            expect(host.children.length).toEqual(0);
            tick(50);
            expect(host.children.length).toEqual(1);
            const button = fixture.debugElement.query(By.css('button'));
            button.nativeElement.dispatchEvent(new Event('click')); // proper way
            tick(50);
            expect(host.children.length).toEqual(2); // no fail now
        }));
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-29
      • 2018-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-31
      相关资源
      最近更新 更多