Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(validation): show correct validation on ZEE and mission observati… #399

Merged
merged 1 commit into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading