import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { MemoryRouter, Route, Routes } from 'react-router-dom' import { WelcomeStep2 } from '../WelcomeStep2' import { useAuthStore } from '@/store/authStore' import { onboardingApi } from '@/api/onboarding' import type { Account, User } from '@/types' vi.mock('@/api/onboarding', async () => { const actual = await vi.importActual( '@/api/onboarding', ) return { ...actual, onboardingApi: { ...actual.onboardingApi, updateStep: vi.fn(), dismissRest: vi.fn(), }, } }) function makeUser(overrides: Partial = {}): User { return { id: 'user-1', email: 'test@example.com', name: 'Test User', role: 'engineer', is_super_admin: false, is_active: true, must_change_password: false, account_id: 'acct-1', account_role: 'owner', team_id: null, created_at: '2026-05-01T00:00:00Z', last_login: null, phone: null, job_title: null, timezone: 'UTC', avatar_url: null, email_verified_at: null, onboarding_step_completed: 1, onboarding_dismissed: false, ...overrides, } } function makeAccount(overrides: Partial = {}): Account { return { id: 'acct-1', name: 'Acme MSP', display_code: 'ACME', owner_id: 'user-1', created_at: '2026-05-01T00:00:00Z', updated_at: '2026-05-01T00:00:00Z', ...overrides, } } function renderPage() { return render( } /> step-3} /> integrations} /> dashboard} /> , ) } describe('WelcomeStep2', () => { beforeEach(() => { useAuthStore.setState({ user: makeUser(), account: makeAccount(), subscription: null, token: null, isAuthenticated: true, fetchUser: vi.fn().mockResolvedValue(undefined), }) vi.mocked(onboardingApi.updateStep).mockResolvedValue({ onboarding_step_completed: 2, onboarding_dismissed: false, }) vi.mocked(onboardingApi.dismissRest).mockResolvedValue({ onboarding_step_completed: null, onboarding_dismissed: true, }) }) afterEach(() => { vi.clearAllMocks() }) it('selecting PSA persists primary_psa', async () => { const user = userEvent.setup() renderPage() await user.click(screen.getByTestId('welcome-step-2-tile-connectwise')) // Selecting a real PSA reveals the inline "Connect now" link. expect(screen.getByTestId('welcome-step-2-connect-now')).toBeInTheDocument() await user.click(screen.getByTestId('welcome-step-2-continue')) await waitFor(() => { expect(onboardingApi.updateStep).toHaveBeenCalledWith({ step: 2, action: 'complete', data: { primary_psa: 'connectwise' }, }) }) await waitFor(() => { expect(screen.getByText('step-3')).toBeInTheDocument() }) }) it('Skip advances without writing primary_psa', async () => { const user = userEvent.setup() renderPage() await user.click(screen.getByTestId('welcome-step-2-skip')) await waitFor(() => { expect(onboardingApi.updateStep).toHaveBeenCalledWith({ step: 2, action: 'skip', }) }) // Confirm no `data` key on the call (skip doesn't persist primary_psa). const call = vi.mocked(onboardingApi.updateStep).mock.calls[0]?.[0] expect(call?.data).toBeUndefined() await waitFor(() => { expect(screen.getByText('step-3')).toBeInTheDocument() }) }) it('"No PSA yet" tile does NOT show the Connect now link', async () => { const user = userEvent.setup() renderPage() await user.click(screen.getByTestId('welcome-step-2-tile-none')) expect(screen.queryByTestId('welcome-step-2-connect-now')).not.toBeInTheDocument() }) it('default action is Continue (not Connect now)', () => { renderPage() // Continue is rendered as a primary button. const continueBtn = screen.getByTestId('welcome-step-2-continue') expect(continueBtn.className).toMatch(/bg-primary/) // Connect-now is hidden until a real PSA is picked. expect(screen.queryByTestId('welcome-step-2-connect-now')).not.toBeInTheDocument() }) it('Skip-the-rest dismisses and navigates to /', async () => { const user = userEvent.setup() renderPage() await user.click(screen.getByTestId('welcome-step-2-dismiss-rest')) await waitFor(() => { expect(onboardingApi.dismissRest).toHaveBeenCalled() }) await waitFor(() => { expect(screen.getByText('dashboard')).toBeInTheDocument() }) }) })