Skip to content
Draft
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const ListElementComponent = ({
'op-suggestion--selected': isSelected,
'op-suggestion--name-hovered': isNameHovered,
})}
data-testid={'op-suggestion'}
role="button"
tabIndex={0}
onMouseDown={(e) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,9 +544,14 @@ const ItineraryModal = ({

return (
<dialog ref={modalRef} className="itinerary-modal" data-testid="itinerary-modal">
<div className="itinerary-modal-form" onClick={handleOutsideMapClick} role="presentation">
<div
className="itinerary-modal-form"
data-testid="itinerary-modal-form"
onClick={handleOutsideMapClick}
role="presentation"
>
{mapSelectionStepId && <div className="map-selection-form-overlay" />}
<div className="itinerary-modal-form-header">
<div className="itinerary-modal-form-header" data-testid="itinerary-modal-form-header">
<ItineraryModalFormHeader
modalFormState={modalFormState}
onModalFormStateChange={setModalFormState}
Expand All @@ -558,7 +563,7 @@ const ItineraryModal = ({
isNameEmpty={isNameEmpty}
/>
</div>
<div className="itinerary-modal-form-body">
<div className="itinerary-modal-form-body" data-testid="itinerary-modal-form-body">
{categoryWarning && <Banner message={categoryWarning} closeable />}
{rollingStockMessage && <Banner type="info" message={rollingStockMessage} />}
{hasInvalidPathStepDisplay && (
Expand Down Expand Up @@ -623,13 +628,15 @@ const ItineraryModal = ({

<div
className="path-step-gap-hitbox"
data-testId="path-step-gap"
onPointerEnter={() => setHoveredGapIndex(i)}
onPointerLeave={() => setHoveredGapIndex(null)}
>
{hoveredGapIndex === i && (
<button
type="button"
className="add-pathitem"
data-testId="add-path-step-button"
onClick={() => handleAddIntermediateStep(i)}
>
<Plus iconColor="var(--white100)" />
Expand Down Expand Up @@ -754,21 +761,28 @@ const ItineraryModal = ({
})}
</div>
</div>
<div className="itinerary-modal-form-footer">
<div className="itinerary-modal-form-footer" data-testid="itinerary-modal-form-footer">
<Button
label={t('cancel')}
variant="Cancel"
size="medium"
onClick={closeModal}
dataTestID="close-itinerary-modal"
/>
<Button label={t('next')} variant="Primary" size="medium" onClick={submitItinerary} />
<Button
label={t('next')}
variant="Primary"
size="medium"
onClick={submitItinerary}
dataTestID="itinerary-modal-next-button"
/>
</div>
</div>
<div
className={cx('itinerary-modal-map', {
'map-selection-active': mapSelectionStepId !== null,
})}
data-testid="itinerary-modal-map"
>
<ItineraryModalMap
pathSteps={pathSteps}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ const ItineraryModalFormHeader = ({
getOptionLabel={(option) => option.label}
getOptionValue={(option) => option.id}
onChange={handleCategoryChange}
data-testid="itinerary-modal-category"
></Select>
</div>
</div>
Expand All @@ -195,6 +196,7 @@ const ItineraryModalFormHeader = ({
onSelectSuggestion={handleRollingStockSelect}
resetSuggestions={resetRollingStockSuggestions}
onChange={handleRollingStockInputChange}
data-testid="itinerary-modal-rolling-stock"
/>
</div>
<div className="composition-code-select">
Expand All @@ -212,13 +214,15 @@ const ItineraryModalFormHeader = ({
speedLimitTag: e,
});
}}
data-testid="itinerary-modal-composition-code"
></Select>
</div>
<div className="train-name-input">
<Input
narrow
small
id="itinerary-modal-train-schedule-name"
data-testid="itinerary-modal-train-name"
label={t('itineraryModal.trainName')}
value={modalFormState.name}
title={modalFormState.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ const ItineraryModalMap = ({
<PathStepMarker
key={step.id}
id={step.id}
testId="path-step-marker"
markerIndicator={(index + 1).toString()}
name={name}
coordinates={coordinates}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,11 @@ const PathStepItem = ({
onDelete();
}}
>
<span className="counter">{!isTrailingPlaceHolder && index}</span>
<span className="counter" data-testId="path-step-counter">
{!isTrailingPlaceHolder && index}
</span>
{!isOnlyStep && (
<span className="remove-path-step-icon">
<span className="remove-path-step-icon" data-testid="delete-path-step-button">
<X />
</span>
)}
Expand Down Expand Up @@ -371,6 +373,7 @@ const PathStepItem = ({
>
<ComboBox
id={`pathStep-name-${pathStep.id}`}
data-testid="combo-box"
value={comboBoxValue}
numberOfSuggestionsToShow={numberOfSuggestionsToShow}
suggestions={visibleSuggestions}
Expand Down Expand Up @@ -466,6 +469,7 @@ const PathStepItem = ({
onChange={(option) => onTrackNameChange(option?.label ?? '')}
small
narrow
data-testid="track-name"
/>
</div>
)}
Expand All @@ -481,6 +485,7 @@ const PathStepItem = ({
toggleType(option);
}}
small
data-testid="stop-pass-segmented-control"
/>
<div className="map-interactions">
<button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ const ManageTrainScheduleLeftPanel = ({
className="scenario-timetable-manage-train-schedule-body"
role="button"
tabIndex={0}
data-testid="open-itinerary-modal-button"
onClick={() => setItineraryModalIsOpen(true)}
>
<button
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import type { Infra, Project, Scenario, Study } from 'common/api/osrdEditoastApi';

import test from '../../page-object-fixture';
import { waitForInfraStateToBeCached } from '../../utils';
import { getInfra } from '../../utils/api-utils';
import createScenario from '../../utils/scenario';
import { deleteScenario } from '../../utils/teardown-utils';

test.describe('Itinerary Modal, Default ', () => {
let project: Project;

let study: Study;

let scenario: Scenario;

let infra: Infra;

test.beforeAll('Fetch infrastructure', async () => {
infra = await getInfra();
});

test.beforeEach(
'Navigate to scenario page and wait for infrastructure to be loaded',

async ({ page, operationalStudiesPage }) => {
({ project, study, scenario } = await createScenario());

await page.goto(
`/operational-studies/projects/${project.id}/studies/${study.id}/scenarios/${scenario.id}`
);

await waitForInfraStateToBeCached(infra.id);
await operationalStudiesPage.openItineraryModal();
}
);

test.afterEach('Delete the created scenario', async () => {
await deleteScenario(study.id, scenario.name);
});

/** *************** Test 1 **************** */
test('Display the itinerary modal default structure', async ({ itineraryModalPage }) => {
await test.step('Empty default state of the itinerary modal', async () => {
await itineraryModalPage.checkItineraryModalDefaultState();
});
await test.step('Check the header content of the itinerary modal', async () => {
await itineraryModalPage.checkItineraryModalHeader();
});
await test.step('Default rocket search', async () => {
await itineraryModalPage.checkItineraryModalEmptyRocket();
});
await test.step('Default itinerary row content', async () => {
await itineraryModalPage.checkItineraryModalDefaultRowContent();
});
});

/** *************** Test 2 **************** */

test('Add and remove empty itinerary rows', async ({ itineraryModalPage }) => {
await test.step('Add itinerary rows', async () => {
await itineraryModalPage.addItineraryRows();
});
await test.step('Check trailing placeholder', async () => {
await itineraryModalPage.checkTrailingPlaceholder();
});
await test.step('Delete numbered rows', async () => {
await itineraryModalPage.deleteNumberedRows();
});
});

/** *************** Test 3 **************** */

test('Create a train with rocket pathfinding', async ({ itineraryModalPage }) => {
await test.step('Create a train', async () => {
await itineraryModalPage.selectRollingStock();
});
await test.step('Launch rocket search', async () => {
await itineraryModalPage.launchRocketSearch();
});
await test.step('Check itinerary rows created after rocket search', async () => {
await itineraryModalPage.checkRowsCreationAfterRocketSearch();
});
await test.step('Check path step marker presence on map', async () => {
await itineraryModalPage.checkMapUpdate(2);
});
await test.step('Check itinerary reverse', async () => {
await itineraryModalPage.checkItineraryReverse();
});
await test.step('Check track selection and stops update', async () => {
await itineraryModalPage.checkTrackSelectionAndStopsUpdate();
});
await test.step('Create a train and verify presence in the timetable', async () => {
await itineraryModalPage.createTrain();
await itineraryModalPage.checkTrainPresenceInTimetable('Test train');
});
});

/** *************** Test 4 **************** */

test(
'Create a train by filling the itinerary form manually',
{ tag: '@smoke' },
async ({ itineraryModalPage }) => {
await test.step('Select rolling stock and check its category ', async () => {
await itineraryModalPage.selectRollingStock();
});

await test.step('Search operational point by name and check suggestions list', async () => {
await itineraryModalPage.fillFirstPathStepByName();
});

await test.step('Select first operational point from suggestions and check its value', async () => {
await itineraryModalPage.selectFirstOpSuggestion();
await itineraryModalPage.checkPathStepValue(1, 'West_station BV');
});

await test.step('Search for second operational point by trigram and check suggestions list', async () => {
await itineraryModalPage.fillSecondPathStepByTrigram();
});

await test.step('Select second operational point from suggestions and check its value', async () => {
await itineraryModalPage.selectFirstOpSuggestion();
await itineraryModalPage.checkPathStepValue(2, 'South_station BV');
});

await test.step('Insert an intermediate operational point between the two existing steps', async () => {
await itineraryModalPage.insertIntermediatePathStep();
});

await test.step('Check track selection and stops update', async () => {
await itineraryModalPage.checkTrackSelectionAndStopsUpdate();
});

await test.step('Check valid pathfinding result and itinerary displayed on map', async () => {
await itineraryModalPage.checkMapUpdate(3);
});
await test.step('Create a train and verify presence in the timetable', async () => {
await itineraryModalPage.createTrain();
await itineraryModalPage.checkTrainPresenceInTimetable('Test train');
});
}
);
});
Loading
Loading