From e38f095f1819e531bc2c6ee77228dda5e6d3c5ad Mon Sep 17 00:00:00 2001 From: "K. Allagbe" Date: Tue, 26 Nov 2024 10:26:28 -0500 Subject: [PATCH] issue #326: tests --- .../__tests__/page.test.tsx | 38 ++- .../__tests__/BaseInformationForm.test.tsx | 11 +- .../__tests__/CautionsForm.test.tsx | 39 +++ .../__tests__/OrganizationsForm.test.tsx | 13 +- .../__tests__/VerifiedBilingualTable.test.tsx | 240 ++++++++++++++++++ 5 files changed, 323 insertions(+), 18 deletions(-) create mode 100644 src/components/__tests__/CautionsForm.test.tsx create mode 100644 src/components/__tests__/VerifiedBilingualTable.test.tsx diff --git a/src/app/label-data-validation/__tests__/page.test.tsx b/src/app/label-data-validation/__tests__/page.test.tsx index c33d5de4..f2fdc46e 100644 --- a/src/app/label-data-validation/__tests__/page.test.tsx +++ b/src/app/label-data-validation/__tests__/page.test.tsx @@ -67,7 +67,7 @@ describe("LabelDataValidationPage Functionality", () => { }); }); -describe("LabelDataValidationPage and OrganizationsForm Integration", () => { +describe("LabelDataValidationPage and Forms Integration", () => { it("marks the Organizations step as Completed or Incomplete when fields are Verified", () => { render(); @@ -91,9 +91,7 @@ describe("LabelDataValidationPage and OrganizationsForm Integration", () => { expect(targetSpan).not.toHaveClass("Mui-completed"); }); -}); -describe("LabelDataValidationPage and BaseInformationForm Integration", () => { it("marks the Base Information step as Completed or Incomplete when fields are Verified", async () => { render(); @@ -129,4 +127,38 @@ describe("LabelDataValidationPage and BaseInformationForm Integration", () => { expect(targetSpan).not.toHaveClass("Mui-completed"); }); + + it("marks the Cautions step as Completed or Incomplete when fields are Verified", async () => { + render(); + + const spans = screen.getAllByText("cautions.stepTitle", { + exact: true, + }); + const targetSpan = spans.find((span) => + span.classList.contains("MuiStepLabel-label"), + ); + expect(targetSpan).not.toHaveClass("Mui-completed"); + + const button = targetSpan!.closest("button"); + await act(async () => { + fireEvent.click(button!); + }); + + const verifyButtons = screen.getAllByTestId(/verify-row-btn-cautions-\d+/); + expect(verifyButtons.length).toBeGreaterThanOrEqual(1); + + for (const button of verifyButtons) { + await act(async () => { + fireEvent.click(button); + }); + } + + expect(targetSpan).toHaveClass("Mui-completed"); + + await act(async () => { + fireEvent.click(verifyButtons[0]); + }); + + expect(targetSpan).not.toHaveClass("Mui-completed"); + }); }); diff --git a/src/components/__tests__/BaseInformationForm.test.tsx b/src/components/__tests__/BaseInformationForm.test.tsx index 3ed1eba7..069e438a 100644 --- a/src/components/__tests__/BaseInformationForm.test.tsx +++ b/src/components/__tests__/BaseInformationForm.test.tsx @@ -1,4 +1,4 @@ -import { DEFAULT_BASE_INFORMATION, LabelData } from "@/types/types"; +import { DEFAULT_LABEL_DATA, LabelData } from "@/types/types"; import { render, screen } from "@testing-library/react"; import { useEffect, useState } from "react"; import { FormProvider, useForm } from "react-hook-form"; @@ -31,14 +31,7 @@ const Wrapper = ({ describe("BaseInformationForm Rendering", () => { it("should render all fields with correct components", () => { - render( - , - ); + render(); const verifiedFields = ["name", "registrationNumber", "lotNumber", "npk"]; const quantityFields = ["weight", "density", "volume"]; diff --git a/src/components/__tests__/CautionsForm.test.tsx b/src/components/__tests__/CautionsForm.test.tsx new file mode 100644 index 00000000..b443c219 --- /dev/null +++ b/src/components/__tests__/CautionsForm.test.tsx @@ -0,0 +1,39 @@ +import { DEFAULT_LABEL_DATA } from "@/types/types"; +import { render, screen } from "@testing-library/react"; +import { useEffect, useState } from "react"; +import { FormProvider, useForm } from "react-hook-form"; +import CautionsForm from "../CautionsForm"; + +const Wrapper = ({ + initialData, + onStateChange, +}: { + initialData: any; + onStateChange?: (data: any) => void; +}) => { + const [labelData, setLabelData] = useState(initialData); + const methods = useForm({ + defaultValues: labelData, + }); + + useEffect(() => { + if (onStateChange) { + onStateChange(labelData); + } + }, [labelData, onStateChange]); + + return ( + + + + ); +}; + +describe("CautionsForm Rendering", () => { + it("should render the VerifiedBilingualTable for cautions", () => { + render(); + + expect(screen.getByTestId("cautions-form")).toBeInTheDocument(); + expect(screen.getByTestId("table-container-cautions")).toBeInTheDocument(); + }); +}); diff --git a/src/components/__tests__/OrganizationsForm.test.tsx b/src/components/__tests__/OrganizationsForm.test.tsx index 4dc49404..2fd3d36c 100644 --- a/src/components/__tests__/OrganizationsForm.test.tsx +++ b/src/components/__tests__/OrganizationsForm.test.tsx @@ -42,6 +42,7 @@ describe("OrganizationsForm Rendering", () => { initialData={{ organizations: [DEFAULT_ORGANIZATION, DEFAULT_ORGANIZATION], baseInformation: DEFAULT_BASE_INFORMATION, + cautions: [], }} />, ); @@ -67,8 +68,8 @@ describe("OrganizationsForm Rendering", () => { render( , ); @@ -84,8 +85,8 @@ describe("OrganizationsForm Functionality", () => { render( , ); @@ -226,8 +227,8 @@ describe("OrganizationsForm Functionality", () => { render( , ); @@ -261,8 +262,8 @@ describe("OrganizationsForm Functionality", () => { render( , @@ -319,8 +320,8 @@ describe("OrganizationsForm Functionality", () => { render( , ); @@ -335,8 +336,8 @@ describe("OrganizationsForm Edge Cases", () => { render( , ); diff --git a/src/components/__tests__/VerifiedBilingualTable.test.tsx b/src/components/__tests__/VerifiedBilingualTable.test.tsx new file mode 100644 index 00000000..a7b35d97 --- /dev/null +++ b/src/components/__tests__/VerifiedBilingualTable.test.tsx @@ -0,0 +1,240 @@ +import { BilingualField } from "@/types/types"; +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { FormProvider, useForm } from "react-hook-form"; +import VerifiedBilingualTable from "../VerifiedBilingualTable"; + +const Wrapper = ({ + path = "bilingualFields", + defaultValues = { + bilingualFields: [ + { en: "English Text", fr: "French Text", verified: false }, + ], + }, + onSubmit = jest.fn(), +}: { + path?: string; + defaultValues?: { + bilingualFields: { en: string; fr: string; verified: boolean }[]; + }; + onSubmit?: (data: { bilingualFields: BilingualField[] }) => void; +}) => { + const methods = useForm({ + defaultValues, + mode: "onSubmit", + }); + + return ( + +
{ + event.preventDefault(); + methods.handleSubmit(onSubmit)(); + }} + > + + + +
+ ); +}; + +describe("VerifiedBilingualTable rendering and functionality", () => { + it("renders with default values", () => { + render(); + + expect( + screen.getByTestId("table-header-english-bilingualFields"), + ).toHaveTextContent("verifiedBilingualTable.english"); + expect( + screen.getByTestId("table-header-french-bilingualFields"), + ).toHaveTextContent("verifiedBilingualTable.french"); + expect( + screen.getByTestId("table-header-actions-bilingualFields"), + ).toHaveTextContent("verifiedBilingualTable.actions"); + + const rows = screen.getAllByTestId(/table-row-bilingualFields-\d+/); + expect(rows.length).toBe(1); + + const englishInputBase = screen.getByTestId( + "input-english-bilingualFields-0", + ); + const englishInput = englishInputBase.querySelector( + "textarea", + ) as HTMLTextAreaElement; + const frenchInputBase = screen.getByTestId( + "input-french-bilingualFields-0", + ); + const frenchInput = frenchInputBase.querySelector( + "textarea", + ) as HTMLTextAreaElement; + + expect(englishInput.value).toBe("English Text"); + expect(frenchInput.value).toBe("French Text"); + }); + + it("adds a new row when Add button is clicked", () => { + render(); + + fireEvent.click(screen.getByTestId("add-row-btn-bilingualFields")); + + const rows = screen.getAllByTestId(/table-row-bilingualFields-\d+/); + expect(rows.length).toBe(2); + + const englishInputBase = screen.getByTestId( + "input-english-bilingualFields-1", + ); + const englishInput = englishInputBase.querySelector( + "textarea", + ) as HTMLTextAreaElement; + const frenchInputBase = screen.getByTestId( + "input-french-bilingualFields-1", + ); + const frenchInput = frenchInputBase.querySelector( + "textarea", + ) as HTMLTextAreaElement; + + expect(englishInput.value).toBe(""); + expect(frenchInput.value).toBe(""); + }); + + it("deletes a row when Delete button is clicked", () => { + render(); + + fireEvent.click(screen.getByTestId("delete-row-btn-bilingualFields-0")); + + const rows = screen.queryAllByTestId(/table-row-bilingualFields-\d+/); + expect(rows.length).toBe(0); + }); + + it("marks all rows as verified when Verify All button is clicked", () => { + render(); + + fireEvent.click(screen.getByTestId("verify-all-btn-bilingualFields")); + + const verifyButtons = screen.getAllByTestId( + /verify-row-btn-bilingualFields-\d+/, + ); + verifyButtons.forEach((button) => { + const icon = button.querySelector("svg"); + expect(icon).toHaveClass("text-green-500"); + }); + + const inputs = screen.getAllByTestId( + /input-(english|french)-bilingualFields-\d+/, + ); + inputs.forEach((baseInput) => { + const textarea = baseInput.querySelector( + "textarea", + ) as HTMLTextAreaElement; + expect(textarea).toBeDisabled(); + }); + + const deleteButtons = screen.getAllByTestId( + /delete-row-btn-bilingualFields-\d+/, + ); + deleteButtons.forEach((button) => { + expect(button).toBeDisabled(); + }); + }); + + it("marks all rows as unverified when Unverify All button is clicked", () => { + const defaultValues = { + bilingualFields: [ + { en: "Verified English 1", fr: "Verified French 1", verified: true }, + { en: "Verified English 2", fr: "Verified French 2", verified: true }, + ], + }; + + render(); + + const verifyButtonsBefore = screen.getAllByTestId( + /verify-row-btn-bilingualFields-\d+/, + ); + verifyButtonsBefore.forEach((button) => { + const icon = button.querySelector("svg"); + expect(icon).toHaveClass("text-green-500"); + }); + + const inputsBefore = screen.getAllByTestId( + /input-(english|french)-bilingualFields-\d+/, + ); + inputsBefore.forEach((baseInput) => { + const textarea = baseInput.querySelector( + "textarea", + ) as HTMLTextAreaElement; + expect(textarea).toBeDisabled(); + }); + + const deleteButtonsBefore = screen.getAllByTestId( + /delete-row-btn-bilingualFields-\d+/, + ); + deleteButtonsBefore.forEach((button) => { + expect(button).toBeDisabled(); + }); + + fireEvent.click(screen.getByTestId("unverify-all-btn-bilingualFields")); + + const verifyButtonsAfter = screen.getAllByTestId( + /verify-row-btn-bilingualFields-\d+/, + ); + verifyButtonsAfter.forEach((button) => { + const icon = button.querySelector("svg"); + expect(icon).not.toHaveClass("text-green-500"); + }); + + const inputsAfter = screen.getAllByTestId( + /input-(english|french)-bilingualFields-\d+/, + ); + inputsAfter.forEach((baseInput) => { + const textarea = baseInput.querySelector( + "textarea", + ) as HTMLTextAreaElement; + expect(textarea).not.toBeDisabled(); + }); + + const deleteButtonsAfter = screen.getAllByTestId( + /delete-row-btn-bilingualFields-\d+/, + ); + deleteButtonsAfter.forEach((button) => { + expect(button).not.toBeDisabled(); + }); + }); + + it("submits correct data on form submit", async () => { + const onSubmit = jest.fn(); + render(); + + const englishTextarea = screen + .getByTestId("input-english-bilingualFields-0") + .querySelector("textarea") as HTMLTextAreaElement; + + const frenchTextarea = screen + .getByTestId("input-french-bilingualFields-0") + .querySelector("textarea") as HTMLTextAreaElement; + + fireEvent.change(englishTextarea, { + target: { value: "Updated English Text" }, + }); + fireEvent.change(frenchTextarea, { + target: { value: "Updated French Text" }, + }); + + fireEvent.click(screen.getByTestId("submit-button")); + + await waitFor(() => { + expect(onSubmit.mock.calls[0][0]).toEqual( + expect.objectContaining({ + bilingualFields: [ + { + en: "Updated English Text", + fr: "Updated French Text", + verified: false, + }, + ], + }), + ); + }); + }); +});