Skip to content

Commit

Permalink
test: add unit tests (#282)
Browse files Browse the repository at this point in the history
* refactor: mutualize route components imports

* chore: type & translation

* test: add unit tests on pages

* chore: remove unused component

* test: make shared wrapper for tests

* test: add unit tests for shared components

* chore: remove unused prop

* chore: typo on shared const

* chore: rename BreadCrumb component into Breadcrumb

* test: add unit tests for orchestrator components

* test: add unit tests for orchestrator menu
  • Loading branch information
QRuhier authored Jan 21, 2025
1 parent d70d795 commit b929d49
Show file tree
Hide file tree
Showing 37 changed files with 2,154 additions and 52 deletions.
9 changes: 9 additions & 0 deletions src/tests/TestWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ThemeProvider } from '@mui/material/styles'

import type { ReactNode } from 'react'

import { theme } from '@/ui/style/theme'

export const TestWrapper = ({ children }: { children: ReactNode }) => {
return <ThemeProvider theme={theme}>{children}</ThemeProvider>
}
13 changes: 13 additions & 0 deletions src/ui/components/CenteredSpinner.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { render, screen } from '@testing-library/react'
import { describe, expect, it } from 'vitest'

import { CenteredSpinner } from './CenteredSpinner'

describe('CenteredSpinner', () => {
it('should render the CircularProgress spinner', () => {
render(<CenteredSpinner />)

const spinner = screen.getByRole('progressbar')
expect(spinner).toBeInTheDocument()
})
})
25 changes: 25 additions & 0 deletions src/ui/components/ErrorComponent.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { render } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'

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

import { ErrorComponent } from './ErrorComponent'

vi.mock('@/i18n', () => ({
useTranslation: () => ({ t: (keyMessage: string) => keyMessage }),
}))

describe('ErrorComponent', () => {
it('should render the error title and message', () => {
const message = 'Something went wrong'

const { getByText } = render(
<TestWrapper>
<ErrorComponent message={message} />
</TestWrapper>,
)

expect(getByText('errorOccured')).toBeInTheDocument()
expect(getByText(message)).toBeInTheDocument()
})
})
108 changes: 108 additions & 0 deletions src/ui/components/Modal.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { fireEvent, render } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'

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

import { Modal } from './Modal'

describe('Modal', () => {
const defaultProps = {
isOpen: true,
dialogTitle: 'Modal Title',
dialogContent: 'This is the modal content',
buttons: [
{ label: 'Close', onClick: vi.fn(), autoFocus: false },
{ label: 'Confirm', onClick: vi.fn(), autoFocus: true },
],
onClose: vi.fn(),
}

afterEach(() => {
vi.clearAllMocks()
})

it('should render the modal with provided props', () => {
const { getByText } = render(
<TestWrapper>
<Modal {...defaultProps} />
</TestWrapper>,
)

expect(getByText('Modal Title')).toBeInTheDocument()
expect(getByText('This is the modal content')).toBeInTheDocument()
expect(getByText('Close')).toBeInTheDocument()
expect(getByText('Confirm')).toBeInTheDocument()
})

it('should close the modal when close button is clicked', () => {
const { getByLabelText } = render(
<TestWrapper>
<Modal {...defaultProps} />
</TestWrapper>,
)
const closeButton = getByLabelText('close')

fireEvent.click(closeButton)

expect(defaultProps.onClose).toHaveBeenCalledTimes(1)
})

it('should not close the modal when clicked outside if mandatory prop is true', () => {
const props = { ...defaultProps, mandatory: true }
const { getByTestId } = render(
<TestWrapper>
<Modal {...props} />
</TestWrapper>,
)

const backdrop = getByTestId('modal-backdrop') // Backdrop div
fireEvent.click(backdrop)

expect(defaultProps.onClose).not.toHaveBeenCalled()
})

it('should trigger button onClick handler when buttons are clicked', () => {
const { getByText } = render(
<TestWrapper>
<Modal {...defaultProps} />
</TestWrapper>,
)

const confirmButton = getByText('Confirm')
fireEvent.click(confirmButton)

// Expect the onClick handler of the confirm button to be called
expect(defaultProps.buttons[1].onClick).toHaveBeenCalledTimes(1)

// as the mock buttons onClick does not do anything, the modal is still open so we can test other clicks
const closeButton = getByText('Close')
fireEvent.click(closeButton)

// Expect the onClick handler of the close button to be called
expect(defaultProps.buttons[0].onClick).toHaveBeenCalledTimes(1)
})

it('should not render the close button when mandatory is true', () => {
const props = { ...defaultProps, mandatory: true }
const { queryByLabelText } = render(
<TestWrapper>
<Modal {...props} />
</TestWrapper>,
)

expect(queryByLabelText('close')).not.toBeInTheDocument()
})

it('should render the modal dialog as closed when isOpen is false', () => {
const props = { ...defaultProps, isOpen: false }
const { queryByRole } = render(
<TestWrapper>
<Modal {...props} />
</TestWrapper>,
)

// Expect the dialog to not be in the document
const dialog = queryByRole('dialog')
expect(dialog).not.toBeInTheDocument()
})
})
2 changes: 1 addition & 1 deletion src/ui/components/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function Modal(props: ModalProps) {
}

return (
<Dialog open={isOpen} onClose={handleClose}>
<Dialog open={isOpen} onClose={handleClose} data-testid="modal-backdrop">
<Stack className={classes.dialog}>
<Stack className={classes.dialogHeader}>
<DialogTitle>{dialogTitle}</DialogTitle>
Expand Down
26 changes: 0 additions & 26 deletions src/ui/components/appVersion.tsx

This file was deleted.

104 changes: 104 additions & 0 deletions src/ui/components/orchestrator/Breadcrumb/Breadcrumb.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { fireEvent, render } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'

import type { GoToPage, OverviewItem } from '../lunaticType'
import { Breadcrumb } from './Breadcrumb'

vi.mock('@/i18n', () => ({
useTranslation: () => ({ t: (keyMessage: string) => keyMessage }),
}))

describe('Breadcrumb Component', () => {
const goToPageMock: GoToPage = vi.fn()

const mockSequence: OverviewItem = {
id: '1',
type: 'sequence',
page: '1',
label: 'Sequence Label',
description: 'Sequence Description',
reached: true,
current: true,
children: [],
}

const mockSubSequence: OverviewItem = {
id: '2',
type: 'subSequence',
page: '2',
label: 'SubSequence Label',
description: 'SubSequence Description',
reached: true,
current: true,
children: [],
}

it('renders sequence and subSequence buttons when both are provided', () => {
const { getByText } = render(
<Breadcrumb
sequence={mockSequence}
subSequence={mockSubSequence}
goToPage={goToPageMock}
/>,
)

expect(getByText('Sequence Label')).toBeInTheDocument()
expect(getByText('SubSequence Label')).toBeInTheDocument()
})

it('calls goToSequencePage when sequence button is clicked', () => {
const { getByText } = render(
<Breadcrumb
sequence={mockSequence}
subSequence={mockSubSequence}
goToPage={goToPageMock}
/>,
)

const sequenceButton = getByText('Sequence Label')
fireEvent.click(sequenceButton)

expect(goToPageMock).toHaveBeenCalledWith({ page: '1' })
})

it('calls goToSubSequencePage when subSequence button is clicked', () => {
const { getByText } = render(
<Breadcrumb
sequence={mockSequence}
subSequence={mockSubSequence}
goToPage={goToPageMock}
/>,
)

const subSequenceButton = getByText('SubSequence Label')
fireEvent.click(subSequenceButton)

expect(goToPageMock).toHaveBeenCalledWith({ page: '2' })
})

it('renders only the sequence button when subSequence is undefined', () => {
const { getByText, queryByText } = render(
<Breadcrumb
sequence={mockSequence}
subSequence={undefined}
goToPage={goToPageMock}
/>,
)

expect(getByText('Sequence Label')).toBeInTheDocument()
expect(queryByText('SubSequence Label')).toBeNull()
})

it('renders only the subSequence button when sequence is undefined', () => {
const { getByText, queryByText } = render(
<Breadcrumb
sequence={undefined}
subSequence={mockSubSequence}
goToPage={goToPageMock}
/>,
)

expect(getByText('SubSequence Label')).toBeInTheDocument()
expect(queryByText('Sequence Label')).toBeNull()
})
})
5 changes: 2 additions & 3 deletions src/ui/components/orchestrator/Breadcrumb/Breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import { useTranslation } from '@/i18n'

import type { GoToPage, OverviewItem } from '../lunaticType'

type BreadCrumbProps = {
type BreadcrumbProps = {
sequence: OverviewItem | undefined
subSequence: OverviewItem | undefined
iteration: number | undefined
goToPage: GoToPage
}

export function BreadCrumb(props: BreadCrumbProps) {
export function Breadcrumb(props: BreadcrumbProps) {
const { sequence, subSequence, goToPage } = props
const { classes, cx } = useStyles()
const { t } = useTranslation('navigationMessage')
Expand Down
Loading

0 comments on commit b929d49

Please sign in to comment.