Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#494@minor: Adds support for FileList to HTMLInputElement. #675

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/happy-dom/src/index.ts
Expand Up @@ -123,6 +123,8 @@ import Attr from './nodes/attr/Attr';
import IAttr from './nodes/attr/IAttr';
import ProcessingInstruction from './nodes/processing-instruction/ProcessingInstruction';
import IProcessingInstruction from './nodes/processing-instruction/IProcessingInstruction';
import FileList from './nodes/html-input-element/FileList';
import IFileList from './nodes/html-input-element/IFileList';

export {
GlobalWindow,
Expand Down Expand Up @@ -250,5 +252,7 @@ export {
Attr,
IAttr,
ProcessingInstruction,
IProcessingInstruction
IProcessingInstruction,
FileList,
IFileList
};
35 changes: 35 additions & 0 deletions packages/happy-dom/src/nodes/html-input-element/FileList.ts
@@ -0,0 +1,35 @@
import File from '../../file/File';
import IFileList from './IFileList';

/**
* FileList.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileList
*/
export default class FileList extends Array implements IFileList<File> {
/**
* Constructor.
*/
constructor() {
super(0);
}

/**
* Returns `Symbol.toStringTag`.
*
* @returns `Symbol.toStringTag`.
*/
public get [Symbol.toStringTag](): string {
return this.constructor.name;
}

/**
* Returns item by index.
*
* @param index Index.
* @returns Item.
*/
public item(index: number): File | null {
return this[index] || null;
}
}
@@ -1,4 +1,3 @@
import File from '../../file/File';
import HTMLElement from '../html-element/HTMLElement';
import ValidityState from '../validity-state/ValidityState';
import DOMException from '../../exception/DOMException';
Expand All @@ -11,6 +10,9 @@ import IHTMLInputElement from './IHTMLInputElement';
import IHTMLFormElement from '../html-form-element/IHTMLFormElement';
import IHTMLElement from '../html-element/IHTMLElement';
import HTMLInputElementValueStepping from './HTMLInputElementValueStepping';
import FileList from './FileList';
import File from '../../file/File';
import IFileList from './IFileList';

/**
* HTML Input Element.
Expand All @@ -36,7 +38,7 @@ export default class HTMLInputElement extends HTMLElement implements IHTMLInputE
public defaultChecked = false;

// Type specific: file
public files: File[] = [];
public files: IFileList<File> = new FileList();

// Events
public oninput: (event: Event) => void | null = null;
Expand Down Expand Up @@ -974,7 +976,7 @@ export default class HTMLInputElement extends HTMLElement implements IHTMLInputE
clone._height = this._height;
clone._width = this._width;
clone.defaultChecked = this.defaultChecked;
clone.files = this.files.slice();
clone.files = <FileList>this.files.slice();
clone._selectionStart = this._selectionStart;
clone._selectionEnd = this._selectionEnd;
clone._selectionDirection = this._selectionDirection;
Expand Down
11 changes: 11 additions & 0 deletions packages/happy-dom/src/nodes/html-input-element/IFileList.ts
@@ -0,0 +1,11 @@
/**
* NodeList.
*/
export default interface IFileList<T> extends Array<T> {
/**
* Returns item by index.
*
* @param index Index.
*/
item(index: number): T;
}
@@ -1,9 +1,10 @@
import File from '../../file/File';
import IHTMLElement from '../html-element/IHTMLElement';
import IHTMLFormElement from '../html-form-element/IHTMLFormElement';
import HTMLInputElementSelectionModeEnum from './HTMLInputElementSelectionModeEnum';
import ValidityState from '../validity-state/ValidityState';
import Event from '../../event/Event';
import File from '../../file/File';
import IFileList from './IFileList';

/**
* HTML Input Element.
Expand All @@ -17,7 +18,7 @@ export default interface IHTMLInputElement extends IHTMLElement {
formMethod: string;
formNoValidate: boolean;
defaultChecked: boolean;
files: File[];
files: IFileList<File>;
defaultValue: string;
height: number;
width: number;
Expand Down
2 changes: 2 additions & 0 deletions packages/happy-dom/src/window/IWindow.ts
Expand Up @@ -104,6 +104,7 @@ import IElement from '../nodes/element/IElement';
import ProcessingInstruction from '../nodes/processing-instruction/ProcessingInstruction';
import IHappyDOMSettings from './IHappyDOMSettings';
import RequestInfo from '../fetch/RequestInfo';
import FileList from '../nodes/html-input-element/FileList';

/**
* Window without dependencies to server side specific packages.
Expand Down Expand Up @@ -218,6 +219,7 @@ export default interface IWindow extends IEventTarget, NodeJS.Global {
readonly XMLHttpRequest: typeof XMLHttpRequest;
readonly XMLHttpRequestUpload: typeof XMLHttpRequestUpload;
readonly XMLHttpRequestEventTarget: typeof XMLHttpRequestEventTarget;
readonly FileList: typeof FileList;

// Events
onload: (event: Event) => void;
Expand Down
2 changes: 2 additions & 0 deletions packages/happy-dom/src/window/Window.ts
Expand Up @@ -115,6 +115,7 @@ import IElement from '../nodes/element/IElement';
import ProcessingInstruction from '../nodes/processing-instruction/ProcessingInstruction';
import IHappyDOMSettings from './IHappyDOMSettings';
import RequestInfo from '../fetch/RequestInfo';
import FileList from '../nodes/html-input-element/FileList';

const ORIGINAL_SET_TIMEOUT = setTimeout;
const ORIGINAL_CLEAR_TIMEOUT = clearTimeout;
Expand Down Expand Up @@ -246,6 +247,7 @@ export default class Window extends EventTarget implements IWindow {
public readonly MimeTypeArray = MimeTypeArray;
public readonly Plugin = Plugin;
public readonly PluginArray = PluginArray;
public readonly FileList = FileList;
public readonly Headers: { new (init?: IHeadersInit): IHeaders } = Headers;
public readonly DOMRect: typeof DOMRect;
public readonly Request: {
Expand Down
@@ -0,0 +1,33 @@
import Window from '../../../src/window/Window';
import IWindow from '../../../src/window/Window';
import IDocument from '../../../src/nodes/document/IDocument';
import File from '../../../src/file/File';
import IHTMLInputElement from '../../../src/nodes/html-input-element/IHTMLInputElement';

describe('FileList', () => {
let window: IWindow;
let document: IDocument;

beforeEach(() => {
window = new Window();
document = window.document;
});

afterEach(() => {
jest.restoreAllMocks();
});

describe('item()', () => {
it('Returns file at index.', () => {
const element = <IHTMLInputElement>document.createElement('input');
const file1 = new File([''], 'file.txt');
const file2 = new File([''], 'file2.txt');

element.files.push(file1);
element.files.push(file2);

expect(element.files.item(0)).toBe(file1);
expect(element.files.item(1)).toBe(file2);
});
});
});