Skip to content

Commit

Permalink
Merge pull request #399 from MTES-MCT/validation-zee
Browse files Browse the repository at this point in the history
fix(validation): show correct validation on ZEE and mission observati…
  • Loading branch information
lwih authored Oct 15, 2024
2 parents eaeaf03 + 93f6d1b commit a838b08
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as useActionByIdModule from '@features/pam/mission/hooks/use-action-by-
import * as useIsMissionFinishedModule from '@features/pam/mission/hooks/use-is-mission-finished.tsx'
import { vi } from 'vitest'
import { render } from '../../../../../../test-utils.tsx'
import { THEME } from '@mtes-mct/monitor-ui'

vi.mock('react-router-dom', async importOriginal => {
const actual = await importOriginal()
Expand Down Expand Up @@ -50,9 +51,10 @@ describe('ActionIllegalImmigrationForm', () => {
})

it('should render error when no values and mission is finished', async () => {
const red = '#e1000f'
vi.spyOn(useIsMissionFinishedModule, 'default').mockReturnValue(true)
const wrapper = render(<ActionIllegalImmigrationForm action={action} />)
expect(wrapper.getByRole('nbOfInterceptedVessels')).toHaveStyle(`border: 1px solid ${red};`)
expect(wrapper.getByRole('nbOfInterceptedVessels')).toHaveStyle(
`border: 1px solid ${THEME.color.maximumRed.toLowerCase()};`
)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import { vi } from 'vitest'
import { fireEvent, render, screen } from '../../../../../../test-utils.tsx'
import UIThemeWrapper from '../../../../../common/components/ui/ui-theme-wrapper.tsx'
import MissionRecognizedVessel from './mission-recognized-vessel.tsx'
import * as useIsMissionFinishedModule from '@features/pam/mission/hooks/use-is-mission-finished.tsx'
import { THEME } from '@mtes-mct/monitor-ui'

const info = {
id: 3,
distanceInNauticalMiles: 23,
consumedGOInLiters: 0,
consumedFuelInLiters: 0,
serviceId: 5,
nbrOfRecognizedVessel: 0
nbrOfRecognizedVessel: 5
} as MissionGeneralInfo

const mutateMock = vi.fn()
Expand All @@ -35,23 +37,52 @@ describe('MissionRecognizedVessel', () => {
expect(screen.getByText(`Nombre total de navires reconnus dans les approches maritimes (ZEE)`)).toBeTruthy()
})

it('should call update information general', () => {
const nbrOfRecognizedVessel = 9
vi.useFakeTimers({ shouldAdvanceTime: true })
const wrapper = render(
<UIThemeWrapper>
<MissionRecognizedVessel missionId={1} generalInfo={info} />
</UIThemeWrapper>
)
const element = wrapper.getByTestId('mission-information-general-recognized-vessel')
fireEvent.change(element, {
target: { value: nbrOfRecognizedVessel }
describe('Validation', () => {
it('should show error validation when mission is finished but no info ', () => {
vi.spyOn(useIsMissionFinishedModule, 'default').mockReturnValue(true)
render(<MissionRecognizedVessel missionId={1} generalInfo={undefined} />)
const element = screen.getByLabelText('Nombre total de navires reconnus dans les approches maritimes (ZEE)')
expect(getComputedStyle(element).borderColor).toBe(THEME.color.maximumRed.toLowerCase())
})
expect(mutateMock).not.toHaveBeenCalled()
vi.advanceTimersByTime(5000)
expect(mutateMock).toHaveBeenCalledTimes(1)
expect(mutateMock).toHaveBeenCalledWith({
variables: { info: expect.objectContaining({ nbrOfRecognizedVessel }) }
it('should not show error validation when mission is finished but info ', () => {
vi.spyOn(useIsMissionFinishedModule, 'default').mockReturnValue(true)
render(<MissionRecognizedVessel missionId={1} generalInfo={info} />)
const element = screen.getByLabelText('Nombre total de navires reconnus dans les approches maritimes (ZEE)')
expect(getComputedStyle(element).borderColor).not.toBe(THEME.color.maximumRed.toLowerCase())
})
it('should not show error validation when mission is not finished but info ', () => {
vi.spyOn(useIsMissionFinishedModule, 'default').mockReturnValue(false)
render(<MissionRecognizedVessel missionId={1} generalInfo={info} />)
const element = screen.getByLabelText('Nombre total de navires reconnus dans les approches maritimes (ZEE)')
expect(getComputedStyle(element).borderColor).not.toBe(THEME.color.maximumRed.toLowerCase())
})
it('should not show error validation when mission is not finished and no info ', () => {
vi.spyOn(useIsMissionFinishedModule, 'default').mockReturnValue(false)
render(<MissionRecognizedVessel missionId={1} generalInfo={undefined} />)
const element = screen.getByLabelText('Nombre total de navires reconnus dans les approches maritimes (ZEE)')
expect(getComputedStyle(element).borderColor).not.toBe(THEME.color.maximumRed.toLowerCase())
})
})

describe('Updating data', () => {
it('should call update information general on change', () => {
const nbrOfRecognizedVessel = 9
vi.useFakeTimers({ shouldAdvanceTime: true })
const wrapper = render(
<UIThemeWrapper>
<MissionRecognizedVessel missionId={1} generalInfo={info} />
</UIThemeWrapper>
)
const element = wrapper.getByTestId('mission-information-general-recognized-vessel')
fireEvent.change(element, {
target: { value: nbrOfRecognizedVessel }
})
expect(mutateMock).not.toHaveBeenCalled()
vi.advanceTimersByTime(5000)
expect(mutateMock).toHaveBeenCalledTimes(1)
expect(mutateMock).toHaveBeenCalledWith({
variables: { info: expect.objectContaining({ nbrOfRecognizedVessel }) }
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FormikEffect, FormikNumberInput } from '@mtes-mct/monitor-ui'
import { Formik } from 'formik'
import React, { useEffect, useRef, useState } from 'react'
import useAddOrUpdateGeneralInfo from '../../../hooks/use-add-update-distance-consumption.tsx'
import useIsMissionFinished from '@features/pam/mission/hooks/use-is-mission-finished.tsx'

const DEBOUNCE_TIME_TRIGGER = 1000

Expand All @@ -17,6 +18,8 @@ interface MissionRecognizedVesselProps {

const MissionRecognizedVessel: React.FC<MissionRecognizedVesselProps> = ({ missionId, generalInfo }) => {
const [updateGeneralInfo] = useAddOrUpdateGeneralInfo()
const isMissionFinished = useIsMissionFinished(missionId?.toString())

const timerRef = useRef<ReturnType<typeof setTimeout>>()
const [initValue, setInitValue] = useState<RecognizedVessel>()

Expand All @@ -30,17 +33,27 @@ const MissionRecognizedVessel: React.FC<MissionRecognizedVesselProps> = ({ missi
}

const updateRecognizedVessel = async (nbrOfRecognizedVessel?: number) => {
if (nbrOfRecognizedVessel === undefined || nbrOfRecognizedVessel === generalInfo?.nbrOfRecognizedVessel) return
const info = { ...generalInfo, missionId, nbrOfRecognizedVessel }
await updateGeneralInfo({
variables: { info }
})
}

const validateError = (isMissionFinished?: boolean, nbrOfRecognizedVessel?: number) =>
isMissionFinished && !nbrOfRecognizedVessel
? { nbrOfRecognizedVessel: 'Nombre total de navires reconnus dans les approches maritimes est requis' }
: undefined

return (
<>
{initValue && (
<Formik initialValues={initValue} onSubmit={handleSubmit} validateOnChange={true}>
<Formik
initialValues={initValue}
initialErrors={validateError(isMissionFinished, initValue.nbrOfRecognizedVessel)}
onSubmit={handleSubmit}
validateOnChange={true}
validate={values => validateError(isMissionFinished, values.nbrOfRecognizedVessel)}
>
<>
<FormikEffect onChange={handleSubmit} />
<FormikNumberInput
Expand All @@ -49,6 +62,7 @@ const MissionRecognizedVessel: React.FC<MissionRecognizedVesselProps> = ({ missi
name="nbrOfRecognizedVessel"
data-testid="mission-information-general-recognized-vessel"
label="Nombre total de navires reconnus dans les approches maritimes (ZEE)"
isErrorMessageHidden={true}
/>
</>
</Formik>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as usePatchModule from '@features/pam/mission/hooks/use-patch-mission-e
import { vi } from 'vitest'
import { fireEvent, render, screen, waitFor } from '../../../../../test-utils.tsx'
import MissionObservationByUnit from './mission-observations-unit.tsx'
import { THEME } from '@mtes-mct/monitor-ui'
import * as useIsMissionFinishedModule from '@features/pam/mission/hooks/use-is-mission-finished.tsx'

const patchMock = vi.fn()

Expand All @@ -17,48 +19,78 @@ describe('MissionObservation', () => {
it('should render observation', () => {
render(<MissionObservationByUnit missionId={1} observationsByUnit={'My beautiful observation'} />)
expect(patchMock).not.toHaveBeenCalled()
expect(screen.getByText(`Observation générale à l'échelle de la mission (remarques, résumé)`)).toBeInTheDocument()
const element = screen.getByLabelText("Observation générale à l'échelle de la mission (remarques, résumé)")
expect(element).toBeInTheDocument()
expect(screen.getByText('My beautiful observation')).toBeInTheDocument()
})

it('should call update observation', () => {
const wrapper = render(<MissionObservationByUnit missionId={1} observationsByUnit={'My beautiful observation'} />)
const element = wrapper.getByTestId('mission-general-observation')
fireEvent.change(element, {
target: { value: 'my new observations' }
describe('Validation', () => {
it('should show error validation when mission is finished but no observations ', () => {
vi.spyOn(useIsMissionFinishedModule, 'default').mockReturnValue(true)
render(<MissionObservationByUnit missionId={1} observationsByUnit={undefined} />)
const element = screen.getByLabelText("Observation générale à l'échelle de la mission (remarques, résumé)")
expect(getComputedStyle(element).borderColor).toBe(THEME.color.maximumRed.toLowerCase())
})
waitFor(() => {
expect(patchMock).toHaveBeenCalled()
it('should not show error validation when mission is finished but observations ', () => {
vi.spyOn(useIsMissionFinishedModule, 'default').mockReturnValue(true)
render(<MissionObservationByUnit missionId={1} observationsByUnit={'dummy'} />)
const element = screen.getByLabelText("Observation générale à l'échelle de la mission (remarques, résumé)")
expect(getComputedStyle(element).borderColor).not.toBe(THEME.color.maximumRed.toLowerCase())
})
})

it('should trigger 5 secondes after typing', () => {
vi.useFakeTimers({ shouldAdvanceTime: true })
const observationsByUnit = 'my observations!!!!!'
const wrapper = render(<MissionObservationByUnit missionId={1} observationsByUnit={'My beautiful observation'} />)
const element = wrapper.getByTestId('mission-general-observation')
fireEvent.change(element, {
target: { value: observationsByUnit }
it('should not show error validation when mission is not finished but observations ', () => {
vi.spyOn(useIsMissionFinishedModule, 'default').mockReturnValue(false)
render(<MissionObservationByUnit missionId={1} observationsByUnit={'dummy'} />)
const element = screen.getByLabelText("Observation générale à l'échelle de la mission (remarques, résumé)")
expect(getComputedStyle(element).borderColor).not.toBe(THEME.color.maximumRed.toLowerCase())
})
expect(patchMock).not.toHaveBeenCalled()
vi.advanceTimersByTime(5000)
expect(patchMock).toHaveBeenCalled()
expect(patchMock).toHaveBeenCalledWith({
variables: { mission: expect.objectContaining({ observationsByUnit }) }
it('should not show error validation when mission is not finished and no observations ', () => {
vi.spyOn(useIsMissionFinishedModule, 'default').mockReturnValue(false)
render(<MissionObservationByUnit missionId={1} observationsByUnit={undefined} />)
const element = screen.getByLabelText("Observation générale à l'échelle de la mission (remarques, résumé)")
expect(getComputedStyle(element).borderColor).not.toBe(THEME.color.maximumRed.toLowerCase())
})
})

it('should call update observations event empty', async () => {
vi.useFakeTimers({ shouldAdvanceTime: true })
const wrapper = render(<MissionObservationByUnit missionId={1} observationsByUnit={'My beautiful observation'} />)
const element = wrapper.getByTestId('mission-general-observation')
fireEvent.change(element, {
target: { value: '' }
describe('Updating the data', () => {
it('should call update observation on change event', () => {
const wrapper = render(<MissionObservationByUnit missionId={1} observationsByUnit={'My beautiful observation'} />)
const element = wrapper.getByTestId('mission-general-observation')
fireEvent.change(element, {
target: { value: 'my new observations' }
})
waitFor(() => {
expect(patchMock).toHaveBeenCalled()
})
})
vi.advanceTimersByTime(5000)
expect(patchMock).toHaveBeenCalled()
expect(patchMock).toHaveBeenCalledWith({
variables: { mission: expect.objectContaining({ observationsByUnit: '' }) }

it('should trigger 5 secondes after typing', () => {
vi.useFakeTimers({ shouldAdvanceTime: true })
const observationsByUnit = 'my observations!!!!!'
const wrapper = render(<MissionObservationByUnit missionId={1} observationsByUnit={'My beautiful observation'} />)
const element = wrapper.getByTestId('mission-general-observation')
fireEvent.change(element, {
target: { value: observationsByUnit }
})
expect(patchMock).not.toHaveBeenCalled()
vi.advanceTimersByTime(5000)
expect(patchMock).toHaveBeenCalled()
expect(patchMock).toHaveBeenCalledWith({
variables: { mission: expect.objectContaining({ observationsByUnit }) }
})
})

it('should call update observations event empty', async () => {
vi.useFakeTimers({ shouldAdvanceTime: true })
const wrapper = render(<MissionObservationByUnit missionId={1} observationsByUnit={'My beautiful observation'} />)
const element = wrapper.getByTestId('mission-general-observation')
fireEvent.change(element, {
target: { value: '' }
})
vi.advanceTimersByTime(5000)
expect(patchMock).toHaveBeenCalled()
expect(patchMock).toHaveBeenCalledWith({
variables: { mission: expect.objectContaining({ observationsByUnit: '' }) }
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { FormikEffect, FormikTextarea } from '@mtes-mct/monitor-ui'
import { Formik } from 'formik'
import React, { useEffect, useRef, useState } from 'react'
import usePatchMissionEnv from '../../hooks/use-patch-mission-env.tsx'
import useIsMissionFinished from '@features/pam/mission/hooks/use-is-mission-finished.tsx'

const DEBOUNCE_TIME_TRIGGER = 5000

Expand All @@ -16,6 +17,8 @@ interface MissionObservationsByUnitProps {

const MissionObservationsUnit: React.FC<MissionObservationsByUnitProps> = ({ missionId, observationsByUnit }) => {
const [patchMissionObservation] = usePatchMissionEnv()
const isMissionFinished = useIsMissionFinished(missionId?.toString())

const timerRef = useRef<ReturnType<typeof setTimeout>>()
const [initValue, setInitValue] = useState<ObservationsByUnit>()

Expand All @@ -40,10 +43,21 @@ const MissionObservationsUnit: React.FC<MissionObservationsByUnitProps> = ({ mis
})
}

const validateError = (isMissionFinished?: boolean, observations?: string) =>
isMissionFinished && !observations
? { observations: "L'observation générale de la mission est requise" }
: undefined

return (
<>
{initValue && (
<Formik initialValues={initValue} onSubmit={handleSubmit} validateOnChange={true}>
<Formik
initialValues={initValue}
initialErrors={validateError(isMissionFinished, initValue.observations)}
onSubmit={handleSubmit}
validateOnChange={true}
validate={values => validateError(isMissionFinished, values.observations)}
>
<>
<FormikEffect onChange={handleSubmit} />
<FormikTextarea
Expand All @@ -52,6 +66,7 @@ const MissionObservationsUnit: React.FC<MissionObservationsByUnitProps> = ({ mis
name="observations"
data-testid="mission-general-observation"
label="Observation générale à l'échelle de la mission (remarques, résumé)"
isErrorMessageHidden={true}
/>
</>
</Formik>
Expand Down

0 comments on commit a838b08

Please sign in to comment.