Skip to content
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

feat(dropdown): Add tests #113

Merged
merged 7 commits into from
Sep 16, 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
2 changes: 1 addition & 1 deletion src/dropdown/list/DropdownList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import DropdownListItem, {
} from "./item/DropdownListItem";
import {computeScrollAmountToMakeChildVisible} from "../../core/utils/dom/domUtils";

interface DropdownListProps<OptionIdShape extends string> {
export interface DropdownListProps<OptionIdShape extends string> {
isVisible: boolean;
options: DropdownOption<OptionIdShape>[];
selectedOption: DropdownSelectedOption<OptionIdShape>;
Expand Down
51 changes: 51 additions & 0 deletions src/dropdown/list/dropdown-list.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from "react";
import {render, screen} from "@testing-library/react";
import "@testing-library/jest-dom";

import {testA11y} from "../../core/utils/test/testUtils";
import DropdownList, {DropdownListProps} from "./DropdownList";

describe("<DropdownList />", () => {
const defaultDropdownListProps: DropdownListProps<string> = {
testid: "dropdown-list",
options: [
{id: "1", title: "dropdown-option-1"},
{id: "2", title: "dropdown-option-2"},
{id: "3", title: "dropdown-option-3"}
],
focusedOption: {id: "1", title: "test"},
isVisible: true,
onFocus: jest.fn(),
onSelect: jest.fn(),
selectedOption: {id: "1", title: "test"},
role: "listbox"
};

it("should render correctly", () => {
render(<DropdownList {...defaultDropdownListProps} />);
});

it("should pass a11y test", async () => {
const {container} = render(<DropdownList {...defaultDropdownListProps} />);

await testA11y(container, {
rules: {
"aria-required-parent": {enabled: false},
list: {enabled: false},
"aria-input-field-name": {enabled: false}
}
});
});

it("should render noOptionsMessage if options are empty", () => {
render(
<DropdownList
{...defaultDropdownListProps}
options={[]}
noOptionsMessage={"No options"}
/>
);

expect(screen.getByRole("listbox")).toContainElement(screen.getByText("No options"));
});
});
2 changes: 1 addition & 1 deletion src/dropdown/list/item/DropdownListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export type DropdownSelectedOption<Id = string, Context = any> =
| null
| undefined;

interface DropdownListItemProps<OptionIdShape = string> {
export interface DropdownListItemProps<OptionIdShape = string> {
testid?: string;
option: DropdownOption<OptionIdShape>;
selectedOption: DropdownSelectedOption<OptionIdShape>;
Expand Down
147 changes: 147 additions & 0 deletions src/dropdown/list/item/dropdown-list-item.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import React from "react";
import {render, screen, fireEvent} from "@testing-library/react";
import "@testing-library/jest-dom";
import userEvent from "@testing-library/user-event";

import {testA11y} from "../../../core/utils/test/testUtils";
import DropdownListItem, {DropdownListItemProps} from "./DropdownListItem";

describe("<DropdownListItem />", () => {
const defaultDropdownListItemProps: DropdownListItemProps = {
testid: "dropdown-list-item",
selectedOption: {id: "1", title: "test"},
option: {id: "1", title: "test"},
onFocus: jest.fn(),
onSelect: jest.fn(),
onKeyDown: jest.fn()
};

it("should render correctly", () => {
render(<DropdownListItem {...defaultDropdownListItemProps} />);
});

it("should pass a11y test", async () => {
const {container} = render(<DropdownListItem {...defaultDropdownListItemProps} />);

await testA11y(container, {rules: {"aria-required-parent": {enabled: false}}});
});

it("should render custom content if it exists", () => {
const {container} = render(
<DropdownListItem
{...defaultDropdownListItemProps}
option={{
...defaultDropdownListItemProps.option,
CustomContent: <p>{"custom content"}</p>
}}
/>
);

expect(container).toContainElement(screen.getByText("custom content"));
});

describe("should handle event handlers correctly", () => {
it("should not run click event handler when option is disabled and option is selected or canSelectAlreadySelected is provided as false", () => {
// isDisabled: true, isSelected: true , canSelectAlreadySelected: default = false
const {rerender} = render(
<DropdownListItem
{...defaultDropdownListItemProps}
option={{...defaultDropdownListItemProps.option, isDisabled: true}}
/>
);

userEvent.click(screen.getByRole("option"));
expect(defaultDropdownListItemProps.onSelect).not.toHaveBeenCalled();

// isDisabled: true, isSelected: false , canSelectAlreadySelected: default = false
rerender(
<DropdownListItem
{...defaultDropdownListItemProps}
selectedOption={{id: "2", title: "test 2"}}
option={{...defaultDropdownListItemProps.option, isDisabled: true}}
/>
);

userEvent.click(screen.getByRole("option"));
expect(defaultDropdownListItemProps.onSelect).not.toHaveBeenCalled();

// isDisabled: true, isSelected: true , canSelectAlreadySelected: true
rerender(
<DropdownListItem
{...defaultDropdownListItemProps}
canSelectAlreadySelected={true}
option={{...defaultDropdownListItemProps.option, isDisabled: true}}
/>
);

userEvent.click(screen.getByRole("option"));
expect(defaultDropdownListItemProps.onSelect).not.toHaveBeenCalled();
});

it("should run click event handler when option is not disabled and option is not selected or canSelectAlreadySelected is provided as true", () => {
// isDisabled: false, isSelected: true , canSelectAlreadySelected: true
const {rerender} = render(
<DropdownListItem
{...defaultDropdownListItemProps}
canSelectAlreadySelected={true}
/>
);

userEvent.click(screen.getByRole("option"));
expect(defaultDropdownListItemProps.onSelect).toHaveBeenCalledTimes(1);

jest.clearAllMocks();

// isDisabled: false, isSelected: false , canSelectAlreadySelected: default = false
rerender(
<DropdownListItem
{...defaultDropdownListItemProps}
selectedOption={{id: "2", title: "test 2"}}
/>
);

userEvent.click(screen.getByRole("option"));
expect(defaultDropdownListItemProps.onSelect).toHaveBeenCalledTimes(1);

jest.clearAllMocks();

// isDisabled: false, isSelected: false , canSelectAlreadySelected: true
rerender(
<DropdownListItem
{...defaultDropdownListItemProps}
selectedOption={{id: "2", title: "test 2"}}
canSelectAlreadySelected={true}
/>
);

userEvent.click(screen.getByRole("option"));
expect(defaultDropdownListItemProps.onSelect).toHaveBeenCalledTimes(1);
});

it("should run focus event handler correctly", () => {
render(<DropdownListItem {...defaultDropdownListItemProps} />);

fireEvent.focus(screen.getByRole("option"));

expect(defaultDropdownListItemProps.onFocus).toHaveBeenCalledTimes(1);
});

it("should run key down event handler correctly", () => {
const {rerender} = render(<DropdownListItem {...defaultDropdownListItemProps} />);

fireEvent.keyDown(screen.getByRole("option"), {
keyCode: 16
});

expect(defaultDropdownListItemProps.onKeyDown).toHaveBeenCalledTimes(1);

jest.clearAllMocks();

rerender(
<DropdownListItem {...defaultDropdownListItemProps} onKeyDown={undefined} />
);

expect(defaultDropdownListItemProps.onKeyDown).not.toHaveBeenCalled();
});
});
});
85 changes: 85 additions & 0 deletions src/dropdown/util/dropdown-utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {DropdownOption} from "../list/item/DropdownListItem";
import {
findIndexForClosestMatch,
generateInitialFocusedDropdownOptionIndex
} from "./dropdownUtils";
import {DropdownPosition} from "./dropdownConstants";

describe("generateInitialFocusedDropdownOptionIndex", () => {
const position: DropdownPosition = "left";
const options: DropdownOption[] = [
{id: "1", title: "Hipo"},
{id: "2", title: "hIpO lAbS"},
{id: "3", title: "lAbS"},
{id: "4", title: "Labss"},
{id: "5", title: ""},
{id: "6", title: "hİpOğÜ_*!>labs"}
];

it("should return provided selectedOption's index if it exists", () => {
expect(
generateInitialFocusedDropdownOptionIndex(position, options, options[1])
).toEqual(1);
});

it("should return 0 when provided selectedOption does not exists and position is not equal to top", () => {
expect(
generateInitialFocusedDropdownOptionIndex(position, options, {
id: "-1",
title: "test"
})
).toEqual(0);

expect(generateInitialFocusedDropdownOptionIndex(position, options, null)).toEqual(0);
expect(
generateInitialFocusedDropdownOptionIndex(position, options, undefined)
).toEqual(0);
});

it("should return last option's index when selectedOption does not exists and position is equal to top", () => {
expect(
generateInitialFocusedDropdownOptionIndex("top", options, {
id: "-1",
title: "test"
})
).toEqual(options.length - 1);
});

expect(generateInitialFocusedDropdownOptionIndex("top", options, null)).toEqual(
options.length - 1
);
expect(generateInitialFocusedDropdownOptionIndex("top", options, undefined)).toEqual(
options.length - 1
);
});

describe("findIndexForClosestMatch", () => {
const options: DropdownOption[] = [
{id: "1", title: "Hipo"},
{id: "2", title: "hIpO lAbS"},
{id: "3", title: "lAbS"},
{id: "4", title: "Labss"},
{id: "5", title: ""},
{id: "6", title: "hİpOğÜ_*!>labs"}
];

it("should return closest index by provided query", () => {
expect(findIndexForClosestMatch(options, "HipO")).toEqual(0);
// eslint-disable-next-line no-magic-numbers
expect(findIndexForClosestMatch(options, "labs")).toEqual(2);
expect(findIndexForClosestMatch(options, "hipo la")).toEqual(1);
});

it("should return 0 if the provided query is empty", () => {
expect(findIndexForClosestMatch(options, "")).toEqual(0);
});

it("should return -1 if the provided query does not exists", () => {
expect(findIndexForClosestMatch(options, "test")).toEqual(-1);
});

it("should handle special characters", () => {
// eslint-disable-next-line no-magic-numbers
expect(findIndexForClosestMatch(options, "hİpOğÜ_*!>")).toEqual(5);
});
});