diff --git a/frontend/cypress/e2e/back_office/administration_list/filters.spec.ts b/frontend/cypress/e2e/back_office/administration_table/filters.spec.ts similarity index 94% rename from frontend/cypress/e2e/back_office/administration_list/filters.spec.ts rename to frontend/cypress/e2e/back_office/administration_table/filters.spec.ts index cd0da42f6..eba48f244 100644 --- a/frontend/cypress/e2e/back_office/administration_list/filters.spec.ts +++ b/frontend/cypress/e2e/back_office/administration_table/filters.spec.ts @@ -1,4 +1,4 @@ -context('Back Office > Administration List > Filters', () => { +context('Back Office > Administration Table > Filters', () => { beforeEach(() => { cy.intercept('GET', `/api/v1/administrations`).as('getAdministrations') diff --git a/frontend/cypress/e2e/back_office/administration_list/row_actions.spec.ts b/frontend/cypress/e2e/back_office/administration_table/row_actions.spec.ts similarity index 94% rename from frontend/cypress/e2e/back_office/administration_list/row_actions.spec.ts rename to frontend/cypress/e2e/back_office/administration_table/row_actions.spec.ts index 07576b1f2..480115e65 100644 --- a/frontend/cypress/e2e/back_office/administration_list/row_actions.spec.ts +++ b/frontend/cypress/e2e/back_office/administration_table/row_actions.spec.ts @@ -1,5 +1,5 @@ // Successful archiving and deleting use cases are tested in `administration_form.spec.ts` for Test Idempotency purpose -context('Back Office > Administration List > Row Actions', () => { +context('Back Office > Administration Table > Row Actions', () => { beforeEach(() => { cy.intercept('GET', `/api/v1/administrations`).as('getAdministrations') diff --git a/frontend/cypress/e2e/back_office/base_list/filters.spec.ts b/frontend/cypress/e2e/back_office/base_table/filters.spec.ts similarity index 92% rename from frontend/cypress/e2e/back_office/base_list/filters.spec.ts rename to frontend/cypress/e2e/back_office/base_table/filters.spec.ts index 8d722ace2..45f4956b8 100644 --- a/frontend/cypress/e2e/back_office/base_list/filters.spec.ts +++ b/frontend/cypress/e2e/back_office/base_table/filters.spec.ts @@ -1,4 +1,4 @@ -context('Back Office > Base List > Filters', () => { +context('Back Office > Base Table > Filters', () => { beforeEach(() => { cy.intercept('GET', `/api/v1/bases`).as('getBases') diff --git a/frontend/cypress/e2e/back_office/control_unit_list/filters.spec.ts b/frontend/cypress/e2e/back_office/control_unit_table/filters.spec.ts similarity index 96% rename from frontend/cypress/e2e/back_office/control_unit_list/filters.spec.ts rename to frontend/cypress/e2e/back_office/control_unit_table/filters.spec.ts index f3579f144..b0608f40c 100644 --- a/frontend/cypress/e2e/back_office/control_unit_list/filters.spec.ts +++ b/frontend/cypress/e2e/back_office/control_unit_table/filters.spec.ts @@ -1,4 +1,4 @@ -context('Back Office > Control Unit List > Filters', () => { +context('Back Office > Control Unit Table > Filters', () => { beforeEach(() => { cy.intercept('GET', `/api/v2/control_units`).as('getControlUnits') diff --git a/frontend/cypress/e2e/back_office/control_unit_list/row_actions.spec.ts b/frontend/cypress/e2e/back_office/control_unit_table/row_actions.spec.ts similarity index 92% rename from frontend/cypress/e2e/back_office/control_unit_list/row_actions.spec.ts rename to frontend/cypress/e2e/back_office/control_unit_table/row_actions.spec.ts index af7b5463d..3c4890c31 100644 --- a/frontend/cypress/e2e/back_office/control_unit_list/row_actions.spec.ts +++ b/frontend/cypress/e2e/back_office/control_unit_table/row_actions.spec.ts @@ -1,5 +1,5 @@ // Successful archiving and deleting use cases are tested in `control_unit_form.spec.ts` for Test Idempotency purpose -context('Back Office > Control Unit List > Row Actions', () => { +context('Back Office > Control Unit Table > Row Actions', () => { beforeEach(() => { cy.intercept('GET', `/api/v2/control_units`).as('getControlUnits') diff --git a/frontend/cypress/e2e/main_window/control_unit_dialog/contact_list.spec.ts b/frontend/cypress/e2e/main_window/control_unit_dialog/contact_list.spec.ts new file mode 100644 index 000000000..5495e9c86 --- /dev/null +++ b/frontend/cypress/e2e/main_window/control_unit_dialog/contact_list.spec.ts @@ -0,0 +1,98 @@ +import { gotToMainWindowAndOpenControlUnit } from './utils' + +context('Main Window > Control Unit Dialog > Contact List', () => { + beforeEach(() => { + gotToMainWindowAndOpenControlUnit(10000) + }) + + it('Should show all contacts by default', () => { + cy.contains('Contact 1').should('be.visible') + cy.contains('Contact 2').should('be.visible') + }) + + it('Should validate the form', () => { + cy.clickButton('Ajouter un contact') + + cy.clickButton('Ajouter') + + cy.contains('Veuillez choisir un nom.').should('be.visible') + cy.contains('Veuillez entrer un téléphone ou un email.').should('be.visible') + + cy.clickButton('Annuler') + + cy.get('p').contains('Ajouter un contact').should('not.exist') + }) + + it('Should add, edit and delete a contact', () => { + // ------------------------------------------------------------------------- + // Create + + cy.intercept('POST', `/api/v1/control_unit_contacts`).as('createControlUnitContact') + + cy.clickButton('Ajouter un contact') + + cy.fill('Nom du contact', 'Adjoint') + cy.fill('Numéro de téléphone', '0123456789') + cy.fill('Adresse mail', 'foo@example.org') + + cy.clickButton('Ajouter') + + cy.wait('@createControlUnitContact').then(interception => { + if (!interception.response) { + assert.fail('`interception.response` is undefined.') + } + + assert.deepInclude(interception.request.body, { + email: 'foo@example.org', + name: 'ADJUNCT', + phone: '0123456789' + }) + }) + + cy.get('p').contains('Ajouter un contact').should('not.exist') + cy.contains('Adjoint').should('be.visible') + + // ------------------------------------------------------------------------- + // Edit + + cy.intercept('PUT', `/api/v1/control_unit_contacts/4`).as('updateControlUnitContact') + + cy.getDataCy('ControlUnitDialog-control-unit-contact').filter('[data-id="4"]').clickButton('Éditer ce contact') + + cy.fill('Nom du contact', 'Passerelle') + cy.fill('Numéro de téléphone', '9876543210') + cy.fill('Adresse mail', 'bar@example.org') + + cy.clickButton('Enregistrer les modifications') + + cy.wait('@updateControlUnitContact').then(interception => { + if (!interception.response) { + assert.fail('`interception.response` is undefined.') + } + + assert.deepInclude(interception.request.body, { + email: 'bar@example.org', + id: 4, + name: 'BRIDGE', + phone: '9876543210' + }) + }) + + cy.get('p').contains('Éditer un contact').should('not.exist') + cy.contains('Enregistrer les modifications').should('not.exist') + cy.contains('Passerelle').should('be.visible') + + // ------------------------------------------------------------------------- + // Delete + + cy.intercept('DELETE', `/api/v1/control_unit_contacts/4`).as('deleteControlUnitContact') + + cy.getDataCy('ControlUnitDialog-control-unit-contact').filter('[data-id="4"]').clickButton('Éditer ce contact') + cy.clickButton('Supprimer ce contact') + cy.clickButton('Supprimer') + + cy.wait('@deleteControlUnitContact') + + cy.contains('Passerelle').should('not.exist') + }) +}) diff --git a/frontend/cypress/e2e/main_window/control_unit_dialog/form.spec.ts b/frontend/cypress/e2e/main_window/control_unit_dialog/form.spec.ts new file mode 100644 index 000000000..b49f650ce --- /dev/null +++ b/frontend/cypress/e2e/main_window/control_unit_dialog/form.spec.ts @@ -0,0 +1,57 @@ +import { gotToMainWindowAndOpenControlUnit } from './utils' + +context('Main Window > Control Unit Dialog > Resource List', () => { + beforeEach(() => { + gotToMainWindowAndOpenControlUnit(10000) + }) + + it('Should edit a control unit', () => { + cy.intercept('PUT', `/api/v2/control_units/10000`).as('updateControlUnit') + + // ------------------------------------------------------------------------- + // Terms note + + cy.getDataCy('ControlUnitDialog-termsNote').forceClick() + + cy.fill('Modalités de contact avec l’unité', 'Des modalités de contact avec l’unité.') + + cy.clickButton('Valider') + + cy.wait('@updateControlUnit').then(interception => { + if (!interception.response) { + assert.fail('`interception.response` is undefined.') + } + + assert.deepInclude(interception.request.body, { + id: 10000, + termsNote: 'Des modalités de contact avec l’unité.' + }) + }) + + cy.contains('Des modalités de contact avec l’unité.').should('be.visible') + cy.get('.Element-Button').contains('Valider').should('not.exist') + + // ------------------------------------------------------------------------- + // Area note + + cy.getDataCy('ControlUnitDialog-areaNote').forceClick() + + cy.fill('Secteur d’intervention', 'Un secteur d’intervention.') + + cy.clickButton('Valider') + + cy.wait('@updateControlUnit').then(interception => { + if (!interception.response) { + assert.fail('`interception.response` is undefined.') + } + + assert.deepInclude(interception.request.body, { + areaNote: 'Un secteur d’intervention.', + id: 10000 + }) + }) + + cy.contains('Un secteur d’intervention.').should('be.visible') + cy.get('.Element-Button').contains('Valider').should('not.exist') + }) +}) diff --git a/frontend/cypress/e2e/main_window/control_unit_dialog/resource_list.spec.ts b/frontend/cypress/e2e/main_window/control_unit_dialog/resource_list.spec.ts new file mode 100644 index 000000000..04f24edd9 --- /dev/null +++ b/frontend/cypress/e2e/main_window/control_unit_dialog/resource_list.spec.ts @@ -0,0 +1,103 @@ +import { gotToMainWindowAndOpenControlUnit } from './utils' + +context('Main Window > Control Unit Dialog > Resource List', () => { + beforeEach(() => { + gotToMainWindowAndOpenControlUnit(10000) + }) + + it('Should show all resources by default', () => { + cy.contains('Barge – Semi-rigide 1').should('be.visible') + cy.contains('Barge – Semi-rigide 2').should('be.visible') + }) + + it('Should validate the form', () => { + cy.clickButton('Ajouter un moyen') + + cy.clickButton('Ajouter') + + cy.contains('Veuillez choisir un type.').should('be.visible') + cy.contains('Veuillez choisir une base.').should('be.visible') + + cy.clickButton('Annuler') + + cy.get('p').contains('Ajouter un moyen').should('not.exist') + }) + + it('Should add, edit and delete a resource', () => { + // ------------------------------------------------------------------------- + // Create + + cy.intercept('POST', `/api/v1/control_unit_resources`).as('createControlUnitResource') + + cy.clickButton('Ajouter un moyen') + + cy.fill('Type de moyen', 'Avion') + // On ne met pas de nom de moyen ici + // pour tester que ce soit bien le type qui soit utilisé comme nom lorsque le nom est vide. + cy.fill('Base du moyen', 'Dunkerque') + cy.fill('Commentaire', 'Un commentaire sur le moyen.') + + cy.clickButton('Ajouter') + + cy.wait('@createControlUnitResource').then(interception => { + if (!interception.response) { + assert.fail('`interception.response` is undefined.') + } + + assert.deepInclude(interception.request.body, { + baseId: 3, + name: 'Avion', + note: 'Un commentaire sur le moyen.', + type: 'AIRPLANE' + }) + }) + + cy.get('p').contains('Ajouter un moyen').should('not.exist') + cy.contains('Avion – Avion').should('be.visible') + + // ------------------------------------------------------------------------- + // Edit + + cy.intercept('PUT', `/api/v1/control_unit_resources/13`).as('updateControlUnitResource') + + cy.getDataCy('ControlUnitDialog-control-unit-resource').filter('[data-id="13"]').clickButton('Éditer ce moyen') + + cy.fill('Type de moyen', 'Bâtiment de soutien') + cy.fill('Nom du moyen', 'Super Moyen') + cy.fill('Base du moyen', 'Saint-Malo') + cy.fill('Commentaire', 'Un autre commentaire sur le moyen.') + + cy.clickButton('Enregistrer les modifications') + + cy.wait('@updateControlUnitResource').then(interception => { + if (!interception.response) { + assert.fail('`interception.response` is undefined.') + } + + assert.deepInclude(interception.request.body, { + baseId: 2, + id: 13, + name: 'Super Moyen', + note: 'Un autre commentaire sur le moyen.', + type: 'SUPPORT_SHIP' + }) + }) + + cy.get('p').contains('Éditer un moyen').should('not.exist') + cy.contains('Enregistrer les modifications').should('not.exist') + cy.contains('Bâtiment de soutien – Super Moyen').should('be.visible') + + // ------------------------------------------------------------------------- + // Delete + + cy.intercept('DELETE', `/api/v1/control_unit_resources/13`).as('deleteControlUnitResource') + + cy.getDataCy('ControlUnitDialog-control-unit-resource').filter('[data-id="13"]').clickButton('Éditer ce moyen') + cy.clickButton('Supprimer ce moyen') + cy.clickButton('Supprimer') + + cy.wait('@deleteControlUnitResource') + + cy.contains('Bâtiment de soutien – Super Moyen').should('not.exist') + }) +}) diff --git a/frontend/cypress/e2e/main_window/control_unit_dialog/utils.ts b/frontend/cypress/e2e/main_window/control_unit_dialog/utils.ts new file mode 100644 index 000000000..57ba47355 --- /dev/null +++ b/frontend/cypress/e2e/main_window/control_unit_dialog/utils.ts @@ -0,0 +1,8 @@ +import { goToMainWindow } from '../utils' + +export function gotToMainWindowAndOpenControlUnit(controlUnitId: number) { + goToMainWindow() + + cy.clickButton('Liste des unités de contrôle') + cy.getDataCy('ControlUnitListDialog-control-unit').filter(`[data-id="${controlUnitId}"]`).forceClick().wait(250) +} diff --git a/frontend/cypress/e2e/main_window/control_unit_list/filters.spec.ts b/frontend/cypress/e2e/main_window/control_unit_list/filters.spec.ts deleted file mode 100644 index e16f19b34..000000000 --- a/frontend/cypress/e2e/main_window/control_unit_list/filters.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { FAKE_MAPBOX_RESPONSE } from '../../constants' - -context('Main Window > Control Unit List > Filters', () => { - beforeEach(() => { - cy.intercept('GET', 'https://api.mapbox.com/**', FAKE_MAPBOX_RESPONSE) - - cy.visit(`/`).wait(1000) - - cy.clickButton('Liste des unités de contrôle') - }) - - it('Should show all control units by default', () => { - cy.getDataCy('control-unit-list-item').should('have.length', 33) - }) - - it('Should find control units matching the search query', () => { - cy.fill('Rechercher une unité', 'marine') - - cy.getDataCy('control-unit-list-item').should('have.length', 4) - - cy.getDataCy('control-unit-10032').should('exist') - cy.getDataCy('control-unit-10023').should('exist') - }) - - it('Should find control units matching the selected administration', () => { - cy.fill('Administration', 'Douane') - - cy.getDataCy('control-unit-list-item').should('have.length', 5) - - cy.getDataCy('control-unit-10013').should('exist') - cy.getDataCy('control-unit-10017').should('exist') - }) - - it('Should find control units matching the selected resource type', () => { - cy.fill('Type de moyen', 'Barge') - - cy.getDataCy('control-unit-list-item').should('have.length', 3) - - cy.getDataCy('control-unit-10000').should('exist') - cy.getDataCy('control-unit-10003').should('exist') - }) - - it('Should find control units matching the selected base', () => { - cy.fill('Base du moyen', 'Marseille') - - cy.getDataCy('control-unit-list-item').should('have.length', 1) - - cy.getDataCy('control-unit-10000').should('exist') - }) -}) diff --git a/frontend/cypress/e2e/main_window/control_unit_list_dialog/filters.spec.ts b/frontend/cypress/e2e/main_window/control_unit_list_dialog/filters.spec.ts new file mode 100644 index 000000000..a7b8d2b99 --- /dev/null +++ b/frontend/cypress/e2e/main_window/control_unit_list_dialog/filters.spec.ts @@ -0,0 +1,53 @@ +import { FAKE_MAPBOX_RESPONSE } from '../../constants' + +context('Main Window > Control Unit List Dialog > Filters', () => { + beforeEach(() => { + cy.intercept('GET', 'https://api.mapbox.com/**', FAKE_MAPBOX_RESPONSE) + + cy.visit(`/`).wait(1000) + + cy.clickButton('Liste des unités de contrôle') + }) + + it('Should show all control units by default', () => { + cy.getDataCy('ControlUnitListDialog-control-unit').should('have.length', 33) + + cy.contains('A636 Maïto').should('exist') + cy.contains('SML 50').should('exist') + }) + + it('Should find control units matching the search query', () => { + cy.fill('Rechercher une unité', 'marine') + + cy.getDataCy('ControlUnitListDialog-control-unit').should('have.length', 4) + + cy.contains('Cultures marines – DDTM 30').should('exist') + cy.contains('A636 Maïto').should('exist') + }) + + it('Should find control units matching the selected administration', () => { + cy.fill('Administration', 'Douane') + + cy.getDataCy('ControlUnitListDialog-control-unit').should('have.length', 5) + + cy.contains('BGC Ajaccio').should('exist') + cy.contains('DF 61 Port-de-Bouc').should('exist') + }) + + it('Should find control units matching the selected resource type', () => { + cy.fill('Type de moyen', 'Barge') + + cy.getDataCy('ControlUnitListDialog-control-unit').should('have.length', 3) + + cy.contains('Cultures marines – DDTM 40').should('exist') + cy.contains('DPM – DDTM 14').should('exist') + }) + + it('Should find control units matching the selected base', () => { + cy.fill('Base du moyen', 'Marseille') + + cy.getDataCy('ControlUnitListDialog-control-unit').should('have.length', 1) + + cy.contains('Cultures marines – DDTM 40').should('exist') + }) +}) diff --git a/frontend/cypress/e2e/main_window/utils.ts b/frontend/cypress/e2e/main_window/utils.ts new file mode 100644 index 000000000..78e9173f2 --- /dev/null +++ b/frontend/cypress/e2e/main_window/utils.ts @@ -0,0 +1,7 @@ +import { FAKE_MAPBOX_RESPONSE } from '../constants' + +export function goToMainWindow() { + cy.intercept('GET', 'https://api.mapbox.com/**', FAKE_MAPBOX_RESPONSE) + + cy.visit(`/`).wait(1000) +} diff --git a/frontend/src/features/ControlUnit/components/ControlUnitDialog/ControlUnitContactList/Form.tsx b/frontend/src/features/ControlUnit/components/ControlUnitDialog/ControlUnitContactList/Form.tsx index 69080f9d4..a5f7cd087 100644 --- a/frontend/src/features/ControlUnit/components/ControlUnitDialog/ControlUnitContactList/Form.tsx +++ b/frontend/src/features/ControlUnit/components/ControlUnitDialog/ControlUnitContactList/Form.tsx @@ -46,11 +46,13 @@ export function Form({ initialValues, isNew, onCancel, onSubmit }: FormProps) { key={key} initialValues={initialValues} onSubmit={onSubmit} + validateOnBlur={false} + validateOnChange={false} validationSchema={CONTROL_UNIT_CONTACT_FORM_SCHEMA} > {({ handleSubmit }) => ( <> - Ajouter un contact + {isNew ? 'Ajouter un contact' : 'Éditer un contact'} diff --git a/frontend/src/features/ControlUnit/components/ControlUnitDialog/ControlUnitContactList/FormikNameSelect.tsx b/frontend/src/features/ControlUnit/components/ControlUnitDialog/ControlUnitContactList/FormikNameSelect.tsx index 038895cf6..fc710171e 100644 --- a/frontend/src/features/ControlUnit/components/ControlUnitDialog/ControlUnitContactList/FormikNameSelect.tsx +++ b/frontend/src/features/ControlUnit/components/ControlUnitDialog/ControlUnitContactList/FormikNameSelect.tsx @@ -1,14 +1,29 @@ -import { FormikTextInput, Select } from '@mtes-mct/monitor-ui' +import { Accent, FormikTextInput, Icon, IconButton, Select } from '@mtes-mct/monitor-ui' import { useField } from 'formik' import { useCallback, useEffect, useState } from 'react' +import styled from 'styled-components' import { CONTROL_UNIT_CONTACT_NAMES, CONTROL_UNIT_CONTACT_NAMES_AS_OPTIONS } from './constants' +import { ControlUnit } from '../../../../../domain/entities/controlUnit' export function FormikNameSelect() { - const [isCustomName, setIsCustomName] = useState(false) - const [field, meta, helpers] = useField('name') + const [isCustomName, setIsCustomName] = useState( + !!field.value && !ControlUnit.ControlUnitContactName[field.value] + ) + + const cancelCustomName = useCallback( + () => { + setIsCustomName(false) + helpers.setValue(undefined) + }, + + // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering + // eslint-disable-next-line react-hooks/exhaustive-deps + [] + ) + const handleChange = useCallback( (nextName: string | undefined) => { if (nextName === 'SWITCH_TO_CUSTOM_NAME') { @@ -32,7 +47,10 @@ export function FormikNameSelect() { }, [field.value, isCustomName]) return isCustomName ? ( - + + + + ) : (