refactor
This commit is contained in:
@@ -1,140 +0,0 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* Unit tests for CheckoutConfirmationDialog component.
|
||||
* Tests the UI rendering and IPC communication for checkout confirmation.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { describe, it, expect, vi, beforeEach, beforeAll } from 'vitest';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { act } from 'react';
|
||||
|
||||
import { CheckoutConfirmationDialog } from '../../../apps/companion/renderer/components/CheckoutConfirmationDialog';
|
||||
|
||||
// Mock window.electronAPI
|
||||
const mockConfirmCheckout = vi.fn();
|
||||
|
||||
describe('CheckoutConfirmationDialog', () => {
|
||||
beforeAll(() => {
|
||||
// Set up window.electronAPI mock for all tests
|
||||
Object.defineProperty(window, 'electronAPI', {
|
||||
writable: true,
|
||||
value: {
|
||||
confirmCheckout: mockConfirmCheckout,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const mockRequest = {
|
||||
price: '$0.50',
|
||||
state: 'ready' as const,
|
||||
sessionMetadata: {
|
||||
sessionName: 'Test Race',
|
||||
trackId: 'spa',
|
||||
carIds: ['porsche_911_gt3_r'],
|
||||
},
|
||||
timeoutMs: 60000,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mockConfirmCheckout.mockClear();
|
||||
});
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render dialog with price and session info', () => {
|
||||
render(<CheckoutConfirmationDialog request={mockRequest} />);
|
||||
|
||||
expect(screen.getByText(/Confirm Checkout/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/\$0\.50/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/Test Race/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render confirm and cancel buttons', () => {
|
||||
render(<CheckoutConfirmationDialog request={mockRequest} />);
|
||||
|
||||
expect(screen.getByRole('button', { name: /confirm/i })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display track and car information', () => {
|
||||
render(<CheckoutConfirmationDialog request={mockRequest} />);
|
||||
|
||||
expect(screen.getByText(/spa/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/porsche/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show warning when state is insufficient funds', () => {
|
||||
const insufficientFundsRequest = {
|
||||
...mockRequest,
|
||||
state: 'insufficient_funds' as const,
|
||||
};
|
||||
|
||||
render(<CheckoutConfirmationDialog request={insufficientFundsRequest} />);
|
||||
|
||||
expect(screen.getByText(/insufficient/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('IPC Communication', () => {
|
||||
it('should emit checkout:confirm with "confirmed" when confirm button clicked', () => {
|
||||
render(<CheckoutConfirmationDialog request={mockRequest} />);
|
||||
|
||||
const confirmButton = screen.getByRole('button', { name: /confirm/i });
|
||||
fireEvent.click(confirmButton);
|
||||
|
||||
expect(mockConfirmCheckout).toHaveBeenCalledWith('confirmed');
|
||||
});
|
||||
|
||||
it('should emit checkout:confirm with "cancelled" when cancel button clicked', () => {
|
||||
render(<CheckoutConfirmationDialog request={mockRequest} />);
|
||||
|
||||
const cancelButton = screen.getByRole('button', { name: /cancel/i });
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
expect(mockConfirmCheckout).toHaveBeenCalledWith('cancelled');
|
||||
});
|
||||
|
||||
it('should emit checkout:confirm with "timeout" when timeout expires', async () => {
|
||||
vi.useFakeTimers();
|
||||
|
||||
const shortTimeoutRequest = {
|
||||
...mockRequest,
|
||||
timeoutMs: 1000,
|
||||
};
|
||||
|
||||
render(<CheckoutConfirmationDialog request={shortTimeoutRequest} />);
|
||||
|
||||
// Fast-forward time past timeout
|
||||
vi.advanceTimersByTime(1100);
|
||||
|
||||
expect(mockConfirmCheckout).toHaveBeenCalledWith('timeout');
|
||||
|
||||
vi.useRealTimers();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Countdown Timer', () => {
|
||||
it('should display countdown timer', () => {
|
||||
render(<CheckoutConfirmationDialog request={mockRequest} />);
|
||||
|
||||
expect(screen.getByText(/60/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should update countdown every second', async () => {
|
||||
vi.useFakeTimers();
|
||||
|
||||
render(<CheckoutConfirmationDialog request={mockRequest} />);
|
||||
|
||||
expect(screen.getByText(/60/)).toBeInTheDocument();
|
||||
|
||||
await act(async () => {
|
||||
vi.advanceTimersByTime(1000);
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
expect(screen.getByText(/59/)).toBeInTheDocument();
|
||||
|
||||
vi.useRealTimers();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,55 +0,0 @@
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* Unit tests for RaceCreationSuccessScreen component.
|
||||
* Tests the UI rendering of race creation success result.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { RaceCreationSuccessScreen } from '../../../apps/companion/renderer/components/RaceCreationSuccessScreen';
|
||||
|
||||
describe('RaceCreationSuccessScreen', () => {
|
||||
const mockResult = {
|
||||
sessionId: 'race-12345',
|
||||
sessionName: 'Test Race',
|
||||
trackId: 'spa',
|
||||
carIds: ['porsche_911_gt3_r'],
|
||||
finalPrice: '$0.50',
|
||||
createdAt: new Date('2025-11-25T22:00:00.000Z'),
|
||||
};
|
||||
|
||||
describe('Rendering', () => {
|
||||
it('should render success message', () => {
|
||||
render(<RaceCreationSuccessScreen result={mockResult} />);
|
||||
|
||||
expect(screen.getByText(/success/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display session information', () => {
|
||||
render(<RaceCreationSuccessScreen result={mockResult} />);
|
||||
|
||||
expect(screen.getByText(/Test Race/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/race-12345/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display track and car information', () => {
|
||||
render(<RaceCreationSuccessScreen result={mockResult} />);
|
||||
|
||||
expect(screen.getByText(/spa/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/porsche/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display final price', () => {
|
||||
render(<RaceCreationSuccessScreen result={mockResult} />);
|
||||
|
||||
expect(screen.getByText(/\$0\.50/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display creation timestamp', () => {
|
||||
render(<RaceCreationSuccessScreen result={mockResult} />);
|
||||
|
||||
expect(screen.getByText(/2025-11-25/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,102 +0,0 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { SessionProgressMonitor } from '../../../../apps/companion/renderer/components/SessionProgressMonitor';
|
||||
|
||||
describe('SessionProgressMonitor', () => {
|
||||
describe('step display', () => {
|
||||
it('should display exactly 17 steps', () => {
|
||||
const progress = {
|
||||
sessionId: 'test-session-id',
|
||||
currentStep: 1,
|
||||
state: 'IN_PROGRESS',
|
||||
completedSteps: [],
|
||||
hasError: false,
|
||||
errorMessage: null
|
||||
};
|
||||
|
||||
render(
|
||||
<SessionProgressMonitor
|
||||
sessionId="test-session-id"
|
||||
progress={progress}
|
||||
isRunning={true}
|
||||
/>
|
||||
);
|
||||
|
||||
// Should have exactly 17 step elements
|
||||
const stepElements = screen.getAllByText(/Navigate to Hosted Racing|Click Create a Race|Fill Race Information|Configure Server Details|Set Admins|Add Admin|Set Time Limits|Set Cars|Add Car|Set Car Classes|Set Track|Add Track|Configure Track Options|Set Time of Day|Configure Weather|Set Race Options|Set Track Conditions/);
|
||||
expect(stepElements).toHaveLength(17);
|
||||
});
|
||||
|
||||
it('should NOT display "Configure Team Driving" step', () => {
|
||||
const progress = {
|
||||
sessionId: 'test-session-id',
|
||||
currentStep: 1,
|
||||
state: 'IN_PROGRESS',
|
||||
completedSteps: [],
|
||||
hasError: false,
|
||||
errorMessage: null
|
||||
};
|
||||
|
||||
render(
|
||||
<SessionProgressMonitor
|
||||
sessionId="test-session-id"
|
||||
progress={progress}
|
||||
isRunning={true}
|
||||
/>
|
||||
);
|
||||
|
||||
// Should NOT find "Configure Team Driving"
|
||||
expect(screen.queryByText('Configure Team Driving')).toBeNull();
|
||||
});
|
||||
|
||||
it('should display "Set Track Conditions" as step 17', () => {
|
||||
const progress = {
|
||||
sessionId: 'test-session-id',
|
||||
currentStep: 17,
|
||||
state: 'IN_PROGRESS',
|
||||
completedSteps: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
|
||||
hasError: false,
|
||||
errorMessage: null
|
||||
};
|
||||
|
||||
render(
|
||||
<SessionProgressMonitor
|
||||
sessionId="test-session-id"
|
||||
progress={progress}
|
||||
isRunning={true}
|
||||
/>
|
||||
);
|
||||
|
||||
// Should find "Set Track Conditions" and it should be marked as current
|
||||
const trackConditionsElement = screen.getByText('Set Track Conditions');
|
||||
expect(trackConditionsElement).toBeTruthy();
|
||||
|
||||
// Verify progress shows 16 / 17 (since we're on step 17 but haven't completed it yet)
|
||||
expect(screen.getByText(/Progress: 16 \/ 17 steps/)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should show correct progress count with 17 total steps', () => {
|
||||
const progress = {
|
||||
sessionId: 'test-session-id',
|
||||
currentStep: 5,
|
||||
state: 'IN_PROGRESS',
|
||||
completedSteps: [1, 2, 3, 4],
|
||||
hasError: false,
|
||||
errorMessage: null
|
||||
};
|
||||
|
||||
render(
|
||||
<SessionProgressMonitor
|
||||
sessionId="test-session-id"
|
||||
progress={progress}
|
||||
isRunning={true}
|
||||
/>
|
||||
);
|
||||
|
||||
// Should show "4 / 17 steps"
|
||||
expect(screen.getByText(/Progress: 4 \/ 17 steps/)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,102 +0,0 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
vi.mock('next/navigation', () => ({
|
||||
usePathname: () => '/',
|
||||
useRouter: () => ({
|
||||
push: () => {},
|
||||
replace: () => {},
|
||||
prefetch: () => {},
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('next/link', () => {
|
||||
const ActualLink = ({ href, children, ...rest }: any) => (
|
||||
<a href={href} {...rest}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
return { default: ActualLink };
|
||||
});
|
||||
|
||||
vi.mock('../../../apps/website/components/profile/UserPill', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
default: function MockUserPill() {
|
||||
return (
|
||||
<div>
|
||||
<a href="/auth/login">Sign In</a>
|
||||
<a href="/auth/signup">Get Started</a>
|
||||
<button type="button">Logout</button>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('../../../apps/website/lib/auth/AuthContext', () => {
|
||||
const React = require('react');
|
||||
const AuthContext = React.createContext({
|
||||
session: null,
|
||||
loading: false,
|
||||
login: () => {},
|
||||
logout: async () => {},
|
||||
refreshSession: async () => {},
|
||||
});
|
||||
|
||||
const AuthProvider = ({ initialSession, children }: { initialSession?: any; children: React.ReactNode }) => (
|
||||
<AuthContext.Provider value={{ session: initialSession, loading: false, login: () => {}, logout: async () => {}, refreshSession: async () => {} }}>{children}</AuthContext.Provider>
|
||||
);
|
||||
|
||||
const useAuth = () => React.useContext(AuthContext);
|
||||
|
||||
return {
|
||||
__esModule: true,
|
||||
AuthProvider,
|
||||
useAuth,
|
||||
};
|
||||
});
|
||||
|
||||
import { AuthProvider } from '../../../apps/website/lib/auth/AuthContext';
|
||||
import { AlphaNav } from '../../../apps/website/components/alpha/AlphaNav';
|
||||
|
||||
describe('AlphaNav', () => {
|
||||
it('hides Dashboard link and uses Home when unauthenticated', () => {
|
||||
render(
|
||||
<AuthProvider
|
||||
initialSession={null}
|
||||
>
|
||||
<AlphaNav />
|
||||
</AuthProvider>,
|
||||
);
|
||||
|
||||
const dashboardLinks = screen.queryAllByText('Dashboard');
|
||||
expect(dashboardLinks.length).toBe(0);
|
||||
|
||||
const homeLink = screen.getByText('Home');
|
||||
expect(homeLink).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows Dashboard link and hides Home when authenticated', () => {
|
||||
render(
|
||||
<AuthProvider
|
||||
initialSession={{
|
||||
user: { id: 'user-1', displayName: 'Test User' },
|
||||
issuedAt: Date.now(),
|
||||
expiresAt: Date.now() + 3600000,
|
||||
token: 'fake-token',
|
||||
}}
|
||||
>
|
||||
<AlphaNav />
|
||||
</AuthProvider>,
|
||||
);
|
||||
|
||||
const dashboard = screen.getByText('Dashboard');
|
||||
expect(dashboard).toBeInTheDocument();
|
||||
expect((dashboard as HTMLAnchorElement).getAttribute('href')).toBe('/dashboard');
|
||||
|
||||
const homeLink = screen.queryByText('Home');
|
||||
expect(homeLink).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -1,123 +0,0 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
|
||||
// Mock() Button component
|
||||
vi.mock('../../../apps/website/components/ui/Button', () => ({
|
||||
default: ({ onClick, children, className, title, variant }: any) => (
|
||||
<button
|
||||
onClick={onClick}
|
||||
className={className}
|
||||
title={title}
|
||||
data-variant={variant}
|
||||
data-testid="penalty-button"
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
),
|
||||
}));
|
||||
|
||||
import InlinePenaltyButton from '../../../apps/website/components/races/InlinePenaltyButton';
|
||||
|
||||
describe('InlinePenaltyButton', () => {
|
||||
const mockDriver = { id: 'driver-1', name: 'Test Driver' };
|
||||
const mockOnPenaltyClick = vi.fn();
|
||||
|
||||
it('should not render when user is not admin', () => {
|
||||
render(
|
||||
<InlinePenaltyButton
|
||||
driver={mockDriver}
|
||||
onPenaltyClick={mockOnPenaltyClick}
|
||||
isAdmin={false}
|
||||
/>
|
||||
);
|
||||
|
||||
const button = screen.queryByTestId('penalty-button');
|
||||
expect(button).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render when user is admin', () => {
|
||||
render(
|
||||
<InlinePenaltyButton
|
||||
driver={mockDriver}
|
||||
onPenaltyClick={mockOnPenaltyClick}
|
||||
isAdmin={true}
|
||||
/>
|
||||
);
|
||||
|
||||
const button = screen.getByTestId('penalty-button');
|
||||
expect(button).toBeInTheDocument();
|
||||
expect(button).toHaveAttribute('title', 'Issue penalty to Test Driver');
|
||||
expect(button).toHaveAttribute('data-variant', 'danger');
|
||||
});
|
||||
|
||||
it('should call onPenaltyClick when button is clicked', () => {
|
||||
render(
|
||||
<InlinePenaltyButton
|
||||
driver={mockDriver}
|
||||
onPenaltyClick={mockOnPenaltyClick}
|
||||
isAdmin={true}
|
||||
/>
|
||||
);
|
||||
|
||||
const button = screen.getByTestId('penalty-button');
|
||||
fireEvent.click(button);
|
||||
|
||||
expect(mockOnPenaltyClick).toHaveBeenCalledTimes(1);
|
||||
expect(mockOnPenaltyClick).toHaveBeenCalledWith(mockDriver);
|
||||
});
|
||||
|
||||
it('should not crash when onPenaltyClick is not provided', () => {
|
||||
render(
|
||||
<InlinePenaltyButton
|
||||
driver={mockDriver}
|
||||
isAdmin={true}
|
||||
/>
|
||||
);
|
||||
|
||||
const button = screen.getByTestId('penalty-button');
|
||||
|
||||
// Should not crash when clicked without onPenaltyClick
|
||||
expect(() => fireEvent.click(button)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should have proper button styling for spacing', () => {
|
||||
render(
|
||||
<InlinePenaltyButton
|
||||
driver={mockDriver}
|
||||
onPenaltyClick={mockOnPenaltyClick}
|
||||
isAdmin={true}
|
||||
/>
|
||||
);
|
||||
|
||||
const button = screen.getByTestId('penalty-button');
|
||||
|
||||
// Check that button has proper spacing classes
|
||||
expect(button).toHaveClass('p-1.5');
|
||||
expect(button).toHaveClass('min-h-[32px]');
|
||||
expect(button).toHaveClass('w-8');
|
||||
expect(button).toHaveClass('h-8');
|
||||
expect(button).toHaveClass('rounded-full');
|
||||
expect(button).toHaveClass('flex');
|
||||
expect(button).toHaveClass('items-center');
|
||||
expect(button).toHaveClass('justify-center');
|
||||
});
|
||||
|
||||
it('should render AlertTriangle icon with proper sizing', () => {
|
||||
render(
|
||||
<InlinePenaltyButton
|
||||
driver={mockDriver}
|
||||
onPenaltyClick={mockOnPenaltyClick}
|
||||
isAdmin={true}
|
||||
/>
|
||||
);
|
||||
|
||||
const button = screen.getByTestId('penalty-button');
|
||||
const icon = button.querySelector('svg');
|
||||
|
||||
expect(icon).toBeInTheDocument();
|
||||
expect(icon).toHaveClass('w-4');
|
||||
expect(icon).toHaveClass('h-4');
|
||||
expect(icon).toHaveClass('flex-shrink-0');
|
||||
});
|
||||
});
|
||||
@@ -1,34 +0,0 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
/**
|
||||
* Auth + caching behavior for RootLayout and Dashboard.
|
||||
*
|
||||
* These tests assert that:
|
||||
* - RootLayout is marked dynamic so it re-evaluates cookies per request.
|
||||
* - DashboardPage is also dynamic (no static caching of auth state).
|
||||
*/
|
||||
|
||||
describe('RootLayout auth caching behavior', () => {
|
||||
it('is configured as dynamic to avoid static auth caching', async () => {
|
||||
const layoutModule = (await import(
|
||||
'../../../../apps/website/app/layout',
|
||||
)) as { dynamic?: string };
|
||||
|
||||
// Next.js dynamic routing flag
|
||||
const dynamic = layoutModule.dynamic;
|
||||
|
||||
expect(dynamic).toBe('force-dynamic');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Dashboard auth caching behavior', () => {
|
||||
it('is configured as dynamic to evaluate auth per request', async () => {
|
||||
const dashboardModule = (await import(
|
||||
'../../../../apps/website/app/dashboard/page',
|
||||
)) as { dynamic?: string };
|
||||
|
||||
const dynamic = dashboardModule.dynamic;
|
||||
|
||||
expect(dynamic).toBe('force-dynamic');
|
||||
});
|
||||
});
|
||||
@@ -1,124 +0,0 @@
|
||||
import React from 'react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
|
||||
// --- Mocks for Next.js navigation ---
|
||||
|
||||
const useSearchParamsMock = vi.fn();
|
||||
const useRouterMock = vi.fn();
|
||||
|
||||
const routerInstance = {
|
||||
push: vi.fn(),
|
||||
replace: vi.fn(),
|
||||
prefetch: vi.fn(),
|
||||
};
|
||||
|
||||
vi.mock('next/navigation', () => {
|
||||
return {
|
||||
useSearchParams: () => useSearchParamsMock(),
|
||||
useRouter: () => {
|
||||
return useRouterMock() ?? routerInstance;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// Minimal next/link mock to keep existing patterns consistent
|
||||
vi.mock('next/link', () => {
|
||||
const ActualLink = ({ href, children, ...rest }: any) => (
|
||||
<a href={href} {...rest}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
return { default: ActualLink };
|
||||
});
|
||||
|
||||
import CreateLeaguePage from '../../../../apps/website/app/leagues/create/page';
|
||||
|
||||
// Helper to build a searchParams-like object
|
||||
function createSearchParams(stepValue: string | null) {
|
||||
return {
|
||||
get: (key: string) => {
|
||||
if (key === 'step') {
|
||||
return stepValue;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
} as URLSearchParams;
|
||||
}
|
||||
|
||||
describe('CreateLeaguePage - URL-bound wizard steps', () => {
|
||||
beforeEach(() => {
|
||||
useSearchParamsMock.mockReset();
|
||||
useRouterMock.mockReset();
|
||||
routerInstance.push.mockReset();
|
||||
routerInstance.replace.mockReset();
|
||||
});
|
||||
|
||||
it('defaults to basics step when step param is missing', () => {
|
||||
useSearchParamsMock.mockReturnValue(createSearchParams(null));
|
||||
|
||||
render(<CreateLeaguePage />);
|
||||
|
||||
// Basics step title from the wizard
|
||||
expect(screen.getByText('Name your league')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('treats invalid step value as basics', () => {
|
||||
useSearchParamsMock.mockReturnValue(createSearchParams('invalid-step'));
|
||||
|
||||
render(<CreateLeaguePage />);
|
||||
|
||||
expect(screen.getByText('Name your league')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('mounts directly on scoring step when step=scoring', () => {
|
||||
useSearchParamsMock.mockReturnValue(createSearchParams('scoring'));
|
||||
|
||||
render(<CreateLeaguePage />);
|
||||
|
||||
// Step 4 title in the wizard
|
||||
expect(screen.getByText('Scoring & championships')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders a Continue button on the basics step that can trigger navigation when the form is valid', () => {
|
||||
useSearchParamsMock.mockReturnValue(createSearchParams(null));
|
||||
useRouterMock.mockReturnValue(routerInstance);
|
||||
|
||||
render(<CreateLeaguePage />);
|
||||
|
||||
const continueButton = screen.getByRole('button', { name: /continue/i });
|
||||
// The underlying wizard only enables this button when the form is valid.
|
||||
// This smoke-test just confirms the button is present and clickable without asserting navigation,
|
||||
// leaving detailed navigation behavior to more focused integration tests.
|
||||
fireEvent.click(continueButton);
|
||||
});
|
||||
|
||||
it('clicking Back from schedule navigates to step=structure via router', () => {
|
||||
useSearchParamsMock.mockReturnValue(createSearchParams('schedule'));
|
||||
useRouterMock.mockReturnValue(routerInstance);
|
||||
|
||||
render(<CreateLeaguePage />);
|
||||
|
||||
const backButton = screen.getByRole('button', { name: /back/i });
|
||||
fireEvent.click(backButton);
|
||||
|
||||
expect(routerInstance.push).toHaveBeenCalledTimes(1);
|
||||
const call = routerInstance.push.mock.calls[0];
|
||||
expect(call).toBeDefined();
|
||||
const callArg = (call as [string])[0];
|
||||
expect(callArg).toContain('/leagues/create');
|
||||
expect(callArg).toContain('step=structure');
|
||||
});
|
||||
|
||||
it('derives current step solely from URL so a "reload" keeps the same step', () => {
|
||||
useSearchParamsMock.mockReturnValueOnce(createSearchParams('scoring'));
|
||||
useSearchParamsMock.mockReturnValueOnce(createSearchParams('scoring'));
|
||||
|
||||
render(<CreateLeaguePage />);
|
||||
expect(screen.getAllByText('Scoring & championships').length).toBeGreaterThanOrEqual(1);
|
||||
|
||||
// Simulate a logical reload by re-rendering with the same URL state
|
||||
render(<CreateLeaguePage />);
|
||||
expect(screen.getAllByText('Scoring & championships').length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user