mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-07-28 04:08:05 +00:00
fix breaking changes for user-event v14
This commit is contained in:
committed by
David Lechner
parent
4299b36e6c
commit
883807b4b4
@@ -2,23 +2,22 @@
|
||||
// Copyright (c) 2021-2022 The Pybricks Authors
|
||||
|
||||
import { getByLabelText, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../test';
|
||||
import AboutDialog from './AboutDialog';
|
||||
|
||||
it('should close when the button is clicked', () => {
|
||||
it('should close when the button is clicked', async () => {
|
||||
const close = jest.fn();
|
||||
|
||||
const [dialog] = testRender(<AboutDialog isOpen={true} onClose={close} />);
|
||||
const [user, dialog] = testRender(<AboutDialog isOpen={true} onClose={close} />);
|
||||
|
||||
userEvent.click(dialog.getByLabelText('Close'));
|
||||
await user.click(dialog.getByLabelText('Close'));
|
||||
|
||||
expect(close).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should manage license dialog open/close', async () => {
|
||||
const [dialog] = testRender(
|
||||
const [user, dialog] = testRender(
|
||||
<AboutDialog isOpen={true} onClose={() => undefined} />,
|
||||
);
|
||||
|
||||
@@ -26,7 +25,7 @@ it('should manage license dialog open/close', async () => {
|
||||
dialog.queryByRole('dialog', { name: 'Open Source Software Licenses' }),
|
||||
).toBeNull();
|
||||
|
||||
userEvent.click(dialog.getByText('Software Licenses'));
|
||||
await user.click(dialog.getByText('Software Licenses'));
|
||||
|
||||
const licenseDialog = dialog.getByRole('dialog', {
|
||||
name: 'Open Source Software Licenses',
|
||||
@@ -34,7 +33,7 @@ it('should manage license dialog open/close', async () => {
|
||||
|
||||
expect(licenseDialog).toBeVisible();
|
||||
|
||||
userEvent.click(getByLabelText(licenseDialog, 'Close'));
|
||||
await user.click(getByLabelText(licenseDialog, 'Close'));
|
||||
|
||||
await waitFor(() => expect(licenseDialog).not.toBeVisible());
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../test';
|
||||
import Activities, { Activity } from './Activities';
|
||||
@@ -15,7 +14,7 @@ afterEach(() => {
|
||||
|
||||
describe('Activities', () => {
|
||||
it('should select explorer by default', () => {
|
||||
const [activities] = testRender(<Activities />);
|
||||
const [, activities] = testRender(<Activities />);
|
||||
|
||||
const tab = activities.getByRole('tab', { name: 'File Explorer' });
|
||||
|
||||
@@ -28,15 +27,15 @@ describe('Activities', () => {
|
||||
JSON.stringify(Activity.Settings),
|
||||
);
|
||||
|
||||
const [activities] = testRender(<Activities />);
|
||||
const [, activities] = testRender(<Activities />);
|
||||
|
||||
const tab = activities.getByRole('tab', { name: 'Settings & Help' });
|
||||
|
||||
expect(tab).toHaveAttribute('aria-selected', 'true');
|
||||
});
|
||||
|
||||
it('should select none when clicking already selected tab', () => {
|
||||
const [activities] = testRender(<Activities />);
|
||||
it('should select none when clicking already selected tab', async () => {
|
||||
const [user, activities] = testRender(<Activities />);
|
||||
|
||||
const explorerTab = activities.getByRole('tab', { name: 'File Explorer' });
|
||||
|
||||
@@ -47,15 +46,15 @@ describe('Activities', () => {
|
||||
);
|
||||
}
|
||||
|
||||
userEvent.click(explorerTab);
|
||||
await user.click(explorerTab);
|
||||
|
||||
for (const tab of activities.getAllByRole('tab')) {
|
||||
expect(tab).toHaveAttribute('aria-selected', 'false');
|
||||
}
|
||||
});
|
||||
|
||||
it('should select new tab when clicking not already selected tab', () => {
|
||||
const [activities] = testRender(<Activities />);
|
||||
it('should select new tab when clicking not already selected tab', async () => {
|
||||
const [user, activities] = testRender(<Activities />);
|
||||
|
||||
const explorerTab = activities.getByRole('tab', { name: 'File Explorer' });
|
||||
const settingsTab = activities.getByRole('tab', { name: 'Settings & Help' });
|
||||
@@ -67,7 +66,7 @@ describe('Activities', () => {
|
||||
);
|
||||
}
|
||||
|
||||
userEvent.click(settingsTab);
|
||||
await user.click(settingsTab);
|
||||
|
||||
for (const tab of activities.getAllByRole('tab')) {
|
||||
expect(tab).toHaveAttribute(
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { RenderResult, cleanup } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../../test';
|
||||
import { Toolbar } from './Toolbar';
|
||||
@@ -40,7 +39,7 @@ function getButtons(toolbar: RenderResult): {
|
||||
|
||||
describe('Toolbar', () => {
|
||||
it('should have toolbar role', () => {
|
||||
const [toolbar] = testRender(<TestToolbar />);
|
||||
const [, toolbar] = testRender(<TestToolbar />);
|
||||
|
||||
expect(toolbar.getByRole('toolbar', { name: 'Test Toolbar' })).toHaveClass(
|
||||
'test-class',
|
||||
@@ -48,7 +47,7 @@ describe('Toolbar', () => {
|
||||
});
|
||||
|
||||
it('should focus the first element by default', async () => {
|
||||
const [toolbar] = testRender(<TestToolbar />);
|
||||
const [user, toolbar] = testRender(<TestToolbar />);
|
||||
|
||||
const { button1, button2, button3 } = getButtons(toolbar);
|
||||
|
||||
@@ -56,7 +55,7 @@ describe('Toolbar', () => {
|
||||
expect(button2).toHaveAttribute('tabindex', '-1');
|
||||
expect(button3).toHaveAttribute('tabindex', '-1');
|
||||
|
||||
userEvent.tab();
|
||||
await user.tab();
|
||||
|
||||
expect(button1).toHaveFocus();
|
||||
expect(button1).not.toHaveAttribute('tabindex');
|
||||
@@ -64,13 +63,13 @@ describe('Toolbar', () => {
|
||||
expect(button3).toHaveAttribute('tabindex', '-1');
|
||||
});
|
||||
|
||||
it('should focus next with right arrow key', () => {
|
||||
const [toolbar] = testRender(<TestToolbar />);
|
||||
it('should focus next with right arrow key', async () => {
|
||||
const [user, toolbar] = testRender(<TestToolbar />);
|
||||
|
||||
const { button1, button2, button3 } = getButtons(toolbar);
|
||||
|
||||
button1.focus();
|
||||
userEvent.keyboard('[ArrowRight]');
|
||||
await user.keyboard('{ArrowRight}');
|
||||
|
||||
expect(button2).toHaveFocus();
|
||||
expect(button1).toHaveAttribute('tabindex', '-1');
|
||||
@@ -78,13 +77,13 @@ describe('Toolbar', () => {
|
||||
expect(button3).toHaveAttribute('tabindex', '-1');
|
||||
});
|
||||
|
||||
it('should focus previous with left arrow key', () => {
|
||||
const [toolbar] = testRender(<TestToolbar />);
|
||||
it('should focus previous with left arrow key', async () => {
|
||||
const [user, toolbar] = testRender(<TestToolbar />);
|
||||
|
||||
const { button1, button2, button3 } = getButtons(toolbar);
|
||||
|
||||
button3.focus();
|
||||
userEvent.keyboard('[ArrowLeft]');
|
||||
await user.keyboard('{ArrowLeft}');
|
||||
|
||||
expect(button2).toHaveFocus();
|
||||
expect(button1).toHaveAttribute('tabindex', '-1');
|
||||
@@ -92,13 +91,13 @@ describe('Toolbar', () => {
|
||||
expect(button3).toHaveAttribute('tabindex', '-1');
|
||||
});
|
||||
|
||||
it('should wrap focus next with right arrow key', () => {
|
||||
const [toolbar] = testRender(<TestToolbar />);
|
||||
it('should wrap focus next with right arrow key', async () => {
|
||||
const [user, toolbar] = testRender(<TestToolbar />);
|
||||
|
||||
const { button1, button2, button3 } = getButtons(toolbar);
|
||||
|
||||
button3.focus();
|
||||
userEvent.keyboard('[ArrowRight]');
|
||||
await user.keyboard('{ArrowRight}');
|
||||
|
||||
expect(button1).toHaveFocus();
|
||||
expect(button1).not.toHaveAttribute('tabindex');
|
||||
@@ -106,13 +105,13 @@ describe('Toolbar', () => {
|
||||
expect(button3).toHaveAttribute('tabindex', '-1');
|
||||
});
|
||||
|
||||
it('should wrap focus previous with left arrow key', () => {
|
||||
const [toolbar] = testRender(<TestToolbar />);
|
||||
it('should wrap focus previous with left arrow key', async () => {
|
||||
const [user, toolbar] = testRender(<TestToolbar />);
|
||||
|
||||
const { button1, button2, button3 } = getButtons(toolbar);
|
||||
|
||||
button1.focus();
|
||||
userEvent.keyboard('[ArrowLeft]');
|
||||
await user.keyboard('{ArrowLeft}');
|
||||
|
||||
expect(button3).toHaveFocus();
|
||||
expect(button1).toHaveAttribute('tabindex', '-1');
|
||||
@@ -120,13 +119,13 @@ describe('Toolbar', () => {
|
||||
expect(button3).not.toHaveAttribute('tabindex');
|
||||
});
|
||||
|
||||
it('should focus first with home key', () => {
|
||||
const [toolbar] = testRender(<TestToolbar />);
|
||||
it('should focus first with home key', async () => {
|
||||
const [user, toolbar] = testRender(<TestToolbar />);
|
||||
|
||||
const { button1, button2, button3 } = getButtons(toolbar);
|
||||
|
||||
button3.focus();
|
||||
userEvent.keyboard('[Home]');
|
||||
await user.keyboard('{Home}');
|
||||
|
||||
expect(button1).toHaveFocus();
|
||||
expect(button1).not.toHaveAttribute('tabindex');
|
||||
@@ -134,13 +133,13 @@ describe('Toolbar', () => {
|
||||
expect(button3).toHaveAttribute('tabindex', '-1');
|
||||
});
|
||||
|
||||
it('should focus last with end key', () => {
|
||||
const [toolbar] = testRender(<TestToolbar />);
|
||||
it('should focus last with end key', async () => {
|
||||
const [user, toolbar] = testRender(<TestToolbar />);
|
||||
|
||||
const { button1, button2, button3 } = getButtons(toolbar);
|
||||
|
||||
button1.focus();
|
||||
userEvent.keyboard('[End]');
|
||||
await user.keyboard('{End}');
|
||||
|
||||
expect(button3).toHaveFocus();
|
||||
expect(button1).toHaveAttribute('tabindex', '-1');
|
||||
@@ -148,13 +147,13 @@ describe('Toolbar', () => {
|
||||
expect(button3).not.toHaveAttribute('tabindex');
|
||||
});
|
||||
|
||||
it('should not change focus with up arrow key', () => {
|
||||
const [toolbar] = testRender(<TestToolbar />);
|
||||
it('should not change focus with up arrow key', async () => {
|
||||
const [user, toolbar] = testRender(<TestToolbar />);
|
||||
|
||||
const { button1, button2, button3 } = getButtons(toolbar);
|
||||
|
||||
button2.focus();
|
||||
userEvent.keyboard('[ArrowUp]');
|
||||
await user.keyboard('{ArrowUp}');
|
||||
|
||||
expect(button2).toHaveFocus();
|
||||
expect(button1).toHaveAttribute('tabindex', '-1');
|
||||
@@ -162,13 +161,13 @@ describe('Toolbar', () => {
|
||||
expect(button3).toHaveAttribute('tabindex', '-1');
|
||||
});
|
||||
|
||||
it('should not change focus with down arrow key', () => {
|
||||
const [toolbar] = testRender(<TestToolbar />);
|
||||
it('should not change focus with down arrow key', async () => {
|
||||
const [user, toolbar] = testRender(<TestToolbar />);
|
||||
|
||||
const { button1, button2, button3 } = getButtons(toolbar);
|
||||
|
||||
button2.focus();
|
||||
userEvent.keyboard('[ArrowDown]');
|
||||
await user.keyboard('{ArrowDown}');
|
||||
|
||||
expect(button2).toHaveFocus();
|
||||
expect(button1).toHaveAttribute('tabindex', '-1');
|
||||
@@ -176,13 +175,13 @@ describe('Toolbar', () => {
|
||||
expect(button3).toHaveAttribute('tabindex', '-1');
|
||||
});
|
||||
|
||||
it('should not focus next item with tab key', () => {
|
||||
const [toolbar] = testRender(<TestToolbar />);
|
||||
it('should not focus next item with tab key', async () => {
|
||||
const [user, toolbar] = testRender(<TestToolbar />);
|
||||
|
||||
const { button1, button2, button3 } = getButtons(toolbar);
|
||||
|
||||
button2.focus();
|
||||
userEvent.tab();
|
||||
await user.tab();
|
||||
|
||||
expect(document.body).toHaveFocus();
|
||||
expect(button1).toHaveAttribute('tabindex', '-1');
|
||||
@@ -190,12 +189,12 @@ describe('Toolbar', () => {
|
||||
expect(button3).toHaveAttribute('tabindex', '-1');
|
||||
});
|
||||
|
||||
it('should focus on click', () => {
|
||||
const [toolbar] = testRender(<TestToolbar />);
|
||||
it('should focus on click', async () => {
|
||||
const [user, toolbar] = testRender(<TestToolbar />);
|
||||
|
||||
const { button1, button2, button3 } = getButtons(toolbar);
|
||||
|
||||
userEvent.click(button2);
|
||||
await user.click(button2);
|
||||
|
||||
expect(button2).toHaveFocus();
|
||||
expect(button1).toHaveAttribute('tabindex', '-1');
|
||||
|
||||
+95
-102
@@ -2,8 +2,7 @@
|
||||
// Copyright (c) 2021-2022 The Pybricks Authors
|
||||
|
||||
import { Classes } from '@blueprintjs/core';
|
||||
import { RenderResult, cleanup, fireEvent, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { cleanup, fireEvent, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { monaco } from 'react-monaco-editor';
|
||||
import { testRender, uuid } from '../../test';
|
||||
@@ -19,6 +18,10 @@ const testFile: FileMetadata = {
|
||||
sha256: '',
|
||||
viewState: null,
|
||||
};
|
||||
jest.setTimeout(1000000);
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
describe('Editor', () => {
|
||||
describe('tabs', () => {
|
||||
@@ -26,29 +29,26 @@ describe('Editor', () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
jest.mocked(useFileStoragePath).mockReturnValue(testFile.path);
|
||||
|
||||
const [editor, dispatch] = testRender(<Editor />, {
|
||||
const [user, editor, dispatch] = testRender(<Editor />, {
|
||||
editor: { openFileUuids: [testFile.uuid] },
|
||||
});
|
||||
|
||||
userEvent.click(editor.getByRole('tab', { name: 'test.file' }));
|
||||
await user.click(editor.getByRole('tab', { name: 'test.file' }));
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(editorActivateFile(testFile.uuid));
|
||||
});
|
||||
|
||||
it.each(['enter', 'space'])(
|
||||
'should dispatch activate action when % button is pressed',
|
||||
async (button) => {
|
||||
it.each(['{Enter}', '{Space}'])(
|
||||
'should dispatch activate action when %s key is pressed',
|
||||
async (key) => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
jest.mocked(useFileStoragePath).mockReturnValue(testFile.path);
|
||||
|
||||
const [editor, dispatch] = testRender(<Editor />, {
|
||||
const [user, editor, dispatch] = testRender(<Editor />, {
|
||||
editor: { openFileUuids: [testFile.uuid] },
|
||||
});
|
||||
|
||||
userEvent.type(
|
||||
editor.getByRole('tab', { name: 'test.file' }),
|
||||
`{${button}}`,
|
||||
);
|
||||
await user.type(editor.getByRole('tab', { name: 'test.file' }), key);
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
editorActivateFile(testFile.uuid),
|
||||
@@ -60,11 +60,11 @@ describe('Editor', () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
jest.mocked(useFileStoragePath).mockReturnValue(testFile.path);
|
||||
|
||||
const [editor, dispatch] = testRender(<Editor />, {
|
||||
const [user, editor, dispatch] = testRender(<Editor />, {
|
||||
editor: { openFileUuids: [testFile.uuid] },
|
||||
});
|
||||
|
||||
userEvent.click(editor.getByRole('button', { name: 'Close test.file' }));
|
||||
await user.click(editor.getByRole('button', { name: 'Close test.file' }));
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(editorCloseFile(testFile.uuid));
|
||||
});
|
||||
@@ -73,122 +73,115 @@ describe('Editor', () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
jest.mocked(useFileStoragePath).mockReturnValue(testFile.path);
|
||||
|
||||
const [editor, dispatch] = testRender(<Editor />, {
|
||||
const [user, editor, dispatch] = testRender(<Editor />, {
|
||||
editor: { openFileUuids: [testFile.uuid] },
|
||||
});
|
||||
|
||||
userEvent.type(editor.getByRole('tab', { name: 'test.file' }), '{delete}');
|
||||
await user.type(editor.getByRole('tab', { name: 'test.file' }), '{Delete}');
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(editorCloseFile(testFile.uuid));
|
||||
});
|
||||
});
|
||||
|
||||
describe('context menu', () => {
|
||||
let editor: RenderResult;
|
||||
let code: monaco.editor.ICodeEditor;
|
||||
|
||||
beforeEach(async () => {
|
||||
it('should hide the context menu when Escape is pressed', async () => {
|
||||
const didCreate = new Promise<monaco.editor.ICodeEditor>((resolve) =>
|
||||
monaco.editor.onDidCreateEditor(resolve),
|
||||
);
|
||||
|
||||
[editor] = testRender(<Editor />);
|
||||
code = await didCreate;
|
||||
const [user, editor] = testRender(<Editor />);
|
||||
const code = await didCreate;
|
||||
|
||||
code.setModel(monaco.editor.createModel('test'));
|
||||
|
||||
expect(
|
||||
editor.queryByRole('menu', { name: 'Editor context menu' }),
|
||||
).toBeNull();
|
||||
|
||||
// HACK: monaco editor uses deprecated event fields (keyCode),
|
||||
// so regular userEvent.type() doesn't work. testing library
|
||||
// doesn't have ContextMenu in its keymap either.
|
||||
fireEvent(
|
||||
editor.getByRole('textbox', { name: /^Editor content/ }),
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ContextMenu',
|
||||
code: 'ContextMenu',
|
||||
keyCode: 93,
|
||||
}),
|
||||
);
|
||||
|
||||
const contextMenu = await editor.findByRole('menu', {
|
||||
name: 'Editor context menu',
|
||||
});
|
||||
|
||||
expect(contextMenu).toBeInTheDocument();
|
||||
|
||||
// a11y: first item in menu should be focused when menu opens
|
||||
await waitFor(() =>
|
||||
expect(editor.getByRole('menuitem', { name: 'Copy' })).toHaveFocus(),
|
||||
);
|
||||
|
||||
// FIXME: use userEvent instead of fireEvent
|
||||
// blocked by https://github.com/palantir/blueprint/pull/5349
|
||||
// await user.keyboard('{Escape}');
|
||||
user;
|
||||
fireEvent.keyDown(document.activeElement ?? document, {
|
||||
key: 'Escape',
|
||||
keyCode: 27,
|
||||
which: 27,
|
||||
});
|
||||
|
||||
await waitFor(() => expect(contextMenu).not.toBeInTheDocument());
|
||||
|
||||
// editor should be focused after context menu closes
|
||||
expect(
|
||||
editor.getByRole('textbox', { name: /^Editor content/ }),
|
||||
).toHaveFocus();
|
||||
});
|
||||
|
||||
describe('keyboard interaction', () => {
|
||||
let contextMenu: HTMLElement;
|
||||
it('should hide the context menu when clicking away', async () => {
|
||||
const didCreate = new Promise<monaco.editor.ICodeEditor>((resolve) =>
|
||||
monaco.editor.onDidCreateEditor(resolve),
|
||||
);
|
||||
|
||||
beforeEach(async () => {
|
||||
// HACK: monaco editor uses deprecated event fields (keyCode),
|
||||
// so regular userEvent.type() doesn't work. testing library
|
||||
// doesn't have ContextMenu in its keymap either.
|
||||
fireEvent(
|
||||
editor.getByRole('textbox', { name: /^Editor content/ }),
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'ContextMenu',
|
||||
code: 'ContextMenu',
|
||||
keyCode: 93,
|
||||
}),
|
||||
);
|
||||
const [user, editor] = testRender(<Editor />);
|
||||
const code = await didCreate;
|
||||
|
||||
contextMenu = await editor.findByRole('menu', {
|
||||
name: 'Editor context menu',
|
||||
});
|
||||
code.setModel(monaco.editor.createModel('test'));
|
||||
|
||||
expect(contextMenu).toBeInTheDocument();
|
||||
expect(
|
||||
editor.queryByRole('menu', { name: 'Editor context menu' }),
|
||||
).toBeNull();
|
||||
|
||||
// a11y: first item in menu should be focused when menu opens
|
||||
await waitFor(() =>
|
||||
expect(
|
||||
editor.getByRole('menuitem', { name: 'Copy' }),
|
||||
).toHaveFocus(),
|
||||
);
|
||||
await user.pointer({
|
||||
keys: '[MouseRight]',
|
||||
target: editor.getByRole('textbox', { name: /^Editor content/ }),
|
||||
});
|
||||
|
||||
it('should hide the context menu when Escape is pressed', async () => {
|
||||
userEvent.keyboard('{esc}');
|
||||
|
||||
await waitFor(() => expect(contextMenu).not.toBeInTheDocument());
|
||||
|
||||
// editor should be focused after context menu closes
|
||||
expect(
|
||||
editor.getByRole('textbox', { name: /^Editor content/ }),
|
||||
).toHaveFocus();
|
||||
const contextMenu = await editor.findByRole('menu', {
|
||||
name: 'Editor context menu',
|
||||
});
|
||||
|
||||
expect(contextMenu).toBeInTheDocument();
|
||||
|
||||
// a11y: first item in menu should be focused when menu opens
|
||||
await waitFor(() =>
|
||||
expect(editor.getByRole('menuitem', { name: 'Copy' })).toHaveFocus(),
|
||||
);
|
||||
const overlay = document
|
||||
.getElementsByClassName(Classes.OVERLAY_BACKDROP)
|
||||
.item(0);
|
||||
|
||||
defined(overlay);
|
||||
|
||||
await user.click(overlay);
|
||||
|
||||
await waitFor(() => expect(contextMenu).not.toBeInTheDocument());
|
||||
|
||||
// editor should be focused after context menu closes
|
||||
expect(
|
||||
editor.getByRole('textbox', { name: /^Editor content/ }),
|
||||
).toHaveFocus();
|
||||
});
|
||||
|
||||
describe('mouse interaction', () => {
|
||||
let contextMenu: HTMLElement;
|
||||
|
||||
beforeEach(async () => {
|
||||
userEvent.click(
|
||||
editor.getByRole('textbox', { name: /^Editor content/ }),
|
||||
{
|
||||
button: 2,
|
||||
},
|
||||
);
|
||||
|
||||
contextMenu = await editor.findByRole('menu', {
|
||||
name: 'Editor context menu',
|
||||
});
|
||||
|
||||
expect(contextMenu).toBeInTheDocument();
|
||||
|
||||
// a11y: first item in menu should be focused when menu opens
|
||||
await waitFor(() =>
|
||||
expect(
|
||||
editor.getByRole('menuitem', { name: 'Copy' }),
|
||||
).toHaveFocus(),
|
||||
);
|
||||
});
|
||||
|
||||
it('should hide the context menu when clicking away', async () => {
|
||||
const overlay = document
|
||||
.getElementsByClassName(Classes.OVERLAY_BACKDROP)
|
||||
.item(0);
|
||||
|
||||
defined(overlay);
|
||||
|
||||
userEvent.click(overlay);
|
||||
|
||||
await waitFor(() => expect(contextMenu).not.toBeInTheDocument());
|
||||
|
||||
// editor should be focused after context menu closes
|
||||
expect(
|
||||
editor.getByRole('textbox', { name: /^Editor content/ }),
|
||||
).toHaveFocus();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { testRender, uuid } from '../../test';
|
||||
import { FileMetadata } from '../fileStorage';
|
||||
@@ -33,36 +32,36 @@ const testFile: FileMetadata = {
|
||||
};
|
||||
|
||||
describe('archive button', () => {
|
||||
it('should dispatch action when clicked', () => {
|
||||
it('should dispatch action when clicked', async () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
const button = explorer.getByTitle('Backup all files');
|
||||
expect(button).toBeEnabled();
|
||||
|
||||
userEvent.click(button);
|
||||
await user.click(button);
|
||||
expect(dispatch).toHaveBeenCalledWith(explorerArchiveAllFiles());
|
||||
});
|
||||
});
|
||||
|
||||
describe('import file button', () => {
|
||||
it('should dispatch action when clicked', async () => {
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
const button = explorer.getByTitle('Import a file');
|
||||
|
||||
userEvent.click(button);
|
||||
await user.click(button);
|
||||
expect(dispatch).toHaveBeenCalledWith(explorerImportFiles());
|
||||
});
|
||||
});
|
||||
|
||||
describe('new file button', () => {
|
||||
it('should dispatch action when clicked', async () => {
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
const button = explorer.getByTitle('Create a new file');
|
||||
|
||||
userEvent.click(button);
|
||||
await user.click(button);
|
||||
expect(dispatch).toHaveBeenCalledWith(explorerCreateNewFile());
|
||||
});
|
||||
});
|
||||
@@ -70,11 +69,11 @@ describe('new file button', () => {
|
||||
describe('tree item', () => {
|
||||
it('should dispatch action when clicked', async () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
const treeItem = explorer.getByRole('treeitem', { name: 'test.file' });
|
||||
|
||||
userEvent.click(treeItem);
|
||||
await user.click(treeItem);
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
explorerUserActivateFile('test.file', uuid(0)),
|
||||
@@ -83,12 +82,12 @@ describe('tree item', () => {
|
||||
|
||||
it('should dispatch action when key is pressed', async () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
const treeItem = explorer.getByRole('treeitem', { name: 'test.file' });
|
||||
|
||||
userEvent.click(treeItem);
|
||||
userEvent.keyboard('{enter}');
|
||||
await user.click(treeItem);
|
||||
await user.keyboard('{Enter}');
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
explorerUserActivateFile('test.file', uuid(0)),
|
||||
@@ -98,13 +97,13 @@ describe('tree item', () => {
|
||||
describe('duplicate', () => {
|
||||
it('should dispatch action when button is clicked', async () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
// NB: this button is intentionally not accessible (by role) since
|
||||
// there is a keyboard shortcut.
|
||||
const button = explorer.getByTitle('Duplicate test.file');
|
||||
|
||||
userEvent.click(button);
|
||||
await user.click(button);
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(explorerDuplicateFile('test.file'));
|
||||
|
||||
@@ -114,12 +113,12 @@ describe('tree item', () => {
|
||||
|
||||
it('should dispatch action when key is pressed', async () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
const treeItem = explorer.getByRole('treeitem', { name: 'test.file' });
|
||||
|
||||
userEvent.click(treeItem);
|
||||
userEvent.keyboard('{ctrl}d');
|
||||
await user.click(treeItem);
|
||||
await user.keyboard('{Control>}d{/Control}');
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(explorerDuplicateFile('test.file'));
|
||||
});
|
||||
@@ -128,13 +127,13 @@ describe('tree item', () => {
|
||||
describe('rename', () => {
|
||||
it('should dispatch action when button is clicked', async () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
// NB: this button is intentionally not accessible (by role) since
|
||||
// there is a keyboard shortcut.
|
||||
const button = explorer.getByTitle('Rename test.file');
|
||||
|
||||
userEvent.click(button);
|
||||
await user.click(button);
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(explorerRenameFile('test.file'));
|
||||
|
||||
@@ -144,12 +143,12 @@ describe('tree item', () => {
|
||||
|
||||
it('should dispatch action when key is pressed', async () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
const treeItem = explorer.getByRole('treeitem', { name: 'test.file' });
|
||||
|
||||
userEvent.click(treeItem);
|
||||
userEvent.keyboard('{f2}');
|
||||
await user.click(treeItem);
|
||||
await user.keyboard('{F2}');
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(explorerRenameFile('test.file'));
|
||||
});
|
||||
@@ -158,13 +157,13 @@ describe('tree item', () => {
|
||||
describe('export', () => {
|
||||
it('should dispatch export action when button is clicked', async () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
// NB: this button is intentionally not accessible (by role) since
|
||||
// there is a keyboard shortcut.
|
||||
const button = explorer.getByTitle('Export test.file');
|
||||
|
||||
userEvent.click(button);
|
||||
await user.click(button);
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(explorerExportFile('test.file'));
|
||||
|
||||
@@ -174,12 +173,12 @@ describe('tree item', () => {
|
||||
|
||||
it('should dispatch export action when key is pressed', async () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
const treeItem = explorer.getByRole('treeitem', { name: 'test.file' });
|
||||
|
||||
userEvent.click(treeItem);
|
||||
userEvent.keyboard('{ctrl}e');
|
||||
await user.click(treeItem);
|
||||
await user.keyboard('{Control>}e{/Control}');
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(explorerExportFile('test.file'));
|
||||
});
|
||||
@@ -188,13 +187,13 @@ describe('tree item', () => {
|
||||
describe('delete', () => {
|
||||
it('should dispatch delete action when button is clicked', async () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
// NB: this button is intentionally not accessible (by role) since
|
||||
// there is a keyboard shortcut.
|
||||
const button = explorer.getByTitle('Delete test.file');
|
||||
|
||||
userEvent.click(button);
|
||||
await user.click(button);
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
explorerDeleteFile('test.file', uuid(0)),
|
||||
@@ -206,12 +205,12 @@ describe('tree item', () => {
|
||||
|
||||
it('should dispatch delete action when key is pressed', async () => {
|
||||
jest.mocked(useFileStorageMetadata).mockReturnValue([testFile]);
|
||||
const [explorer, dispatch] = testRender(<Explorer />);
|
||||
const [user, explorer, dispatch] = testRender(<Explorer />);
|
||||
|
||||
const treeItem = explorer.getByRole('treeitem', { name: 'test.file' });
|
||||
|
||||
userEvent.click(treeItem);
|
||||
userEvent.keyboard('{del}');
|
||||
await user.click(treeItem);
|
||||
await user.keyboard('{Delete}');
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
explorerDeleteFile('test.file', uuid(0)),
|
||||
|
||||
@@ -12,7 +12,7 @@ it('should be valid', () => {
|
||||
// TODO: refactor this to a common function to be used by all alerts
|
||||
|
||||
// it should render
|
||||
const [message] = testRender(<>{toast.message}</>);
|
||||
const [, message] = testRender(<>{toast.message}</>);
|
||||
expect(message).toBeDefined();
|
||||
|
||||
// it should have a dismiss callback
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { cleanup, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { cleanup, fireEvent, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../../test';
|
||||
import DeleteFileAlert from './DeleteFileAlert';
|
||||
@@ -14,48 +13,56 @@ afterEach(() => {
|
||||
|
||||
describe('accept', () => {
|
||||
it('should dispatch accept action when delete button is clicked', async () => {
|
||||
const [dialog, dispatch] = testRender(<DeleteFileAlert />, {
|
||||
const [user, dialog, dispatch] = testRender(<DeleteFileAlert />, {
|
||||
explorer: { deleteFileAlert: { fileName: 'test.file', isOpen: true } },
|
||||
});
|
||||
|
||||
userEvent.click(dialog.getByRole('button', { name: 'Delete' }));
|
||||
await user.click(dialog.getByRole('button', { name: 'Delete' }));
|
||||
expect(dispatch).toHaveBeenCalledWith(deleteFileAlertDidAccept());
|
||||
});
|
||||
|
||||
it('should dispatch accept action when enter is pressed ', async () => {
|
||||
const [dialog, dispatch] = testRender(<DeleteFileAlert />, {
|
||||
const [user, dialog, dispatch] = testRender(<DeleteFileAlert />, {
|
||||
explorer: { deleteFileAlert: { fileName: 'test.file', isOpen: true } },
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(dialog.getByRole('button', { name: 'Delete' })).toHaveFocus(),
|
||||
);
|
||||
userEvent.keyboard('{enter}');
|
||||
await user.keyboard('{Enter}');
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(deleteFileAlertDidAccept());
|
||||
});
|
||||
});
|
||||
|
||||
describe('cancel', () => {
|
||||
it('should dispatch cancel when keep button is clicked', () => {
|
||||
const [dialog, dispatch] = testRender(<DeleteFileAlert />, {
|
||||
it('should dispatch cancel when keep button is clicked', async () => {
|
||||
const [user, dialog, dispatch] = testRender(<DeleteFileAlert />, {
|
||||
explorer: { deleteFileAlert: { fileName: 'test.file', isOpen: true } },
|
||||
});
|
||||
|
||||
userEvent.click(dialog.getByRole('button', { name: 'Keep' }));
|
||||
await user.click(dialog.getByRole('button', { name: 'Keep' }));
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(deleteFileAlertDidCancel());
|
||||
});
|
||||
|
||||
it('should dispatch cancel when escape button is pressed', async () => {
|
||||
const [dialog, dispatch] = testRender(<DeleteFileAlert />, {
|
||||
const [user, dialog, dispatch] = testRender(<DeleteFileAlert />, {
|
||||
explorer: { deleteFileAlert: { fileName: 'test.file', isOpen: true } },
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(dialog.getByRole('button', { name: 'Delete' })).toHaveFocus(),
|
||||
);
|
||||
userEvent.keyboard('{esc}');
|
||||
// FIXME: use userEvent instead of fireEvent
|
||||
// blocked by https://github.com/palantir/blueprint/pull/5349
|
||||
// await user.keyboard('{Escape}');
|
||||
user;
|
||||
fireEvent.keyDown(document.activeElement ?? document, {
|
||||
key: 'Escape',
|
||||
keyCode: 27,
|
||||
which: 27,
|
||||
});
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(deleteFileAlertDidCancel());
|
||||
});
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { waitFor } from '@testing-library/dom';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { fireEvent, waitFor } from '@testing-library/dom';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../../test';
|
||||
import DuplicateFileDialog from './DuplicateFileDialog';
|
||||
@@ -10,7 +9,7 @@ import { duplicateFileDialogDidAccept, duplicateFileDialogDidCancel } from './ac
|
||||
|
||||
describe('duplicate button', () => {
|
||||
it('should accept the dialog Duplicate is clicked', async () => {
|
||||
const [dialog, dispatch] = testRender(<DuplicateFileDialog />, {
|
||||
const [user, dialog, dispatch] = testRender(<DuplicateFileDialog />, {
|
||||
explorer: {
|
||||
duplicateFileDialog: { isOpen: true, fileName: 'source.file' },
|
||||
},
|
||||
@@ -21,17 +20,17 @@ describe('duplicate button', () => {
|
||||
// have to type a new file name before Duplicate button is enabled
|
||||
const input = dialog.getByRole('textbox', { name: 'File name' });
|
||||
await waitFor(() => expect(input).toHaveFocus());
|
||||
userEvent.type(input, 'new');
|
||||
await user.type(input, 'new', { skipClick: true });
|
||||
await waitFor(() => expect(button).not.toBeDisabled());
|
||||
|
||||
userEvent.click(button);
|
||||
await user.click(button);
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
duplicateFileDialogDidAccept('source.file', 'new.file'),
|
||||
);
|
||||
});
|
||||
|
||||
it('should accept the dialog when enter is pressed in the text input', async () => {
|
||||
const [dialog, dispatch] = testRender(<DuplicateFileDialog />, {
|
||||
const [user, dialog, dispatch] = testRender(<DuplicateFileDialog />, {
|
||||
explorer: {
|
||||
duplicateFileDialog: { isOpen: true, fileName: 'source.file' },
|
||||
},
|
||||
@@ -40,7 +39,7 @@ describe('duplicate button', () => {
|
||||
// have to type a new file name before Duplicate button is enabled
|
||||
const input = dialog.getByRole('textbox', { name: 'File name' });
|
||||
await waitFor(() => expect(input).toHaveFocus());
|
||||
userEvent.type(input, 'new{enter}');
|
||||
await user.type(input, 'new{Enter}', { skipClick: true });
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
duplicateFileDialogDidAccept('source.file', 'new.file'),
|
||||
@@ -48,7 +47,7 @@ describe('duplicate button', () => {
|
||||
});
|
||||
|
||||
it('should cancel when user clicks close button', async () => {
|
||||
const [dialog, dispatch] = testRender(<DuplicateFileDialog />, {
|
||||
const [user, dialog, dispatch] = testRender(<DuplicateFileDialog />, {
|
||||
explorer: {
|
||||
duplicateFileDialog: { isOpen: true, fileName: 'source.file' },
|
||||
},
|
||||
@@ -58,12 +57,12 @@ describe('duplicate button', () => {
|
||||
|
||||
await waitFor(() => expect(button).toBeVisible());
|
||||
|
||||
userEvent.click(button);
|
||||
await user.click(button);
|
||||
expect(dispatch).toHaveBeenCalledWith(duplicateFileDialogDidCancel());
|
||||
});
|
||||
|
||||
it('should cancel when user user presses esc key', async () => {
|
||||
const [dialog, dispatch] = testRender(<DuplicateFileDialog />, {
|
||||
const [user, dialog, dispatch] = testRender(<DuplicateFileDialog />, {
|
||||
explorer: {
|
||||
duplicateFileDialog: { isOpen: true, fileName: 'source.file' },
|
||||
},
|
||||
@@ -72,8 +71,15 @@ describe('duplicate button', () => {
|
||||
await waitFor(() =>
|
||||
expect(dialog.getByRole('textbox', { name: 'File name' })).toHaveFocus(),
|
||||
);
|
||||
|
||||
userEvent.keyboard('{esc}');
|
||||
// FIXME: use userEvent instead of fireEvent
|
||||
// blocked by https://github.com/palantir/blueprint/pull/5349
|
||||
// await user.keyboard('{Escape}');
|
||||
user;
|
||||
fireEvent.keyDown(document.activeElement ?? document, {
|
||||
key: 'Escape',
|
||||
keyCode: 27,
|
||||
which: 27,
|
||||
});
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(duplicateFileDialogDidCancel());
|
||||
});
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { waitFor } from '@testing-library/dom';
|
||||
import { fireEvent, waitFor } from '@testing-library/dom';
|
||||
import { cleanup } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../../test';
|
||||
import NewFileWizard from './NewFileWizard';
|
||||
@@ -15,30 +14,30 @@ afterEach(() => {
|
||||
|
||||
describe('accept', () => {
|
||||
it('should dispatch accept action when button is clicked', async () => {
|
||||
const [dialog, dispatch] = testRender(<NewFileWizard />, {
|
||||
const [user, dialog, dispatch] = testRender(<NewFileWizard />, {
|
||||
explorer: { newFileWizard: { isOpen: true } },
|
||||
});
|
||||
|
||||
const button = dialog.getByLabelText('Create');
|
||||
|
||||
// have to type a file name before Create button is enabled
|
||||
userEvent.type(dialog.getByRole('textbox', { name: 'File name' }), 'test');
|
||||
await user.type(dialog.getByRole('textbox', { name: 'File name' }), 'test');
|
||||
await waitFor(() => expect(button).not.toBeDisabled());
|
||||
|
||||
userEvent.click(button);
|
||||
await user.click(button);
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
newFileWizardDidAccept('test', '.py', Hub.Technic),
|
||||
);
|
||||
});
|
||||
|
||||
it('should dispatch accept action when enter is pressed ', async () => {
|
||||
const [dialog, dispatch] = testRender(<NewFileWizard />, {
|
||||
const [user, dialog, dispatch] = testRender(<NewFileWizard />, {
|
||||
explorer: { newFileWizard: { isOpen: true } },
|
||||
});
|
||||
|
||||
userEvent.type(
|
||||
await user.type(
|
||||
dialog.getByRole('textbox', { name: 'File name' }),
|
||||
'test{enter}',
|
||||
'test{Enter}',
|
||||
);
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
@@ -48,18 +47,18 @@ describe('accept', () => {
|
||||
});
|
||||
|
||||
describe('cancel', () => {
|
||||
it('should dispatch cancel when close button is clicked', () => {
|
||||
const [dialog, dispatch] = testRender(<NewFileWizard />, {
|
||||
it('should dispatch cancel when close button is clicked', async () => {
|
||||
const [user, dialog, dispatch] = testRender(<NewFileWizard />, {
|
||||
explorer: { newFileWizard: { isOpen: true } },
|
||||
});
|
||||
|
||||
userEvent.click(dialog.getByRole('button', { name: 'Close' }));
|
||||
await user.click(dialog.getByRole('button', { name: 'Close' }));
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(newFileWizardDidCancel());
|
||||
});
|
||||
|
||||
it('should dispatch cancel when escape button is pressed', async () => {
|
||||
const [dialog, dispatch] = testRender(<NewFileWizard />, {
|
||||
const [user, dialog, dispatch] = testRender(<NewFileWizard />, {
|
||||
explorer: { newFileWizard: { isOpen: true } },
|
||||
});
|
||||
|
||||
@@ -67,7 +66,15 @@ describe('cancel', () => {
|
||||
expect(dialog.getByRole('textbox', { name: 'File name' })).toHaveFocus(),
|
||||
);
|
||||
|
||||
userEvent.keyboard('{esc}');
|
||||
// FIXME: use userEvent instead of fireEvent
|
||||
// blocked by https://github.com/palantir/blueprint/pull/5349
|
||||
// await user.keyboard('{Escape}');
|
||||
user;
|
||||
fireEvent.keyDown(document.activeElement ?? document, {
|
||||
key: 'Escape',
|
||||
keyCode: 27,
|
||||
which: 27,
|
||||
});
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(newFileWizardDidCancel());
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { waitFor } from '@testing-library/dom';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../../test';
|
||||
import RenameFileDialog from './RenameFileDialog';
|
||||
@@ -10,7 +9,7 @@ import { renameFileDialogDidAccept, renameFileDialogDidCancel } from './actions'
|
||||
|
||||
describe('rename button', () => {
|
||||
it('should accept the dialog Rename is clicked', async () => {
|
||||
const [dialog, dispatch] = testRender(<RenameFileDialog />, {
|
||||
const [user, dialog, dispatch] = testRender(<RenameFileDialog />, {
|
||||
explorer: { renameFileDialog: { isOpen: true, fileName: 'old.file' } },
|
||||
});
|
||||
|
||||
@@ -19,24 +18,24 @@ describe('rename button', () => {
|
||||
// have to type a new file name before Rename button is enabled
|
||||
const input = dialog.getByLabelText('File name');
|
||||
await waitFor(() => expect(input).toHaveFocus());
|
||||
userEvent.type(input, 'new');
|
||||
await user.type(input, 'new', { skipClick: true });
|
||||
await waitFor(() => expect(button).not.toBeDisabled());
|
||||
|
||||
userEvent.click(button);
|
||||
await user.click(button);
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
renameFileDialogDidAccept('old.file', 'new.file'),
|
||||
);
|
||||
});
|
||||
|
||||
it('should accept the dialog when enter is pressed in the text input', async () => {
|
||||
const [dialog, dispatch] = testRender(<RenameFileDialog />, {
|
||||
const [user, dialog, dispatch] = testRender(<RenameFileDialog />, {
|
||||
explorer: { renameFileDialog: { isOpen: true, fileName: 'old.file' } },
|
||||
});
|
||||
|
||||
// have to type a new file name before Rename button is enabled
|
||||
const input = dialog.getByLabelText('File name');
|
||||
await waitFor(() => expect(input).toHaveFocus());
|
||||
userEvent.type(input, 'new{enter}');
|
||||
await user.type(input, 'new{Enter}', { skipClick: true });
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
renameFileDialogDidAccept('old.file', 'new.file'),
|
||||
@@ -44,7 +43,7 @@ describe('rename button', () => {
|
||||
});
|
||||
|
||||
it('should be cancellable', async () => {
|
||||
const [dialog, dispatch] = testRender(<RenameFileDialog />, {
|
||||
const [user, dialog, dispatch] = testRender(<RenameFileDialog />, {
|
||||
explorer: { renameFileDialog: { isOpen: true } },
|
||||
});
|
||||
|
||||
@@ -52,7 +51,7 @@ describe('rename button', () => {
|
||||
|
||||
await waitFor(() => expect(button).toBeVisible());
|
||||
|
||||
userEvent.click(button);
|
||||
await user.click(button);
|
||||
expect(dispatch).toHaveBeenCalledWith(renameFileDialogDidCancel());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@ afterEach(() => {
|
||||
|
||||
describe('LicenseDialog', () => {
|
||||
it('should show placeholder if no license is selected', () => {
|
||||
const [dialog] = testRender(
|
||||
const [, dialog] = testRender(
|
||||
<LicenseDialog isOpen={true} onClose={() => undefined} />,
|
||||
);
|
||||
|
||||
@@ -37,7 +37,7 @@ describe('LicenseDialog', () => {
|
||||
),
|
||||
);
|
||||
|
||||
const [dialog] = testRender(
|
||||
const [user, dialog] = testRender(
|
||||
<LicenseDialog isOpen={true} onClose={() => undefined} />,
|
||||
);
|
||||
|
||||
@@ -50,7 +50,7 @@ describe('LicenseDialog', () => {
|
||||
expect(dialog.queryByText('Joe Somebody')).toBeNull();
|
||||
|
||||
// then when you click on a license name, the license is shown
|
||||
treeNode.click();
|
||||
await user.click(treeNode);
|
||||
expect(dialog.getByText('Joe Somebody')).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Copyright (c) 2022 The Pybricks Authors
|
||||
|
||||
import { cleanup, getByLabelText, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../test';
|
||||
import Settings from './Settings';
|
||||
@@ -14,44 +13,44 @@ afterEach(() => {
|
||||
|
||||
describe('showDocs setting switch', () => {
|
||||
it('should toggle setting', async () => {
|
||||
const [settings] = testRender(<Settings />);
|
||||
const [user, settings] = testRender(<Settings />);
|
||||
|
||||
const showDocs = settings.getByLabelText('Documentation');
|
||||
expect(showDocs).toBeChecked();
|
||||
|
||||
userEvent.click(showDocs);
|
||||
await user.click(showDocs);
|
||||
expect(showDocs).not.toBeChecked();
|
||||
});
|
||||
});
|
||||
|
||||
describe('darkMode setting switch', () => {
|
||||
it('should toggle setting', async () => {
|
||||
const [settings] = testRender(<Settings />);
|
||||
const [user, settings] = testRender(<Settings />);
|
||||
|
||||
const darkMode = settings.getByLabelText('Dark mode');
|
||||
expect(darkMode).not.toBeChecked();
|
||||
expect(localStorage.getItem('usehooks-ts-ternary-dark-mode')).toBe(null);
|
||||
|
||||
userEvent.click(darkMode);
|
||||
await user.click(darkMode);
|
||||
expect(darkMode).toBeChecked();
|
||||
expect(localStorage.getItem('usehooks-ts-ternary-dark-mode')).toBe('"dark"');
|
||||
|
||||
userEvent.click(darkMode);
|
||||
await user.click(darkMode);
|
||||
expect(darkMode).not.toBeChecked();
|
||||
expect(localStorage.getItem('usehooks-ts-ternary-dark-mode')).toBe('"light"');
|
||||
});
|
||||
});
|
||||
|
||||
describe('flashCurrentProgram setting switch', () => {
|
||||
it('should toggle the setting', () => {
|
||||
const [settings] = testRender(<Settings />);
|
||||
it('should toggle the setting', async () => {
|
||||
const [user, settings] = testRender(<Settings />);
|
||||
|
||||
expect(localStorage.getItem('setting.flashCurrentProgram')).toBe(null);
|
||||
|
||||
settings.getByLabelText('Include current program').click();
|
||||
await user.click(settings.getByLabelText('Include current program'));
|
||||
expect(localStorage.getItem('setting.flashCurrentProgram')).toBe('true');
|
||||
|
||||
settings.getByLabelText('Include current program').click();
|
||||
await user.click(settings.getByLabelText('Include current program'));
|
||||
expect(localStorage.getItem('setting.flashCurrentProgram')).toBe('false');
|
||||
});
|
||||
});
|
||||
@@ -61,20 +60,20 @@ describe('hubName setting', () => {
|
||||
// old settings did not use json format, so lack quotes
|
||||
localStorage.setItem('setting.hubName', 'old name');
|
||||
|
||||
const [settings] = testRender(<Settings />);
|
||||
const [, settings] = testRender(<Settings />);
|
||||
|
||||
const textBox = settings.getByLabelText('Hub name');
|
||||
|
||||
expect(textBox).toHaveValue('old name');
|
||||
});
|
||||
|
||||
it('should update the setting', () => {
|
||||
const [settings] = testRender(<Settings />);
|
||||
it('should update the setting', async () => {
|
||||
const [user, settings] = testRender(<Settings />);
|
||||
|
||||
expect(localStorage.getItem('setting.hubName')).toBe(null);
|
||||
|
||||
const textBox = settings.getByLabelText('Hub name');
|
||||
userEvent.type(textBox, 'test name');
|
||||
await user.type(textBox, 'test name');
|
||||
|
||||
expect(localStorage.getItem('setting.hubName')).toBe('"test name"');
|
||||
});
|
||||
@@ -82,19 +81,19 @@ describe('hubName setting', () => {
|
||||
|
||||
describe('about dialog', () => {
|
||||
it('should open the dialog when the button is clicked', async () => {
|
||||
const [settings] = testRender(<Settings />);
|
||||
const [user, settings] = testRender(<Settings />);
|
||||
|
||||
const appName = process.env.REACT_APP_NAME;
|
||||
|
||||
expect(settings.queryByRole('dialog', { name: `About ${appName}` })).toBeNull();
|
||||
|
||||
settings.getByText('About').click();
|
||||
await user.click(settings.getByText('About'));
|
||||
|
||||
const dialog = settings.getByRole('dialog', { name: `About ${appName}` });
|
||||
|
||||
expect(dialog).toBeVisible();
|
||||
|
||||
getByLabelText(dialog, 'Close').click();
|
||||
await user.click(getByLabelText(dialog, 'Close'));
|
||||
|
||||
await waitFor(() => expect(dialog).not.toBeVisible());
|
||||
});
|
||||
|
||||
+3
-3
@@ -78,9 +78,9 @@ function addWhichToKeyboardEvent(e: KeyboardEvent) {
|
||||
Object.defineProperty(e, 'which', { value: which });
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', addWhichToKeyboardEvent);
|
||||
document.addEventListener('keypress', addWhichToKeyboardEvent);
|
||||
document.addEventListener('keyup', addWhichToKeyboardEvent);
|
||||
document.addEventListener('keydown', addWhichToKeyboardEvent, { capture: true });
|
||||
document.addEventListener('keypress', addWhichToKeyboardEvent, { capture: true });
|
||||
document.addEventListener('keyup', addWhichToKeyboardEvent, { capture: true });
|
||||
|
||||
Object.defineProperty(global.self, 'crypto', {
|
||||
value: crypto.webcrypto,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Copyright (c) 2021-2022 The Pybricks Authors
|
||||
|
||||
import { waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../test';
|
||||
import { BleConnectionState } from '../ble/reducers';
|
||||
@@ -11,7 +10,7 @@ import StatusBar from './StatusBar';
|
||||
it('should show popover when hub name is clicked', async () => {
|
||||
const testHubName = 'Test hub';
|
||||
|
||||
const [statusBar] = testRender(<StatusBar />, {
|
||||
const [user, statusBar] = testRender(<StatusBar />, {
|
||||
ble: {
|
||||
connection: BleConnectionState.Connected,
|
||||
deviceName: testHubName,
|
||||
@@ -22,7 +21,7 @@ it('should show popover when hub name is clicked', async () => {
|
||||
},
|
||||
});
|
||||
|
||||
userEvent.click(statusBar.getByText(testHubName));
|
||||
await user.click(statusBar.getByText(testHubName));
|
||||
|
||||
await waitFor(() => statusBar.getByText('Connected to:'));
|
||||
});
|
||||
@@ -30,7 +29,7 @@ it('should show popover when hub name is clicked', async () => {
|
||||
it('should show popover when battery is clicked', async () => {
|
||||
const testHubName = 'Test hub';
|
||||
|
||||
const [statusBar] = testRender(<StatusBar />, {
|
||||
const [user, statusBar] = testRender(<StatusBar />, {
|
||||
ble: {
|
||||
connection: BleConnectionState.Connected,
|
||||
deviceName: testHubName,
|
||||
@@ -41,7 +40,7 @@ it('should show popover when battery is clicked', async () => {
|
||||
},
|
||||
});
|
||||
|
||||
userEvent.click(statusBar.getByTitle('Battery'));
|
||||
await user.click(statusBar.getByTitle('Battery'));
|
||||
|
||||
await waitFor(() => statusBar.getByText('Battery level is OK.'));
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import Toolbar from './Toolbar';
|
||||
|
||||
describe('toolbar', () => {
|
||||
it('should have bluetooth button', () => {
|
||||
const [toolbar] = testRender(<Toolbar />);
|
||||
const [, toolbar] = testRender(<Toolbar />);
|
||||
|
||||
const runButton = toolbar.getByRole('button', { name: 'Bluetooth' });
|
||||
|
||||
@@ -15,7 +15,7 @@ describe('toolbar', () => {
|
||||
});
|
||||
|
||||
it('should have flash button', () => {
|
||||
const [toolbar] = testRender(<Toolbar />);
|
||||
const [, toolbar] = testRender(<Toolbar />);
|
||||
|
||||
const runButton = toolbar.getByRole('button', { name: 'Flash' });
|
||||
|
||||
@@ -23,7 +23,7 @@ describe('toolbar', () => {
|
||||
});
|
||||
|
||||
it('should have run button', () => {
|
||||
const [toolbar] = testRender(<Toolbar />);
|
||||
const [, toolbar] = testRender(<Toolbar />);
|
||||
|
||||
const runButton = toolbar.getByRole('button', { name: 'Run' });
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('toolbar', () => {
|
||||
});
|
||||
|
||||
it('should have stop button', () => {
|
||||
const [toolbar] = testRender(<Toolbar />);
|
||||
const [, toolbar] = testRender(<Toolbar />);
|
||||
|
||||
const runButton = toolbar.getByRole('button', { name: 'Stop' });
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('toolbar', () => {
|
||||
});
|
||||
|
||||
it('should have repl button', () => {
|
||||
const [toolbar] = testRender(<Toolbar />);
|
||||
const [, toolbar] = testRender(<Toolbar />);
|
||||
|
||||
const runButton = toolbar.getByRole('button', { name: 'REPL' });
|
||||
|
||||
|
||||
@@ -11,12 +11,12 @@ afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should dispatch action when clicked', () => {
|
||||
const [button, dispatch] = testRender(
|
||||
it('should dispatch action when clicked', async () => {
|
||||
const [user, button, dispatch] = testRender(
|
||||
<BluetoothButton id="test-bluetooth-button" />,
|
||||
);
|
||||
|
||||
button.getByRole('button', { name: 'Bluetooth' }).click();
|
||||
await user.click(button.getByRole('button', { name: 'Bluetooth' }));
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(toggleBluetooth());
|
||||
});
|
||||
|
||||
@@ -11,10 +11,10 @@ afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should dispatch action when clicked', () => {
|
||||
const [button, dispatch] = testRender(<FlashButton id="test-flash-button" />);
|
||||
it('should dispatch action when clicked', async () => {
|
||||
const [user, button, dispatch] = testRender(<FlashButton id="test-flash-button" />);
|
||||
|
||||
button.getByRole('button', { name: 'Flash' }).click();
|
||||
await user.click(button.getByRole('button', { name: 'Flash' }));
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(flashFirmware(null, false, ''));
|
||||
});
|
||||
|
||||
@@ -12,12 +12,12 @@ afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should dispatch action when clicked', () => {
|
||||
const [button, dispatch] = testRender(<ReplButton id="test-repl-button" />, {
|
||||
it('should dispatch action when clicked', async () => {
|
||||
const [user, button, dispatch] = testRender(<ReplButton id="test-repl-button" />, {
|
||||
hub: { runtime: HubRuntimeState.Idle },
|
||||
});
|
||||
|
||||
button.getByRole('button', { name: 'REPL' }).click();
|
||||
await user.click(button.getByRole('button', { name: 'REPL' }));
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(repl());
|
||||
});
|
||||
|
||||
@@ -12,13 +12,13 @@ afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should dispatch action when clicked', () => {
|
||||
const [button, dispatch] = testRender(<RunButton id="test-run-button" />, {
|
||||
it('should dispatch action when clicked', async () => {
|
||||
const [user, button, dispatch] = testRender(<RunButton id="test-run-button" />, {
|
||||
editor: { isReady: true },
|
||||
hub: { runtime: HubRuntimeState.Idle },
|
||||
});
|
||||
|
||||
button.getByRole('button', { name: 'Run' }).click();
|
||||
await user.click(button.getByRole('button', { name: 'Run' }));
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(downloadAndRun());
|
||||
});
|
||||
|
||||
@@ -12,12 +12,12 @@ afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('should dispatch action when clicked', () => {
|
||||
const [button, dispatch] = testRender(<StopButton id="test-stop-button" />, {
|
||||
it('should dispatch action when clicked', async () => {
|
||||
const [user, button, dispatch] = testRender(<StopButton id="test-stop-button" />, {
|
||||
hub: { runtime: HubRuntimeState.Running },
|
||||
});
|
||||
|
||||
button.getByRole('button', { name: 'Stop' }).click();
|
||||
await user.click(button.getByRole('button', { name: 'Stop' }));
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(stop());
|
||||
});
|
||||
|
||||
+5
-2
@@ -4,6 +4,8 @@
|
||||
import { HotkeysProvider } from '@blueprintjs/core';
|
||||
import { I18nContext, I18nManager } from '@shopify/react-i18n';
|
||||
import { RenderResult, render } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import type { UserEvent } from '@testing-library/user-event/dist/types/setup';
|
||||
import React, { ReactElement } from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { AnyAction, DeepPartial, PreloadedState, createStore } from 'redux';
|
||||
@@ -141,7 +143,8 @@ export function lookup(obj: unknown, id: string): string | undefined {
|
||||
export const testRender = (
|
||||
component: ReactElement,
|
||||
state?: PreloadedState<RootState>,
|
||||
): [RenderResult, jest.SpyInstance<AnyAction, [action: AnyAction]>] => {
|
||||
): [UserEvent, RenderResult, jest.SpyInstance<AnyAction, [action: AnyAction]>] => {
|
||||
const user = userEvent.setup();
|
||||
const store = createStore(rootReducer, state);
|
||||
const dispatch = jest.spyOn(store, 'dispatch');
|
||||
|
||||
@@ -155,7 +158,7 @@ export const testRender = (
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
return [result, dispatch];
|
||||
return [user, result, dispatch];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user