Skip to content

Commit

Permalink
Create a resuable combo box component to choose and search a particul…
Browse files Browse the repository at this point in the history
…ar skill (#93)

* feat: implement the combo box for common and for endorsements page, correct the test to add combo box in the endorsements page

* feat:add the combo box and the mock values alogn with the unit andintegration test cases for this

* fix:re-arrange the types values

* fix:the typescript error of the value type and the null value in the tests

* fix:prettier issue

* fix:remove theunused var

* fix:remove the unused var and fix the indentation

* fix:prettier check

* fix:prettier indentation error and lint error
  • Loading branch information
Abhay5855 authored Jul 29, 2024
1 parent 61f6969 commit bba1d0b
Show file tree
Hide file tree
Showing 14 changed files with 1,419 additions and 717 deletions.
14 changes: 14 additions & 0 deletions __mocks__/combobox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const ComboboxMockData = [
{
id: 1,
name: "React",
},
{
id: 2,
name: "Go",
},
{
id: 3,
name: "Vanilla JS",
},
];
114 changes: 114 additions & 0 deletions __tests__/Unit/Componets/Combobox/Combobox.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import React from "react";
import { render, fireEvent, screen, waitFor } from "@testing-library/react";
import { ComboboxMockData } from "../../../../__mocks__/combobox";
import ComboboxDropdown from "@/components/Combobox";

describe("Combobox Component", () => {
it("should render with placeholder and dropdown closed", () => {
render(<ComboboxDropdown options={ComboboxMockData} placeholder="placeholder" />);

const input = screen.getByRole("combobox");
expect(input).toHaveAttribute("placeholder", "placeholder");

expect(screen.queryByRole("listbox")).not.toBeInTheDocument(); // Check listbox is not visible
});

it("should open dropdown on button click and display the options", async () => {
render(<ComboboxDropdown options={ComboboxMockData} placeholder="placeholder" />);

const button = screen.getByRole("button");

expect(screen.queryByRole("listbox")).not.toBeInTheDocument(); // Check listbox is initially closed

fireEvent.click(button);

await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for dropdown animation

await screen.findByRole("listbox");

expect(screen.getByText("React")).toBeInTheDocument();
expect(screen.getByText("Go")).toBeInTheDocument();
expect(screen.getByText("Vanilla JS")).toBeInTheDocument();
});

it("Select a value from the combobox list", async () => {
const onChangeMock = jest.fn();
render(<ComboboxDropdown options={ComboboxMockData} placeholder="placeholder" onChange={onChangeMock} />);
const button = screen.getByRole("button");

expect(screen.queryByRole("listbox")).not.toBeInTheDocument(); // Check listbox is initially closed

fireEvent.click(button);

await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for dropdown animation

await screen.findByRole("listbox");

expect(screen.getByText("React")).toBeInTheDocument();
expect(screen.getByText("Go")).toBeInTheDocument();
expect(screen.getByText("Vanilla JS")).toBeInTheDocument();

fireEvent.click(screen.getByText("React"));
expect(onChangeMock).toHaveBeenCalledWith({ id: 1, name: "React" });
});

it("filters the options based on input value", async () => {
render(<ComboboxDropdown onChange={() => {}} placeholder="placeholder" options={ComboboxMockData} />);
expect(screen.queryByRole("listbox")).not.toBeInTheDocument();
const button = screen.getByRole("button");
fireEvent.click(button);
await screen.findByRole("listbox");

const input = screen.getByPlaceholderText("placeholder");
fireEvent.change(input, { target: { value: "React", id: 1 } });

await waitFor(() => {
expect(screen.getByText("React")).toBeInTheDocument();
});

screen.debug();
});

it("Display No Results option when no options are present", async () => {
render(<ComboboxDropdown options={ComboboxMockData} placeholder="placeholder" />);
const input = screen.getByRole("combobox");
expect(screen.queryByRole("listbox")).not.toBeInTheDocument(); // Check listbox is initially closed

fireEvent.change(input, { target: { value: "NonexistentSkill" } });

await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for dropdown animation

await screen.findByRole("listbox");

await screen.findByText("No Results");

expect(screen.getByText("No Results")).toBeInTheDocument();
});

it("Close the combo box when clicked outside", async () => {
render(
<div>
<ComboboxDropdown onChange={() => {}} placeholder="placeholder" options={ComboboxMockData} />
<div data-testid="outside-element">Outside Element</div>
</div>
);

expect(screen.queryByRole("listbox")).not.toBeInTheDocument();
const button = screen.getByRole("button");
fireEvent.click(button);

// Ensure the dropdown is open
await screen.findByRole("listbox");
expect(screen.getByRole("listbox")).toBeInTheDocument();

const outsideElement = screen.getByTestId("outside-element");
fireEvent.mouseDown(outsideElement);
fireEvent.mouseUp(outsideElement);
fireEvent.click(outsideElement);

// Wait for the dropdown to close
await waitFor(() => {
expect(screen.queryByRole("listbox")).not.toBeInTheDocument();
});
});
});
123 changes: 123 additions & 0 deletions __tests__/Unit/Componets/SkillComboBox/SkillComboBox.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import React from "react";
import { render, fireEvent, screen, waitFor } from "@testing-library/react";
import SkillCombobox from "@/components/SkillComboBox";
import { skillMockData } from "../../../../__mocks__/endorsements";

describe("SkillCombobox Component", () => {
it("should render with placeholder and dropdown closed", () => {
render(<SkillCombobox options={skillMockData} placeholder="select skill" />);

const input = screen.getByRole("combobox");
expect(input).toHaveAttribute("placeholder", "select skill");

expect(screen.queryByRole("listbox")).not.toBeInTheDocument(); // Check listbox is not visible
});

it("should open dropdown on button click and display the options", async () => {
render(<SkillCombobox options={skillMockData} placeholder="select skill" />);

const button = screen.getByRole("button");

expect(screen.queryByRole("listbox")).not.toBeInTheDocument(); // Check listbox is initially closed

fireEvent.click(button);

await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for dropdown animation

await screen.findByRole("listbox");

expect(screen.getByText("React")).toBeInTheDocument();
expect(screen.getByText("Go")).toBeInTheDocument();
expect(screen.getByText("Vanilla JS")).toBeInTheDocument();
});

it("Select a value from the combobox list", async () => {
const onChangeMock = jest.fn();
render(<SkillCombobox options={skillMockData} placeholder="select skill" onChange={onChangeMock} />);
const button = screen.getByRole("button");

expect(screen.queryByRole("listbox")).not.toBeInTheDocument(); // Check listbox is initially closed

fireEvent.click(button);

await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for dropdown animation

await screen.findByRole("listbox");

expect(screen.getByText("React")).toBeInTheDocument();
expect(screen.getByText("Go")).toBeInTheDocument();
expect(screen.getByText("Vanilla JS")).toBeInTheDocument();

fireEvent.click(screen.getByText("React"));
expect(onChangeMock).toHaveBeenCalledWith({ id: 1, skill: "React" });
});

it("filters the options based on input value", async () => {
render(<SkillCombobox onChange={() => {}} placeholder="select skill" options={skillMockData} />);
expect(screen.queryByRole("listbox")).not.toBeInTheDocument();
const button = screen.getByRole("button");
fireEvent.click(button);
await screen.findByRole("listbox");

const input = screen.getByPlaceholderText("select skill");
fireEvent.change(input, { target: { value: "React", id: 1 } });

await waitFor(() => {
expect(screen.getByText("React")).toBeInTheDocument();
});

screen.debug();
});

it("Display Add new Skill option when no options are present and add new skill click perform action", async () => {
const handleAddSkill = jest.fn();

render(<SkillCombobox options={skillMockData} placeholder="select skill" handleAddSkill={handleAddSkill} />);
const input = screen.getByRole("combobox");
expect(screen.queryByRole("listbox")).not.toBeInTheDocument(); // Check listbox is initially closed

fireEvent.change(input, { target: { value: "NonexistentSkill" } });

await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for dropdown animation

await screen.findByRole("listbox");

await screen.findByText("Add New Skill");

await fireEvent.click(screen.getByText("Add New Skill"));

expect(handleAddSkill).toHaveBeenCalled();
});

it("Close the combo box when clicked outside", async () => {
render(
<div>
<SkillCombobox
onChange={() => {}}
placeholder="select skill"
options={skillMockData}
handleAddSkill={() => {}}
/>
<div data-testid="outside-element">Outside Element</div>
</div>
);

expect(screen.queryByRole("listbox")).not.toBeInTheDocument();
const button = screen.getByRole("button");
fireEvent.click(button);

// Ensure the dropdown is open
await screen.findByRole("listbox");
expect(screen.getByRole("listbox")).toBeInTheDocument();

const outsideElement = screen.getByTestId("outside-element");
fireEvent.mouseDown(outsideElement);
fireEvent.mouseUp(outsideElement);
fireEvent.click(outsideElement);

// Wait for the dropdown to close
await waitFor(() => {
expect(screen.queryByRole("listbox")).not.toBeInTheDocument();
});
});
});
90 changes: 90 additions & 0 deletions __tests__/components/combobox/Combobox.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React from "react";
import { render, fireEvent, screen, waitFor } from "@testing-library/react";
import { ComboboxMockData } from "../../../__mocks__/combobox";
import ComboboxDropdown from "@/components/Combobox";

global.ResizeObserver = class {
observe() {}
unobserve() {}
disconnect() {}
};

describe("Combobox Component", () => {
it("Should display combobox with placeholder and Down arrow icon", async () => {
render(<ComboboxDropdown options={ComboboxMockData} placeholder="placeholder" />);

expect(screen.getByRole("combobox")).toBeInTheDocument();
expect(screen.getByPlaceholderText("placeholder")).toBeInTheDocument();
expect(screen.getByAltText("expand")).toBeInTheDocument();
});

it("should open dropdown on button click and display the options", async () => {
render(<ComboboxDropdown options={ComboboxMockData} placeholder="placeholder" />);

const button = screen.getByRole("button");

expect(screen.queryByRole("listbox")).not.toBeInTheDocument(); // Check listbox is initially closed

fireEvent.click(button);

await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for dropdown animation

await screen.findByRole("listbox");

expect(screen.getByText("React")).toBeInTheDocument();
expect(screen.getByText("Go")).toBeInTheDocument();
expect(screen.getByText("Vanilla JS")).toBeInTheDocument();
});

it("Select a value from the combobox list", async () => {
const onChangeMock = jest.fn();
render(<ComboboxDropdown options={ComboboxMockData} placeholder="placeholder" onChange={onChangeMock} />);
const button = screen.getByRole("button");

expect(screen.queryByRole("listbox")).not.toBeInTheDocument(); // Check listbox is initially closed

fireEvent.click(button);

await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for dropdown animation

await screen.findByRole("listbox");

expect(screen.getByText("React")).toBeInTheDocument();
expect(screen.getByText("Go")).toBeInTheDocument();
expect(screen.getByText("Vanilla JS")).toBeInTheDocument();

fireEvent.click(screen.getByText("React"));
expect(onChangeMock).toHaveBeenCalledWith({ id: 1, name: "React" });
});

it("filters the options based on input value", async () => {
render(<ComboboxDropdown onChange={() => {}} placeholder="placeholder" options={ComboboxMockData} />);
expect(screen.queryByRole("listbox")).not.toBeInTheDocument();
const button = screen.getByRole("button");
fireEvent.click(button);
await screen.findByRole("listbox");

const input = screen.getByPlaceholderText("placeholder");
fireEvent.change(input, { target: { value: "React", id: 1 } });

await waitFor(() => {
expect(screen.getByText("React")).toBeInTheDocument();
});

screen.debug();
});

it("Display No Results option when no options are present", async () => {
render(<ComboboxDropdown options={ComboboxMockData} placeholder="placeholder" />);
const input = screen.getByRole("combobox");
expect(screen.queryByRole("listbox")).not.toBeInTheDocument(); // Check listbox is initially closed

fireEvent.change(input, { target: { value: "NonexistentSkill" } });

await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for dropdown animation

await screen.findByRole("listbox");

await screen.findByText("No Results");
});
});
Loading

0 comments on commit bba1d0b

Please sign in to comment.