我有一个具有form属性的指令。指令放置在表单的“提交”按钮上,并侦听单击事件。单击“提交”按钮时,伪指令将检查表单是否有效,如果无效,则将click事件冒泡到ngSubmit
处理程序中。它还将每个表单控件标记为脏的,以便显示验证消息。
该指令工作正常,我想添加单元测试,但是我不知道如何设置包含提交按钮的表单。到目前为止,这是我的测试,但是我无法弄清楚该指令所采用的NgForm
与我创建的包含按钮的伪造形式之间的联系。
describe('ValidateBeforeSubmitDirective', () => {
let fakeSubmitButtonRef: ElementRef<HTMLButtonElement>;
let fakeForm: HTMLFormElement;
beforeEach(() => {
const fakeSubmitButton = document.createElement('BUTTON') as HTMLButtonElement;
fakeSubmitButton.type = 'submit';
fakeSubmitButtonRef = new ElementRef(fakeSubmitButton);
fakeForm = document.createElement('form');
fakeForm.appendChild(fakeSubmitButton);
});
it('should bubble click event to the submit method if form is valid', () => {
//arrange
const directive = new ValidateBeforeSubmitDirective(fakeSubmitButtonRef);
directive.form = new NgForm([], []);
spyOn(directive.form, 'ngSubmit');
expect(directive.form.valid).toBe(true, 'Test has been set up incorrectly, the form should be valid for this test.');
//*** What do I need to do to link my NgForm with fakeForm? ***
//act
fakeSubmitButtonRef.nativeElement.click();
//assert
expect(directive.form.ngSubmit).toHaveBeenCalled();
});
});
作为参考,这是我的指令代码:
@Directive({
selector: '[appValidateBeforeSubmit]'
})
export class ValidateBeforeSubmitDirective {
/**
* @param element This will be the element on which the directive is being used.
*/
constructor(private readonly element: ElementRef<HTMLButtonElement>) { }
@Input('appValidateBeforeSubmit')
form: NgForm;
@HostListener('click', ['$event'])
private onClick(event: Event) {
if (!this.form.valid) {
Object.keys(this.form.controls).forEach(key => {
this.form.controls[key].markAsDirty();
});
}
return this.form.valid; //if false, this will prevent the event from bubbling up to the ngSubmit handler
}
}
它的用法如下:
<form #componentTypeForm="ngForm" (ngSubmit)="ok()">
<button type="submit" [appValidateBeforeSubmit]="componentTypeForm">Submit</button>
</form>
有什么想法可以在测试中设置表单,以使按钮click
事件冒泡到表单的ngSubmit
处理程序吗?
答案 0 :(得分:0)
有人确实发布了一个答案,使我处于正确的位置,但是他们可悲地删除了他们的答案,所以我不能给他们功劳。他们指出directives should be tested using a dummy component是在测试文件中定义的。我创建了一个组件,该组件的模板是带有输入的表单,并且已经能够通过测试该组件来测试指令的行为。
这是我的工作测试代码:
import { NgForm, FormsModule } from '@angular/forms';
import { Component } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { ValidateBeforeSubmitDirective } from './validate-before-submit.directive';
@Component({
//The input on this form is required, so we can easily set the form validity by giving it an empty/non-empty string.
template: `<form #testForm="ngForm">
<input name="providedValue" [(ngModel)]="providedValue" type="text" required />
<button type="submit" [appValidateBeforeSubmit]="testForm">Submit</button>
</form>`
})
class TestValidateBeforeSubmitComponent {
providedValue: string;
}
describe('ValidateBeforeSubmitDirective', () => {
let form: NgForm;
let fixture: ComponentFixture<TestValidateBeforeSubmitComponent>;
beforeEach(() => {
fixture = TestBed.configureTestingModule({
declarations: [ValidateBeforeSubmitDirective, TestValidateBeforeSubmitComponent],
imports: [FormsModule],
providers: [NgForm, HTMLButtonElement]
}).createComponent(TestValidateBeforeSubmitComponent);
const formElement = fixture.debugElement.children[0];
form = formElement.injector.get(NgForm);
fixture.detectChanges(); // initial binding
});
it('should allow submission of a valid form', async(() => {
//arrange
fixture.componentInstance.providedValue = 'Arbitrary content'; //valid value
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(form.valid).toBe(true, 'Test has been set up incorrectly, form should be valid.');
//act
const buttonElement = fixture.debugElement.children[0].children[1];
const button = buttonElement.nativeElement;
button.click();
//assert
expect(form.submitted).toBe(true, 'Clicking the submit button on a valid form should have submitted the form.');
});
}));
it('should prevent submission of an invalid form', async(() => {
//arrange
fixture.componentInstance.providedValue = ''; //invalid value
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(form.valid).toBe(false, 'Test has been set up incorrectly, form should be invalid.');
//act
const buttonElement = fixture.debugElement.children[0].children[1];
const button = buttonElement.nativeElement;
button.click();
//assert
expect(form.submitted).toBe(false, 'The directive should prevent an invalid form from submitting when the submit button is clicked.');
});
}));
});