Подтвердить что ты не робот

Angular 2 unit test error Не удалось получить свойство "preventDefault" из undefined или null reference

Я создал кучу модульных тестов для компонента, который у меня есть. Первоначально он был неудачным, потому что я получил вышеприведенную ошибку, поэтому я извлек событие event.defaultPrevented без фактического понимания того, что он делает.

Хорошо, что исправил мои ошибки, но, очевидно, имел очень плохой побочный эффект от поведения пользовательского интерфейса, поэтому мне пришлось вернуть этот материал в свой код.

Итак, теперь я вернулся к исправлению моих модульных тестов. Как я могу издеваться/вводить материал Event в свои модульные тесты?

Только по умолчанию "должен создать" тест, который был заглушен Angular, CLI не работает, вот код:

let component: MemberAddComponent;
let fixture: ComponentFixture<MemberAddComponent>;
let contractsService: ContractsService;
let notesService: NotesService;
let saveButton: any;

beforeEach(async(() => {
    let router = { navigate: jasmine.createSpy('navigate') };

    TestBed.configureTestingModule({
        imports: [
            HttpModule,
            FormsModule,
            ReactiveFormsModule,
            RouterTestingModule
        ],
        declarations: [
            MemberAddComponent,
            // lots more here
        ],
        providers: [
            AppDataService,
            ErrorService,
            {
                provide: ContractsService,
                useClass: MockContractsService
            },
            {
                provide: NotesService,
                useClass: MockNotesService
            }
        ]
    })
    .compileComponents();
}));

beforeEach(() => {
    fixture = TestBed.createComponent(MemberAddComponent);
    component = fixture.componentInstance;
    contractsService = fixture.debugElement.injector.get(ContractsService);
    saveButton = fixture.nativeElement.querySelector('#saveButton');
    fixture.detectChanges();
});

it('should create', () => {
    expect(component).toBeTruthy();
});

И здесь функция ngOnInit, которая должна быть единственной проверкой для этого теста:

ngOnInit() {
    this.log('ngOnInit', 'ngOnInit...');

    this.routeSubscription = this.route.params.subscribe(params => {
        this.memberId = params['id'] || null;
        this.effectiveDate = params['from'] || null;
        this.cancelDate = params['to'] || null;
        this.group = params['group'] || null;
        this.subgroup = params['subgroup'] || null;
    });

    this.contractRequest = new models.AddContractRequestUI();

    this.dataservice.effectiveDateOfChange = this.dataservice.getCurrentDateMountainTimezone();
    this.dataservice.todaysDateString = this.dataservice.effectiveDateOfChange;

    if (this.contractRequest.subscriber.class.length === 0) {
        this.contractRequest.subscriber.class.push(new models.AddContractRequestSubscriberClass(this.dataservice.effectiveDateOfChange));
    }

    this.loadContractDetails();

    this.dependent.originalEffectiveDt = this.dataservice.effectiveDateOfChange;
    this.memberComplete = false;
    this.transactionStartTime = new Date();
}

Изменить: обратите внимание, что в тестируемом коде нет event.preventDefault или event.defaultPrevented. Это существует только в функции onSubmit для процесса post/submit на этом компоненте. Но все же он все еще делает ошибку unit test.

Edit2: Здесь html-страница, а также функция onSave()

Html:

<div class="container">
    <div *ngIf="!waiting" class="row mb-20">
        <div class="col-xs-12">
            <a class="link-icon" (click)="onClickBack()">
                <span class="icon-wmkCaretLeft"></span>
                <span class="link-text text-uppercase text-condensed">Back</span>
            </a>
        </div>
    </div>
    <div class="row">
        <div class="col-xs-12">
            <form *ngIf="(!loadError)" novalidate (ngSubmit)="onSave()">
                <template [ngIf]="groupComplete">
                    <wm-groupinfo-view [groupName]="contractRequest.groupName" [groupId]="contractRequest.groupIdentifier" [subgroupId]="contractRequest.subgroupIdentifier"></wm-groupinfo-view>
                </template>
                <template [ngIf]="groupComplete && !effectiveDateComplete">
                    <member-add-effective-date [componentTitle]="enterEffectiveDateTitle" [effectiveDateString]="dataservice.effectiveDateOfChange" (complete)="onEffectiveDateComplete($event)"></member-add-effective-date>
                </template>
                <template [ngIf]="groupComplete && effectiveDateComplete">
                    <h3 class="text-uppercase">Effective Date</h3>
                    <p><span class="field-label">Effective Date of Change: </span>{{ dataservice.effectiveDateOfChange | wmFixDateFormat }}</p>
                    <div class="buttons">
                        <button class="btn btn-primary" (click)="onClickEditEffectiveDate()">
                            <i class="glyphicon glyphicon-edit"></i>
                            Edit Effective Date
                        </button>
                    </div>
                </template>
                <template [ngIf]="effectiveDateComplete">
                    <member-add-subscriber-info [member]="contractRequest.member[0]" [subscriberId]="memberId" (complete)="onSubscriberInfoComplete($event)"></member-add-subscriber-info>
                </template>
                <template [ngIf]="subscriberDemoComplete">
                    <template [ngIf]="!homeAddressInfoComplete">
                        <member-add-subscriber-address [address]="homeAddressObject" (complete)="onAddressInfoComplete($event)"></member-add-subscriber-address>
                    </template>
                    <template [ngIf]="homeAddressInfoComplete">
                        <h3 class="text-uppercase">Subscriber Home Address Information</h3>
                        <p *ngIf="dataservice.selectedContract.address[0].type === 'Primary'"><strong>Address Type: </strong>HOME</p>
                        <p *ngIf="dataservice.selectedContract.address[0].type !== 'Primary'"><strong>Address Type: </strong>MAILING</p>
                        <p><strong>Address Line 1: </strong>{{dataservice.selectedContract.address[0].addressLine1}}</p>
                        <p><strong>Address Line 2: </strong>{{dataservice.selectedContract.address[0].addressLine2}}</p>
                        <p><strong>City: </strong>{{dataservice.selectedContract.address[0].city}}</p>
                        <p><strong>State: </strong>{{dataservice.selectedContract.address[0].state}}</p>
                        <p><strong>Zip Code: </strong>{{getZipString(0)}}</p>
                        <p><strong>County: </strong>{{dataservice.selectedContract.address[0].county?.description}}</p>
                        <p><strong>Email: </strong>{{dataservice.selectedContract.address[0].email}}</p>
                        <p><strong>Phone Number: </strong>{{ dataservice.selectedContract.phoneNumber | wmPhonePipe }}</p>
                        <div class="buttons">
                            <button class="btn btn-primary" (click)="onClickEditAddressInfo()">
                                <i class="glyphicon glyphicon-edit"></i>
                                Edit Subscriber Home Address
                            </button>
                        </div>
                        <template [ngIf]="!showMailingAddress">
                            <div class="buttons">
                                <button class="btn btn-primary" (click)="onClickAddMailingAddressInfo()">
                                    <i class="glyphicon glyphicon-add"></i>
                                    Add Subscriber Mailing Address
                                </button>
                            </div>
                        </template>
                        <template [ngIf]="showMailingAddress">
                            <template [ngIf]="!mailingAddressInfoComplete">
                                <member-add-subscriber-address [address]="mailingAddressObject" (complete)="onMailingAddressInfoComplete($event)" (delete)="onClickDeleteMailingAddressInfo($event)"></member-add-subscriber-address>
                            </template>
                            <template [ngIf]="mailingAddressInfoComplete">
                                <h3 class="text-uppercase">Subscriber Mailing Address Information</h3>
                                <p *ngIf="dataservice.selectedContract.address[1].type === 'Primary'"><strong>Address Type: </strong>HOME</p>
                                <p *ngIf="dataservice.selectedContract.address[1].type !== 'Primary'"><strong>Address Type: </strong>MAILING</p>
                                <p><strong>Address Line 1: </strong>{{dataservice.selectedContract.address[1].addressLine1}}</p>
                                <p><strong>Address Line 2: </strong>{{dataservice.selectedContract.address[1].addressLine2}}</p>
                                <p><strong>City: </strong>{{dataservice.selectedContract.address[1].city}}</p>
                                <p><strong>State: </strong>{{dataservice.selectedContract.address[1].state}}</p>
                                <p><strong>Zip Code: </strong>{{dataservice.selectedContract.address[1].zip}}</p>
                                <p><strong>County: </strong>{{dataservice.selectedContract.address[1].county?.description}}</p>
                                <div class="buttons">
                                    <button class="btn btn-primary" (click)="onClickEditMailingAddressInfo()">
                                        <i class="glyphicon glyphicon-edit"></i>
                                        Edit Subscriber Mailing Address
                                    </button>
                                    <button class="btn btn-primary" (click)="onClickDeleteMailingAddressInfo()">
                                        <i class="glyphicon glyphicon-edit"></i>
                                        Delete Subscriber Mailing Address
                                    </button>
                                </div>
                            </template>
                        </template>
                    </template>
                </template>
                <ng-container *ngIf="subscriberDemoComplete && homeAddressInfoComplete && (!showMailingAddress || mailingAddressInfoComplete)">
                    <member-add-dependent *ngIf="addingDependents" [member]="dependent" [editing]="isEditingDependent" (complete)="onDependentComplete($event)"></member-add-dependent>
                    <div *ngIf="dependentComplete">
                        <h3 class="text-uppercase">Dependent/Member Information</h3>
                        <p><strong>Relationship: </strong>{{ dataservice.getRelationshipString(dependent.relationship) }}</p>
                        <p><strong>First Name: </strong>{{dependent.firstName}}</p>
                        <p><strong>Middle Initial: </strong>{{dependent.middleInitial}}</p>
                        <p><strong>Last Name: </strong>{{dependent.lastName}}</p>
                        <p><strong>Title: </strong>{{dependent.title}}</p>
                        <p><strong>Date of Birth: </strong>{{ dependent.birthDt | wmFixDateFormat }}</p>
                        <p><strong>Social Security Number: </strong>{{dependent.ssn}}</p>
                        <p><strong>Gender: </strong>{{dependent.sex}}</p>
                        <p><strong>Marital Status: </strong>{{dependent.maritalStatus}}</p>
                        <p><strong>Original Effective Date: </strong>{{dependent.originalEffectiveDt | wmFixDateFormat}}</p>
                        <div class="buttons">
                            <button class="btn btn-primary" (click)="onClickEditDependentDemo(dependent)">
                                <i class="glyphicon glyphicon-edit"></i>
                                Edit Dependent Information
                            </button>
                        </div>
                    </div>
                </ng-container>
                <ng-container *ngIf="showProducts && dependentComplete">
                    <member-add-products [members]="contractRequest.member" [addingMember]="true" (complete)="onProductsComplete($event)"></member-add-products>
                </ng-container>
                <div>
                    <wm-error-list [errors]="errorList" (clickError)="focusField($event)" (addError)="errorAdded($event)"></wm-error-list>
                </div>
                <div *ngIf="(!waiting)" class="buttons pb-10">
                    <div *ngIf="canSave()">
                        <button id="saveButton" class="btn btn-primary pull-right" type="submit">Add&nbsp;Member</button>
                    </div>
                    <div *ngIf="!canSave()">
                        <button [disabled]="true" class="btn btn-primary pull-right">Add&nbsp;Member</button>
                    </div>
                    <button class="btn btn-secondary pull-right" type="button" (click)="onClickCancel()">Cancel</button>
                </div>
                <div *ngIf="(waiting)">
                    <wm-spinner></wm-spinner>
                </div>
            </form>
            <div *ngIf="(loadError)">
                <h3>{{errorMessage}}</h3>
            </div>
        </div>
    </div>
</div>

OnSave():

onSave() {
    if (event.defaultPrevented || this.waiting) {
        return;
    }

    this.clearErrors();
    this.checkErrors();

    if (this.hasErrors() || (!this.unitTesting && !confirm("You are about to add this member. Are you sure you want to continue?"))) {
        return;
    }

    this.waiting = true;

    this.saveUpdatedSubscriberInformation();

    var addMemberObject = this.buildAddMemberObject();

    this.contractsService.addMember(addMemberObject)
        .subscribe(response => {
            this.parseAddMemberResponse(response, addMemberObject, true);
            //only save the note on success of adding member
            this.saveNote();
        }, error => {
            this.parseAddMemberResponse(error, addMemberObject, false);
        });
}
4b9b3361

Ответ 1

Получил эту работу некоторое время назад, но я забыл обновить мой вопрос SO...

Все, что нужно было сделать, это создать фиктивный объект "события" на моем компоненте, а затем явно установить некоторые значения в тесте перед запуском всего. Как только это было сделано, все работает нормально.

Итак, что-то вроде этого могло бы работать в компоненте:

if (event && event.preventDefault) { event.preventDefault(); }

Или это могло быть сделано в тесте:

component.event = { preventDefault: function () {} };

Ответ 2

Если вы хотите предотвратить событие, вам придется добавить событие в свою функцию onSave, поэтому замените

<form *ngIf="(!loadError)" novalidate (ngSubmit)="onSave()">

с

<form #myForm="ngForm" *ngIf="(!loadError)" novalidate (ngSubmit)="onSave(myForm, $event)">

и добавьте параметры в функцию OnSave

public onSave(myForm: any, event: Event) {
    event.preventDefault(); // or event.defaultPrevented to check
    .... rest of your code
}