如何在Angular应用中测试非Angular表单的提交?
问题描述
我有一个包含PayPal按钮的Angular组件,HTML代码如下:
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top"> <input type="hidden" name="cmd" value="_s-xclick" /> <input type="hidden" name="encrypted" value="key-goes-here" /> <button type="submit" class="btn btn-large btn-success">Donate!</button> <img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1" /> </form>
组件的TS文件无任何业务逻辑。我想编写测试用例确保点击按钮时表单能正常提交,于是尝试用spyOn监听表单的原生submit方法,点击按钮后验证form.submit是否被调用,但测试报错:
Expected spy submit to have been called.
我的测试文件代码如下:
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { DonateButtonComponent } from './donate-button.component'; describe('DonateButtonComponent', () => { let component: DonateButtonComponent; let fixture: ComponentFixture<DonateButtonComponent>; beforeEach(() => { TestBed.configureTestingModule({ declarations: [DonateButtonComponent], }); fixture = TestBed.createComponent(DonateButtonComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); it('should redirect to Paypal when the button is clicked', () => { const btn = fixture.debugElement.query(By.css('.btn')); const form: HTMLFormElement = fixture.debugElement.query(By.css('form')).nativeElement; spyOn(form, 'submit'); btn.triggerEventHandler('click', {}); fixture.detectChanges(); expect(form.submit).toHaveBeenCalled(); }); });
请问该如何正确测试此类非Angular表单的提交功能?
解决方案
问题核心在于Angular测试提供的triggerEventHandler只会触发组件层面的事件绑定,不会触发浏览器原生DOM的默认行为,所以模拟点击后不会自动触发表单提交。可以用以下两种方式解决:
方法一:调用按钮的原生点击方法
直接获取按钮的原生DOM元素,调用click()方法,这样会触发浏览器默认的表单提交逻辑:
it('should trigger form submission when donate button is clicked', () => { // 获取原生DOM元素 const btn = fixture.debugElement.query(By.css('.btn')).nativeElement; const form: HTMLFormElement = fixture.debugElement.query(By.css('form')).nativeElement; // 监听submit方法并添加空实现避免跳转 spyOn(form, 'submit').and.callFake(() => {}); btn.click(); // 调用原生点击方法 expect(form.submit).toHaveBeenCalled(); });
方法二:监听表单的submit事件
如果不想依赖submit方法的调用,也可以直接监听表单的submit事件,验证事件是否正常触发:
it('should fire form submit event when button is clicked', (done) => { const btn = fixture.debugElement.query(By.css('.btn')).nativeElement; const form = fixture.debugElement.query(By.css('form')).nativeElement; // 监听submit事件 form.addEventListener('submit', (e) => { e.preventDefault(); // 阻止默认跳转,避免测试环境报错 expect(true).toBeTruthy(); // 验证事件已触发 done(); // 异步测试需调用done结束 }); btn.click(); });
关键注意点
- 测试时一定要阻止表单的默认跳转行为(
e.preventDefault()或给submitspy加空实现),否则测试环境会尝试跳转到PayPal,导致测试失败或报错。 - 用原生DOM方法模拟用户行为(比如
click())更贴近真实用户操作,适合测试这类原生表单逻辑。
内容的提问来源于stack exchange,提问作者Chris Barr
相关产品推荐
相关产品推荐

