diff --git a/__mocks__/react-native-localize.ts b/__mocks__/react-native-localize.ts new file mode 100644 index 0000000..bc40dd1 --- /dev/null +++ b/__mocks__/react-native-localize.ts @@ -0,0 +1,2 @@ +// __mocks__/react-native-localize.ts +export * from "react-native-localize/mock"; // or "react-native-localize/mock/jest" diff --git a/jest/setupFiles.js b/jest/setupFiles.js index 0099594..60cb858 100644 --- a/jest/setupFiles.js +++ b/jest/setupFiles.js @@ -49,14 +49,14 @@ jest.mock("react-i18next", () => ({ })); jest.mock("react-native-responsive-fontsize", () => ({ - RFValue: jest.fn(), - RFPercentage: jest.fn(), - fixedRFValue: jest.fn(), + RFValue: jest.fn().mockImplementation(() => 10), + RFPercentage: jest.fn().mockImplementation(() => 10), + fixedRFValue: jest.fn().mockImplementation(() => 10), })); jest.mock("react-native-responsive-screen", () => ({ - widthPercentageToDP: jest.fn(), - heightPercentageToDP: jest.fn(), - width: jest.fn(), - height: jest.fn(), + widthPercentageToDP: jest.fn().mockImplementation(() => 10), + heightPercentageToDP: jest.fn().mockImplementation(() => 10), + width: jest.fn().mockImplementation(() => 10), + height: jest.fn().mockImplementation(() => 10), })); diff --git a/src/components/DrawerContent/__tests__/DrawerContent.test.tsx b/src/components/DrawerContent/__tests__/DrawerContent.test.tsx index 29caa2f..c44270e 100644 --- a/src/components/DrawerContent/__tests__/DrawerContent.test.tsx +++ b/src/components/DrawerContent/__tests__/DrawerContent.test.tsx @@ -1,9 +1,60 @@ -import { render } from "@testing-library/react-native"; +import { fireEvent, render, screen } from "@testing-library/react-native"; import CustomDrawerContent from ".."; describe("DrawerContent", () => { it("should render correctly", () => { render(); + + expect(screen.getByText(/Principal/i)).toBeTruthy(); + }); + + describe("Main menu", () => { + it("should navigate to the correct screen", async () => { + render(); + + const drawerItem = await screen.findAllByTestId("drawerItem"); + + drawerItem.forEach((item) => { + fireEvent.press(item); + }); + + expect(screen.getByText(/Principal/i)).toBeTruthy(); + }); + + it("should open and close the sub menu", async () => { + render(); + + const drawerItem = await screen.findAllByTestId("drawerItem"); + + fireEvent.press(drawerItem[2]); + + const drawerItemSub = await screen.findAllByTestId("drawerItemSub"); + + expect(drawerItemSub).toHaveLength(4); + + fireEvent.press(drawerItem[2]); + + expect(screen.queryByTestId("drawerItemSub")).toBeNull(); + }); + }); + + describe("Sub menu", () => { + it("should navigate to the correct screen", async () => { + render(); + + const drawerItem = await screen.findAllByTestId("drawerItem"); + + fireEvent.press(drawerItem[2]); + fireEvent.press(drawerItem[3]); + + const drawerItemSub = await screen.findAllByTestId("drawerItemSub"); + + drawerItemSub.forEach((item) => { + fireEvent.press(item); + }); + + expect(screen.getByText(/Principal/i)).toBeTruthy(); + }); }); }); diff --git a/src/components/DrawerContent/index.tsx b/src/components/DrawerContent/index.tsx index 0e95d25..bc3b48a 100644 --- a/src/components/DrawerContent/index.tsx +++ b/src/components/DrawerContent/index.tsx @@ -42,6 +42,7 @@ const CustomDrawerContent = () => { {drawerMenu.map((item, index) => ( { LayoutAnimation.configureNext( LayoutAnimation.create(200, "easeInEaseOut", "opacity") @@ -59,6 +60,7 @@ const CustomDrawerContent = () => { <> {item.menuList?.map((subItem, subIndex) => ( navigation.navigate(subItem.route)} > diff --git a/src/components/LogoComponent/__tests__/LogoComponent.test.tsx b/src/components/LogoComponent/__tests__/LogoComponent.test.tsx new file mode 100644 index 0000000..a9501a5 --- /dev/null +++ b/src/components/LogoComponent/__tests__/LogoComponent.test.tsx @@ -0,0 +1,15 @@ +import { render } from "@testing-library/react-native"; + +import LogoComponent from ".."; + +describe("LogoComponent", () => { + it("should render correctly", () => { + render( + + ); + }); +}); diff --git a/src/components/LogoComponent/index.tsx b/src/components/LogoComponent/index.tsx index 02f89ee..2cd7ee8 100644 --- a/src/components/LogoComponent/index.tsx +++ b/src/components/LogoComponent/index.tsx @@ -13,7 +13,9 @@ interface LogoComponentProps { const LogoComponent = ({ style, width, height }: LogoComponentProps) => { const { theme } = useTheme(); const Logo = theme === "light" ? Marca : MarcaLight; - return ; + return ( + + ); }; export default LogoComponent; diff --git a/src/components/PrivacyPolicesAndTerms/__tests__/PrivacyPolicesAndTerms.test.tsx b/src/components/PrivacyPolicesAndTerms/__tests__/PrivacyPolicesAndTerms.test.tsx new file mode 100644 index 0000000..ce039bf --- /dev/null +++ b/src/components/PrivacyPolicesAndTerms/__tests__/PrivacyPolicesAndTerms.test.tsx @@ -0,0 +1,115 @@ +import AsyncStorage from "@react-native-async-storage/async-storage"; +import { + fireEvent, + render, + screen, + waitFor, +} from "@testing-library/react-native"; +import { Alert } from "react-native"; + +import PrivacyPolicesAndTerms from ".."; +import type { NavigationType } from "../../../types/navigationProps"; + +const mockNavigation = { + navigate: jest.fn(), + dispatch: jest.fn(), + reset: jest.fn(), + goBack: jest.fn(), + isFocused: jest.fn(), +} as unknown as NavigationType; + +jest.mock("react-native-vector-icons/MaterialCommunityIcons", () => "Icon"); + +describe("PrivacyPolicesAndTerms", () => { + it("should render correctly", () => { + render(); + }); + + describe("open links", () => { + it("should open the terms link", () => { + render(); + + const button = screen.getByText("Ler termos de uso"); + + fireEvent.press(button); + }); + + it("should open the privacy link", () => { + render(); + + const button = screen.getByText("Ler politicas de privacidade"); + + fireEvent.press(button); + }); + }); + + describe("checkbox", () => { + it("should apear activeSpan if checkbox is not checked", async () => { + render(); + + const button = screen.getByText("Continuar"); + + fireEvent.press(button); + + const textActiveSpan = await screen.findByText( + "Para continuar vocĂȘ precisa aceitar os termos" + ); + + expect(textActiveSpan).toBeTruthy(); + }); + + it("should not apear activeSpan if checkbox is checked", async () => { + render(); + + const checkbox = screen.getByTestId("checkbox"); + + fireEvent.press(checkbox); + + const button = screen.getByText("Continuar"); + + fireEvent.press(button); + + const textActiveSpan = screen.queryByText( + "Para continuar vocĂȘ precisa aceitar os termos" + ); + + await waitFor(() => { + expect(textActiveSpan).toBeNull(); + }); + }); + + it("should check the checkbox", () => { + render(); + + const checkbox = screen.getByTestId("checkbox"); + + fireEvent.press(checkbox); + }); + }); + + describe("error handling", () => { + it("should show alert on AsyncStorage.setItem error", async () => { + jest.spyOn(Alert, "alert"); + + (AsyncStorage.setItem as jest.Mock).mockRejectedValueOnce( + new Error("AsyncStorage error") + ); + + render(); + + const checkbox = screen.getByTestId("checkbox"); + + fireEvent.press(checkbox); + + const button = screen.getByText("Continuar"); + + fireEvent.press(button); + + await waitFor(() => { + expect(Alert.alert).toHaveBeenCalledWith( + "Alguma coisa errada aconteceu, contate o desenvolvedor" + ); + }); + }); + }); +}); diff --git a/src/components/PrivacyPolicesAndTerms/index.tsx b/src/components/PrivacyPolicesAndTerms/index.tsx index 122863d..b0c85e6 100644 --- a/src/components/PrivacyPolicesAndTerms/index.tsx +++ b/src/components/PrivacyPolicesAndTerms/index.tsx @@ -94,6 +94,7 @@ export default function PrivacyPolicesAndTerms({ style={styles.checkboxContainer} onPress={handleCheckboxChange} activeOpacity={0.8} + testID="checkbox" > {checkboxIcon} diff --git a/src/components/Responsive/__tests__/Responsive.test.ts b/src/components/Responsive/__tests__/Responsive.test.ts new file mode 100644 index 0000000..87fcba4 --- /dev/null +++ b/src/components/Responsive/__tests__/Responsive.test.ts @@ -0,0 +1,35 @@ +import { + height, + RFPercentage, + RFValue, + RFValueWithFixedSecondParam, + width, +} from ".."; + +describe("Responsive", () => { + it("should calculate width correctly", () => { + const calculatedWidth = width("100%"); + expect(calculatedWidth).toBeGreaterThan(0); + }); + + it("should calculate height correctly", () => { + const calculatedHeight = height(50); + expect(calculatedHeight).toBeGreaterThan(0); + }); + + it("should calculate RFPercentage correctly", () => { + const calculatedRFPercentage = RFPercentage(50); + expect(calculatedRFPercentage).toBeGreaterThan(0); + }); + + it("should calculate RFValue correctly", () => { + const calculatedRFValue = RFValue(16); + expect(calculatedRFValue).toBeGreaterThan(0); + }); + + it("should calculate RFValueWithFixedSecondParam correctly", () => { + const calculatedRFValueWithFixedSecondParam = + RFValueWithFixedSecondParam(16); + expect(calculatedRFValueWithFixedSecondParam).toBeGreaterThan(0); + }); +}); diff --git a/src/components/Urls/__tests__/Urls.test.ts b/src/components/Urls/__tests__/Urls.test.ts new file mode 100644 index 0000000..04a3bc9 --- /dev/null +++ b/src/components/Urls/__tests__/Urls.test.ts @@ -0,0 +1,19 @@ +import { termsURL, privacyURL, buyMeACoffeeURL, repoGithubURL } from ".."; + +describe("Urls", () => { + it("should have the correct terms URL", () => { + expect(termsURL).toBe("https://2devs.tech/terms"); + }); + + it("should have the correct privacy URL", () => { + expect(privacyURL).toBe("https://2devs.tech/PrivacyPolicy"); + }); + + it("should have the correct buy me a coffee URL", () => { + expect(buyMeACoffeeURL).toBe("https://www.buymeacoffee.com/gabriellogan"); + }); + + it("should have the correct GitHub repository URL", () => { + expect(repoGithubURL).toBe("https://github.com/gabriel-logan/2Devs-Mobile"); + }); +});