Testing a component using File API (HTMLInputElement, file upload) - File and FileList not defined

Hello,

I would like to test a simple component’s file input field. I’ve seen loads of examples for react and angular.
All in all File and FileList are not defined.

I’ve spent a long time on trying to find a way to have a File and FileList defined within the scope of the test.
This is what I have so far:

  • uploadtest.tsx:
import { Component, EventEmitter, Event, h, State } from '@stencil/core';

@Component({ tag: 'upload-test' })
export class UploadTest {
  @Event() valueChanged: EventEmitter;
  @State() files: File[] = [];

  onChangeInputFile(event) {
    if (!event.target) return;
    if (!(event.target as HTMLInputElement).files) return;
    const eventFiles = event.target.files;
    console.log(eventFiles);
    this.files = eventFiles;
  }

  render() {
    return (
      <div>
        <input
          type="file"
          onChange={(event) => this.onChangeInputFile(event)}
        />

        <ul>
          {this.files.map((f) => (
            <li data-testid="file">{f.name}</li>
          ))}
        </ul>
      </div>
    );
  }
}
  • uploadtest.spec.tsx:
import { h } from '@stencil/core';
import { newSpecPage, SpecPage } from '@stencil/core/testing';
import { UploadTest } from './uploadtest';

describe('list selected files', (): void => {
  test('list two files', async () => {
    const specPage: SpecPage = await newSpecPage({
      components: [UploadTest],
      template: () => <upload-test />,
    });
    const inputElement = specPage.root.querySelector('input');

    inputElement.files = mockFileList([
      mockFile('file-a', 2 * 1024 * 1024),
      mockFile('file-b', 6 * 1024 * 1024),
    ]);
    inputElement.dispatchEvent(new CustomEvent('change'));
    await specPage.waitForChanges();

    const fileElements = specPage.root.querySelectorAll('[data-testid="file"]');
    expect(fileElements).toHaveLength(2);
  });
});


function mockFile(name: string, size: number): File {
  const file = new File([''], name);
  Object.defineProperty(file, 'size', { value: size });
  return file;
};

function mockFileList(files: File[]): FileList {
  const fileList: FileList = Object.create({});
  for (let i = 0; i < files.length; i++) {
    fileList[i] = files[i];
  }
  Object.defineProperty(fileList, 'length', { value: files.length });
  return fileList;
};

running npx jest uploadtest.spec fails:

 FAIL uploadtest.spec.tsx
  list selected files
    ✕ list two files (19 ms)

  ● list selected files › list two files

    ReferenceError: File is not defined

the package.json has the following content:

{
  "name": "uploadComponentTest",
  "version": "0.0.1",
  "description": "",
  "keywords": [],
  "repository": {
    "type": "git",
    "url": "***"
  },
  "license": "UNLICENSED",
  "author": "me",
  "main": "dist/index.cjs.js",
  "unpkg": "dist/pill/pill.js",
  "module": "dist/index.js",
  "types": "dist/types/components.d.ts",
  "files": [
    "dist/"
  ],
  "scripts": {
    "build": "stencil build",
    "build:watch": "stencil build --watch",
    "clean": "rm -rf node_modules && rm -rf dist",
    "generate": "stencil generate",
    "test": "stencil test --specs",
    "test:watch": "stencil test --specs --watch"
  },
  "dependencies": {
    "@stencil/core": "3.2.0"
  },
  "collection": "dist/collection/collection-manifest.json",
  "collection:main": "dist/collection/index.js",
  "es2015": "dist/esm/index.mjs",
  "es2017": "dist/esm/index.mjs"
}

could someone point me in the right direction?