From 93f6d1bc2e19f574d341f64e672e531187743b95 Mon Sep 17 00:00:00 2001 From: lwih Date: Tue, 15 Oct 2024 13:05:44 +0200 Subject: [PATCH] fix(validation): show correct validation on ZEE and mission observation fields --- .../action-illegal-immigration-form.test.tsx | 6 +- .../mission-recognized-vessel.test.tsx | 65 +++++++++---- .../mission-recognized-vessel.tsx | 18 +++- .../mission-observation-unit.test.tsx | 96 ++++++++++++------- .../elements/mission-observations-unit.tsx | 17 +++- 5 files changed, 148 insertions(+), 54 deletions(-) diff --git a/frontend/src/features/pam/mission/components/elements/actions/action-illegal-immigration-form.test.tsx b/frontend/src/features/pam/mission/components/elements/actions/action-illegal-immigration-form.test.tsx index ba3e7284..8ae7542b 100644 --- a/frontend/src/features/pam/mission/components/elements/actions/action-illegal-immigration-form.test.tsx +++ b/frontend/src/features/pam/mission/components/elements/actions/action-illegal-immigration-form.test.tsx @@ -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() @@ -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() - expect(wrapper.getByRole('nbOfInterceptedVessels')).toHaveStyle(`border: 1px solid ${red};`) + expect(wrapper.getByRole('nbOfInterceptedVessels')).toHaveStyle( + `border: 1px solid ${THEME.color.maximumRed.toLowerCase()};` + ) }) }) diff --git a/frontend/src/features/pam/mission/components/elements/general-info/mission-recognized-vessel.test.tsx b/frontend/src/features/pam/mission/components/elements/general-info/mission-recognized-vessel.test.tsx index b0547fd3..a39589bf 100644 --- a/frontend/src/features/pam/mission/components/elements/general-info/mission-recognized-vessel.test.tsx +++ b/frontend/src/features/pam/mission/components/elements/general-info/mission-recognized-vessel.test.tsx @@ -4,6 +4,8 @@ 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, @@ -11,7 +13,7 @@ const info = { consumedGOInLiters: 0, consumedFuelInLiters: 0, serviceId: 5, - nbrOfRecognizedVessel: 0 + nbrOfRecognizedVessel: 5 } as MissionGeneralInfo const mutateMock = vi.fn() @@ -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( - - - - ) - 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() + 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() + 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() + 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() + 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( + + + + ) + 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 }) } + }) }) }) }) diff --git a/frontend/src/features/pam/mission/components/elements/general-info/mission-recognized-vessel.tsx b/frontend/src/features/pam/mission/components/elements/general-info/mission-recognized-vessel.tsx index 24aedc23..03f3a904 100644 --- a/frontend/src/features/pam/mission/components/elements/general-info/mission-recognized-vessel.tsx +++ b/frontend/src/features/pam/mission/components/elements/general-info/mission-recognized-vessel.tsx @@ -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 @@ -17,6 +18,8 @@ interface MissionRecognizedVesselProps { const MissionRecognizedVessel: React.FC = ({ missionId, generalInfo }) => { const [updateGeneralInfo] = useAddOrUpdateGeneralInfo() + const isMissionFinished = useIsMissionFinished(missionId?.toString()) + const timerRef = useRef>() const [initValue, setInitValue] = useState() @@ -30,17 +33,27 @@ const MissionRecognizedVessel: React.FC = ({ 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 && ( - + validateError(isMissionFinished, values.nbrOfRecognizedVessel)} + > <> = ({ missi name="nbrOfRecognizedVessel" data-testid="mission-information-general-recognized-vessel" label="Nombre total de navires reconnus dans les approches maritimes (ZEE)" + isErrorMessageHidden={true} /> diff --git a/frontend/src/features/pam/mission/components/elements/mission-observation-unit.test.tsx b/frontend/src/features/pam/mission/components/elements/mission-observation-unit.test.tsx index b78d3aaf..311cdf62 100644 --- a/frontend/src/features/pam/mission/components/elements/mission-observation-unit.test.tsx +++ b/frontend/src/features/pam/mission/components/elements/mission-observation-unit.test.tsx @@ -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() @@ -17,48 +19,78 @@ describe('MissionObservation', () => { it('should render observation', () => { render() 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() - 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() + 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() + 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() - 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() + 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() + 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() - 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() + 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() + 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() + 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: '' }) } + }) }) }) }) diff --git a/frontend/src/features/pam/mission/components/elements/mission-observations-unit.tsx b/frontend/src/features/pam/mission/components/elements/mission-observations-unit.tsx index 1f298a2e..bedcbcb9 100644 --- a/frontend/src/features/pam/mission/components/elements/mission-observations-unit.tsx +++ b/frontend/src/features/pam/mission/components/elements/mission-observations-unit.tsx @@ -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 @@ -16,6 +17,8 @@ interface MissionObservationsByUnitProps { const MissionObservationsUnit: React.FC = ({ missionId, observationsByUnit }) => { const [patchMissionObservation] = usePatchMissionEnv() + const isMissionFinished = useIsMissionFinished(missionId?.toString()) + const timerRef = useRef>() const [initValue, setInitValue] = useState() @@ -40,10 +43,21 @@ const MissionObservationsUnit: React.FC = ({ mis }) } + const validateError = (isMissionFinished?: boolean, observations?: string) => + isMissionFinished && !observations + ? { observations: "L'observation générale de la mission est requise" } + : undefined + return ( <> {initValue && ( - + validateError(isMissionFinished, values.observations)} + > <> = ({ mis name="observations" data-testid="mission-general-observation" label="Observation générale à l'échelle de la mission (remarques, résumé)" + isErrorMessageHidden={true} />