Skip to content

Commit

Permalink
test: added test for timepicker (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
anuraghazra authored Oct 12, 2020
1 parent 786077b commit 759e100
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 11 deletions.
4 changes: 2 additions & 2 deletions src/timepicker/TimePickerColumn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { TIME_PICKER_COLUMN_KEYS } from "./__keys";
import { TimePickerColumnStateReturn } from "./TimePickerColumnState";

export type TimePickerColumnOptions = CompositeOptions &
Pick<TimePickerColumnStateReturn, "type">;
Pick<TimePickerColumnStateReturn, "columnType">;

export type TimePickerColumnHTMLProps = CompositeHTMLProps;

Expand All @@ -27,7 +27,7 @@ export const useTimePickerColumn = createHook<
useProps(options, htmlProps) {
return {
role: "listbox",
"aria-label": options.type,
"aria-label": options.columnType,
...htmlProps,
};
},
Expand Down
10 changes: 5 additions & 5 deletions src/timepicker/TimePickerColumnState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type ColumnType = "hour" | "minute" | "meridian";

export interface TimePickerColumnInitialState extends ValueBase<Date> {
visible?: boolean;
type?: ColumnType;
columnType?: ColumnType;
}

export const useTimePickerColumnState = (
Expand All @@ -19,7 +19,7 @@ export const useTimePickerColumnState = (
defaultValue = new Date(),
onChange,
visible,
type = "hour",
columnType = "hour",
} = props;

const [date, setDate] = useControllableState({
Expand All @@ -28,7 +28,7 @@ export const useTimePickerColumnState = (
onChange,
});

const selected = getSelectedValueFromDate(date, type);
const selected = getSelectedValueFromDate(date, columnType);

const composite = useCompositeState({
loop: true,
Expand All @@ -37,10 +37,10 @@ export const useTimePickerColumnState = (
});

const setSelected = (value: number) => {
setDate(getSelectedDateFromValue(value, date, type));
setDate(getSelectedDateFromValue(value, date, columnType));
};

return { selected, setSelected, visible, type, ...composite };
return { selected, setSelected, visible, columnType, ...composite };
};

export type TimePickerColumnStateReturn = ReturnType<
Expand Down
6 changes: 3 additions & 3 deletions src/timepicker/TimePickerState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,21 @@ export const useTimePickerState = (props: TimePickerStateProps = {}) => {
};

const hourState = useTimePickerColumnState({
type: "hour",
columnType: "hour",
value: time,
onChange: setTimeProp,
visible: popover.visible,
});

const minuteState = useTimePickerColumnState({
type: "minute",
columnType: "minute",
value: time,
onChange: setTimeProp,
visible: popover.visible,
});

const meridiesState = useTimePickerColumnState({
type: "meridian",
columnType: "meridian",
value: time,
onChange: setTimeProp,
visible: popover.visible,
Expand Down
2 changes: 1 addition & 1 deletion src/timepicker/__keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const TIME_PICKER_COLUMN_STATE_KEYS = [
"selected",
"setSelected",
"visible",
"type",
"columnType",
] as const;
const TIME_PICKER_STATE_KEYS = [
"fieldValue",
Expand Down
148 changes: 148 additions & 0 deletions src/timepicker/__tests__/TimePicker.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import * as React from "react";
import { axe, render, press } from "reakit-test-utils";
import {
TimePicker,
TimePickerColumn,
TimePickerTrigger,
TimePickerSegment,
TimePickerContent,
useTimePickerState,
TimePickerStateProps,
TimePickerColumnValue,
TimePickerSegmentField,
} from "..";

beforeAll(() => {
// https://github.com/jsdom/jsdom/issues/1695
Element.prototype.scrollIntoView = jest.fn();

// ChakraUI's focus() uses requestAnimationFrame so we need to mock it
jest
.spyOn(window, "requestAnimationFrame")
.mockImplementation((cb: any) => cb());
});

afterAll(() => {
(window.requestAnimationFrame as any).mockRestore();
});

const TimePickerComp: React.FC<TimePickerStateProps> = props => {
const state = useTimePickerState(props);

return (
<>
<TimePicker {...state}>
<TimePickerSegmentField data-testid="current-time" {...state}>
{state.segments.map((segment, i) => (
<TimePickerSegment key={i} segment={segment} {...state} />
))}
</TimePickerSegmentField>
<TimePickerTrigger {...state}>open</TimePickerTrigger>
</TimePicker>
<TimePickerContent data-testid="timepicker-content" {...state}>
<TimePickerColumn {...state.hourState}>
{state.hours.map(n => {
return (
<TimePickerColumnValue key={n} value={n} {...state.hourState}>
{n}
</TimePickerColumnValue>
);
})}
</TimePickerColumn>
<TimePickerColumn {...state.minuteState}>
{state.minutes.map((n, i) => {
return (
<TimePickerColumnValue key={n} value={i} {...state.minuteState}>
{n}
</TimePickerColumnValue>
);
})}
</TimePickerColumn>
<TimePickerColumn {...state.meridiesState}>
{state.meridies.map((n, i) => {
return (
<TimePickerColumnValue key={n} value={i} {...state.meridiesState}>
{n}
</TimePickerColumnValue>
);
})}
</TimePickerColumn>
</TimePickerContent>
</>
);
};

describe("TimePicker", () => {
it("should render correctly", () => {
const { getByTestId: testId } = render(
<TimePickerComp defaultValue="12:45pm" />,
);

expect(testId("current-time")).toHaveTextContent("12:45 PM");
});

it("should open and change time value", () => {
const { getByTestId: testId } = render(
<TimePickerComp defaultValue="12:45pm" />,
);

expect(testId("timepicker-content")).not.toBeVisible();
press.Tab();

press.ArrowDown(null, { altKey: true });

expect(testId("timepicker-content")).toBeVisible();

expect(document.activeElement).toHaveTextContent("12");
press.ArrowDown();
expect(document.activeElement).toHaveTextContent("1");

press.Enter();
expect(testId("timepicker-content")).not.toBeVisible();
expect(testId("current-time")).toHaveTextContent("1:45 PM");
});

it("should be able to navigate with keyboard", () => {
const { getByTestId: testId } = render(
<TimePickerComp defaultValue="12:45pm" />,
);

expect(testId("timepicker-content")).not.toBeVisible();
press.Tab();

press.ArrowDown(null, { altKey: true });

expect(testId("timepicker-content")).toBeVisible();

expect(document.activeElement).toHaveTextContent("12");
press.ArrowDown();
press.ArrowDown();
press.ArrowDown();
expect(document.activeElement).toHaveTextContent("3");

// Go to minute column
press.ArrowRight();
expect(document.activeElement).toHaveTextContent("45");
press.ArrowUp();
press.ArrowUp();
press.ArrowUp();
expect(document.activeElement).toHaveTextContent("42");

// Go to meridian column
press.ArrowRight();
expect(document.activeElement).toHaveTextContent("PM");
press.ArrowUp();
expect(document.activeElement).toHaveTextContent("AM");

press.Enter();
expect(testId("timepicker-content")).not.toBeVisible();
expect(testId("current-time")).toHaveTextContent("12:45 AM");
});

test("TimePicker renders with no a11y violations", async () => {
const { container } = render(<TimePickerComp />);
const results = await axe(container);

expect(results).toHaveNoViolations();
});
});

0 comments on commit 759e100

Please sign in to comment.