add unit tests on feat/PRO-3638/sell-feature-pulse#394
Conversation
WalkthroughAdds data-testid attributes and minor wrapper divs to HomeScreen, Buy, Sell, and Search for testability. Introduces comprehensive unit/integration tests across App, Buy, Sell, Search components and several hooks (useChainSelect, useRelaySdk, useRelaySell). No public API or logic changes; functional behavior remains unchanged. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Pre-merge checks (1 passed, 2 warnings)❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
Poem
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. ✨ Finishing Touches
🧪 Generate unit tests
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. Comment |
Deploying x with
|
| Latest commit: |
8f64079
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://ec378753.x-e62.pages.dev |
| Branch Preview URL: | https://feat-pro-3638-sell-feature-p.x-e62.pages.dev |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/apps/pulse/components/Sell/Sell.tsx (1)
93-107: Make balance lookup robust across APIs (evm:/eip155:) and by address-first.Current lookup may miss balances if symbol collides or chainId prefix differs. Prefer matching the contract address and support both prefixes.
Apply:
- // Find the asset in the portfolio - const assetData = walletPortfolioData.result.data.assets.find( - (asset) => asset.asset.symbol === token.symbol - ); + // Find the asset by matching contract address (most precise), tolerate evm:/eip155: prefixes + const assetData = walletPortfolioData.result.data.assets.find((asset) => + asset.contracts_balances?.some( + (contract) => + contract.address?.toLowerCase() === token.address.toLowerCase() && + (contract.chainId === `evm:${token.chainId}` || + contract.chainId === `eip155:${token.chainId}`) + ) + ); @@ - const contractBalance = assetData.contracts_balances.find( - (contract) => - contract.address.toLowerCase() === token.address.toLowerCase() && - contract.chainId === `evm:${token.chainId}` - ); + const contractBalance = assetData.contracts_balances.find( + (contract) => + contract.address?.toLowerCase() === token.address.toLowerCase() && + (contract.chainId === `evm:${token.chainId}` || + contract.chainId === `eip155:${token.chainId}`) + );src/apps/pulse/components/Search/Search.tsx (1)
286-333: Active filter highlight is wrong for “Top Gainers” and “My Holdings”.item.includes(searchType) won’t match “Top Gainers” or “My Holdings” (spaces/emojis). Compare against the enum instead and expose stable testids/aria-pressed.
- <div className="flex gap-1.5" data-testid="pulse-search-filter-buttons"> + <div className="flex gap-1.5" data-testid="pulse-search-filter-buttons"> {(isBuy ? ['🔥 Trending', '🌱 Fresh', '🚀 Top Gainers', '💰My Holdings'] : ['My Holdings'] ).map((item, index) => { // For sell screen, always map to MyHoldings index (3) const actualIndex = isBuy ? index : 3; + const typeOrder = [ + SearchType.Trending, + SearchType.Fresh, + SearchType.TopGainers, + SearchType.MyHoldings, + ]; + const currentType = typeOrder[actualIndex]; + const isActive = searchType === currentType; if (!isBuy) { return ( <div key={item} className="flex items-center"> <p className="text-[13px] font-normal text-white tracking-[-0.26px] px-3"> {item} </p> </div> ); } return ( <div key={item} className="flex bg-black w-[100px] h-10 rounded-[10px]" > <button - className={`flex-1 items-center justify-center rounded-[6px] m-0.5 mb-1 ${ - searchType && item.includes(searchType) - ? 'bg-[#2E2A4A]' - : 'bg-[#1E1D24]' - }`} + className={`flex-1 items-center justify-center rounded-[6px] m-0.5 mb-1 ${ + isActive ? 'bg-[#2E2A4A]' : 'bg-[#1E1D24]' + }`} + data-testid={`pulse-search-filter-${currentType}`} + aria-pressed={isActive} type="button" onClick={() => { handleSearchTypeChange(actualIndex); }} > <p - className={`text-xs font-normal text-center ${ - searchType && item.includes(searchType) - ? 'text-white' - : 'text-white opacity-50' - }`} + className={`text-xs font-normal text-center ${ + isActive ? 'text-white' : 'text-white opacity-50' + }`} > {item} </p> </button> </div> ); })} </div>
🧹 Nitpick comments (18)
src/apps/pulse/components/Sell/Sell.tsx (2)
142-155: Reset amount on token change to avoid stale state (aligns with product behavior).Per your past decision, switching tokens should clear the input and related state to prevent stale liquidity/quotes.
Apply:
useEffect(() => { if (tokenAmount && tokenAmount.trim() !== '') { const inputAmount = parseFloat(tokenAmount); if (!Number.isNaN(inputAmount)) { setNotEnoughLiquidity(inputAmount > tokenBalance); } else { setNotEnoughLiquidity(false); } } else { setNotEnoughLiquidity(false); } }, [token, tokenBalance, tokenAmount]); + +// Clear input and derived state when token changes +useEffect(() => { + setTokenAmount(''); + setParentTokenAmount(''); + setDebouncedTokenAmount(''); + setNotEnoughLiquidity(false); + setLocalSellOffer(null); +}, [token?.address]);
1-1: Drop lodash parseInt to reduce bundle and avoid shadowing globals.Use the built-in with radix; remove lodash import.
Apply:
-import { parseInt } from 'lodash'; @@ - const percentage = isMax ? 100 : parseInt(item); + const percentage = isMax ? 100 : Number.parseInt(item, 10);Also applies to: 311-311
src/apps/pulse/components/Search/tests/PortfolioTokenList.test.tsx (4)
164-169: Avoid brittle currency text assertions.Hardcoding '$1.5', '$2', '$4' breaks with formatting tweaks. Prefer regex or container-scoped assertions.
Example:
-expect(screen.getAllByText('$1.5')).toHaveLength(2); +expect(screen.getAllByText(/^\$1(\.50)?$/)).toHaveLength(2);
236-241: Selector relies on Tailwind classes (brittle).Querying by a compound class string is fragile. Expose a test id (e.g., data-testid="avatar-fallback") in the component and assert via that.
300-346: Test name vs. data mismatch: “null price” uses 0.If you intend to cover null/undefined price, mock that explicitly and assert the fallback formatting. Otherwise rename the test for clarity.
215-221: Ordering test should target token rows, not all buttons.getAllByRole('button') may capture unrelated buttons. Scope to the list container or add role/test-id to token rows.
src/apps/pulse/components/Sell/tests/SellButton.test.tsx (1)
136-142: Style assertions are fragile.Checking exact inline colors can yield false negatives on design tweaks. Consider asserting disabled/enabled and text instead.
Also applies to: 154-160, 157-159
src/apps/pulse/components/Sell/tests/PreviewSell.test.tsx (1)
168-180: Copy feedback assertion could be more explicit.Querying for any svg is loose. If feasible, render a data-testid on the checkmark in the component and assert by that id.
src/apps/pulse/components/Buy/tests/BuyButton.test.tsx (1)
232-265: Minor: prefer userEvent for interactions.userEvent better approximates real user input vs. fireEvent (typing/click delays). Optional for now.
src/apps/pulse/components/Buy/tests/PreviewBuy.test.tsx (1)
186-211: Stabilize async “failure” path assertion.Use waitForElementToBeRemoved (or waitFor not.toBeInTheDocument) for the spinner removal; current check may race.
Apply:
-import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { fireEvent, render, screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react'; @@ -// Should not show tracker on error -expect( - screen.queryByText('Waiting for signature...') -).not.toBeInTheDocument(); +await waitForElementToBeRemoved(() => + screen.queryByText('Waiting for signature...') +);src/apps/pulse/components/App/tests/HomeScreen.test.tsx (1)
64-77: Mock shape mismatch: use assets not tokens.The queried data structure elsewhere uses result.data.assets; the mock sets tokens. Align to reduce surprises.
Apply:
- data: { - tokens: [], - total_wallet_balance: 0, - }, + data: { + assets: [], + total_wallet_balance: 0, + },src/apps/pulse/components/Buy/tests/Buy.test.tsx (1)
205-221: Prefer userEvent for typing/clicks (optional).Improves realism of input handling and caret behavior.
src/apps/pulse/components/Search/tests/Search.test.tsx (2)
1-2: Consider addressing these ESLint disables.The broad ESLint disables (
jsx-props-no-spreadingandno-explicit-any) suggest potential code quality issues that could be addressed instead of suppressed.-/* eslint-disable react/jsx-props-no-spreading */ -/* eslint-disable @typescript-eslint/no-explicit-any */For the
jsx-props-no-spreading, consider explicitly destructuring props where needed. Forno-explicit-any, consider using proper typing for the mocked functions.
173-185: Filter button interaction test could be more comprehensive.The test clicks the trending button but only verifies that the button still exists, not that the actual filter state changed or that the component behaves correctly.
it('handles filter button clicks in buy mode', () => { + const mockSetSearchText = vi.fn(); + (useTokenSearch.useTokenSearch as any).mockReturnValue({ + ...mockUseTokenSearch, + setSearchText: mockSetSearchText, + }); + render( <MemoryRouter> <Search {...defaultProps} isBuy /> </MemoryRouter> ); const trendingButton = screen.getByText('🔥 Trending'); fireEvent.click(trendingButton); - // Should trigger search type change - expect(screen.getByText('🔥 Trending')).toBeInTheDocument(); + // Verify that clicking filter button clears search text + expect(mockSetSearchText).toHaveBeenCalledWith(''); + + // Verify the button remains visible after click + expect(screen.getByText('🔥 Trending')).toBeInTheDocument(); });src/apps/pulse/components/Search/Search.tsx (2)
228-235: Modal needs a11y roles; also verify the new full-screen black backdrop doesn’t regress UX.Add role/aria to the dialog and confirm the bg-black/min-h-screen wrapper doesn’t unexpectedly darken pages.
- <div - className="flex items-center justify-center min-h-screen bg-black" + <div + className="flex items-center justify-center min-h-screen bg-black" data-testid="pulse-search-view" > - <div + <div className="flex flex-col w-full max-w-[446px] max-h-[500px] overflow-y-auto bg-[#1E1D24] p-3 border border-white/[0.05] rounded-2xl shadow-[0px_2px_15px_0px_rgba(18,17,22,0.5)]" + role="dialog" + aria-modal="true" + aria-label="Token search" data-testid="pulse-search-modal" >If the backdrop is only for tests, consider dropping bg-black to avoid visual change:
- className="flex items-center justify-center min-h-screen bg-black" + className="flex items-center justify-center min-h-screen"
241-247: Minor a11y/testability: label the input and hint the input type.Add aria-label and search-friendly attributes; tests continue to use data-testid.
- <input + <input ref={inputRef} type="text" className="flex-1 w-fit ml-4 font-normal text-xs text-gray-500" value={searchText} data-testid="pulse-search-input" + aria-label="Search tokens" + inputMode="search" + autoComplete="off"src/apps/pulse/hooks/tests/useChainSelect.test.tsx (1)
1-2: Drop unnecessary ESLint disables.No JSX spreading or any usage of
anyhere.-/* eslint-disable react/jsx-props-no-spreading */ -/* eslint-disable @typescript-eslint/no-explicit-any */src/apps/pulse/hooks/tests/useRelaySdk.test.tsx (1)
1-2: Remove unused ESLint disables.They aren’t needed in this test file.
-/* eslint-disable react/jsx-props-no-spreading */ -/* eslint-disable @typescript-eslint/no-explicit-any */
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (10)
src/apps/pulse/components/App/tests/__snapshots__/AppWrapper.test.tsx.snapis excluded by!**/*.snapsrc/apps/pulse/components/App/tests/__snapshots__/HomeScreen.test.tsx.snapis excluded by!**/*.snapsrc/apps/pulse/components/Buy/tests/__snapshots__/Buy.test.tsx.snapis excluded by!**/*.snapsrc/apps/pulse/components/Buy/tests/__snapshots__/BuyButton.test.tsx.snapis excluded by!**/*.snapsrc/apps/pulse/components/Buy/tests/__snapshots__/PreviewBuy.test.tsx.snapis excluded by!**/*.snapsrc/apps/pulse/components/Search/tests/__snapshots__/PortfolioTokenList.test.tsx.snapis excluded by!**/*.snapsrc/apps/pulse/components/Search/tests/__snapshots__/Search.test.tsx.snapis excluded by!**/*.snapsrc/apps/pulse/components/Sell/tests/__snapshots__/PreviewSell.test.tsx.snapis excluded by!**/*.snapsrc/apps/pulse/components/Sell/tests/__snapshots__/Sell.test.tsx.snapis excluded by!**/*.snapsrc/apps/pulse/components/Sell/tests/__snapshots__/SellButton.test.tsx.snapis excluded by!**/*.snap
📒 Files selected for processing (17)
src/apps/pulse/components/App/HomeScreen.tsx(3 hunks)src/apps/pulse/components/App/tests/AppWrapper.test.tsx(1 hunks)src/apps/pulse/components/App/tests/HomeScreen.test.tsx(1 hunks)src/apps/pulse/components/Buy/Buy.tsx(2 hunks)src/apps/pulse/components/Buy/tests/Buy.test.tsx(1 hunks)src/apps/pulse/components/Buy/tests/BuyButton.test.tsx(1 hunks)src/apps/pulse/components/Buy/tests/PreviewBuy.test.tsx(1 hunks)src/apps/pulse/components/Search/Search.tsx(3 hunks)src/apps/pulse/components/Search/tests/PortfolioTokenList.test.tsx(1 hunks)src/apps/pulse/components/Search/tests/Search.test.tsx(1 hunks)src/apps/pulse/components/Sell/Sell.tsx(7 hunks)src/apps/pulse/components/Sell/tests/PreviewSell.test.tsx(1 hunks)src/apps/pulse/components/Sell/tests/Sell.test.tsx(1 hunks)src/apps/pulse/components/Sell/tests/SellButton.test.tsx(1 hunks)src/apps/pulse/hooks/tests/useChainSelect.test.tsx(1 hunks)src/apps/pulse/hooks/tests/useRelaySdk.test.tsx(1 hunks)src/apps/pulse/hooks/tests/useRelaySell.test.tsx(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-09T12:40:15.611Z
Learnt from: RanaBug
PR: pillarwallet/x#391
File: src/apps/pulse/components/Sell/Sell.tsx:113-130
Timestamp: 2025-09-09T12:40:15.611Z
Learning: In the Pulse app Sell component, when a user changes/switches tokens, the input amount automatically resets to 0, which means liquidity validation state doesn't become stale when tokens change.
Applied to files:
src/apps/pulse/components/Sell/Sell.tsx
🧬 Code graph analysis (13)
src/apps/pulse/hooks/tests/useChainSelect.test.tsx (1)
src/apps/pulse/hooks/useChainSelect.ts (1)
useChainSelect(4-11)
src/apps/pulse/components/Search/tests/Search.test.tsx (3)
src/types/api.ts (1)
PortfolioData(739-748)src/apps/pulse/hooks/useTokenSearch.ts (1)
useTokenSearch(5-45)src/apps/pulse/components/Search/Search.tsx (1)
Search(57-388)
src/apps/pulse/components/App/tests/HomeScreen.test.tsx (3)
src/apps/pulse/contexts/RefreshContext.tsx (1)
RefreshProvider(24-70)src/apps/pulse/contexts/LoadingContext.tsx (1)
LoadingProvider(15-32)src/apps/pulse/components/App/HomeScreen.tsx (1)
HomeScreen(36-266)
src/apps/pulse/components/Sell/tests/Sell.test.tsx (4)
src/apps/pulse/types/tokens.ts (1)
SelectedToken(1-10)src/types/api.ts (1)
WalletPortfolioMobulaResponse(750-752)src/apps/pulse/contexts/RefreshContext.tsx (2)
useRefresh(72-78)RefreshProvider(24-70)src/apps/pulse/contexts/LoadingContext.tsx (1)
LoadingProvider(15-32)
src/apps/pulse/hooks/tests/useRelaySdk.test.tsx (1)
src/apps/pulse/hooks/useRelaySdk.ts (1)
useRelaySdk(21-64)
src/apps/pulse/components/Sell/tests/SellButton.test.tsx (2)
src/apps/pulse/types/tokens.ts (1)
SelectedToken(1-10)src/apps/pulse/hooks/useRelaySell.ts (1)
SellOffer(41-44)
src/apps/pulse/hooks/tests/useRelaySell.test.tsx (6)
src/apps/pulse/types/tokens.ts (1)
SelectedToken(1-10)src/apps/pulse/hooks/useRelaySdk.ts (1)
useRelaySdk(21-64)src/hooks/useTransactionDebugLogger.tsx (1)
useTransactionDebugLogger(1-15)src/apps/pulse/contexts/LoadingContext.tsx (1)
useLoading(34-40)src/apps/pulse/hooks/useRelaySell.ts (1)
useRelaySell(54-924)src/apps/the-exchange/utils/wrappedTokens.ts (1)
getWrappedTokenAddressIfNative(33-44)
src/apps/pulse/components/Buy/tests/PreviewBuy.test.tsx (3)
src/apps/pulse/types/tokens.ts (1)
SelectedToken(1-10)src/apps/pulse/hooks/useIntentSdk.ts (1)
useIntentSdk(9-41)src/apps/pulse/components/Buy/PreviewBuy.tsx (1)
PreviewBuy(25-320)
src/apps/pulse/components/Sell/tests/PreviewSell.test.tsx (4)
src/apps/pulse/contexts/RefreshContext.tsx (1)
RefreshProvider(24-70)src/apps/pulse/contexts/LoadingContext.tsx (1)
LoadingProvider(15-32)src/apps/pulse/hooks/useRelaySell.ts (1)
useRelaySell(54-924)src/hooks/useTransactionDebugLogger.tsx (1)
useTransactionDebugLogger(1-15)
src/apps/pulse/components/Buy/tests/BuyButton.test.tsx (2)
src/apps/pulse/types/tokens.ts (1)
SelectedToken(1-10)src/apps/pulse/components/Buy/BuyButton.tsx (1)
BuyButton(57-113)
src/apps/pulse/components/App/tests/AppWrapper.test.tsx (1)
src/apps/pulse/components/App/AppWrapper.tsx (1)
AppWrapper(13-79)
src/apps/pulse/components/Search/tests/PortfolioTokenList.test.tsx (1)
src/types/api.ts (1)
PortfolioData(739-748)
src/apps/pulse/components/Buy/tests/Buy.test.tsx (7)
src/apps/pulse/types/tokens.ts (1)
SelectedToken(1-10)src/types/api.ts (1)
WalletPortfolioMobulaResponse(750-752)src/apps/pulse/hooks/useIntentSdk.ts (1)
useIntentSdk(9-41)src/apps/pulse/hooks/useModularSdk.ts (1)
useModularSdk(17-129)src/apps/pulse/contexts/RefreshContext.tsx (1)
RefreshProvider(24-70)src/apps/pulse/contexts/LoadingContext.tsx (1)
LoadingProvider(15-32)src/apps/pulse/components/Buy/Buy.tsx (1)
Buy(35-442)
🔇 Additional comments (34)
src/apps/pulse/hooks/tests/useRelaySell.test.tsx (5)
134-144: LGTM: Comprehensive environment setupGood practice to stub environment variables and clean them up in
afterEach. TheVITE_SWAP_FEE_RECEIVERvariable is properly managed.
146-199: LGTM: Initial state validationThe test properly verifies the hook's default state and function signatures. Comprehensive mocking setup ensures isolation.
266-312: LGTM: USDC address retrieval testsBoth positive and negative test cases are covered for USDC address resolution, ensuring proper chain support validation.
486-556: LGTM: Successful quote retrieval testThe test properly mocks the complete flow and validates the expected sell offer structure with correct calculations.
633-687: LGTM: Error state validationThe test correctly verifies error handling when the hook is not properly initialized.
src/apps/pulse/components/App/HomeScreen.tsx (3)
152-152: LGTM: Buy toggle test ID addedThe test ID enables reliable testing of buy/sell toggle functionality.
174-174: LGTM: Sell toggle test ID addedConsistent with the buy toggle, this enables testing of the sell mode selection.
261-261: LGTM: Home view test ID addedThe root container test ID enables tests to verify the presence of the home screen.
src/apps/pulse/components/Buy/Buy.tsx (2)
183-183: LGTM: Component wrapper with test IDThe replacement of the React Fragment with a styled div container that includes a test ID is appropriate for testing purposes. The
flex flex-colclasses maintain the expected layout behavior.
440-440: LGTM: Closing div for test wrapperProperly closes the test wrapper div introduced at the beginning of the component.
src/apps/pulse/components/Sell/tests/Sell.test.tsx (7)
80-88: LGTM: Well-structured mock propsThe mock props object provides comprehensive test data matching the expected component interface.
90-105: LGTM: Centralized mocking utilitiesThe
defaultMockshelper function provides consistent mock setup across tests, improving maintainability.
107-115: LGTM: Provider wrapper utilityThe
renderWithProvidersfunction ensures components are properly wrapped with required context providers for testing.
117-126: LGTM: Snapshot test for regression detectionThe snapshot test provides a baseline for detecting unintended UI changes.
128-153: LGTM: Conditional rendering testsTests properly validate different UI states based on whether a token is selected, covering both positive and negative scenarios.
155-203: LGTM: User interaction testingComprehensive tests for user interactions including input changes, button clicks, and validation of component callbacks.
205-241: LGTM: State-dependent behavior testsTests properly validate component behavior in different states including disabled states, error conditions, and missing data scenarios.
src/apps/pulse/components/App/tests/AppWrapper.test.tsx (6)
36-65: LGTM: Comprehensive default mocking setupThe
defaultMocksfunction provides consistent and comprehensive mock data for all required services, ensuring reliable test isolation.
84-102: LGTM: Default rendering validationThe test properly validates that the HomeScreen renders by default when no asset parameter is provided, using appropriate test IDs.
104-145: LGTM: Invalid asset parameter handlingComprehensive tests for various invalid asset parameter scenarios (invalid address, empty, malformed) ensure robust URL parameter validation.
147-197: LGTM: Valid asset parameter routingTests properly validate that valid Ethereum addresses trigger the search view and that query parameters are correctly handled and prefilled.
199-239: LGTM: Service state handlingTests cover loading and error states for the wallet portfolio service, ensuring the app handles various data fetching states appropriately.
241-266: LGTM: Wallet address change handlingThe test validates that the component properly handles wallet address changes through the rerender lifecycle.
src/apps/pulse/components/Sell/Sell.tsx (1)
58-86: Effect deps: confirm getBestSellOffer stability or include in deps.You’ve disabled exhaustive-deps; ensure getBestSellOffer is referentially stable from useRelaySell or wrap in ref to avoid stale closures.
src/apps/pulse/components/Sell/tests/SellButton.test.tsx (1)
200-214: LGTM — interaction flows and states covered.Assertions for enabled/disabled and handler invocations look solid.
src/apps/pulse/components/Sell/tests/PreviewSell.test.tsx (1)
182-205: LGTM — exec flow and waiting state validated.Good use of waitFor and argument verification to executeSell.
src/apps/pulse/components/Buy/tests/BuyButton.test.tsx (1)
118-128: LGTM — state matrix is well covered.Enable/disable permutations and text variants are exercised thoroughly.
Also applies to: 130-139
src/apps/pulse/components/Buy/tests/PreviewBuy.test.tsx (1)
167-183: LGTM — shortlist flow verified end-to-end.Good coverage of state transition to tracker.
src/apps/pulse/components/App/tests/HomeScreen.test.tsx (1)
189-207: LGTM — core interactions (search, toggles) verified.Provider stack and callbacks are wired correctly.
src/apps/pulse/components/Search/tests/Search.test.tsx (3)
42-75: Well-structured mock data that matches the expected portfolio structure.The mock portfolio data correctly implements the
PortfolioDatainterface and provides realistic test data with proper asset structure, contract balances, and wallet information.
96-377: Comprehensive test coverage with good structure.The test suite provides excellent coverage of the Search component's functionality including:
- Rendering verification for different modes (buy/sell)
- User interaction handling (input changes, button clicks)
- Loading and error states
- URL parameter handling
- Component lifecycle behavior
The tests are well-organized and cover the key user flows effectively.
25-35: Mock react-router-dom setup provides good test isolation.The router mocking correctly isolates the component from actual routing while providing the necessary context and URL parameters for testing the asset parameter handling functionality.
src/apps/pulse/hooks/tests/useChainSelect.test.tsx (1)
11-60: LGTM — tests cover init, updates, and setter stability.Solid coverage for this simple state hook.
src/apps/pulse/hooks/tests/useRelaySdk.test.tsx (1)
68-117: Overall test flow looks good.Mocks, initialization assertions, error path, and reinit checks are thorough.
Description
How Has This Been Tested?
Screenshots (if appropriate):
Types of changes
Summary by CodeRabbit
Refactor
Tests
Note