diff --git a/app/index.tsx b/app/index.tsx
index b88823e..bed4639 100644
--- a/app/index.tsx
+++ b/app/index.tsx
@@ -78,7 +78,7 @@ const IndexScreen: React.FC = () => {
const loadedState = await loadState(slot);
if (loadedState) {
setPlayerCount(loadedState.playerCount);
- setBuyInAmount(loadedState.buyInAmount);
+ setBuyInAmount(loadedState.buyInAmount ?? 20);
setNumberOfChips(loadedState.numberOfChips);
setTotalChipsCount(loadedState.totalChipsCount);
setSelectedCurrency(loadedState.selectedCurrency || "$");
diff --git a/components/__tests__/BuyInSelector.test.tsx b/components/__tests__/BuyInSelector.test.tsx
index b20d528..ce29dbf 100644
--- a/components/__tests__/BuyInSelector.test.tsx
+++ b/components/__tests__/BuyInSelector.test.tsx
@@ -2,6 +2,7 @@ import React from "react";
import { fireEvent, render } from "@testing-library/react-native";
import BuyInSelector from "@/components/BuyInSelector";
+// Mocking vector icons to prevent errors
jest.mock("@expo/vector-icons", () => {
const { Text } = require("react-native");
return {
@@ -10,63 +11,73 @@ jest.mock("@expo/vector-icons", () => {
});
describe("BuyInSelector Component", () => {
- let setBuyInAmount;
- let getByText;
- let getByPlaceholderText;
- let queryByText;
+ let setBuyInAmount: jest.Mock;
- // Render the component with the necessary props
+ // Render the component and return query methods
const renderComponent = (selectedCurrency = "$") => {
- const result = render(
+ const utils = render(
);
- getByText = result.getByText;
- getByPlaceholderText = result.getByPlaceholderText;
- queryByText = result.queryByText;
+ return {
+ ...utils,
+ getByText: utils.getByText,
+ getByPlaceholderText: utils.getByPlaceholderText,
+ queryByText: utils.queryByText,
+ };
};
beforeEach(() => {
setBuyInAmount = jest.fn();
- renderComponent();
});
it("renders the buy-in options and input correctly", () => {
+ const { getByText, getByPlaceholderText, queryByText } = renderComponent();
+
expect(getByText("$ 10")).toBeTruthy();
expect(getByText("$ 25")).toBeTruthy();
expect(getByText("$ 50")).toBeTruthy();
expect(getByPlaceholderText("Enter custom buy-in")).toBeTruthy();
-
- // Check default selection with a more flexible approach
- expect(queryByText(/Selected Buy-in.*None/)).toBeTruthy();
+ expect(queryByText(/Selected Buy-in:.*None/i)).toBeTruthy();
});
it("sets a predefined buy-in amount correctly", () => {
+ const { getByText } = renderComponent();
+
fireEvent.press(getByText("$ 25"));
expect(setBuyInAmount).toHaveBeenCalledWith(25);
});
it("sets a custom buy-in amount correctly", () => {
+ const { getByPlaceholderText } = renderComponent();
+
fireEvent.changeText(getByPlaceholderText("Enter custom buy-in"), "100");
expect(setBuyInAmount).toHaveBeenCalledWith(100);
});
it("resets custom amount if invalid input is entered", () => {
+ const { getByPlaceholderText } = renderComponent();
+
fireEvent.changeText(getByPlaceholderText("Enter custom buy-in"), "-10");
- expect(setBuyInAmount).toHaveBeenCalledWith(25);
+ expect(setBuyInAmount).toHaveBeenCalledWith(25); // Default reset
+
fireEvent.changeText(getByPlaceholderText("Enter custom buy-in"), "abc");
expect(setBuyInAmount).toHaveBeenCalledWith(25);
});
it("clears the custom amount when selecting a predefined option", () => {
+ const { getByPlaceholderText, getByText } = renderComponent();
+
fireEvent.changeText(getByPlaceholderText("Enter custom buy-in"), "100");
fireEvent.press(getByText("$ 50"));
expect(setBuyInAmount).toHaveBeenCalledWith(50);
});
it("handles valid and invalid input for custom amount correctly", () => {
+ const { getByPlaceholderText } = renderComponent();
+
fireEvent.changeText(getByPlaceholderText("Enter custom buy-in"), "75");
expect(setBuyInAmount).toHaveBeenCalledWith(75);
@@ -78,33 +89,40 @@ describe("BuyInSelector Component", () => {
});
it("triggers state update every time a buy-in option is clicked, even if it's the same", () => {
+ const { getByText } = renderComponent();
+
fireEvent.press(getByText("$ 25"));
fireEvent.press(getByText("$ 25"));
expect(setBuyInAmount).toHaveBeenCalledTimes(2);
});
it("resets to default buy-in when custom input is cleared", () => {
+ const { getByPlaceholderText } = renderComponent();
const input = getByPlaceholderText("Enter custom buy-in");
+
fireEvent.changeText(input, "75");
expect(setBuyInAmount).toHaveBeenCalledWith(75);
+
fireEvent.changeText(input, "");
expect(setBuyInAmount).toHaveBeenCalledWith(25);
});
it("updates state correctly when selecting predefined buy-in after entering a custom amount", () => {
+ const { getByPlaceholderText, getByText } = renderComponent();
+
fireEvent.changeText(getByPlaceholderText("Enter custom buy-in"), "200");
expect(setBuyInAmount).toHaveBeenCalledWith(200);
+
fireEvent.press(getByText("$ 10"));
expect(setBuyInAmount).toHaveBeenCalledWith(10);
});
it("displays selected currency correctly", () => {
- renderComponent("€");
+ const { getByText, queryByText } = renderComponent("€");
+
expect(getByText("€ 10")).toBeTruthy();
expect(getByText("€ 25")).toBeTruthy();
expect(getByText("€ 50")).toBeTruthy();
-
- // Check default selection text with a flexible regex
- expect(queryByText(/Selected Buy-in.*None/)).toBeTruthy();
+ expect(queryByText(/Selected Buy-in:.*None/i)).toBeTruthy();
});
});
diff --git a/components/__tests__/ChipDetection.test.tsx b/components/__tests__/ChipDetection.test.tsx
index 45ecb5e..2dac26c 100644
--- a/components/__tests__/ChipDetection.test.tsx
+++ b/components/__tests__/ChipDetection.test.tsx
@@ -17,11 +17,10 @@ jest.mock("expo-image-picker", () => ({
describe("ChipDetection", () => {
beforeEach(() => {
jest.clearAllMocks();
- global.fetch = jest.fn(() =>
- Promise.resolve({
- ok: true,
- json: () =>
- Promise.resolve({
+ jest.spyOn(global, "fetch").mockImplementation(() =>
+ Promise.resolve(
+ new Response(
+ JSON.stringify({
choices: [
{
message: {
@@ -34,10 +33,16 @@ describe("ChipDetection", () => {
},
],
}),
- })
+ { status: 200, headers: { "Content-Type": "application/json" } }
+ )
+ )
);
});
+ afterEach(() => {
+ jest.restoreAllMocks(); // Reset all mocks to prevent test contamination
+ });
+
it("renders correctly", () => {
const { getByText } = render(
@@ -48,7 +53,7 @@ describe("ChipDetection", () => {
});
it("picks an image from the library", async () => {
- ImagePicker.launchImageLibraryAsync.mockResolvedValueOnce({
+ (ImagePicker.launchImageLibraryAsync as jest.Mock).mockResolvedValueOnce({
canceled: false,
assets: [{ uri: "test-uri", base64: "test-base64" }],
});
@@ -62,10 +67,12 @@ describe("ChipDetection", () => {
});
it("takes a photo with the camera", async () => {
- ImagePicker.requestCameraPermissionsAsync.mockResolvedValueOnce({
+ (
+ ImagePicker.requestCameraPermissionsAsync as jest.Mock
+ ).mockResolvedValueOnce({
granted: true,
});
- ImagePicker.launchCameraAsync.mockResolvedValueOnce({
+ (ImagePicker.launchCameraAsync as jest.Mock).mockResolvedValueOnce({
canceled: false,
assets: [{ uri: "test-camera-uri", base64: "test-camera-base64" }],
});
@@ -81,7 +88,9 @@ describe("ChipDetection", () => {
});
it("handles camera permission denied", async () => {
- ImagePicker.requestCameraPermissionsAsync.mockResolvedValueOnce({
+ (
+ ImagePicker.requestCameraPermissionsAsync as jest.Mock
+ ).mockResolvedValueOnce({
granted: false,
});
@@ -98,16 +107,18 @@ describe("ChipDetection", () => {
});
it("displays error message on image processing failure", async () => {
- ImagePicker.launchImageLibraryAsync.mockResolvedValueOnce({
+ (ImagePicker.launchImageLibraryAsync as jest.Mock).mockResolvedValueOnce({
canceled: false,
assets: [{ uri: "test-uri", base64: "test-base64" }],
});
- global.fetch.mockImplementationOnce(() =>
- Promise.resolve({
- ok: false,
- json: () => Promise.resolve({ choices: [] }),
- })
+ jest.spyOn(global, "fetch").mockImplementationOnce(() =>
+ Promise.resolve(
+ new Response(JSON.stringify({ choices: [] }), {
+ status: 400,
+ headers: { "Content-Type": "application/json" },
+ })
+ )
);
const { getByText } = render(
@@ -121,16 +132,15 @@ describe("ChipDetection", () => {
});
it("handles valid API response correctly", async () => {
- ImagePicker.launchImageLibraryAsync.mockResolvedValueOnce({
+ (ImagePicker.launchImageLibraryAsync as jest.Mock).mockResolvedValueOnce({
canceled: false,
assets: [{ uri: "test-uri", base64: "test-base64" }],
});
- global.fetch.mockImplementationOnce(() =>
- Promise.resolve({
- ok: true,
- json: () =>
- Promise.resolve({
+ jest.spyOn(global, "fetch").mockImplementationOnce(() =>
+ Promise.resolve(
+ new Response(
+ JSON.stringify({
choices: [
{
message: {
@@ -139,7 +149,9 @@ describe("ChipDetection", () => {
},
],
}),
- })
+ { status: 200, headers: { "Content-Type": "application/json" } }
+ )
+ )
);
const { getByText } = render(