Skip to content

Commit

Permalink
feat: upload multiple roms
Browse files Browse the repository at this point in the history
  • Loading branch information
thenick775 committed Jan 9, 2025
1 parent 20d5927 commit 4f6671a
Show file tree
Hide file tree
Showing 5 changed files with 293 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { screen, waitForElementToBeRemoved } from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import { describe, expect, it, vi } from 'vitest';

import { UploadRomModal } from './upload-rom.tsx';
import { UploadRomsModal } from './upload-roms.tsx';
import { testRomLocation } from '../../../test/mocks/handlers.ts';
import { renderWithContext } from '../../../test/render-with-context.tsx';
import * as contextHooks from '../../hooks/context.tsx';
Expand All @@ -12,7 +12,7 @@ import { productTourLocalStorageKey } from '../product-tour/consts.tsx';

import type { GBAEmulator } from '../../emulator/mgba/mgba-emulator.tsx';

describe('<UploadRomModal />', () => {
describe('<UploadRomsModal />', () => {
it('uploads file and closes modal', async () => {
const setIsModalOpenSpy = vi.fn();
const uploadRomSpy: (file: File, cb?: () => void) => void = vi.fn(
Expand Down Expand Up @@ -51,7 +51,7 @@ describe('<UploadRomModal />', () => {

const testRom = new File(['Some rom file contents'], 'rom1.gba');

renderWithContext(<UploadRomModal />);
renderWithContext(<UploadRomsModal />);

const romInput = screen.getByTestId('hidden-file-input');

Expand All @@ -67,9 +67,157 @@ describe('<UploadRomModal />', () => {
expect(uploadRomSpy).toHaveBeenCalledOnce();
expect(uploadRomSpy).toHaveBeenCalledWith(testRom, expect.anything());

expect(runGameSpy).toHaveBeenCalledOnce();
expect(runGameSpy).toHaveBeenCalledWith('rom1.gba');
expect(syncActionIfEnabledSpy).toHaveBeenCalledOnce();
expect(setIsModalOpenSpy).toHaveBeenCalledOnce();
expect(setIsModalOpenSpy).toHaveBeenCalledWith(false);
});

it('uploads multiple files, loads first file, and closes modal', async () => {
const setIsModalOpenSpy = vi.fn();
const uploadRomSpy: (file: File, cb?: () => void) => void = vi.fn(
(_file, cb) => cb && cb()
);
const syncActionIfEnabledSpy = vi.fn();
const runGameSpy = vi.fn(() => true);

const {
useEmulatorContext: originalEmulator,
useModalContext: originalModal
} = await vi.importActual<typeof contextHooks>('../../hooks/context.tsx');
const { useAddCallbacks: originalCallbacks } = await vi.importActual<
typeof addCallbackHooks
>('../../hooks/emulator/use-add-callbacks.tsx');

vi.spyOn(contextHooks, 'useEmulatorContext').mockImplementation(() => ({
...originalEmulator(),
emulator: {
uploadRom: uploadRomSpy
} as GBAEmulator
}));

vi.spyOn(contextHooks, 'useModalContext').mockImplementation(() => ({
...originalModal(),
setIsModalOpen: setIsModalOpenSpy
}));

vi.spyOn(addCallbackHooks, 'useAddCallbacks').mockImplementation(() => ({
...originalCallbacks(),
syncActionIfEnabled: syncActionIfEnabledSpy
}));

vi.spyOn(runGameHooks, 'useRunGame').mockReturnValue(runGameSpy);

const testRomFiles = [
new File(['Some rom file contents 1'], 'rom1.gba'),
new File(['Some rom file contents 2'], 'rom2.gba')
];

renderWithContext(<UploadRomsModal />);

const romInput = screen.getByTestId('hidden-file-input');

expect(romInput).toBeInTheDocument();

await userEvent.upload(romInput, testRomFiles);

expect(screen.getByText('Files to upload:')).toBeVisible();
expect(screen.getByText('rom1.gba')).toBeVisible();
expect(screen.getByText('rom2.gba')).toBeVisible();

await userEvent.click(screen.getByRole('button', { name: 'Upload' }));

expect(uploadRomSpy).toHaveBeenCalledTimes(2);
expect(uploadRomSpy).toHaveBeenCalledWith(
testRomFiles[0],
expect.anything()
);
expect(uploadRomSpy).toHaveBeenCalledWith(
testRomFiles[1],
expect.anything()
);

expect(runGameSpy).toHaveBeenCalledOnce();
expect(runGameSpy).toHaveBeenCalledWith('rom1.gba');

expect(syncActionIfEnabledSpy).toHaveBeenCalledOnce();
expect(setIsModalOpenSpy).toHaveBeenCalledOnce();
expect(setIsModalOpenSpy).toHaveBeenCalledWith(false);
});

it('uploads multiple files, loads selected file, and closes modal', async () => {
const setIsModalOpenSpy = vi.fn();
const uploadRomSpy: (file: File, cb?: () => void) => void = vi.fn(
(_file, cb) => cb && cb()
);
const syncActionIfEnabledSpy = vi.fn();
const runGameSpy = vi.fn(() => true);

const {
useEmulatorContext: originalEmulator,
useModalContext: originalModal
} = await vi.importActual<typeof contextHooks>('../../hooks/context.tsx');
const { useAddCallbacks: originalCallbacks } = await vi.importActual<
typeof addCallbackHooks
>('../../hooks/emulator/use-add-callbacks.tsx');

vi.spyOn(contextHooks, 'useEmulatorContext').mockImplementation(() => ({
...originalEmulator(),
emulator: {
uploadRom: uploadRomSpy
} as GBAEmulator
}));

vi.spyOn(contextHooks, 'useModalContext').mockImplementation(() => ({
...originalModal(),
setIsModalOpen: setIsModalOpenSpy
}));

vi.spyOn(addCallbackHooks, 'useAddCallbacks').mockImplementation(() => ({
...originalCallbacks(),
syncActionIfEnabled: syncActionIfEnabledSpy
}));

vi.spyOn(runGameHooks, 'useRunGame').mockReturnValue(runGameSpy);

const testRomFiles = [
new File(['Some rom file contents 1'], 'rom1.gba'),
new File(['Some rom file contents 2'], 'rom2.gba')
];

renderWithContext(<UploadRomsModal />);

const romInput = screen.getByTestId('hidden-file-input');

expect(romInput).toBeInTheDocument();

await userEvent.upload(romInput, testRomFiles);

await userEvent.click(
screen.getByLabelText('Load rom2.gba', { selector: 'input' })
);
expect(
screen.getByLabelText('Load rom2.gba', { selector: 'input' })
).toBeChecked();

await userEvent.click(screen.getByRole('button', { name: 'Upload' }));

expect(uploadRomSpy).toHaveBeenCalledTimes(2);
expect(uploadRomSpy).toHaveBeenCalledWith(
testRomFiles[0],
expect.anything()
);
expect(uploadRomSpy).toHaveBeenCalledWith(
testRomFiles[1],
expect.anything()
);

expect(runGameSpy).toHaveBeenCalledOnce();
expect(runGameSpy).toHaveBeenCalledWith('rom2.gba');

expect(syncActionIfEnabledSpy).toHaveBeenCalledOnce();
expect(setIsModalOpenSpy).toHaveBeenCalledOnce();
expect(setIsModalOpenSpy).toHaveBeenCalledWith(false);
});

Expand Down Expand Up @@ -112,7 +260,7 @@ describe('<UploadRomModal />', () => {

vi.spyOn(runGameHooks, 'useRunGame').mockReturnValue(runGameSpy);

renderWithContext(<UploadRomModal />);
renderWithContext(<UploadRomsModal />);

const uploadRomFromURLInput = screen.getByLabelText('Upload from a URL');

Expand Down Expand Up @@ -157,7 +305,7 @@ describe('<UploadRomModal />', () => {
} as GBAEmulator
}));

renderWithContext(<UploadRomModal />);
renderWithContext(<UploadRomsModal />);

const uploadRomFromURLInput = screen.getByLabelText('Upload from a URL');

Expand All @@ -184,12 +332,27 @@ describe('<UploadRomModal />', () => {
).toBeVisible();
});

it('renders invalid url error', async () => {
renderWithContext(<UploadRomsModal />);

await userEvent.type(
screen.getByLabelText('Upload from a URL'),
`invalid url`
);

await userEvent.click(screen.getByRole('button', { name: 'Upload' }));

expect(screen.getByText(/Invalid URL/)).toBeVisible();
});

it('renders form validation error', async () => {
renderWithContext(<UploadRomModal />);
renderWithContext(<UploadRomsModal />);

await userEvent.click(screen.getByRole('button', { name: 'Upload' }));

expect(screen.getByText(/A rom file or URL is required/)).toBeVisible();
expect(
screen.getByText(/At least one rom file or URL is required/)
).toBeVisible();
});

it('closes modal using the close button', async () => {
Expand All @@ -203,7 +366,7 @@ describe('<UploadRomModal />', () => {
setIsModalOpen: setIsModalOpenSpy
}));

renderWithContext(<UploadRomModal />);
renderWithContext(<UploadRomsModal />);

// click the close button
const closeButton = screen.getByText('Close', { selector: 'button' });
Expand All @@ -228,7 +391,7 @@ describe('<UploadRomModal />', () => {
'{"hasCompletedProductTourIntro":"finished"}'
);

renderWithContext(<UploadRomModal />);
renderWithContext(<UploadRomsModal />);

expect(
await screen.findByText(
Expand Down
Loading

0 comments on commit 4f6671a

Please sign in to comment.