diff --git a/__tests__/components/backlog/new-sprint-trigger.test.tsx b/__tests__/components/backlog/new-sprint-trigger.test.tsx new file mode 100644 index 0000000..72c669e --- /dev/null +++ b/__tests__/components/backlog/new-sprint-trigger.test.tsx @@ -0,0 +1,57 @@ +// @vitest-environment jsdom +import { describe, it, expect, beforeEach, vi } from 'vitest' +import { render, screen } from '@testing-library/react' +import '@testing-library/jest-dom' +import type { ReactNode } from 'react' + +const workflowMock: { + value: { pendingSprintDraft?: Record } | undefined +} = { value: undefined } + +vi.mock('@/stores/user-settings/store', () => ({ + useUserSettingsStore: ( + selector: (s: { + entities: { + settings: { + workflow: { pendingSprintDraft?: Record } | undefined + } + } + }) => unknown, + ) => selector({ entities: { settings: { workflow: workflowMock.value } } }), +})) + +vi.mock('./new-sprint-metadata-dialog', () => ({ + NewSprintMetadataDialog: () => null, +})) + +vi.mock('@/components/shared/demo-tooltip', () => ({ + DemoTooltip: ({ children }: { children: ReactNode }) => children, +})) + +import { NewSprintTrigger } from '@/components/backlog/new-sprint-trigger' + +beforeEach(() => { + workflowMock.value = undefined +}) + +describe('NewSprintTrigger', () => { + it('renders the button on an active product without a draft', () => { + render() + expect(screen.getByText('Nieuwe sprint')).toBeInTheDocument() + }) + + it('renders nothing on a non-active product (G6)', () => { + const { container } = render( + , + ) + expect(container).toBeEmptyDOMElement() + }) + + it('renders nothing when a sprint draft is pending', () => { + workflowMock.value = { pendingSprintDraft: { p1: { goal: 'X' } } } + const { container } = render( + , + ) + expect(container).toBeEmptyDOMElement() + }) +}) diff --git a/__tests__/components/shared/sprint-switcher.test.tsx b/__tests__/components/shared/sprint-switcher.test.tsx index 29c29c0..8af2df1 100644 --- a/__tests__/components/shared/sprint-switcher.test.tsx +++ b/__tests__/components/shared/sprint-switcher.test.tsx @@ -24,6 +24,11 @@ vi.mock('sonner', () => ({ })) const isDemoMock = { value: false } +const workflowMock: { + value: + | { pendingSprintDraft?: Record } + | undefined +} = { value: undefined } // Mock-state shape moet alle paden dekken die SprintSwitcher selecteert: // - s.context.isDemo (oude code) // - s.entities.settings.workflow?.pendingSprintDraft?.[productId]?.goal (PBI-79) @@ -38,8 +43,11 @@ type MockStoreState = { } } vi.mock('@/stores/user-settings/store', () => ({ - useUserSettingsStore: (selector: (s: { context: { isDemo: boolean }; entities: { settings: { workflow: null } } }) => unknown) => - selector({ context: { isDemo: isDemoMock.value }, entities: { settings: { workflow: null } } }), + useUserSettingsStore: (selector: (s: MockStoreState) => unknown) => + selector({ + context: { isDemo: isDemoMock.value }, + entities: { settings: { workflow: workflowMock.value } }, + }), })) vi.mock('@/components/ui/dropdown-menu', () => { @@ -85,6 +93,7 @@ const sprints = [ beforeEach(() => { vi.clearAllMocks() isDemoMock.value = false + workflowMock.value = undefined actionMock.mockResolvedValue({ success: true }) pathnameMock.mockReturnValue('/products/p1/sprint') }) @@ -137,4 +146,29 @@ describe('SprintSwitcher', () => { expect(pushMock).not.toHaveBeenCalled() expect(actionMock).not.toHaveBeenCalled() }) + + it('shows the concept-sprint on the trigger when a draft is pending (G5)', () => { + workflowMock.value = { pendingSprintDraft: { p1: { goal: 'Test goal' } } } + render( + , + ) + expect(screen.getByText('⚙ Concept — Test goal')).toBeInTheDocument() + }) + + it('shows no concept label on the trigger when no draft is pending', () => { + render( + , + ) + expect(screen.queryByText(/⚙ Concept/)).not.toBeInTheDocument() + }) })