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

Add IpaToggleGroup unit tests #650

Merged
merged 2 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
263 changes: 263 additions & 0 deletions src/components/Form/IpaToggleGroup/IpaToggleGroup.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import "@testing-library/jest-dom";
// Component
import IpaToggleGroup, { ToggleOptionProps } from "./IpaToggleGroup";
// Utils
import { updateIpaObject } from "src/utils/ipaObjectUtils";

// Mock of util function: updateIpaObject
jest.mock("src/utils/ipaObjectUtils", () => ({
...jest.requireActual("src/utils/ipaObjectUtils.ts"),
updateIpaObject: jest.fn(),
}));

describe("IpaToggleGroup Component", () => {
const mockOnChange = jest.fn((ipaObject) => {
console.log("mockOnChange called with:", ipaObject);
});

const mockSetOptionSelected = jest.fn((option: string) => {
console.log("mockSetOptionSelected called with:", option);
});

const mockMetadata = {
objects: {
user: {
name: "user",
takes_params: [
{
alwaysask: false,
attribute: true,
autofill: false,
class: "StrEnum",
cli_metavar: "['all', '']",
cli_name: "usercategory2",
confirm: false,
deprecated_cli_aliases: [],
deprecated: false,
doc: "Types of supported user authentication",
flags: [],
label: "User authentication types",
maxlength: 255,
multivalue: false,
name: "usercategory2",
no_convert: false,
noextrawhitespace: true,
optionSelected: "all",
pattern_errmsg: "",
pattern: "",
primary_key: false,
query: false,
required: false,
sortorder: 1,
type: "str",
values: ["all", ""],
writable: true,
},
],
},
},
};

const defaultProps: ToggleOptionProps = {
name: "usercategory2",
ariaLabel: "User Category",
ipaObject: {},
onChange: mockOnChange,
required: true,
readOnly: false,
metadata: mockMetadata,
objectName: "user",
options: [
{ value: "all", label: "Anyone" },
{
value: "",
label: "Specified Users and Groups",
},
],
optionSelected: "Anyone",
setOptionSelected: mockSetOptionSelected,
};

afterEach(() => {
jest.clearAllMocks();
});

it("should render the component", () => {
render(<IpaToggleGroup {...defaultProps} />);
// Validate group
const toggleGroupElems = screen.getAllByRole("group");

// Returns an array
expect(Array.isArray(toggleGroupElems)).toBe(true);

// Is single element
expect(toggleGroupElems.length).toBe(1);

// Validate properties of the group
const toggleGroupElem = toggleGroupElems[0];
expect(toggleGroupElem.tagName).toBe("DIV");
expect(toggleGroupElem).toHaveAttribute("role", "group");

// Validate group items
const toggleGroupItemElems = screen.getAllByRole("button");

// Returns an array
expect(Array.isArray(toggleGroupItemElems)).toBe(true);

// Is not empty
expect(toggleGroupItemElems.length).toBeGreaterThan(0);

// It has 2 elements (options.length)
expect(toggleGroupItemElems).toHaveLength(defaultProps.options.length);

// Validate individual properties of each group item
toggleGroupItemElems.forEach((toggleGroupItem, idx) => {
// Is a button
expect(toggleGroupItem.tagName).toBe("BUTTON");
expect(toggleGroupItem).toHaveAttribute("type", "button");

// Has correct id
expect(toggleGroupItem).toHaveAttribute(
"id",
defaultProps.options[idx].label
);

// Check inner span text
expect(toggleGroupItem.children.length).toBe(1);
const span = toggleGroupItem.children[0];
expect(span.innerHTML).toBe(defaultProps.options[idx].label);
});
});

it("disables buttons if readOnly is true", () => {
render(<IpaToggleGroup {...defaultProps} readOnly={true} />);

// Validate group items
const toggleGroupItemElems = screen.getAllByRole("button");

// Validate individual properties of each group item
toggleGroupItemElems.forEach((toggleGroupItem, idx) => {
// Is a button
expect(toggleGroupItem.tagName).toBe("BUTTON");
expect(toggleGroupItem).toHaveAttribute("type", "button");

// Has correct id
expect(toggleGroupItem).toHaveAttribute(
"id",
defaultProps.options[idx].label
);

// Check inner span text
expect(toggleGroupItem.children.length).toBe(1);
const span = toggleGroupItem.children[0];
expect(span.innerHTML).toBe(defaultProps.options[idx].label);

// Is disabled
expect(toggleGroupItem).toBeDisabled();
});
});

it("does nothing if already selected", () => {
render(<IpaToggleGroup {...defaultProps} />);

const toggleGroupItemElems = screen.getAllByRole("button");

// Click the already selected
fireEvent.click(toggleGroupItemElems[0]);

// Verify nothing has changed
expect(updateIpaObject).toHaveBeenCalledTimes(0);
});

it("handles correctly different default value", () => {
render(
<IpaToggleGroup
{...defaultProps}
optionSelected="Specified Users and Groups"
/>
);

const toggleGroupItemElems = screen.getAllByRole("button");

// Click the already selected
fireEvent.click(toggleGroupItemElems[1]);

// Verify nothing has changed
expect(updateIpaObject).toHaveBeenCalledTimes(0);
});

it("updates if selecting new element", () => {
render(<IpaToggleGroup {...defaultProps} />);

const toggleGroupItemElems = screen.getAllByRole("button");
fireEvent.click(toggleGroupItemElems[1]);

// Verify item has been updated exactly once
expect(updateIpaObject).toHaveBeenCalledTimes(1);
});

it("handles correctly bigger group", () => {
const biggerProps: ToggleOptionProps = {
...defaultProps,
options: [
{ value: "all", label: "Anyone" },
{
value: "",
label: "Specified Users and Groups",
},
{
value: "another",
label: "Another option",
},
{
value: "yet_another",
label: "Yet another option",
},
],
};

render(<IpaToggleGroup {...biggerProps} />);

// Validate group items
const toggleGroupItemElems = screen.getAllByRole("button");

// Returns an array
expect(Array.isArray(toggleGroupItemElems)).toBe(true);

// Is not empty
expect(toggleGroupItemElems.length).toBeGreaterThan(0);

// It has 4 elements (options.length)
expect(toggleGroupItemElems).toHaveLength(biggerProps.options.length);

// Validate individual properties of each group item
toggleGroupItemElems.forEach((toggleGroupItem, idx) => {
// Is a button
expect(toggleGroupItem.tagName).toBe("BUTTON");
expect(toggleGroupItem).toHaveAttribute("type", "button");

// Has correct id
expect(toggleGroupItem).toHaveAttribute(
"id",
biggerProps.options[idx].label
);

// Check inner span text
expect(toggleGroupItem.children.length).toBe(1);
const span = toggleGroupItem.children[0];
expect(span.innerHTML).toBe(biggerProps.options[idx].label);
});

fireEvent.click(toggleGroupItemElems[1]);
// This one shouldn't count
fireEvent.click(toggleGroupItemElems[1]);
fireEvent.click(toggleGroupItemElems[3]);
fireEvent.click(toggleGroupItemElems[2]);
fireEvent.click(toggleGroupItemElems[0]);

// Verify item has been updated
expect(updateIpaObject).toHaveBeenCalledTimes(4);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ interface ToggleOptions {
value: string;
}

interface ToggleOptionProps extends IPAParamDefinition {
export interface ToggleOptionProps extends IPAParamDefinition {
options: ToggleOptions[];
optionSelected: string;
setOptionSelected: (value: string) => void;
Expand Down
2 changes: 1 addition & 1 deletion src/components/SudoRuleSections/RunCommands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Metadata, SudoRule } from "src/utils/datatypes/globalDataTypes";
import KeytabTableWithFilter, {
TableEntry,
} from "src/components/tables/KeytabTableWithFilter";
import IpaToggleGroup from "src/components/Form/IpaToggleGroup";
import IpaToggleGroup from "src/components/Form/IpaToggleGroup/IpaToggleGroup";
// RPC
import { BatchResponse, ErrorResult, FindRPCResponse } from "src/services/rpc";
import {
Expand Down
2 changes: 1 addition & 1 deletion src/components/SudoRuleSections/SudoRuleAsWhom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Metadata, SudoRule } from "src/utils/datatypes/globalDataTypes";
import KeytabTableWithFilter, {
TableEntry,
} from "src/components/tables/KeytabTableWithFilter";
import IpaToggleGroup from "src/components/Form/IpaToggleGroup";
import IpaToggleGroup from "src/components/Form/IpaToggleGroup/IpaToggleGroup";
// RPC
import { ErrorResult } from "src/services/rpc";
import {
Expand Down
2 changes: 1 addition & 1 deletion src/components/SudoRuleSections/SudoRulesWho.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Metadata, SudoRule } from "src/utils/datatypes/globalDataTypes";
import KeytabTableWithFilter, {
TableEntry,
} from "src/components/tables/KeytabTableWithFilter";
import IpaToggleGroup from "src/components/Form/IpaToggleGroup";
import IpaToggleGroup from "src/components/Form/IpaToggleGroup/IpaToggleGroup";
// RPC
import {
AddRemoveToSudoRulesResult,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/SudoRules/AccessThisHost.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Metadata, SudoRule } from "src/utils/datatypes/globalDataTypes";
import KeytabTableWithFilter, {
TableEntry,
} from "src/components/tables/KeytabTableWithFilter";
import IpaToggleGroup from "src/components/Form/IpaToggleGroup";
import IpaToggleGroup from "src/components/Form/IpaToggleGroup/IpaToggleGroup";
// RPC
import { ErrorResult } from "src/services/rpc";
import {
Expand Down
Loading