Angular 2单元测试报错Unable to get property 'preventDefault' of undefined or null reference

标签 angular unit-testing jasmine angular-cli

我为我拥有的一个组件创建了一堆单元测试。它最初是失败的,因为我得到了上述错误,所以我取出了 event.defaultPrevented 东西,但实际上并不知道它在做什么。

好吧,这修复了我的错误,但显然对 UI 行为产生了非常糟糕的副作用,所以我不得不将这些东西放回我的代码中。

所以,现在我要回去修复我的单元测试了。我如何能够模拟/注入(inject)事件内容到我的单元测试中?

只有 Angular CLI stub 的默认“应该创建”测试失败了,代码如下:

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.preventDefaultevent.defaultPrevented。它仅存在于该组件上发布/提交过程的 onSubmit 函数中。但它仍然使单元测试失败。

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

最佳答案

如果你想阻止你的事件,你必须将事件添加到你的 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
}

关于Angular 2单元测试报错Unable to get property 'preventDefault' of undefined or null reference,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45820968/

相关文章:

html - Angular 9 中丢失图像的错误处理

angular - 如何动态地将垫错误添加到垫输入字段?

C# 7 如何对本地函数进行单元测试

javascript - 如何在 JavaScript 中导出和导入两个不同的函数对象?

javascript - Jasmine 在尝试耙动/启动时停顿?

css - Ionic 3高度问题

javascript - 当我更改页面时,地理位置给我一个错误

android - 使用 fragment 对 Android 应用程序进行 JUnit 测试

javascript - 我如何解决 AngularJS 单元测试中的 promise

javascript - 使用 jasmine 和 karma 测试 typescript ang Angular 时出现 Angularjs 错误