UNPKG

@guardian/threads

Version:
283 lines 17 kB
import { __awaiter, __generator } from "tslib"; import { fireEvent, waitFor, queryHelpers, act } from '@testing-library/react'; import { renderFocusedAsyncChip, renderFocusedAsyncChipWithMenu, keyCodes, } from './selectAsyncChipHelpers'; import { getEditButtonTestId } from '../SelectAsyncChip'; import { stagedForDeletionKey } from '../ChipWrapper'; import { menuItemTestId, menuItemEmulateHoverKey, } from '../../../../Menu/MenuItem'; var onInputChange = jest.fn(function (_) { return Promise.resolve([ { value: '1', label: '1' }, { value: '2', label: '2' }, { value: '3', label: '3' }, ]); }); describe('SelectAsyncChip', function () { describe('navigation between chips', function () { it('should focus the input and select its contents when entered from the left hand side', function () { return __awaiter(void 0, void 0, void 0, function () { var _a, selectAsyncChipInput, lhsInlineInput; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, renderFocusedAsyncChipWithMenu({ onInputChange: onInputChange, })]; case 1: _a = _b.sent(), selectAsyncChipInput = _a.selectAsyncChipInput, lhsInlineInput = _a.lhsInlineInput; fireEvent.keyDown(selectAsyncChipInput, keyCodes.Enter); // Select item '1' lhsInlineInput.selectionStart = lhsInlineInput.selectionEnd = 3; lhsInlineInput.focus(); fireEvent.keyDown(lhsInlineInput, keyCodes.ArrowRight); // Item '1' is now present and selected return [4 /*yield*/, waitFor(function () { expect(selectAsyncChipInput.selectionStart).toEqual(0); expect(selectAsyncChipInput.selectionEnd).toEqual(1); expect(document.activeElement).toBe(selectAsyncChipInput); })]; case 2: // Item '1' is now present and selected _b.sent(); return [2 /*return*/]; } }); }); }); it('should focus the input and select its contents when entered from the right hand side', function () { return __awaiter(void 0, void 0, void 0, function () { var _a, selectAsyncChipInput, rhsInlineInput; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, renderFocusedAsyncChipWithMenu({ onInputChange: onInputChange, })]; case 1: _a = _b.sent(), selectAsyncChipInput = _a.selectAsyncChipInput, rhsInlineInput = _a.rhsInlineInput; fireEvent.keyDown(selectAsyncChipInput, keyCodes.Enter); // Select item '1' rhsInlineInput.focus(); fireEvent.keyDown(rhsInlineInput, keyCodes.ArrowLeft); // Item '1' is now present and selected expect(selectAsyncChipInput.selectionStart).toEqual(0); expect(selectAsyncChipInput.selectionEnd).toEqual(1); expect(document.activeElement).toBe(selectAsyncChipInput); return [2 /*return*/]; } }); }); }); it('should focus the next chip at the start of the input when a right arrow key is pressed and the cursor is at the end of the input value', function () { var _a = renderFocusedAsyncChip(), selectAsyncChipInput = _a.selectAsyncChipInput, rhsInlineInput = _a.rhsInlineInput; selectAsyncChipInput.selectionStart = selectAsyncChipInput.selectionEnd = 7; fireEvent.keyDown(selectAsyncChipInput, keyCodes.ArrowRight); expect(document.activeElement).toEqual(rhsInlineInput); expect(rhsInlineInput.selectionStart).toBe(0); }); it('should focus the previous chip when a left arrow key is pressed and the cursor is at the beginning of the input value', function () { var _a = renderFocusedAsyncChip(), selectAsyncChipInput = _a.selectAsyncChipInput, lhsInlineInput = _a.lhsInlineInput; fireEvent.keyDown(selectAsyncChipInput, keyCodes.ArrowLeft); expect(document.activeElement).toEqual(lhsInlineInput); expect(lhsInlineInput.selectionStart).toBe(3); }); }); describe('input', function () { it('should render an input and present its value', function () { var selectAsyncChipInput = renderFocusedAsyncChip().selectAsyncChipInput; expect(selectAsyncChipInput.value).toBe('example'); }); it('should call onInputChanged when the input changes', function () { var _onInputChange = jest.fn(function (_) { return Promise.resolve([]); }); renderFocusedAsyncChip({ onInputChange: _onInputChange, }); // A change event is fired when renderFocusedAsyncChip is called, // to set the initial value of the input. expect(_onInputChange.mock.calls[0][0]).toBe('example'); }); it('should enter edit mode if a selection has been made and the element is focused', function () { var _a = renderFocusedAsyncChip(), selectAsyncChipInput = _a.selectAsyncChipInput, queryByTestId = _a.queryByTestId; expect(document.activeElement).toEqual(selectAsyncChipInput); expect(selectAsyncChipInput.selectionStart).toEqual(0); expect(selectAsyncChipInput.selectionEnd).toEqual(0); expect(queryByTestId(getEditButtonTestId(1))).toBe(null); }); it("should keep its input value, and display an 'invalid' state, when it loses focus and no option is selected", function () { return __awaiter(void 0, void 0, void 0, function () { var _a, selectAsyncChipInput, selectAsyncChipWrapper, rhsInlineInput; return __generator(this, function (_b) { _a = renderFocusedAsyncChip({ value: '' }), selectAsyncChipInput = _a.selectAsyncChipInput, selectAsyncChipWrapper = _a.selectAsyncChipWrapper, rhsInlineInput = _a.rhsInlineInput; selectAsyncChipInput.selectionStart = selectAsyncChipInput.selectionEnd = 7; act(function () { fireEvent.change(selectAsyncChipInput, { target: { value: 'omg' }, }); fireEvent.keyDown(selectAsyncChipInput, keyCodes.ArrowRight); }); expect(document.activeElement).toEqual(rhsInlineInput); expect(selectAsyncChipInput.value).toEqual('omg'); expect(selectAsyncChipWrapper.getAttribute('data-invalid')).toBe('true'); return [2 /*return*/]; }); }); }); it('should revert to the previously selected value when it loses focus and no option is selected', function () { return __awaiter(void 0, void 0, void 0, function () { var _a, menuItems, selectAsyncChipInput, lhsInlineInput; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, renderFocusedAsyncChipWithMenu({ onInputChange: onInputChange, })]; case 1: _a = _b.sent(), menuItems = _a.menuItems, selectAsyncChipInput = _a.selectAsyncChipInput, lhsInlineInput = _a.lhsInlineInput; fireEvent.click(menuItems[0]); // Select item '1' selectAsyncChipInput.focus(); // Enter edit mode fireEvent.change(selectAsyncChipInput, { target: { value: 'something else' }, }); // Change some text lhsInlineInput.focus(); // Focus elsewhere without selecting an option return [4 /*yield*/, waitFor(function () { return expect(selectAsyncChipInput.value).toEqual('1'); })]; case 2: _b.sent(); return [2 /*return*/]; } }); }); }); describe('character deletion', function () { /** * Test whether the async chip is staged for deletion given a combination of chip * input value and keyDown event. */ var testIfKeydownStagesDeletion = function (value, keyCode) { var opts = renderFocusedAsyncChip({ value: value, }); fireEvent.keyDown(opts.selectAsyncChipInput, keyCode); return queryHelpers.queryByAttribute(stagedForDeletionKey, opts.container, 'true'); }; [keyCodes.Delete, keyCodes.Backspace].forEach(function (keyCode) { it("should not stage deletion if the input is not empty and a " + keyCode.key + " keydown event is detected", function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { expect(testIfKeydownStagesDeletion('input has content', keyCode)).toBe(null); return [2 /*return*/]; }); }); }); it("should stage deletion if the input is empty and a " + keyCode.key + " keydown event is detected", function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { expect(testIfKeydownStagesDeletion('', keyCode)).not.toBe(null); return [2 /*return*/]; }); }); }); }); }); }); describe('option display and selection', function () { it('should display a menu when options are received', function () { return __awaiter(void 0, void 0, void 0, function () { var queryAllByTestId; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, renderFocusedAsyncChipWithMenu({ onInputChange: onInputChange, })]; case 1: queryAllByTestId = (_a.sent()).queryAllByTestId; expect(queryAllByTestId(menuItemTestId).length).toBe(3); return [2 /*return*/]; } }); }); }); it('should highlight the first option in the menu by default', function () { return __awaiter(void 0, void 0, void 0, function () { var queryAllByTestId, menuItems; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, renderFocusedAsyncChipWithMenu({ onInputChange: onInputChange, })]; case 1: queryAllByTestId = (_a.sent()).queryAllByTestId; menuItems = queryAllByTestId(menuItemTestId); expect(menuItems[0].getAttribute(menuItemEmulateHoverKey)).toBe('true'); expect(menuItems[1].getAttribute(menuItemEmulateHoverKey)).toBe(null); expect(menuItems[2].getAttribute(menuItemEmulateHoverKey)).toBe(null); return [2 /*return*/]; } }); }); }); it('should allow navigation of options with the arrow keys', function () { return __awaiter(void 0, void 0, void 0, function () { var _a, queryAllByTestId, selectAsyncChipInput, menuItems; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, renderFocusedAsyncChipWithMenu({ onInputChange: onInputChange })]; case 1: _a = _b.sent(), queryAllByTestId = _a.queryAllByTestId, selectAsyncChipInput = _a.selectAsyncChipInput; fireEvent.keyDown(selectAsyncChipInput, keyCodes.ArrowDown); fireEvent.keyDown(selectAsyncChipInput, keyCodes.ArrowDown); menuItems = queryAllByTestId(menuItemTestId); expect(menuItems[0].getAttribute(menuItemEmulateHoverKey)).toBe(null); expect(menuItems[1].getAttribute(menuItemEmulateHoverKey)).toBe(null); expect(menuItems[2].getAttribute(menuItemEmulateHoverKey)).toBe('true'); fireEvent.keyDown(selectAsyncChipInput, keyCodes.ArrowUp); expect(menuItems[0].getAttribute(menuItemEmulateHoverKey)).toBe(null); expect(menuItems[1].getAttribute(menuItemEmulateHoverKey)).toBe('true'); expect(menuItems[2].getAttribute(menuItemEmulateHoverKey)).toBe(null); return [2 /*return*/]; } }); }); }); it('should call onUpdate() when the enter key is pressed and an option is highlighted', function () { return __awaiter(void 0, void 0, void 0, function () { var onUpdate, selectAsyncChipInput, queryElements; return __generator(this, function (_a) { switch (_a.label) { case 0: onUpdate = jest.fn(); return [4 /*yield*/, renderFocusedAsyncChipWithMenu({ onInputChange: onInputChange, onUpdate: onUpdate, })]; case 1: selectAsyncChipInput = (_a.sent()).selectAsyncChipInput; fireEvent.keyDown(selectAsyncChipInput, keyCodes.ArrowDown); fireEvent.keyDown(selectAsyncChipInput, keyCodes.Enter); queryElements = onUpdate.mock.calls[0][0]; return [4 /*yield*/, waitFor(function () { return expect(queryElements[1].value).toEqual('2'); })]; case 2: _a.sent(); return [2 /*return*/]; } }); }); }); it('should call onUpdate() when an option is clicked', function () { return __awaiter(void 0, void 0, void 0, function () { var onUpdate, menuItems, queryElements; return __generator(this, function (_a) { switch (_a.label) { case 0: onUpdate = jest.fn(); return [4 /*yield*/, renderFocusedAsyncChipWithMenu({ onInputChange: onInputChange, onUpdate: onUpdate, })]; case 1: menuItems = (_a.sent()).menuItems; fireEvent.click(menuItems[0]); queryElements = onUpdate.mock.calls[0][0]; return [4 /*yield*/, waitFor(function () { return expect(queryElements[1].value).toEqual('1'); })]; case 2: _a.sent(); return [2 /*return*/]; } }); }); }); it('should select the highlighted option if the chip loses focus', function () { return __awaiter(void 0, void 0, void 0, function () { var onUpdate, selectAsyncChipInput, queryElements; return __generator(this, function (_a) { switch (_a.label) { case 0: onUpdate = jest.fn(); return [4 /*yield*/, renderFocusedAsyncChipWithMenu({ onUpdate: onUpdate, onInputChange: onInputChange })]; case 1: selectAsyncChipInput = (_a.sent()).selectAsyncChipInput; fireEvent.keyDown(selectAsyncChipInput, keyCodes.ArrowLeft); queryElements = onUpdate.mock.calls[0][0]; return [4 /*yield*/, waitFor(function () { return expect(queryElements[1].value).toEqual('1'); })]; case 2: _a.sent(); return [2 /*return*/]; } }); }); }); }); }); //# sourceMappingURL=SelectAsyncChip.spec.js.map