From 8f8595965919b134e846b6bbd87e77cf4e648c49 Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Sun, 3 Sep 2023 20:27:01 +0800 Subject: [PATCH] Update maskedtextinput tests Ensure component has 100% test coverage. --- .../MaskedTextInput/MaskedTextInput.test.tsx | 103 +++++++++++++++++- .../src/components/MaskedTextInput/index.tsx | 29 +++-- 2 files changed, 117 insertions(+), 15 deletions(-) diff --git a/categories/web/freeform/react/src/components/MaskedTextInput/MaskedTextInput.test.tsx b/categories/web/freeform/react/src/components/MaskedTextInput/MaskedTextInput.test.tsx index 2b94df0..f1fdab6 100644 --- a/categories/web/freeform/react/src/components/MaskedTextInput/MaskedTextInput.test.tsx +++ b/categories/web/freeform/react/src/components/MaskedTextInput/MaskedTextInput.test.tsx @@ -1,8 +1,9 @@ import * as React from 'react'; import { - cleanup, - render, - screen, + cleanup, fireEvent, + render, + screen, + act, waitFor, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { TextControl } from '@tesseract-design/web-base'; @@ -91,6 +92,102 @@ describe('MaskedTextInput', () => { expect(indicator).toBeInTheDocument(); }); + it('renders the indicator changing when switching visibility state', async () => { + render( + , + ); + + const indicator = screen.getByTestId('indicator'); + + await userEvent.click(indicator); + expect(indicator).toHaveTextContent('Hide'); + + await userEvent.click(indicator); + expect(indicator).toHaveTextContent('Show'); + }); + + it('renders the indicator changing when switching visibility state using function ref', async () => { + render( + , + ); + + const indicator = screen.getByTestId('indicator'); + + await userEvent.click(indicator); + expect(indicator).toHaveTextContent('Hide'); + + await userEvent.click(indicator); + expect(indicator).toHaveTextContent('Show'); + }); + + it('highlights the indicator when visibility is toggled via keyboard', async () => { + render( + , + ); + + const input = screen.getByTestId('input'); + const indicator = screen.getByTestId('indicator'); + + input.focus(); + fireEvent.keyDown(input, { code: 'Space', ctrlKey: true }); + expect(indicator).toHaveClass('text-tertiary'); + + fireEvent.keyUp(input, { code: 'Space', ctrlKey: true }); + expect(indicator).toHaveClass('text-primary'); + }); + + it('handles keydown events', async () => { + const onKeyDown = vi.fn(); + render( + , + ); + + const input = screen.getByTestId('input'); + + input.focus(); + fireEvent.keyDown(input, { code: 'Space', ctrlKey: true }); + expect(onKeyDown).toBeCalled(); + }); + + it('handles keyup events', async () => { + const onKeyUp = vi.fn(); + render( + , + ); + + const input = screen.getByTestId('input'); + + input.focus(); + fireEvent.keyUp(input, { code: 'Space', ctrlKey: true }); + expect(onKeyUp).toBeCalled(); + }); + + it('accepts a function ref', () => { + const ref = vi.fn(); + + render( + , + ); + + expect(ref).toBeCalled(); + }); + describe.each` size | inputClassName | hintClassName | indicatorClassName ${'small'} | ${'h-10'} | ${'pr-10'} | ${'w-10'} diff --git a/categories/web/freeform/react/src/components/MaskedTextInput/index.tsx b/categories/web/freeform/react/src/components/MaskedTextInput/index.tsx index c5aea57..b7eaefd 100644 --- a/categories/web/freeform/react/src/components/MaskedTextInput/index.tsx +++ b/categories/web/freeform/react/src/components/MaskedTextInput/index.tsx @@ -12,6 +12,10 @@ export type MaskedTextInputDerivedElement = HTMLElementTagNameMap[ typeof MaskedTextInputDerivedElementComponent ]; +type SelectionDirection = 'none' | 'forward' | 'backward'; + +const AVAILABLE_AUTO_COMPLETE_VALUES = ['current-password', 'new-password'] as const; + /** * Props of the {@link MaskedTextInput} component. */ @@ -55,7 +59,7 @@ export interface MaskedTextInputProps extends Omit { - const { current } = typeof ref === 'object' ? ref : defaultRef; - let selectionStart = 0; - let selectionEnd = 0; - let selectionDirection: 'none' | 'forward' | 'backward' | undefined = 'none' as const; - if (current) { - selectionStart = current.selectionStart ?? 0; - selectionEnd = current.selectionEnd ?? 0; - selectionDirection = current.selectionDirection ?? 'none' as const; - } + const effectiveRef = typeof ref === 'object' ? ref : defaultRef; + const current = effectiveRef.current as MaskedTextInputDerivedElement; + const selectionStart = current.selectionStart as number; + const selectionEnd = current.selectionEnd as number; + const selectionDirection = current.selectionDirection as SelectionDirection; + setVisible((prev) => !prev); setTimeout(() => { - current?.focus(); - current?.setSelectionRange(selectionStart, selectionEnd, selectionDirection); + current.focus(); + current.setSelectionRange(selectionStart, selectionEnd, selectionDirection); }); }, [ref, defaultRef]); @@ -288,7 +289,11 @@ export const MaskedTextInput = React.forwardRef< }, )} onClick={handleToggleVisible} + title={visible ? 'Hide' : 'Show'} > + + {visible ? 'Hide' : 'Show'} +