From 26dfb575be234d1fcfbfac3598f85209782a737b Mon Sep 17 00:00:00 2001 From: root Date: Wed, 6 May 2026 20:30:16 +0000 Subject: [PATCH] test(plans): harden route navigation coverage --- .../components/layout/AppShell.dom.test.tsx | 10 +++ web/src/views/PortfolioView.dom.test.tsx | 84 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 web/src/views/PortfolioView.dom.test.tsx diff --git a/web/src/components/layout/AppShell.dom.test.tsx b/web/src/components/layout/AppShell.dom.test.tsx index e02b77d..54e24c2 100644 --- a/web/src/components/layout/AppShell.dom.test.tsx +++ b/web/src/components/layout/AppShell.dom.test.tsx @@ -53,6 +53,16 @@ vi.mock('../../views/SettingsView', () => ({ })); describe('AppShell routing fallback', () => { + it('renders the plans view directly on the canonical /plans route', async () => { + render( + + + , + ); + + expect(await screen.findByText('Simple view')).toBeInTheDocument(); + }); + it('keeps /simple as a redirect alias to the plans view', async () => { render( diff --git a/web/src/views/PortfolioView.dom.test.tsx b/web/src/views/PortfolioView.dom.test.tsx new file mode 100644 index 0000000..67a94f5 --- /dev/null +++ b/web/src/views/PortfolioView.dom.test.tsx @@ -0,0 +1,84 @@ +// @vitest-environment jsdom +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { MemoryRouter } from 'react-router-dom'; +import { describe, expect, it, vi } from 'vitest'; +import { PortfolioView } from './PortfolioView'; + +const navigateMock = vi.fn(); + +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); + return { + ...actual, + useNavigate: () => navigateMock, + }; +}); + +vi.mock('../context/AppContext', () => ({ + useAppContext: () => ({ + botState: { + symbols: {}, + alerts: [], + positions: [], + orders: [], + history: [], + settings: { + executionMode: 'Paper', + riskPerTrade: 0.01, + totalCapital: 1000, + maxOpenTrades: 3, + isAlgoEnabled: true, + enabledRules: [], + }, + uptime: 1000, + }, + }), +})); + +vi.mock('../tabs/PositionsTab', () => ({ + PositionsTab: ({ onManageHolding }: any) => ( +
+ + +
+ ), +})); + +vi.mock('../tabs/HistoryTab', () => ({ + HistoryTab: () =>
History tab
, +})); + +describe('PortfolioView navigation', () => { + it('navigates to the canonical plans route for exact plan drill-in and new exit plans', async () => { + const user = userEvent.setup(); + render( + + + , + ); + + await user.click(screen.getByRole('button', { name: 'open linked plan' })); + expect(navigateMock).toHaveBeenCalledWith('/plans?setupId=setup-aapl'); + + await user.click(screen.getByRole('button', { name: 'create exit plan' })); + expect(navigateMock).toHaveBeenCalledWith('/plans?mode=sell&symbol=MSFT&tradeId=TRD-MSFT'); + }); +});