Angular带下拉框的模态表单提交单元测试问题修正
问题:Angular模态表单单元测试中
savePermission方法接收空参数的问题 我正在为包含两个下拉框和提交按钮的Angular模态表单编写单元测试。点击按钮打开模态框并填充下拉框数据,用户选择值后可提交表单。但测试运行时,savePermission方法被调用但参数为空,请求修正测试代码。
原表单代码:
<form *ngIf="formResetToggle" class="form-horizontal" name="permissionEditorForm" #f="ngForm" novalidate (ngSubmit)="f.form.valid && isPermissionValid(selectedUserRole.value,selectedScopeName.value) ? savePermission(selectedUserRole.value,selectedScopeName.value) : showErrorAlert('Please enter mandatory fields')"> <div> <label>User Role</label> <div ng-class="{'valid':userrole.$valid}"> <select #selectedUserRole id="userrole" autofocus name='userrole' class="form-control" [(ngModel)]='userrole' required> <option value="">--Select User Role--</option> <option *ngFor="let userrole of userroles; let i = index" [value]="userrole.userroleid" > {{userrole.username}} </option> </select> <span *ngIf="(f.submitted && !userrole.valid && !userrole) || (!userrole.valid && userrole.dirty)" class="errorMessage"> <i class="abb_icon_16 ui_error_circle1 erroricon"></i> User Role Required! </span> </div> </div> <div> <label>Scope Name</label> <div> <select #selectedScopeName autofocus name='scopename' class="form-control" [(ngModel)]='scopename' required> <option value="">--Select Scope Name--</option> <option *ngFor="let scope of scopes; let i=index" [value]="scope.scopeid" > {{scope.scopevalue}} </option> </select> <span *ngIf="(f.submitted && !scopename.valid && !scopename) || (!scopename.valid && scopename.dirty)" class="errorMessage"> <i class="abb_icon_16 ui_error_circle1 erroricon"></i> Scope Name Required! </span> </div> </div> <div class="modal-footer"> <button type="button" (click)="permissionmapModal.hide()" class="btn btn-default" data-dismiss="modal">Cancel</button> <button type="submit" id="savePermission" class="btn btn-primary">Add Permisson</button> </div> <div class="clearfix"></div> </form>
组件中的savePermission方法:
savePermission(userrolevalue, scopevalue) { // 方法逻辑 }
原测试代码:
it('add permission', () => { component.permissionform.form.controls.scopename.setValue('/bmw/v1/s1'); component.permissionform.form.controls.userrole.setValue('subscriber'); let savePermissionButton = fixture.debugElement.nativeElement.querySelector('#savePermission'); component.permissionform.form.valid; savePermissionButton.click(); })
问题分析
你的测试直接修改了表单控件的值,但模板中的提交逻辑是依赖模板引用变量selectedUserRole和selectedScopeName的DOM值,而非直接从表单控件读取。虽然ngModel是双向绑定,但直接修改表单控件不会同步更新DOM元素的value属性,导致点击提交时,模板里获取到的参数还是空值。
正确的做法是模拟用户真实的交互流程:操作DOM下拉框选择选项,触发change事件,让Angular自动同步ngModel和表单状态,这样提交时就能传递正确的参数。
修正后的测试代码
it('should call savePermission with correct parameters when form is submitted', () => { // 1. 确保模态框已打开,表单渲染(设置formResetToggle为true并触发变更检测) component.formResetToggle = true; fixture.detectChanges(); // 2. 模拟下拉框数据(如果组件的userroles和scopes未预先填充,需要先设置) component.userroles = [{ userroleid: 'subscriber', username: 'Subscriber' }]; component.scopes = [{ scopeid: '/bmw/v1/s1', scopevalue: 'BMW Scope' }]; fixture.detectChanges(); // 更新下拉选项 // 3. 获取两个下拉框DOM元素 const userRoleSelect = fixture.debugElement.nativeElement.querySelector('#userrole'); const scopeNameSelect = fixture.debugElement.nativeElement.querySelector('[name="scopename"]'); // 4. 设置下拉框值并触发change事件(Angular依赖该事件同步ngModel) userRoleSelect.value = 'subscriber'; userRoleSelect.dispatchEvent(new Event('change')); scopeNameSelect.value = '/bmw/v1/s1'; scopeNameSelect.dispatchEvent(new Event('change')); // 5. 触发变更检测,让Angular同步表单状态和绑定值 fixture.detectChanges(); // 6. 监听savePermission方法,验证调用情况 spyOn(component, 'savePermission'); // 7. 点击提交按钮 const saveBtn = fixture.debugElement.nativeElement.querySelector('#savePermission'); saveBtn.click(); // 8. 验证方法是否以正确参数被调用 expect(component.savePermission).toHaveBeenCalledWith('subscriber', '/bmw/v1/s1'); });
关键说明
- 必须触发
change事件:Angular的ngModel通过监听DOM元素的change事件更新绑定值,仅设置value不会触发同步。 - 多次调用
fixture.detectChanges():确保每次数据更新后,模板重新渲染,下拉选项和表单状态正确同步。 - 使用
spyOn验证:通过间谍函数可以明确确认savePermission是否接收到了预期的参数。
内容的提问来源于stack exchange,提问作者Niranjan
相关产品推荐
相关产品推荐

