mirror of
https://github.com/whscullin/apple2js.git
synced 2024-01-12 14:14:38 +00:00
203d89b8d9
This removes the `FileSystemFileHandleLike` interface in preference to just implementing the correct interface. The advantage of the `FileSystemFileHandle` interface is that it can be passed to the worker directly to load the file.
132 lines
5.1 KiB
TypeScript
132 lines
5.1 KiB
TypeScript
/**
|
|
* @jest-environment ./test/env/jsdom-with-backdoors
|
|
*/
|
|
|
|
import { h } from 'preact';
|
|
import { fireEvent, render, screen, waitFor } from '@testing-library/preact';
|
|
|
|
import 'test/env/jsdom-with-backdoors';
|
|
import { FileChooser, FileChooserProps } from '../../js/components/FileChooser';
|
|
|
|
type ShowOpenFilePicker = typeof window.showOpenFilePicker;
|
|
|
|
const FAKE_FILE_HANDLE = {
|
|
kind: 'file',
|
|
name: 'file name',
|
|
createWritable: jest.fn(),
|
|
getFile: jest.fn(),
|
|
isSameEntry: jest.fn(),
|
|
queryPermission: jest.fn(),
|
|
requestPermission: jest.fn(),
|
|
isFile: true,
|
|
isDirectory: false,
|
|
} as const;
|
|
|
|
const NOP = () => { /* do nothing */ };
|
|
|
|
// eslint-disable-next-line no-undef
|
|
const EMPTY_FILE_LIST = backdoors.newFileList();
|
|
|
|
const FAKE_FILE = new File([], 'fake');
|
|
|
|
describe('FileChooser', () => {
|
|
describe('input-based chooser', () => {
|
|
it('should be instantiable', () => {
|
|
const { container } = render(<FileChooser control='input' onChange={NOP} />);
|
|
|
|
expect(container).not.toBeNull();
|
|
});
|
|
|
|
it('should use the file input element', async () => {
|
|
render(<FileChooser control='input' onChange={NOP} />);
|
|
|
|
const inputElement = await screen.findByRole('button') as HTMLInputElement;
|
|
expect(inputElement.type).toBe('file');
|
|
});
|
|
|
|
it('should fire a callback with empty list when no files are selected', async () => {
|
|
const onChange = jest.fn();
|
|
render(<FileChooser control='input' onChange={onChange} />);
|
|
const inputElement = await screen.findByRole('button') as HTMLInputElement;
|
|
inputElement.files = EMPTY_FILE_LIST;
|
|
fireEvent.change(inputElement);
|
|
await waitFor(() => {
|
|
expect(onChange).toBeCalledWith([]);
|
|
});
|
|
});
|
|
|
|
it('should fire a callback with a file handle when a file is selected', async () => {
|
|
const onChange = jest.fn<ReturnType<FileChooserProps['onChange']>, Parameters<FileChooserProps['onChange']>>();
|
|
render(<FileChooser control='input' onChange={onChange} />);
|
|
const inputElement = await screen.findByRole('button') as HTMLInputElement;
|
|
// eslint-disable-next-line no-undef
|
|
inputElement.files = backdoors.newFileList(FAKE_FILE);
|
|
fireEvent.change(inputElement);
|
|
await waitFor(async () => {
|
|
expect(onChange).toHaveBeenCalled();
|
|
const handleList = onChange.mock.calls[0][0];
|
|
expect(handleList).toHaveLength(1);
|
|
const handle = handleList[0];
|
|
expect(handle.kind).toBe('file');
|
|
expect(handle.name).toBe(FAKE_FILE.name);
|
|
await expect(handle.getFile()).resolves.toBe(FAKE_FILE);
|
|
await expect(handle.createWritable()).rejects.toEqual('File not writable.');
|
|
await expect(handle.queryPermission({ mode: 'readwrite' })).resolves.toBe('denied');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('picker-base chooser', () => {
|
|
const mockFilePicker = jest.fn<ReturnType<ShowOpenFilePicker>, Parameters<ShowOpenFilePicker>>();
|
|
|
|
beforeEach(() => {
|
|
if (typeof window.showOpenFilePicker !== 'undefined') {
|
|
throw new Error('window.showOpenFilePicker not undefined');
|
|
}
|
|
window.showOpenFilePicker = mockFilePicker as unknown as ShowOpenFilePicker;
|
|
mockFilePicker.mockReset();
|
|
});
|
|
|
|
afterEach(() => {
|
|
window.showOpenFilePicker = undefined as unknown as typeof window.showOpenFilePicker;
|
|
});
|
|
|
|
it('should be instantiable', () => {
|
|
const { container } = render(<FileChooser control='picker' onChange={NOP} />);
|
|
|
|
expect(container).not.toBeNull();
|
|
});
|
|
|
|
it('should fire a callback with empty list when no files are selected', async () => {
|
|
mockFilePicker.mockResolvedValueOnce([]);
|
|
const onChange = jest.fn();
|
|
render(<FileChooser control='picker' onChange={onChange} />);
|
|
|
|
fireEvent.click(await screen.findByText('Choose File'));
|
|
|
|
await waitFor(() => {
|
|
expect(mockFilePicker).toBeCalled();
|
|
expect(onChange).toBeCalledWith([]);
|
|
});
|
|
});
|
|
|
|
it('should fire a callback with a file handle when a file is selected', async () => {
|
|
mockFilePicker.mockResolvedValueOnce([FAKE_FILE_HANDLE]);
|
|
const onChange = jest.fn<ReturnType<FileChooserProps['onChange']>, Parameters<FileChooserProps['onChange']>>();
|
|
render(<FileChooser control='picker' onChange={onChange} />);
|
|
|
|
fireEvent.click(await screen.findByText('Choose File'));
|
|
|
|
await waitFor(() => {
|
|
expect(mockFilePicker).toBeCalled();
|
|
expect(onChange).toHaveBeenCalled();
|
|
const handleList = onChange.mock.calls[0][0];
|
|
expect(handleList).toHaveLength(1);
|
|
const handle = handleList[0];
|
|
expect(handle.kind).toBe(FAKE_FILE_HANDLE.kind);
|
|
expect(handle.name).toBe(FAKE_FILE_HANDLE.name);
|
|
});
|
|
});
|
|
});
|
|
});
|