Skip to content

Convert components tests to typescript #117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@deephaven/eslint-config": "file:packages/eslint-config",
"@deephaven/prettier-config": "file:packages/prettier-config",
"@deephaven/stylelint-config": "file:packages/stylelint-config",
"@types/eslint": "^7.22.0",
"@types/stylelint": "^9.10.1",
"@typescript-eslint/eslint-plugin": "^4.19.0",
"@typescript-eslint/parser": "^4.19.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"@types/react": "^16.14.8",
"@types/react-beautiful-dnd": "^13.0.0",
"@types/react-dom": "^16.9.13",
"@types/react-test-renderer": "^16.9.0",
"@types/react-transition-group": "^4.4.0",
"@types/react-virtualized-auto-sizer": "^1.x",
"@types/react-window": "^1.x",
Expand All @@ -109,6 +110,7 @@
"prop-types": "^15.7.2",
"react-beautiful-dnd": "^13.0.0",
"react-dom": "^16.14.0",
"react-test-renderer": "^16.14.0",
"react-transition-group": "^2.3.1",
"react-virtualized-auto-sizer": "^1.0.2",
"react-window": "^1.8.5",
Expand Down
7 changes: 4 additions & 3 deletions packages/components/src/MaskedInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ type MaskedInputProps = {
/** One or more examples of valid values. Used when deciding if next keystroke is valid (as rest of the current value may be incomplete) */
example: string | string[];
/** The current selection to use for the input */
selection: SelectionSegment | null;
selection?: SelectionSegment;
/** Called when the value changes. Note the value may still be incomplete. */
onChange?(value: string): void;
/** Called when selection changes */
/** Called when selection changes */
onSelect?(segment: SelectionSegment): void;
/** Retrieve the next value for a provided segment */
getNextSegmentValue?(
Expand Down Expand Up @@ -254,7 +254,7 @@ const MaskedInput = React.forwardRef<HTMLInputElement, MaskedInputProps>(
selectionDirection
);
if (
selection !== null &&
selection != null &&
selectionStart === selection.selectionStart &&
selectionEnd === selection.selectionEnd
) {
Expand Down Expand Up @@ -472,6 +472,7 @@ MaskedInput.defaultProps = {
// no-op
},
getNextSegmentValue: (range, delta, segmentValue) => segmentValue,
selection: undefined,
onFocus(): void {
// no-op
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import RadioGroup from './RadioGroup';
import RadioItem from './RadioItem';

it('shows no markup with no children', () => {
const radio = mount(<RadioGroup onChange={jest.fn()}>{null}</RadioGroup>);
const radio = mount(<RadioGroup onChange={jest.fn()} />);
expect(radio.html()).toBe(null);
radio.unmount();
});
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/RadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import shortid from 'shortid';

type RadioGroupProps = {
/** The radio items to populate this radio. Should be of type RadioItem. */
children: React.ReactElement | React.ReactElement[];
children?: React.ReactElement | React.ReactElement[];

/** The name to use for the radio items. If not specified, a name is automatically generated */
name?: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React from 'react';
import { mount } from 'enzyme';
import type { ReactWrapper } from 'enzyme';
import { TimeUtils } from '@deephaven/utils';
import type { SelectionSegment } from './MaskedInput';
import TimeInput from './TimeInput';

type SelectionDirection = SelectionSegment['selectionDirection'];

const DEFAULT_VALUE = TimeUtils.parseTime('12:34:56');

function makeTimeInput({ value = DEFAULT_VALUE, onChange = jest.fn() } = {}) {
Expand All @@ -12,23 +16,26 @@ function makeTimeInput({ value = DEFAULT_VALUE, onChange = jest.fn() } = {}) {
function makeSelection(
selectionStart = 0,
selectionEnd = 0,
selectionDirection = 'none'
) {
selectionDirection: SelectionDirection = 'none'
): SelectionSegment {
return { selectionStart, selectionEnd, selectionDirection };
}

function typeString(timeInput, str) {
function typeString(timeInput: ReactWrapper, str: string) {
const inputField = timeInput.find('input');
for (let i = 0; i < str.length; i += 1) {
inputField.simulate('keydown', { key: str.charAt(i) });
}
}

function selectRange(timeInput, selectionRange) {
function selectRange(
timeInput: ReactWrapper,
selectionRange: SelectionSegment
) {
timeInput.find('input').simulate('select', { target: selectionRange });
}

function selectCursorPosition(timeInput, cursorPosition) {
function selectCursorPosition(timeInput: ReactWrapper, cursorPosition: number) {
selectRange(timeInput, makeSelection(cursorPosition, cursorPosition));
}

Expand All @@ -38,7 +45,7 @@ it('mounts and unmounts properly', () => {
});

describe('typing in matches mask', () => {
function testInput(text, expectedResult = text) {
function testInput(text: string, expectedResult = text) {
const timeInput = makeTimeInput({ value: 0 });
selectCursorPosition(timeInput, 0);
typeString(timeInput, text);
Expand Down Expand Up @@ -69,16 +76,17 @@ describe('typing in matches mask', () => {

describe('selection', () => {
function testSelectSegment(
cursorPosition,
expectedStart,
expectedEnd,
expectedDirection = 'backward'
cursorPosition: number,
expectedStart: number,
expectedEnd: number,
expectedDirection: SelectionDirection = 'backward'
) {
const timeInput = makeTimeInput();

selectCursorPosition(timeInput, cursorPosition);

const domInput = timeInput.find('input').getDOMNode();
const domInput = timeInput.find('input').getDOMNode() as HTMLInputElement;
expect(domInput).toBeInstanceOf(HTMLInputElement);
expect(domInput.selectionStart).toEqual(expectedStart);
expect(domInput.selectionEnd).toEqual(expectedEnd);
expect(domInput.selectionDirection).toEqual(expectedDirection);
Expand All @@ -87,9 +95,9 @@ describe('selection', () => {
}

function testSelectRange(
selectionStart,
selectionEnd,
selectionDirection = 'forward'
selectionStart: number,
selectionEnd: number,
selectionDirection: SelectionDirection = 'forward'
) {
const timeInput = makeTimeInput();

Expand All @@ -100,7 +108,8 @@ describe('selection', () => {
);
timeInput.find('input').simulate('select', { target: selection });

const domInput = timeInput.find('input').getDOMNode();
const domInput = timeInput.find('input').getDOMNode() as HTMLInputElement;
expect(domInput).toBeInstanceOf(HTMLInputElement);
expect(domInput.selectionStart).toEqual(selectionStart);
expect(domInput.selectionEnd).toEqual(selectionEnd);
expect(domInput.selectionDirection).toEqual(selectionDirection);
Expand Down Expand Up @@ -129,7 +138,11 @@ describe('selection', () => {
});

describe('select and type', () => {
function testSelectAndType(cursorPosition, str, expectedResult) {
function testSelectAndType(
cursorPosition: number,
str: string,
expectedResult: string
) {
const timeInput = makeTimeInput();
selectCursorPosition(timeInput, cursorPosition);

Expand All @@ -156,16 +169,20 @@ describe('select and type', () => {
describe('arrow left and right jumps segments', () => {
/**
*
* @param {number} cursorPosition The initial cursor position to start at
* @param {number|Array<number>} movement Keyboard movement to simulate, positive for right, negative for left. Eg. 2 means 2 right arrow presses, -3 means 3 left arrow presses
* @param {object} expectedSelection The selection to expect
* @param cursorPosition The initial cursor position to start at
* @param movement Keyboard movement to simulate, positive for right, negative for left. Eg. 2 means 2 right arrow presses, -3 means 3 left arrow presses
* @param expectedSelection The selection to expect
*/
function testArrowNavigation(cursorPosition, movement, expectedSelection) {
function testArrowNavigation(
cursorPosition: number,
movement: number | number[],
expectedSelection: SelectionSegment
) {
const timeInput = makeTimeInput();

selectRange(timeInput, makeSelection(cursorPosition, cursorPosition));

const movements = [].concat(movement);
const movements: number[] = ([] as number[]).concat(movement);
const inputField = timeInput.find('input');
for (let i = 0; i < movements.length; i += 1) {
const arrowMovement = movements[i];
Expand All @@ -183,7 +200,8 @@ describe('arrow left and right jumps segments', () => {
selectionEnd,
selectionDirection,
} = expectedSelection;
const domInput = timeInput.find('input').getDOMNode();
const domInput = timeInput.find('input').getDOMNode() as HTMLInputElement;
expect(domInput).toBeInstanceOf(HTMLInputElement);
expect(domInput.selectionStart).toEqual(selectionStart);
expect(domInput.selectionEnd).toEqual(selectionEnd);
expect(domInput.selectionDirection).toEqual(selectionDirection);
Expand Down Expand Up @@ -217,16 +235,16 @@ describe('arrow left and right jumps segments', () => {

describe('arrow up and down updates values in segments', () => {
function testArrowValue(
cursorPosition,
movement,
expectedValue,
cursorPosition: number,
movement: number | number[],
expectedValue: string,
value = DEFAULT_VALUE
) {
const timeInput = makeTimeInput({ value });

selectRange(timeInput, makeSelection(cursorPosition, cursorPosition));

const movements = [].concat(movement);
const movements: number[] = ([] as number[]).concat(movement);
const inputField = timeInput.find('input');
for (let i = 0; i < movements.length; i += 1) {
const arrowMovement = movements[i];
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/TimeInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const TimeInput = React.forwardRef<HTMLInputElement, TimeInputProps>(
onBlur = () => false,
} = props;
const [value, setValue] = useState(TimeUtils.formatTime(propsValue));
const [selection, setSelection] = useState<SelectionSegment | null>(null);
const [selection, setSelection] = useState<SelectionSegment>();
useEffect(() => {
setValue(TimeUtils.formatTime(propsValue));
}, [propsValue]);
Expand Down
36 changes: 0 additions & 36 deletions packages/components/src/__mocks__/lodash.debounce/index.js

This file was deleted.

40 changes: 40 additions & 0 deletions packages/components/src/__mocks__/lodash.debounce/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type debounceFn from 'lodash.debounce';

// lodash debounce needs mocking: https://github.com/facebook/jest/issues/3465#issuecomment-539496798

const debounce = jest
.fn<ReturnType<typeof debounceFn>, Parameters<typeof debounceFn>>()
.mockImplementation((callback, delay) => {
let timer: ReturnType<typeof setTimeout> | null = null;
let pendingArgs: Parameters<typeof debounceFn> | never[] = [];

const cancel = jest.fn(() => {
if (timer) {
clearTimeout(timer);
}
timer = null;
pendingArgs = [];
});

const flush = jest.fn(() => {
if (timer) {
callback(...pendingArgs);
cancel();
}
});

const wrapped = (...args: Parameters<typeof debounceFn>) => {
cancel();

pendingArgs = args;
timer = setTimeout(flush, wrapped.delay);
};

wrapped.cancel = cancel;
wrapped.flush = flush;
wrapped.delay = delay;

return wrapped;
});

export default debounce;
Loading