Skip to content

Commit

Permalink
test: add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
gabriel-logan committed Sep 3, 2024
1 parent ee1f961 commit 5363e27
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: gabriellogan
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
6 changes: 3 additions & 3 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
with:
node-version: 20
cache: "npm"

- name: Install dependencies
run: yarn install

Expand All @@ -28,6 +28,6 @@ jobs:

- name: Run lint
run: yarn lint

- name: Run test
run: yarn test:verbose:coverage
run: yarn test:verbose:coverage
1 change: 1 addition & 0 deletions __mocks__/svgMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = "SvgMock";
3 changes: 3 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ module.exports = {
preset: "react-native",
setupFilesAfterEnv: ["./jest/setupFilesAfterEnv.ts"],
setupFiles: ["./jest/setupFiles.js"],
moduleNameMapper: {
"\\.svg": "<rootDir>/__mocks__/svgMock.js",
},
};
29 changes: 29 additions & 0 deletions jest/setupFiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,32 @@ jest.mock("@react-navigation/native", () => {
jest.mock("@react-native-async-storage/async-storage", () =>
require("@react-native-async-storage/async-storage/jest/async-storage-mock")
);

jest.mock("react-i18next", () => ({
// this mock makes sure any components using the translate hook can use it without a warning being shown
useTranslation: () => {
return {
t: (str) => str,
i18n: {
changeLanguage: () => new Promise(() => {}),
},
};
},
initReactI18next: {
type: "3rdParty",
init: () => {},
},
}));

jest.mock("react-native-responsive-fontsize", () => ({
RFValue: jest.fn(),
RFPercentage: jest.fn(),
fixedRFValue: jest.fn(),
}));

jest.mock("react-native-responsive-screen", () => ({
widthPercentageToDP: jest.fn(),
heightPercentageToDP: jest.fn(),
width: jest.fn(),
height: jest.fn(),
}));
9 changes: 9 additions & 0 deletions src/components/DrawerContent/__tests__/DrawerContent.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { render } from "@testing-library/react-native";

import CustomDrawerContent from "..";

describe("DrawerContent", () => {
it("should render correctly", () => {
render(<CustomDrawerContent />);
});
});
24 changes: 24 additions & 0 deletions src/components/DrawerContent/__tests__/drawerMenu.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import drawerMenu from "../drawerMenu";

describe("drawerMenu", () => {
it("should have the correct number of items", () => {
expect(drawerMenu).toHaveLength(7);
});

it("should have the correct structure for each item", () => {
drawerMenu.forEach((item) => {
expect(item).toHaveProperty("title");
if ("route" in item) {
expect(item).toHaveProperty("route");
expect(item).not.toHaveProperty("menuList");
} else {
expect(item).toHaveProperty("menuList");
expect(item).not.toHaveProperty("route");
item.menuList.forEach((subItem) => {
expect(subItem).toHaveProperty("title");
expect(subItem).toHaveProperty("route");
});
}
});
});
});
132 changes: 132 additions & 0 deletions src/components/ThemeContext/__tests__/ThemeContext.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
import {
render,
fireEvent,
screen,
waitFor,
} from "@testing-library/react-native";
import { Text, TouchableOpacity } from "react-native";

import ThemeProvider, { useTheme } from "..";

describe("ThemeContext", () => {
describe("ThemeProvider", () => {
test("renders children correctly", () => {
render(
<ThemeProvider>
<Text>Test</Text>
</ThemeProvider>
);

expect(screen.getByText("Test")).toBeDefined();
});

test("toggles theme correctly", () => {
const TestComponent = () => {
const { theme, toggleTheme } = useTheme();

return (
<TouchableOpacity
onPress={() => toggleTheme(theme === "light" ? "dark" : "light")}
>
<Text>{theme}</Text>
</TouchableOpacity>
);
};

render(
<ThemeProvider>
<TestComponent />
</ThemeProvider>
);

const toggleButton = screen.getByText("light");

fireEvent.press(toggleButton);

expect(screen.getByText("dark")).toBeDefined();
});

describe("useEffect", () => {
test("themeSelected from AsyncStorage is system", async () => {
const valueStoraged = "system";

(AsyncStorage.getItem as jest.Mock).mockResolvedValueOnce(
valueStoraged
);

render(
<ThemeProvider>
<Text>Test</Text>
</ThemeProvider>
);

await waitFor(() => {
expect(screen.getByText("Test")).toBeDefined();
});
});

test("themeSelected from AsyncStorage is not system", async () => {
const valueStoraged = "dark";

(AsyncStorage.getItem as jest.Mock).mockResolvedValueOnce(
valueStoraged
);

render(
<ThemeProvider>
<Text>Test</Text>
</ThemeProvider>
);

await waitFor(() => {
expect(screen.getByText("Test")).toBeDefined();
});
});

test("error on AsyncStorage.getItem", async () => {
(AsyncStorage.getItem as jest.Mock).mockRejectedValueOnce(
new Error("AsyncStorage error")
);

render(
<ThemeProvider>
<Text>Test</Text>
</ThemeProvider>
);

await waitFor(() => {
expect(screen.getByText("Test")).toBeDefined();
});
});
});
});

describe("useTheme", () => {
test("returns theme and toggleTheme function", () => {
const TestComponent = () => {
const { theme, toggleTheme } = useTheme();

return (
<TouchableOpacity
onPress={() => toggleTheme(theme === "light" ? "dark" : "light")}
>
<Text>{theme}</Text>
</TouchableOpacity>
);
};

render(
<ThemeProvider>
<TestComponent />
</ThemeProvider>
);

const toggleButton = screen.getByText("light");

fireEvent.press(toggleButton);

expect(screen.getByText("dark")).toBeDefined();
});
});
});
12 changes: 2 additions & 10 deletions src/components/ThemeContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,7 @@ export default function ThemeProvider({ children }: { children: ReactNode }) {
);

const toggleTheme = async (newTheme: Theme) => {
try {
setTheme(newTheme);
} catch {
Alert.alert(
"Something strange happened when trying to change the theme, contact the developer"
);
}
setTheme(newTheme);
};

const contextValue: ThemeContextProps = {
Expand Down Expand Up @@ -70,8 +64,6 @@ export default function ThemeProvider({ children }: { children: ReactNode }) {

export const useTheme = () => {
const context = useContext(ThemeContext) as ThemeContextProps;
if (!context) {
throw new Error("useTheme must be used within a ThemeProvider");
}

return context;
};

0 comments on commit 5363e27

Please sign in to comment.