Skip to content

Conversation

@Devasy
Copy link
Owner

@Devasy Devasy commented Aug 2, 2025

Retrieve and display friends' balances in the FriendsScreen, improving balance calculation logic. Update HomeScreen header to streamline group creation and joining actions by removing redundant buttons.

Summary by CodeRabbit

  • New Features

    • Added a tooltip to the friends list explaining the meaning of displayed balances, with a close button to dismiss.
    • Introduced direct fetching of friends' balance data, showing clearer breakdowns by friend and group.
  • Improvements

    • Updated balance calculations and display to more accurately reflect who paid for expenses.
    • Enhanced group details and friends screens with clearer, color-coded balance information.
    • Replaced logout action with new buttons for creating and joining groups in the home screen header; removed redundant buttons from the bottom of the screen.
  • Bug Fixes

    • Improved accuracy in identifying the payer of expenses when displaying and calculating balances.

@Devasy Devasy requested a review from vrajpatelll as a code owner August 2, 2025 17:56
@Devasy Devasy self-assigned this Aug 2, 2025
@Devasy Devasy requested a review from AneeshAhuja31 August 2, 2025 17:56
@Devasy Devasy added this to Splitwiser Aug 2, 2025
@github-project-automation github-project-automation bot moved this to Backlog in Splitwiser Aug 2, 2025
@netlify
Copy link

netlify bot commented Aug 2, 2025

Deploy Preview for splitwizer failed. Why did it fail? →

Name Link
🔨 Latest commit 2da0356
🔍 Latest deploy log https://app.netlify.com/projects/splitwizer/deploys/6890db02ddc6e3000868d141

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 2, 2025

Walkthrough

The changes introduce a new API function to fetch friends' balance data and update the FriendsScreen to use this endpoint, simplifying balance calculations and improving UI feedback. Expense payer logic is updated across relevant files to prioritize a new paidBy field. UI adjustments are made to HomeScreen actions, and a redundant package.json is removed.

Changes

Cohort / File(s) Change Summary
API Enhancement
frontend/api/groups.js
Added getFriendsBalance function to fetch friends' balance data from a new API endpoint using a bearer token.
Friends Screen Refactor & UI Update
frontend/screens/FriendsScreen.js
Updated to fetch and display friends' balances via the new API, added a tooltip for balance meaning, improved group balance display, and adjusted imports and error handling.
Expense Payer Logic Update
frontend/screens/GroupDetailsScreen.js, frontend/utils/balanceCalculator.js
Modified logic to prioritize the paidBy property over createdBy for determining expense payer in both display and balance calculations.
Home Screen UI Actions
frontend/screens/HomeScreen.js
Replaced logout button with group creation and join buttons in the app bar; removed bottom action buttons and related styles.
Manifest Removal
frontend/frontend/package.json
Deleted the package.json manifest listing frontend dependencies; no other configuration was present.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant FriendsScreen
    participant API
    participant Backend

    User->>FriendsScreen: Open Friends Screen
    FriendsScreen->>API: getFriendsBalance(token)
    API->>Backend: GET /users/me/friends-balance
    Backend-->>API: Friends balance data
    API-->>FriendsScreen: Friends balance data
    FriendsScreen->>User: Render friends balances with tooltips
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15 minutes

Suggested labels

enhancement, gssoc25, level3

Poem

A bunny hops through code so bright,
Fetching friends' balances just right.
With payers clear and tooltips near,
The UI shines—no bugs to fear!
Old buttons gone, new actions bloom,
This code brings joy to every room.
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df45073 and 2da0356.

📒 Files selected for processing (1)
  • frontend/screens/HomeScreen.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/screens/HomeScreen.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Redirect rules - splitwizer
  • GitHub Check: Header rules - splitwizer
  • GitHub Check: Pages changed - splitwizer
  • GitHub Check: bundle-analysis
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/settlement-view-inconsistencies

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@codecov
Copy link

codecov bot commented Aug 2, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.86%. Comparing base (6faafc6) to head (2da0356).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #114   +/-   ##
=======================================
  Coverage   71.86%   71.86%           
=======================================
  Files          17       17           
  Lines        1667     1667           
  Branches      153      153           
=======================================
  Hits         1198     1198           
  Misses        416      416           
  Partials       53       53           
Components Coverage Δ
Authentication System 75.45% <ø> (ø)
Expense Management 68.94% <ø> (ø)
Group Management 66.77% <ø> (ø)
User Management 97.16% <ø> (ø)
Backend Core 69.41% <ø> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link

github-actions bot commented Aug 2, 2025

🚀 Expo preview is ready!

  • Project → frontend
  • Platforms → android, ios
  • Runtime Version → 1.0.0
  • More info

Learn more about 𝝠 Expo Github Action

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 2, 2025

Note

Unit test generation is an Early Access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 2, 2025

Creating a local commit for the generated unit tests...

The unit tests have been committed to the current branch. Commit ID: df450737195a378b806b9924c14e90d120707610

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🧹 Nitpick comments (6)
frontend/package.json (1)

32-32: Consider updating @babel/core to a more recent version

The specified version ^7.20.0 is from 2022. Consider updating to ^7.25.0 or later for better compatibility and bug fixes.

-    "@babel/core": "^7.20.0",
+    "@babel/core": "^7.25.0",
frontend/api/groups.test.js (2)

39-39: Avoid using require() in ES6 modules

The code uses require('./groups') which is inconsistent with ES6 module syntax used elsewhere. Consider using dynamic import or restructuring the test.

-      // Import the module to trigger axios.create
-      require('./groups');
+      // Import the module to trigger axios.create
+      jest.isolateModules(() => {
+        require('./groups');
+      });

807-812: Consider reducing performance test timeout threshold

A 5-second timeout for processing 100 groups with 50 members and 100 expenses each seems excessive for a calculation function. Consider a more aggressive target.

-      expect(endTime - startTime).toBeLessThan(5000); // Should complete within 5 seconds
+      expect(endTime - startTime).toBeLessThan(1000); // Should complete within 1 second
frontend/screens/HomeScreen.test.js (1)

809-829: Test for memory leaks with auth context changes

The lifecycle test checks functionality but doesn't verify that old subscriptions/effects are cleaned up properly.

Add a test to verify cleanup:

it('should cleanup effects when component unmounts', async () => {
  const { unmount } = renderWithAuthContext();
  
  await waitFor(() => {
    expect(getGroups).toHaveBeenCalledTimes(1);
  });
  
  unmount();
  
  // Verify no additional API calls are made after unmount
  await act(async () => {
    await new Promise(resolve => setTimeout(resolve, 100));
  });
  
  expect(getGroups).toHaveBeenCalledTimes(1);
});
frontend/screens/GroupDetailsScreen.test.js (2)

104-104: Redundant mockClear() call

Alert.alert is already defined as jest.fn() in the React Native mock (line 21), which creates a fresh mock function. The mockClear() call here is redundant since jest.clearAllMocks() on line 103 already clears all mocks.

  beforeEach(() => {
    jest.clearAllMocks();
-   Alert.alert.mockClear();
  });

798-800: Use more specific variable declaration

Consider using a more specific initial value or type for better code clarity.

  it('should update loading state correctly during data fetch', async () => {
-   let resolvePromises;
+   let resolvePromises = null;
    const promises = new Promise(resolve => { resolvePromises = resolve; });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11be213 and df45073.

📒 Files selected for processing (9)
  • frontend/api/groups.test.js (1 hunks)
  • frontend/babel.config.js (1 hunks)
  • frontend/jest.setup.js (1 hunks)
  • frontend/package.json (2 hunks)
  • frontend/screens/FriendsScreen.test.js (1 hunks)
  • frontend/screens/GroupDetailsScreen.test.js (1 hunks)
  • frontend/screens/HomeScreen.js (1 hunks)
  • frontend/screens/HomeScreen.test.js (1 hunks)
  • frontend/utils/balanceCalculator.test.js (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • frontend/babel.config.js
  • frontend/jest.setup.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/screens/HomeScreen.js
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: Devasy23/splitwiser#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-26T09:41:01.332Z
Learning: Applies to backend/app/expenses/**/*.py : Settlements must track debt resolution between users in the expense tracking logic.
Learnt from: CR
PR: Devasy23/splitwiser#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-26T09:41:01.332Z
Learning: Applies to backend/app/expenses/**/*.py : Support for different expense split types (equal, unequal, percentage-based) must be implemented in the expense tracking logic.
🧬 Code Graph Analysis (1)
frontend/screens/GroupDetailsScreen.test.js (3)
frontend/screens/FriendsScreen.test.js (3)
  • RN (19-19)
  • mockAuthContext (39-42)
  • renderWithContext (80-86)
frontend/screens/HomeScreen.test.js (1)
  • mockNavigation (22-24)
frontend/screens/GroupDetailsScreen.js (2)
  • GroupDetailsScreen (7-188)
  • settlements (12-12)
🔇 Additional comments (2)
frontend/utils/balanceCalculator.test.js (1)

693-696: Parsed amounts are already validated

Upon inspection of frontend/utils/balanceCalculator.js, both split amounts and group balances are explicitly guarded against invalid parsing:

  • Around line 96–99, splitAmount is parsed with parseFloat and immediately filtered by isNaN(splitAmount) and splitAmount <= 0.
  • Around line 145–150, group balances are parsed and then filtered using !isNaN(group.balance).

No additional validation is needed for string-to-number parsing in these sections—please disregard the original suggestion.

Likely an incorrect or invalid review comment.

frontend/screens/GroupDetailsScreen.test.js (1)

1-1078: Excellent comprehensive test coverage!

This test file provides thorough coverage of the GroupDetailsScreen component with well-organized test suites covering:

  • Initial loading and setup
  • Data fetching with various API response scenarios
  • Currency formatting
  • Member name resolution
  • Expense rendering with different payment scenarios
  • Settlement summary calculations
  • Empty states and edge cases
  • Navigation functionality
  • State management and performance

The testing patterns follow best practices with proper mocking, context providers, and async handling.

Comment on lines 571 to 580
data: {
totalOwed: 0,
totalOwing: 0,
netBalance: 0
}
};
mockApiClient.get.mockResolvedValue(mockResponse);

const result = await getUserBalanceSummary(mockToken);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Console spy not properly restored in some test paths

The console.warn spy is created but only restored in the happy path. If the test fails before line 579, the spy won't be restored.

   it('should log warnings for invalid input', () => {
     const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
     
-    calculateFriendBalances(null, 'currentUser');
-    expect(consoleSpy).toHaveBeenCalledWith('Invalid input to calculateFriendBalances:', { groupsWithDetails: null, currentUserId: 'currentUser' });
-    
-    calculateFriendBalances([], null);
-    expect(consoleSpy).toHaveBeenCalledWith('Invalid input to calculateFriendBalances:', { groupsWithDetails: [], currentUserId: null });
-    
-    consoleSpy.mockRestore();
+    try {
+      calculateFriendBalances(null, 'currentUser');
+      expect(consoleSpy).toHaveBeenCalledWith('Invalid input to calculateFriendBalances:', { groupsWithDetails: null, currentUserId: 'currentUser' });
+      
+      calculateFriendBalances([], null);
+      expect(consoleSpy).toHaveBeenCalledWith('Invalid input to calculateFriendBalances:', { groupsWithDetails: [], currentUserId: null });
+    } finally {
+      consoleSpy.mockRestore();
+    }
   });

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In frontend/api/groups.test.js around lines 571 to 580, the console.warn spy is
created but only restored in the successful test path, risking it not being
restored if the test fails earlier. To fix this, ensure the console.warn spy is
restored in a finally block or use afterEach/afterAll hooks to restore the spy
regardless of test outcome, guaranteeing cleanup in all test paths.

"private": true,
"jest": {
"preset": "react-native",
"testEnvironment": "jsdom",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect test environment for React Native

React Native tests typically run in a Node environment, not jsdom. The jsdom environment is for web-based React applications.

-    "testEnvironment": "jsdom",
+    "testEnvironment": "node",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"testEnvironment": "jsdom",
"testEnvironment": "node",
🤖 Prompt for AI Agents
In frontend/package.json at line 40, the testEnvironment is set to "jsdom",
which is incorrect for React Native tests. Change the testEnvironment value from
"jsdom" to "node" to properly configure the testing environment for React
Native.

Comment on lines 56 to 60
"collectCoverageFrom": [
"api/**/*.{js,jsx}",
"!api/**/*.test.{js,jsx}",
"!**/node_modules/**"
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Expand test coverage collection to include screens and utils

Currently, coverage is only collected from the api directory. Consider including other important directories like screens, utils, and context.

     "collectCoverageFrom": [
       "api/**/*.{js,jsx}",
+      "screens/**/*.{js,jsx}",
+      "utils/**/*.{js,jsx}",
+      "context/**/*.{js,jsx}",
       "!api/**/*.test.{js,jsx}",
+      "!screens/**/*.test.{js,jsx}",
+      "!utils/**/*.test.{js,jsx}",
+      "!context/**/*.test.{js,jsx}",
       "!**/node_modules/**"
     ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"collectCoverageFrom": [
"api/**/*.{js,jsx}",
"!api/**/*.test.{js,jsx}",
"!**/node_modules/**"
]
"collectCoverageFrom": [
"api/**/*.{js,jsx}",
"screens/**/*.{js,jsx}",
"utils/**/*.{js,jsx}",
"context/**/*.{js,jsx}",
"!api/**/*.test.{js,jsx}",
"!screens/**/*.test.{js,jsx}",
"!utils/**/*.test.{js,jsx}",
"!context/**/*.test.{js,jsx}",
"!**/node_modules/**"
]
🤖 Prompt for AI Agents
In frontend/package.json around lines 56 to 60, the test coverage collection is
limited to the api directory. Update the collectCoverageFrom array to also
include files from the screens, utils, and context directories by adding
appropriate glob patterns for these directories, while continuing to exclude
test files and node_modules as before.

Comment on lines 29 to 36
const originalConsoleError = console.error;
beforeAll(() => {
console.error = jest.fn();
});

afterAll(() => {
console.error = originalConsoleError;
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Console error mock not properly restored on test failure

The console.error is mocked but restoration depends on all tests passing. Use Jest's built-in console mocking instead.

-// Mock console.error to avoid noise in tests
-const originalConsoleError = console.error;
-beforeAll(() => {
-  console.error = jest.fn();
-});
-
-afterAll(() => {
-  console.error = originalConsoleError;
-});
+// Mock console.error to avoid noise in tests
+beforeEach(() => {
+  jest.spyOn(console, 'error').mockImplementation(() => {});
+});
+
+afterEach(() => {
+  console.error.mockRestore();
+});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const originalConsoleError = console.error;
beforeAll(() => {
console.error = jest.fn();
});
afterAll(() => {
console.error = originalConsoleError;
});
// Mock console.error to avoid noise in tests
beforeEach(() => {
jest.spyOn(console, 'error').mockImplementation(() => {});
});
afterEach(() => {
console.error.mockRestore();
});
🤖 Prompt for AI Agents
In frontend/screens/FriendsScreen.test.js around lines 29 to 36, the
console.error mock is manually overridden and restored, which can fail if tests
error out before restoration. Replace this manual mocking with Jest's built-in
console mocking utilities such as jest.spyOn(console,
'error').mockImplementation() in beforeAll and restore it properly in afterAll
or use jest.restoreAllMocks() to ensure console.error is always restored even if
tests fail.

Comment on lines 126 to 127
const iconButtons = UNSAFE_getByType('IconButton');
fireEvent.press(iconButtons);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid using UNSAFE_getByType in tests

UNSAFE_getByType is marked as unsafe and may break in future versions. Consider using more stable query methods.

-      // Find the IconButton by type since it may not have accessible role
-      const iconButtons = UNSAFE_getByType('IconButton');
-      fireEvent.press(iconButtons);
+      // Find the close button by its testID or accessible role
+      const closeButton = getByTestId('tooltip-close-button') || getByLabelText('Close tooltip');
+      fireEvent.press(closeButton);

Note: This change requires adding a testID or accessibilityLabel to the IconButton component in the actual FriendsScreen implementation.

Also applies to: 482-483

🤖 Prompt for AI Agents
In frontend/screens/FriendsScreen.test.js around lines 126-127 and also lines
482-483, replace the use of UNSAFE_getByType('IconButton') with a more stable
query method like getByTestId or getByAccessibilityLabel. To do this, first add
a testID or accessibilityLabel prop to the IconButton component in the
FriendsScreen source code, then update the test to query IconButton using that
identifier and trigger the press event on the found element.

}));

// Mock Alert
jest.spyOn(Alert, 'alert').mockImplementation(() => {});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Alert mock should be properly restored

The Alert.alert is mocked with spyOn but never restored, which could affect other tests.

-// Mock Alert
-jest.spyOn(Alert, 'alert').mockImplementation(() => {});
+// Mock Alert will be set up in beforeEach

 // In the describe block:
 beforeEach(() => {
   jest.clearAllMocks();
-  Alert.alert.mockClear();
+  jest.spyOn(Alert, 'alert').mockImplementation(() => {});
   mockNavigation.navigate.mockClear();
   mockConsoleError.mockClear();
 });
+
+afterEach(() => {
+  Alert.alert.mockRestore();
+});

Also applies to: 44-44

🤖 Prompt for AI Agents
In frontend/screens/HomeScreen.test.js at lines 16 and 44, the Alert.alert
method is mocked using jest.spyOn but the mock is never restored, which can
cause side effects in other tests. To fix this, add code to restore the original
Alert.alert implementation after each test, typically by calling mockRestore()
in an afterEach or afterAll block to ensure the mock does not persist beyond the
intended test scope.

Comment on lines 296 to 298
getOptimizedSettlements.mockImplementation(() => new Promise(resolve =>
setTimeout(() => resolve({ data: { optimizedSettlements: [] } }), 100)
));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

setTimeout without cleanup can cause test flakiness

The setTimeout in the mock implementation should be cleaned up to prevent test interference.

       // Delay the settlement response to simulate loading
-      getOptimizedSettlements.mockImplementation(() => new Promise(resolve => 
-        setTimeout(() => resolve({ data: { optimizedSettlements: [] } }), 100)
-      ));
+      let timeoutId;
+      getOptimizedSettlements.mockImplementation(() => new Promise(resolve => {
+        timeoutId = setTimeout(() => resolve({ data: { optimizedSettlements: [] } }), 100);
+      }));
+      
+      // Add cleanup in afterEach
+      afterEach(() => {
+        if (timeoutId) clearTimeout(timeoutId);
+      });

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In frontend/screens/HomeScreen.test.js around lines 296 to 298, the mock
implementation of getOptimizedSettlements uses setTimeout without cleanup, which
can cause test flakiness. Refactor the mock to use jest's fake timers or return
a resolved Promise immediately to avoid asynchronous delays. Alternatively,
ensure the timeout is cleared after the test to prevent interference with other
tests.

Comment on lines 502 to 505
// Button should be disabled and show loading
const createButton = getByText('Create');
expect(createButton.props.disabled).toBeTruthy();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Testing disabled state on text element instead of button

The test is checking the disabled prop on a Text element returned by getByText, but buttons don't work this way in React Native.

       // Button should be disabled and show loading
-      const createButton = getByText('Create');
-      expect(createButton.props.disabled).toBeTruthy();
+      // Find the actual button component, not the text
+      const createButton = getByTestId('create-button');
+      expect(createButton.props.disabled).toBeTruthy();

Note: This requires adding a testID="create-button" to the actual button component in HomeScreen.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Button should be disabled and show loading
const createButton = getByText('Create');
expect(createButton.props.disabled).toBeTruthy();
// Button should be disabled and show loading
+ // Find the actual button component, not the text
- const createButton = getByText('Create');
+ const createButton = getByTestId('create-button');
expect(createButton.props.disabled).toBeTruthy();
🤖 Prompt for AI Agents
In frontend/screens/HomeScreen.test.js around lines 502 to 505, the test
incorrectly checks the disabled prop on a Text element instead of the actual
Button component. To fix this, add a testID="create-button" prop to the Button
component in HomeScreen, then update the test to use
getByTestId('create-button') to select the button and check its disabled prop
correctly.

Comment on lines 784 to 787
const maliciousObj = { '__proto__': { polluted: 'value' } };
expect(safeGet(maliciousObj, '__proto__.polluted')).toBe('value');
expect(safeGet({}, 'polluted', 'safe')).toBe('safe'); // Should not be polluted
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Test doesn't verify prototype pollution protection

The test checks that safeGet handles __proto__ keys but doesn't verify that the prototype pollution attempt is actually prevented in the implementation.

Add a more comprehensive test:

     it('should handle prototype pollution attempts', () => {
       const maliciousObj = { '__proto__': { polluted: 'value' } };
       expect(safeGet(maliciousObj, '__proto__.polluted')).toBe('value');
-      expect(safeGet({}, 'polluted', 'safe')).toBe('safe'); // Should not be polluted
+      
+      // Verify prototype pollution is prevented
+      const testObj = {};
+      const beforeProto = Object.getPrototypeOf(testObj);
+      safeGet(maliciousObj, '__proto__.polluted');
+      const afterProto = Object.getPrototypeOf(testObj);
+      expect(beforeProto).toBe(afterProto);
+      expect(testObj.polluted).toBeUndefined();
     });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const maliciousObj = { '__proto__': { polluted: 'value' } };
expect(safeGet(maliciousObj, '__proto__.polluted')).toBe('value');
expect(safeGet({}, 'polluted', 'safe')).toBe('safe'); // Should not be polluted
});
it('should handle prototype pollution attempts', () => {
const maliciousObj = { '__proto__': { polluted: 'value' } };
expect(safeGet(maliciousObj, '__proto__.polluted')).toBe('value');
// Verify prototype pollution is prevented
const testObj = {};
const beforeProto = Object.getPrototypeOf(testObj);
safeGet(maliciousObj, '__proto__.polluted');
const afterProto = Object.getPrototypeOf(testObj);
expect(beforeProto).toBe(afterProto);
expect(testObj.polluted).toBeUndefined();
});
🤖 Prompt for AI Agents
In frontend/utils/balanceCalculator.test.js around lines 784 to 787, the test
for safeGet checks access to __proto__ keys but does not confirm that prototype
pollution is prevented. Enhance the test by verifying that the prototype of an
object is not polluted after using safeGet with __proto__ keys, ensuring the
implementation properly blocks prototype pollution attempts.

Copy link
Collaborator

@AneeshAhuja31 AneeshAhuja31 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update "testEnvironment" to "node" in package.json file. React Native typically dont run on jsdom

… utils, and screen components"

This reverts commit df45073.
@Devasy Devasy merged commit 6adeb76 into main Aug 5, 2025
33 of 37 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in Splitwiser Aug 5, 2025
@Devasy Devasy deleted the fix/settlement-view-inconsistencies branch August 5, 2025 05:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants