Skip to content

Commit

Permalink
test: add unit tests for orchestrator menu
Browse files Browse the repository at this point in the history
  • Loading branch information
QRuhier committed Jan 20, 2025
1 parent df06ea4 commit 1fc28a4
Show file tree
Hide file tree
Showing 4 changed files with 511 additions and 0 deletions.
132 changes: 132 additions & 0 deletions src/ui/components/orchestrator/LoopPanel/LoopPanel.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { fireEvent, render } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'

import type { PageTag, SurveyUnitData } from '@/core/model'

import { isIterationReachable } from '../tools/functions'
import { LoopPanel } from './LoopPanel'

const mockGoToPage = vi.fn()

vi.mock('@/ui/components/orchestrator/tools/functions', () => ({
isIterationReachable: vi.fn(),
}))

describe('LoopPanel Component', () => {
const mockLoopVariables = ['loopTitle']
const mockData: SurveyUnitData = {
COLLECTED: {
loopTitle: {
COLLECTED: ['Iteration 1', 'Iteration 2', 'Iteration 3'],
},
},
}
const mockLastReachedPage: PageTag = '2'

const defaultProps = {
loopVariables: mockLoopVariables,
page: 1,
subPage: undefined,
iteration: undefined,
lastReachedPage: mockLastReachedPage,
data: mockData,
goToPage: mockGoToPage,
}

it('renders correctly every iteration panel', () => {
const { getAllByRole, getByText } = render(<LoopPanel {...defaultProps} />)

const buttons = getAllByRole('button')

expect(buttons).toHaveLength(3)
expect(getByText('Iteration 1')).toBeInTheDocument()
expect(getByText('Iteration 2')).toBeInTheDocument()
expect(getByText('Iteration 3')).toBeInTheDocument()
})

it('disables buttons for unreachable iterations', () => {
// we mock the isIterationReachable function : every iteration is reachable except iteration 1
vi.mocked(isIterationReachable).mockImplementation(
(_page, _lastReachedPage, iteration) => iteration !== 1,
)

const { getAllByRole } = render(<LoopPanel {...defaultProps} />)

const buttons = getAllByRole('button')

// considering isIterationReachable mock : only button for iteration 1 is disabled
expect(buttons[0]).not.toBeDisabled()
expect(buttons[1]).toBeDisabled()
expect(buttons[2]).not.toBeDisabled()
})

it('go to the page {page, subPage:0} page on button click', () => {
const { getAllByRole } = render(<LoopPanel {...defaultProps} />)

const buttons = getAllByRole('button')

// iteration 0
fireEvent.click(buttons[0])
expect(mockGoToPage).toHaveBeenCalledWith({
page: 1,
subPage: 0,
iteration: 0,
})

// iteration 2
fireEvent.click(buttons[2])
expect(mockGoToPage).toHaveBeenCalledWith({
page: 1,
subPage: 0,
iteration: 2,
})
})

it('applies different styles for current and non-current iterations', () => {
const props = { ...defaultProps, iteration: 1 }

const { getAllByRole } = render(<LoopPanel {...props} />)

const buttons = getAllByRole('button')
expect(buttons[0].className).toContain('notCurrentIteration')
expect(buttons[1].className).toContain('currentIteration')
expect(buttons[2].className).toContain('notCurrentIteration')
})

it('returns null if loopVariables is empty (we are not in a loop)', () => {
const props = { ...defaultProps, loopVariables: [] }

const { container } = render(<LoopPanel {...props} />)
expect(container.firstChild).toBeNull()
})

it('returns null if lastReachedPage is undefined', () => {
const props = { ...defaultProps, lastReachedPage: undefined }

const { container } = render(<LoopPanel {...props} />)
expect(container.firstChild).toBeNull()
})

it('returns null if data.COLLECTED is undefined', () => {
const props = { ...defaultProps, data: { COLLECTED: undefined } }

const { container } = render(<LoopPanel {...props} />)
expect(container.firstChild).toBeNull()
})

it('returns null if there is no data as title', () => {
const props = {
...defaultProps,
data: {
COLLECTED: {
loopTitle: {
COLLECTED: undefined,
},
},
},
}

const { container } = render(<LoopPanel {...props} />)
expect(container.firstChild).toBeNull()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { fireEvent, render } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'

import { TestWrapper } from '@/tests/TestWrapper'

import { MenuNavigationButton } from '../../buttons/MenuNavigationButton/MenuNavigationButton'
import type { Overview } from '../../lunaticType'
import { SequenceNavigation } from './SequenceNavigation'

vi.mock('../../buttons/MenuNavigationButton/MenuNavigationButton', () => ({
MenuNavigationButton: vi
.fn()
.mockImplementation(({ label, onClick }) => (
<button onClick={onClick}>{label}</button>
)),
}))

describe('SequenceNavigation Component', () => {
const mockSequenceOnClick = vi.fn()

const defaultOverview: Overview = [
{
id: 'seq-1',
type: 'sequence',
page: '1',
label: 'Sequence 1',
description: 'Description 1',
reached: true,
current: false,
children: [],
},
{
id: 'seq-2',
type: 'sequence',
page: '2',
label: 'Sequence 2',
description: 'Description 2',
reached: false,
current: false,
children: [],
},
]

const defaultProps = {
questionnaireTitle: 'Questionnaire Title',
overview: defaultOverview,
selectedSequence: undefined,
sequenceOnClick: mockSequenceOnClick,
}

it('renders the questionnaire title', () => {
const { getByText } = render(
<TestWrapper>
<SequenceNavigation {...defaultProps} />
</TestWrapper>,
)

expect(getByText('Questionnaire Title')).toBeInTheDocument()
})

it('renders all sequences as MenuNavigationButton components', () => {
render(
<TestWrapper>
<SequenceNavigation {...defaultProps} />
</TestWrapper>,
)

expect(MenuNavigationButton).toHaveBeenCalledWith(
expect.objectContaining({
label: defaultProps.overview[0].label,
disabled: false,
endIcon: undefined,
onClick: expect.any(Function),
}),
{},
)

expect(MenuNavigationButton).toHaveBeenCalledWith(
expect.objectContaining({
label: defaultProps.overview[1].label,
disabled: true,
endIcon: undefined,
onClick: expect.any(Function),
}),
{},
)
})

it('triggers the sequenceOnClick when a sequence is clicked in the menu', () => {
const { getByRole } = render(
<TestWrapper>
<SequenceNavigation {...defaultProps} />
</TestWrapper>,
)

// click on the second sequence button
const button = getByRole('button', {
name: defaultProps.overview[1].label as string,
})

fireEvent.click(button)

expect(mockSequenceOnClick).toHaveBeenCalledWith(defaultProps.overview[1])
})

it('highlights the selected sequence', () => {
const props = {
...defaultProps,
selectedSequence: defaultProps.overview[0],
}

render(
<TestWrapper>
<SequenceNavigation {...props} />
</TestWrapper>,
)

expect(MenuNavigationButton).toHaveBeenCalledWith(
expect.objectContaining({
label: defaultProps.overview[0].label,
className: expect.stringContaining('sequenceOpen'),
}),
{},
)
})

it('displays icon only for sequences with subSequences', () => {
const overview: Overview = [
...defaultProps.overview,
{
id: 'seq-3',
type: 'sequence',
page: '3',
label: 'Sequence 3',
description: 'Description 3',
reached: true,
current: false,
children: [
{
id: 'sub-seq-1',
type: 'sub-sequence',
page: '4',
label: 'Sub-Sequence 1',
description: 'Description 4',
reached: true,
current: false,
children: [],
},
],
},
]

const props = {
...defaultProps,
overview: overview,
}

render(
<TestWrapper>
<SequenceNavigation {...props} />
</TestWrapper>,
)

// Third sequence has subSequences
expect(MenuNavigationButton).toHaveBeenCalledWith(
expect.objectContaining({
label: props.overview[2].label,
endIcon: expect.anything(),
}),
{},
)

// First sequence dos not have subSequences
expect(MenuNavigationButton).toHaveBeenCalledWith(
expect.objectContaining({
label: defaultProps.overview[0].label,
endIcon: undefined,
}),
{},
)
})
})
Loading

0 comments on commit 1fc28a4

Please sign in to comment.