Skip to content

Conversation

@ignaciosantise
Copy link
Collaborator

Summary

Phase 3 of testing plan - Component testing for core UI components.

  • Button: 9 tests covering rendering, press interactions, and disabled state
  • NumericKeyboard: 12 tests covering key rendering, press handling, and rapid input sequences
  • QrCode: 17 tests covering loading/shimmer state, URI rendering, press interactions, and memoization

Changes

  • Added 38 new component tests (total tests now: 192)
  • Updated jest.setup.js with mocks for:
    • pressto (PressableScale)
    • expo-asset
    • expo-image
    • Improved react-native mock with proper StyleSheet and components
    • Rewritten react-native-reanimated mock
  • Added forceExit: true to jest.config.js to prevent Jest hanging
  • Added afterAll cleanup for React Query scheduler

Test plan

  • All 192 tests pass
  • Run npm test to verify
  • Lint check passes

…ase 3)

- Add button.test.tsx: 9 tests for rendering, interactions, and disabled state
- Add numeric-keyboard.test.tsx: 12 tests for key rendering and press handling
- Add qr-code.test.tsx: 17 tests for loading state, URI rendering, press, and memoization
- Update jest.setup.js with mocks for pressto, expo-asset, expo-image, and improved
  react-native and react-native-reanimated mocks
- Add forceExit: true to jest.config.js to prevent Jest hanging
- Add afterAll cleanup for React Query scheduler

Total tests: 192 (38 new component tests)
Copilot AI review requested due to automatic review settings January 7, 2026 18:52
@vercel
Copy link

vercel bot commented Jan 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
react-native-examples Ready Ready Preview, Comment Jan 7, 2026 7:26pm

@claude
Copy link

claude bot commented Jan 7, 2026

Claude finished @ignaciosantise's task in 1m 50s —— View job


Code Review Complete

Tasks

  • Read changed files and understand implementation
  • Analyze test quality and patterns
  • Review Jest configuration changes
  • Check mock implementations
  • Run automated checks
  • Report findings

Issues Found

Issue 1: QrCode memo comparison incomplete

ID: qr-code-memo-incomplete-4a8c
File: dapps/pos-app/components/qr-code.tsx:95-101
Severity: MEDIUM
Category: code_quality

The memo comparison function checks prevProps.style === nextProps.style using reference equality. For style objects/arrays, this fails to detect deep changes, causing unnecessary re-renders when styles are recreated with same values or missed updates when style content changes.

Recommendation: Either remove style from memo deps (let React's default shallow comparison handle it) or implement deep comparison:

export default memo(QrCode_, (prevProps, nextProps) => {
  return (
    prevProps.size === nextProps.size &&
    prevProps.uri === nextProps.uri &&
    prevProps.logoBorderRadius === nextProps.logoBorderRadius &&
    prevProps.onPress === nextProps.onPress
    // Remove style comparison - let React handle it
  );
});

Issue 2: Disabled button test doesn't verify prevented execution

ID: button-test-disabled-no-verify-7b2f
File: dapps/pos-app/tests/components/button.test.tsx:114-128
Severity: LOW
Category: test_quality

Test "passes enabled={false} to PressableScale when disabled" only checks accessibility state but doesn't verify the critical behavior: onPress should not fire when disabled=true.

Recommendation: Add test verifying disabled buttons don't execute onPress:

it("does not call onPress when disabled", () => {
  const onPressMock = jest.fn();
  const { getByTestId } = render(
    <Button onPress={onPressMock} disabled>
      <View testID="button-content">
        <Text>Disabled</Text>
      </View>
    </Button>,
  );

  const button = getByTestId("button-content").parent!;
  fireEvent.press(button);
  expect(onPressMock).not.toHaveBeenCalled();
});

Issue 3: forceExit masks test cleanup issues

ID: jest-config-forceexit-mask-9c3d
File: dapps/pos-app/jest.config.js:37
Severity: MEDIUM
Category: code_quality

forceExit: true forces Jest to terminate regardless of open handles. While pragmatic for CI, this masks real cleanup issues (unclosed timers, pending promises, active subscriptions) that should be resolved. The comment mentions React Query causing hangs, but the jest.setup.js shows attempt to fix this via notifyManager scheduler.

Recommendation: Investigate if forceExit is still needed after the notifyManager.setScheduler fix in jest.setup.js:14-17. If React Query cleanup is working, remove forceExit to catch real resource leaks:

// Try removing this line and verify tests still complete:
// forceExit: true,

If issues persist, document specific unresolved async operations requiring forceExit.


Issue 4: Test helpers unmount override may not be called

ID: test-helpers-unmount-override-5d1e
File: dapps/pos-app/tests/utils/test-helpers.tsx:46-52
Severity: LOW
Category: code_quality

renderWithProviders overrides result.unmount to add QueryClient cleanup. If test code holds reference to original unmount before calling renderWithProviders, the cleanup won't execute. Also, if unmount throws, QueryClient cleanup is skipped.

Recommendation: Wrap cleanup in try/finally to ensure execution:

result.unmount = () => {
  try {
    originalUnmount();
  } finally {
    queryClient.cancelQueries();
    queryClient.removeQueries();
    queryClient.clear();
  }
};

Issue 5: react-native mock Pressable uses onClick instead of onPress

ID: jest-setup-pressable-onclick-3f7a
File: dapps/pos-app/jest.setup.js:69
Severity: LOW
Category: test_quality

The Pressable mock sets onClick instead of onPress. While this works with fireEvent.press (which normalizes events), it's inconsistent with React Native's actual API and could cause confusion.

Recommendation: Use onPress to match React Native API:

return React.createElement("View", {
  testID,
  ref,
  style,
  onPress: disabled ? undefined : onPress,  // Use onPress not onClick
  accessibilityRole,
  accessibilityState: { ...accessibilityState, disabled },
  ...props,
}, /* ... */);

Automated Checks

✅ No external domain URLs detected
✅ No cache-control issues detected
✅ No workflow security issues detected
✅ No WalletConnect Pay architecture violations detected


Summary

Phase 3 component tests are well-structured with good coverage of rendering, interactions, and edge cases. Found 5 issues:

  • 2 MEDIUM severity (memo comparison, forceExit masking)
  • 3 LOW severity (test gaps, cleanup robustness, mock inconsistency)

Test patterns follow React Native Testing Library best practices. Mock implementations are comprehensive. Main concerns are around memo optimization correctness and whether forceExit is still necessary given the React Query scheduler fix.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds comprehensive component tests for three core UI components (Button, NumericKeyboard, and QrCode) as part of Phase 3 of the testing plan. The PR introduces 38 new tests bringing the total test count to 192, along with significant improvements to the Jest test infrastructure.

  • Added component tests covering rendering, interactions, and edge cases for Button (9 tests), NumericKeyboard (12 tests), and QrCode (17 tests)
  • Enhanced Jest mocking infrastructure with custom implementations for react-native, react-native-reanimated, pressto, expo-asset, and expo-image
  • Improved test cleanup with QueryClient lifecycle management and React Query scheduler reset

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
dapps/pos-app/jest.setup.js Rewrote mocks for react-native, react-native-reanimated, and added new mocks for pressto, expo-asset, and expo-image; added afterAll cleanup for React Query scheduler
dapps/pos-app/jest.config.js Added forceExit configuration to prevent Jest from hanging on open async handles
dapps/pos-app/__tests__/utils/test-helpers.tsx Enhanced renderWithProviders to properly cleanup QueryClient on unmount
dapps/pos-app/__tests__/components/button.test.tsx Added 9 tests covering Button rendering, press interactions, and disabled state
dapps/pos-app/__tests__/components/numeric-keyboard.test.tsx Added 12 tests covering NumericKeyboard key rendering, press handling, and rapid input sequences
dapps/pos-app/__tests__/components/qr-code.test.tsx Added 17 tests covering QrCode loading/shimmer state, URI rendering, press interactions, and memoization

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +480 to +490
afterAll(async () => {
// Reset React Query notifyManager scheduler
// This ensures any pending callbacks are executed
const { notifyManager } = require("@tanstack/react-query");
notifyManager.setScheduler((callback) => {
callback();
});

// Give any pending async operations time to complete
// Use a small delay to let React Query and other async operations finish
await new Promise((resolve) => setTimeout(resolve, 100));
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

The setTimeout delay of 100ms in the afterAll hook is arbitrary and may not be sufficient for all async operations to complete, or it may be unnecessarily long for most cases. Consider using a more deterministic approach such as awaiting specific operations or using a smaller delay with jest.runAllTimers() if using fake timers. This arbitrary delay can make tests slower and less reliable.

Suggested change
afterAll(async () => {
// Reset React Query notifyManager scheduler
// This ensures any pending callbacks are executed
const { notifyManager } = require("@tanstack/react-query");
notifyManager.setScheduler((callback) => {
callback();
});
// Give any pending async operations time to complete
// Use a small delay to let React Query and other async operations finish
await new Promise((resolve) => setTimeout(resolve, 100));
afterAll(() => {
// Reset React Query notifyManager scheduler
// This ensures any pending callbacks are executed
const { notifyManager } = require("@tanstack/react-query");
notifyManager.setScheduler((callback) => {
callback();
});

Copilot uses AI. Check for mistakes.
Comment on lines +240 to +274
describe("logo configuration", () => {
it("renders with custom logoSize", () => {
const { getByTestId } = render(
<QrCode
{...defaultProps}
uri="https://example.com"
testID="qr-code"
logoSize={50}
>
<View testID="logo">
<Text>Logo</Text>
</View>
</QrCode>,
);

expect(getByTestId("qr-code")).toBeTruthy();
});

it("renders with custom logoBorderRadius", () => {
const { getByTestId } = render(
<QrCode
{...defaultProps}
uri="https://example.com"
testID="qr-code"
logoBorderRadius={10}
>
<View testID="logo">
<Text>Logo</Text>
</View>
</QrCode>,
);

expect(getByTestId("qr-code")).toBeTruthy();
});
});
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

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

The tests at lines 240-273 verify that logoSize and logoBorderRadius props don't cause crashes, but they don't verify the actual behavior of these props. According to the component implementation, these props affect the QR code generation (logoAreaSize and logoAreaBorderRadius). Consider adding assertions to verify these props are actually applied to the QRCodeSkia component, such as checking the rendered structure or using test IDs to verify the configuration.

Copilot uses AI. Check for mistakes.
- Fix Pressable mock to use onPress instead of onClick (matches RN API)
- Add try/finally to test-helpers unmount for reliable QueryClient cleanup
- Update disabled button test to verify onPress is undefined when disabled
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants