From c563e43e22466d791437d98da4206a47d72c5370 Mon Sep 17 00:00:00 2001 From: Vijay Kumar S <94220135+vijay151096@users.noreply.github.com> Date: Tue, 30 Apr 2024 18:01:10 +0530 Subject: [PATCH] add unit testing and update the language selector (#49) Signed-off-by: Vijay <94220135+vijay151096@users.noreply.github.com> --- inji-web/package.json | 2 +- .../src/__tests__/EmptyListContainer.test.tsx | 10 --- .../Common/EmptyListContainer.test.tsx | 18 +++++ .../components/Common/HeaderTile.test.tsx | 19 +++++ .../components/Common/IntroBox.test.tsx | 37 ++++++++++ .../components/Common/ItemBox.test.tsx | 26 +++++++ .../components/Common/SpinningLoader.test.tsx | 14 ++++ .../Credentials/Credentials.test.tsx | 45 +++++++++++ .../components/Help/HelpAccordion.test.tsx | 49 ++++++++++++ .../Help/HelpAccordionItem.test.tsx | 35 +++++++++ inji-web/src/__tests__/mockUtils.ts | 14 ++++ .../components/Common/LanguageSelector.tsx | 74 ++++++++++++------- inji-web/src/components/Common/NavBar.tsx | 4 +- .../src/components/Common/SpinningLoader.tsx | 2 +- .../src/components/Issuers/SearchIssuer.tsx | 2 +- .../src/components/PageTemplate/Header.tsx | 6 +- inji-web/src/index.css | 2 +- inji-web/src/pages/HomePage.tsx | 2 +- inji-web/src/types/data.d.ts | 1 + 19 files changed, 316 insertions(+), 46 deletions(-) delete mode 100644 inji-web/src/__tests__/EmptyListContainer.test.tsx create mode 100644 inji-web/src/__tests__/components/Common/EmptyListContainer.test.tsx create mode 100644 inji-web/src/__tests__/components/Common/HeaderTile.test.tsx create mode 100644 inji-web/src/__tests__/components/Common/IntroBox.test.tsx create mode 100644 inji-web/src/__tests__/components/Common/ItemBox.test.tsx create mode 100644 inji-web/src/__tests__/components/Common/SpinningLoader.test.tsx create mode 100644 inji-web/src/__tests__/components/Credentials/Credentials.test.tsx create mode 100644 inji-web/src/__tests__/components/Help/HelpAccordion.test.tsx create mode 100644 inji-web/src/__tests__/components/Help/HelpAccordionItem.test.tsx create mode 100644 inji-web/src/__tests__/mockUtils.ts diff --git a/inji-web/package.json b/inji-web/package.json index 4d5f51a..cb3ffc0 100644 --- a/inji-web/package.json +++ b/inji-web/package.json @@ -36,7 +36,7 @@ "scripts": { "start": "react-scripts start", "build": "react-scripts build", - "test": "react-scripts test --testPathPattern=__tests__", + "test": "react-scripts test --silent --testPathPattern=__tests__", "eject": "react-scripts eject" }, "eslintConfig": { diff --git a/inji-web/src/__tests__/EmptyListContainer.test.tsx b/inji-web/src/__tests__/EmptyListContainer.test.tsx deleted file mode 100644 index 1983b37..0000000 --- a/inji-web/src/__tests__/EmptyListContainer.test.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import {EmptyListContainer} from "../components/Common/EmptyListContainer"; - - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText("Hello"); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/inji-web/src/__tests__/components/Common/EmptyListContainer.test.tsx b/inji-web/src/__tests__/components/Common/EmptyListContainer.test.tsx new file mode 100644 index 0000000..aa03ecb --- /dev/null +++ b/inji-web/src/__tests__/components/Common/EmptyListContainer.test.tsx @@ -0,0 +1,18 @@ +import React,{act} from 'react'; +import { render, screen } from '@testing-library/react'; +import {EmptyListContainer} from "../../../components/Common/EmptyListContainer"; + + +describe("Test Empty List Container",() => { + test('check the presence of the container', () => { + render(); + const emptyElement = screen.getByTestId("EmptyList-Outer-Container"); + expect(emptyElement).toBeInTheDocument(); + }); + test('check if content is rendered properly', () => { + render(); + const emptyElement = screen.getByTestId("EmptyList-Outer-Container"); + expect(emptyElement).toHaveTextContent("No Issuers Found") + }); +}) + diff --git a/inji-web/src/__tests__/components/Common/HeaderTile.test.tsx b/inji-web/src/__tests__/components/Common/HeaderTile.test.tsx new file mode 100644 index 0000000..231fd8d --- /dev/null +++ b/inji-web/src/__tests__/components/Common/HeaderTile.test.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import {HeaderTile} from "../../../components/Common/HeaderTile"; + + + +describe("Test Header Tile Container",() => { + test('check the presence of the container', () => { + render(); + const headerElement = screen.getByTestId("HeaderTile-Text"); + expect(headerElement).toBeInTheDocument(); + }); + test('check if content is rendered properly', () => { + render(); + const headerElement = screen.getByTestId("HeaderTile-Text"); + expect(headerElement).toHaveTextContent("No Issuers Found") + }); +}) + diff --git a/inji-web/src/__tests__/components/Common/IntroBox.test.tsx b/inji-web/src/__tests__/components/Common/IntroBox.test.tsx new file mode 100644 index 0000000..d820e16 --- /dev/null +++ b/inji-web/src/__tests__/components/Common/IntroBox.test.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import {IntroBox} from "../../../components/Common/IntroBox"; + + + +describe("Test Intro Box Layout",() => { + test('check the presence of the container', () => { + render(); + const introBoxElement = screen.getByTestId("IntroBox-Container"); + expect(introBoxElement).toBeInTheDocument(); + }); + test('check the presence of the title', () => { + render(); + const introBoxElement = screen.getByTestId("IntroBox-Text"); + expect(introBoxElement).toBeInTheDocument(); + }); + test('check the presence of the subTitle', () => { + render(); + const introBoxElement = screen.getByTestId("IntroBox-SubText"); + expect(introBoxElement).toBeInTheDocument(); + }); +}) + + +describe("Test Intro Box Content",() => { + test('check if content is rendered properly', () => { + render(); + const headerElement = screen.getByTestId("IntroBox-Text"); + expect(headerElement).toHaveTextContent("Intro.title") + }); + test('check if content is rendered properly', () => { + render(); + const headerElement = screen.getByTestId("IntroBox-SubText"); + expect(headerElement).toHaveTextContent("Intro.subTitle") + }); +}) diff --git a/inji-web/src/__tests__/components/Common/ItemBox.test.tsx b/inji-web/src/__tests__/components/Common/ItemBox.test.tsx new file mode 100644 index 0000000..89f36c4 --- /dev/null +++ b/inji-web/src/__tests__/components/Common/ItemBox.test.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import {fireEvent, render, screen} from '@testing-library/react'; +import {ItemBox} from "../../../components/Common/ItemBox"; +describe("Test Item Box Container",() => { + test('check the presence of the container', () => { + const clickHandler = jest.fn(); + render(); + const itemBoxElement = screen.getByTestId("ItemBox-Outer-Container"); + expect(itemBoxElement).toBeInTheDocument(); + }); + test('check if content is rendered properly', () => { + const clickHandler = jest.fn(); + render(); + const itemBoxElement = screen.getByTestId("ItemBox-Outer-Container"); + expect(itemBoxElement).toHaveTextContent("TitleOfItemBox") + }); + + test('check if item box onClick handler is working', () => { + const clickHandler = jest.fn(); + render(); + const itemBoxElement = screen.getByTestId("ItemBox-Outer-Container"); + fireEvent.click(itemBoxElement); + expect(clickHandler).toBeCalled() + }); +}) + diff --git a/inji-web/src/__tests__/components/Common/SpinningLoader.test.tsx b/inji-web/src/__tests__/components/Common/SpinningLoader.test.tsx new file mode 100644 index 0000000..416feee --- /dev/null +++ b/inji-web/src/__tests__/components/Common/SpinningLoader.test.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import {SpinningLoader} from "../../../components/Common/SpinningLoader"; + + + +describe("Test Spinning Loader Container",() => { + test('check the presence of the container', () => { + render(); + const spinningElement = screen.getByTestId("SpinningLoader-Container"); + expect(spinningElement).toBeInTheDocument(); + }); +}) + diff --git a/inji-web/src/__tests__/components/Credentials/Credentials.test.tsx b/inji-web/src/__tests__/components/Credentials/Credentials.test.tsx new file mode 100644 index 0000000..f7e303d --- /dev/null +++ b/inji-web/src/__tests__/components/Credentials/Credentials.test.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import {fireEvent, render, screen} from '@testing-library/react'; +import {Credential} from "../../../components/Credentials/Crendential"; +import {CredentialWellknownObject, DisplayArrayObject, LogoObject} from "../../../types/data"; +import {Provider} from "react-redux"; + +const getCredentialObject = (): CredentialWellknownObject => { + return { + format: "ldp_vc", + id: "id", + scope: "mosip_ldp_vc", + display: { + name: "Name", + language: "en", + locale: "en", + logo: { + url: "https://url.com", + alt_text: "alt text of the url" + }, + title: "Title", + description: "Description", + } + } +} +describe("Test Credentials Item Layout",() => { + test.skip('check the presence of the container', () => { + const clickHandler = jest.fn(); + const credential:CredentialWellknownObject = getCredentialObject(); + render( + + + + ); + const itemBoxElement = screen.getByTestId("ItemBox-Outer-Container"); + expect(itemBoxElement).toBeInTheDocument(); + }); + test.skip('check if content is rendered properly', () => { + const clickHandler = jest.fn(); + const credential:CredentialWellknownObject = getCredentialObject(); + render(); + const itemBoxElement = screen.getByTestId("ItemBox-Outer-Container"); + expect(itemBoxElement).toHaveTextContent("TitleOfItemBox") + }); +}) + diff --git a/inji-web/src/__tests__/components/Help/HelpAccordion.test.tsx b/inji-web/src/__tests__/components/Help/HelpAccordion.test.tsx new file mode 100644 index 0000000..c57a804 --- /dev/null +++ b/inji-web/src/__tests__/components/Help/HelpAccordion.test.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import {fireEvent, render, screen} from '@testing-library/react'; +import {HelpAccordion} from "../../../components/Help/HelpAccordion"; + +describe("Test Help Accordion Container",() => { + test('check the presence of the container', () => { + render(); + const helpElement = screen.getByTestId("Help-Accordion-Container"); + expect(helpElement).toBeInTheDocument(); + }); + + test('check the presence of the container', () => { + render(); + const helpItemElement = screen.getAllByTestId("Help-Item-Container"); + expect(helpItemElement.length).toBe(7) + }); + test('check first item should be expanded', () => { + render(); + const helpItemElement = screen.getAllByTestId("Help-Item-Title-Text"); + expect(helpItemElement.length).toBe(7) + }); + test('check first item should be expanded', () => { + render(); + const helpItemElement = screen.getAllByTestId("Help-Item-Content-Text"); + expect(helpItemElement.length).toBe(1) + }); +}) + +describe("Test Help Accordion Working",() => { + test('The Description should open when we press on the title', () => { + render(); + const helpItemElement = screen.getAllByTestId("Help-Item-Container")[1]; + const button = screen.getAllByTestId("Help-Item-Title-Button")[1]; + expect(helpItemElement.childElementCount).toBe(1) + fireEvent.click(button); + expect(helpItemElement.childElementCount).toBe(2) + }); + + test('only one description should be open at a time, rest should close', () => { + render(); + const helpItemElement = screen.getAllByTestId("Help-Item-Container")[1]; + const button = screen.getAllByTestId("Help-Item-Title-Button")[1]; + expect(helpItemElement.childElementCount).toBe(1) + fireEvent.click(button); + expect(helpItemElement.childElementCount).toBe(2) + const overallDescElemet = screen.getAllByTestId("Help-Item-Content-Text"); + expect(overallDescElemet.length).toBe(1) + }); +}) diff --git a/inji-web/src/__tests__/components/Help/HelpAccordionItem.test.tsx b/inji-web/src/__tests__/components/Help/HelpAccordionItem.test.tsx new file mode 100644 index 0000000..95764b1 --- /dev/null +++ b/inji-web/src/__tests__/components/Help/HelpAccordionItem.test.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import {fireEvent, render, screen} from '@testing-library/react'; +import {HelpAccordionItem} from "../../../components/Help/HelpAccordionItem"; + +describe("Test Help Accordion Container",() => { + test('check the presence of the container', () => { + const openHandler = jest.fn(); + render(); + const helpElement = screen.getByTestId("Help-Item-Container"); + expect(helpElement).toBeInTheDocument(); + }); + + test('if current help item is not open, it should not show description', () => { + const openHandler = jest.fn(); + render(); + const helpElement = screen.getByTestId("Help-Item-Container"); + expect(helpElement.childElementCount).toBe(1); + }); + test('if current help item is open, it should show description', () => { + const openHandler = jest.fn(); + render(); + const helpElement = screen.getByTestId("Help-Item-Container"); + expect(helpElement.childElementCount).toBe(2); + }); + + test('if current help item is open, it should show description', () => { + const openHandler = jest.fn(); + render(); + const helpElement = screen.getByTestId("Help-Item-Container"); + expect(helpElement.childElementCount).toBe(1); + const buttonElement = screen.getByTestId("Help-Item-Title-Button"); + fireEvent.click(buttonElement); + expect(openHandler).toHaveBeenCalled(); + }); +}) diff --git a/inji-web/src/__tests__/mockUtils.ts b/inji-web/src/__tests__/mockUtils.ts new file mode 100644 index 0000000..4325c4c --- /dev/null +++ b/inji-web/src/__tests__/mockUtils.ts @@ -0,0 +1,14 @@ +export const mockUseTranslation = () => { + return jest.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (key:string) => key, + }), + })); +} + +export const mockUseNavigate = () => { + return jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: jest.fn(), + })); +} diff --git a/inji-web/src/components/Common/LanguageSelector.tsx b/inji-web/src/components/Common/LanguageSelector.tsx index 9ffc01b..5ee32c6 100644 --- a/inji-web/src/components/Common/LanguageSelector.tsx +++ b/inji-web/src/components/Common/LanguageSelector.tsx @@ -4,37 +4,61 @@ import {LanguagesSupported, switchLanguage} from "../../utils/i18n"; import {useDispatch, useSelector} from "react-redux"; import {storeLanguage} from "../../redux/reducers/commonReducer"; import {RootState} from "../../types/redux"; +import {FaCheck} from "react-icons/fa6"; +import {IoIosArrowDown} from "react-icons/io"; +import {RiArrowDownSFill, RiArrowUpSFill} from "react-icons/ri"; export const LanguageSelector: React.FC = () => { const dispatch = useDispatch(); let language = useSelector((state: RootState) => state.common.language); - language = language ? language : 'en'; - const [currentLanguage, setCurrentLanguage] = useState(language); + language = language ?? 'en'; + const [isOpen, setIsOpen] = useState(false); - const handleChange = (language: string) => { - switchLanguage(language); - dispatch(storeLanguage(language)); + + interface DropdownItem { + label: string; + value: string; + } + + const handleChange = (item: DropdownItem) => { + setIsOpen(false); + switchLanguage(item.value); + dispatch(storeLanguage(item.value)); } - return -
- - + return
+ +
+ + + {isOpen && ( +
setIsOpen(false)}> +
    + {LanguagesSupported.map((item) => ( +
  • + +
  • + ))} +
+
+ )}
- +
} diff --git a/inji-web/src/components/Common/NavBar.tsx b/inji-web/src/components/Common/NavBar.tsx index 279bc34..3bc2717 100644 --- a/inji-web/src/components/Common/NavBar.tsx +++ b/inji-web/src/components/Common/NavBar.tsx @@ -43,10 +43,10 @@ export const NavBar: React.FC = (props) => { {props.search &&
-
+
{ return -
+
= (props) => { apiRequest.methodType, apiRequest.headers() ); - dispatch(storeIssuers(response?.response?.issuers.filter((issuer: IssuerObject) => issuer.credential_issuer === 'Sunbird'))) + dispatch(storeIssuers(response?.response?.issuers.filter((issuer: IssuerObject) => issuer.protocol !== 'OTP'))) } return diff --git a/inji-web/src/components/PageTemplate/Header.tsx b/inji-web/src/components/PageTemplate/Header.tsx index 9a08938..325ad1f 100644 --- a/inji-web/src/components/PageTemplate/Header.tsx +++ b/inji-web/src/components/PageTemplate/Header.tsx @@ -3,6 +3,7 @@ import {useTranslation} from "react-i18next"; import {useNavigate} from "react-router-dom"; import {LanguageSelector} from "../Common/LanguageSelector"; import {ThemeMode} from "../Common/ThemeMode"; +import {NavBar} from "../Common/NavBar"; export const Header: React.FC = () => { @@ -30,10 +31,7 @@ export const Header: React.FC = () => { rel="noreferrer" className="text-light-title dark:text-dark-title font-bold">{t("Header.aboutInji")} -
  • -
  • -
  • -
  • +
  • diff --git a/inji-web/src/index.css b/inji-web/src/index.css index 9436b06..6f63ac0 100644 --- a/inji-web/src/index.css +++ b/inji-web/src/index.css @@ -18,6 +18,6 @@ } .root-body { - @apply fixed top-20 left-0 right-0 h-5/6 + @apply top-20 left-0 right-0 h-5/6 mt-20 } } diff --git a/inji-web/src/pages/HomePage.tsx b/inji-web/src/pages/HomePage.tsx index 9bf3381..ff09122 100644 --- a/inji-web/src/pages/HomePage.tsx +++ b/inji-web/src/pages/HomePage.tsx @@ -25,7 +25,7 @@ export const HomePage: React.FC = () => { apiRequest.methodType, apiRequest.headers() ); - const issuers = response?.response?.issuers.filter((issuer: IssuerObject) => issuer.credential_issuer === "Sunbird") + const issuers = response?.response?.issuers.filter((issuer: IssuerObject) => issuer.protocol !== "OTP") dispatch(storeIssuers(issuers)); } fetchCall(); diff --git a/inji-web/src/types/data.d.ts b/inji-web/src/types/data.d.ts index f36751e..01c2611 100644 --- a/inji-web/src/types/data.d.ts +++ b/inji-web/src/types/data.d.ts @@ -34,6 +34,7 @@ export type CodeChallengeObject = { export type IssuerObject = { name: string; desc: string; + protocol: 'OTP' | 'OpenId4VCI'; credential_issuer: string, authorization_endpoint: string; credentials_endpoint: string;