Тестирование углового компонента, который содержит пользовательский элемент управления? - PullRequest
0 голосов
/ 05 сентября 2018

У меня есть простой угловой компонент, как показано ниже.

import { Component, Input, forwardRef, ViewEncapsulation } from "@angular/core";
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from "@angular/forms";

export const CUSTOM_CHECKBOX_CONTROL_VALUE_ACCESSOR: any = {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => CheckBoxComponent),
    multi: true
};

@Component({
    selector: "checkbox",
    templateUrl: "./checkBox.component.html",
    styleUrls: ["./checkBox.component.scss"],
    providers: [CUSTOM_CHECKBOX_CONTROL_VALUE_ACCESSOR],
    encapsulation: ViewEncapsulation.None
})
export class CheckBoxComponent implements ControlValueAccessor {
    @Input() name: string;
    // Placeholders for the callbacks which are later provided
    // by the Control Value Accessor
    private innerValue: any = "";
    private onTouchedCallback: () => void = () => { };
    private onChangeCallback: (_: any) => void = () => { };

    // get and set accessor----------------------
    get value(): any {
        return this.innerValue;
    }
    set value(v: any) {
        if (v !== this.innerValue) {
            this.innerValue = v;
            this.onChangeCallback(v);
        }
    }

    // From ControlValueAccessor interfaces--------------
    writeValue(value: any): void {
        if (value !== this.innerValue) {
            this.innerValue = value;
        }
    }
    registerOnChange(fn: any): void { this.onChangeCallback = fn; }
    registerOnTouched(fn: any): void { this.onTouchedCallback = fn; }
}

Я пишу модульный тест для. Мой тест как ниже

    import { CheckBoxComponent, CUSTOM_CHECKBOX_CONTROL_VALUE_ACCESSOR } from "./checkBox.component";
        import { TestBed, async, ComponentFixture, fakeAsync, tick } from "@angular/core/testing";
        import { DebugElement, Component } from "@angular/core";
        import { By } from "@angular/platform-browser";
        import { FormsModule } from "@angular/forms";
        import { CommonModule } from "@angular/common";

        @Component({
            selector: "tac-checkbox",
            template: `<checkbox name="checkboxId1" label="Checkbox Label" [(ngModel)] = "checkValue" > `,
        })
        class CustomTestClass {
            checkValue = false;
        }

        describe("Component: CheckBoxComponent", () => {
            let component: CheckBoxComponent;
            let fixture: ComponentFixture<CheckBoxComponent>;
            let testComponent: CustomTestClass;
            let testFixture: ComponentFixture<CustomTestClass>;

            beforeEach(async(() => {
                TestBed.configureTestingModule({
                    imports: [FormsModule, CommonModule],
                    declarations: [CheckBoxComponent, CustomTestClass],
                    providers: [CUSTOM_CHECKBOX_CONTROL_VALUE_ACCESSOR],
                }).compileComponents().then(() => {
                    fixture = TestBed.createComponent(CheckBoxComponent);
                    component = fixture.componentInstance;
                    component.name = "checkbox";
                });
            }));

            it("...", fakeAsync(() => {
                testFixture = TestBed.createComponent(CustomTestClass);
                testComponent = testFixture.componentInstance;

                fixture.detectChanges();
                const onChangeEvent = (change: any) => { console.log("There were changes ", change); };
                const registerOnChangeMock = spyOn(component, "registerOnChange").and.callThrough();
                const registerOnTouchedMock = spyOn(component, "registerOnTouched").and.callThrough();
                const onMockWriteValue = spyOn(component, "writeValue").and.callThrough();

                component.registerOnChange(onChangeEvent);

                component.registerOnTouched(onChangeEvent);

                testComponent.checkValue = !testComponent.checkValue;
                fixture.detectChanges();
                testFixture.detectChanges();
                tick();
                fixture.whenStable().then(() => {
                    expect(registerOnChangeMock).toHaveBeenCalledTimes(1); //pass
                    expect(registerOnTouchedMock).toHaveBeenCalledTimes(1);
 //pass
                    expect(onMockWriteValue).toHaveBeenCalled(); //failed
                    expect(testComponent.checkValue).toEqual(component.value); //failed
                });
            }));

        });

Из моего теста выше, я ожидаю, что component.value будет равно testComponent.value. Это не удалось, однако, мой вопрос заключается в том, что я изменил значение testComponent, разве контрольное значение также не должно обновляться? Также я ожидал, что writeValue будет вызываться всякий раз, когда я меняю значение testComponent, однако это не так. Пожалуйста, что я делаю не так? Любая помощь будет оценена.

1 Ответ

0 голосов
/ 05 сентября 2018

Это потому, что component - это не тот экземпляр, который вы ожидаете. В beforeEach вы создаете новый CheckBoxComponent, а в it вы создаете экземпляр своего тестового хост-компонента CustomTestClass. Angular создает новый CheckBoxComponent как дочерний элемент вашего тестового хоста, поэтому при изменении входного значения для хост-компонента оно не отражается в component экземпляре.

Что вам нужно сделать, это создать только тестовый хост-компонент, и в этом компоненте ввести CheckBoxComponent с @ViewChild и использовать этот экземпляр в тестах.

Код:

удалить .then часть в beforeEach.

отредактируйте ваш тестовый хост-компонент:

class CustomTestClass {
   checkValue = false;
   @ViewChild(CheckBoxComponent) checkBoxComponent: CheckBoxComponent;
}

замените component на testComponent.checkBoxComponent в вашем тесте.

...