我提交了input
HTML
File
<input type="file" class="custom-file-input" id="question-file-upload" formControlName="image" (change)="handleFileSelect($event)">
我想对handleFileSelect
函数进行单元测试。但是我不知道如何触发输入的onChange
方法。以下是我写的spec
,但出现错误imageInputNE.onchange is not a function
fit('should keep track of image counter when an image is loaded', () => {
let newPracticeQuestionComponent = component;
expect(newPracticeQuestionComponent.currentImageAttachmentCount).toBe(0);
let imageInputDE = fixture.debugElement.query(By.css("#question-file-upload"));
expect(imageInputDE).toBeTruthy();
spyOn(newPracticeQuestionComponent,'handleFileSelect');
let imageInputNE:HTMLElement = imageInputDE.nativeElement as HTMLElement;
imageInputNE.onchange(new Event("some event"));
expect(newPracticeQuestionComponent.handleFileSelect).toHaveBeenCalled();
});
答案 0 :(得分:0)
请参阅Mozilla网站上的文档,事件通常由“外部”源(如Buttons)触发,也可以通过编程方式触发,例如通过调用元素的HTMLElement.click()方法。或通过定义事件,然后使用EventTarget.dispatchEvent()将其发送到指定的目标。
我认为click
是一个简单的事件,可以通过编程方式触发,但是change
的{{1}}事件更复杂,因为它需要选择一个文件,转换为博客,更新{ {1}}属性等。因此可能由于这个原因,我不能简单地调用<input type=file..>
。
所以我想到了使用files
,它似乎可行
1)我明确创建了一个事件。我想imageElementNE.change()
的构造函数有2个参数,第2个是可选的。
来自https://developer.mozilla.org/en-US/docs/Web/API/Event/Event
dispatchEvent
根据文档,Event
是代表事件名称的DOMString。换句话说,第一个参数似乎是事件的event = new Event(typeArg, eventInit);
。当我要发送typeArg
事件时,我需要将其称为type
。
对于change
部分,我查看了https://developer.mozilla.org/en-US/docs/Web/Events/change处change
事件的定义,并从那里选择了eventInit
和change
的值>
bubbles
这将创建一个cancelable
,其外观如下(我必须承认我不太了解它)
let fileSelectEvent = new Event("change",{bubbles:true,
cancelable: false});
2)创建Event
之后,我在 Event {isTrusted: false, type: "change", target: input#question-file-upload.custom-file-input.ng-untouched.ng-pristine.ng-valid, currentTarget: input#question-file-upload.custom-file-input.ng-untouched.ng-pristine.ng-valid, eventPhase: 2, …}bubbles: truecancelBubble: falsecancelable: falsecomposed: falsecurrentTarget: nulldefaultPrevented: falseeventPhase: 0isTrusted: falsepath: (10) [input#question-file-upload.custom-file-input.ng-untouched.ng-pristine.ng-valid, div#file-upload.custom-file, div.form-group, form#new-question-form.practice-question-form.ng-untouched.ng-pristine.ng-invalid, div#form-div.body__div--background, div#root0, body, html, document, Window]returnValue: truesrcElement: input#question-file-upload.custom-file-input.ng-untouched.ng-pristine.ng-validtarget: input#question-file-upload.custom-file-input.ng-untouched.ng-pristine.ng-validtimeStamp: 3759.4000000026426type: "change"__proto__: Event
上调用了Event
方法。与dispatchEvent
相比,我认为这意味着imageInputNE
正在触发事件(在我的情况下EventTarget.dispatchEvent()
正在触发EventTarget
。
imageInputNE
通过的整个规格是
fileSelectEvent
以上内容可能不是最好的解决方案,因为我无法在imageInputNE.dispatchEvent(fileSelectEvent);
字段中操作 fit('should keep track of image counter when an image is loaded', () => {
let newPracticeQuestionComponent = component;
expect(newPracticeQuestionComponent.currentImageAttachmentCount).toBe(0);
let imageInputDE = fixture.debugElement.query(By.css("#question-file-upload"));
expect(imageInputDE).toBeTruthy();
spyOn(newPracticeQuestionComponent,'handleFileSelect');/*.and.callThrough();/*.and.callFake((event)=>{
console.log("fake handleFileSelect called with event",event);
});*/
/*
nativeElemenet hasn'nt got any type. As this program will run in a browser, we can
typecast it to HTMLElement so that we can access prperties and methods of the
corresponding nativeElement
The HTMLElement interface represents any HTML element. Some elements directly
implement this interface, while others implement it via an interface that inherits it.
*/
let imageInputNE = imageInputDE.nativeElement ;
console.log("input element is ",imageInputNE);
console.log("debug element is ",imageInputDE);
//imageInputNE.click();
let fileSelectEvent = new Event("change",{bubbles:true,
cancelable: false});
console.log("created event ",fileSelectEvent);
imageInputNE.dispatchEvent(fileSelectEvent);
expect(newPracticeQuestionComponent.handleFileSelect).toHaveBeenCalled();
});
,但这是我能想到的最好的方法!
答案 1 :(得分:0)
从other answer开始,我建议您将handleFileSelect
更改为仅使用files
。
interface File {
// the properties you need, for example:
name: string;
}
// You don't need all this unless you must use `item()`
// interface FileList {
// readonly length: number;
// item(index: number): File | null;
// [index: number]: File;
// }
// instead, just use ArrayLike<File>
export function handleFileSelect(files: ArrayLike<File>) {
// Write code here, for example:
if (files.length > 0) {
console.log(files[0].name);
}
}
然后您的测试应该是:
const files = [{
name: 'File 1'
}];
handleFileSelect(files);
您的组件将只是:
handleFileSelect(event.target.files);
Here's an example展示了这两种用法如何不会在编译器中触发错误。