Skip to content

Commit d56137c

Browse files
committed
front: add e2e tests for add paced train feature
Signed-off-by: SharglutDev <[email protected]>
1 parent 0be3a36 commit d56137c

File tree

9 files changed

+261
-23
lines changed

9 files changed

+261
-23
lines changed

front/src/common/BootstrapSNCF/ModalSNCF/ModalHeaderSNCF.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ const ModalHeaderSNCF = ({
1919
<div className="modal-header">
2020
{children}
2121
{withCloseButton && (
22-
<button type="button" className="close" aria-label="Close" onClick={closeModal}>
22+
<button
23+
data-testid="modal-close-button"
24+
type="button"
25+
className="close"
26+
aria-label="Close"
27+
onClick={closeModal}
28+
>
2329
<span aria-hidden="true">&times;</span>
2430
</button>
2531
)}

front/src/common/Tabs.tsx

+4-5
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,10 @@ const Tabs = ({ tabs, pills = false, fullWidth = false, fullHeight = false }: Ta
4141
{tabs.map((tab, index) => (
4242
<div
4343
data-testid={`tab-${tab.id}`}
44-
className={cx(
45-
'tab',
46-
index === activeTabIndex && 'active',
47-
tab.withWarning && 'warning'
48-
)}
44+
className={cx('tab', {
45+
active: index === activeTabIndex,
46+
warning: tab.withWarning,
47+
})}
4948
key={`tab-${tab.label}-${index}}`}
5049
role="button"
5150
tabIndex={0}

front/src/common/UserSettings.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ const UserSettings = () => {
6565
<SwitchSNCF
6666
id="paced-train-switch"
6767
type="switch"
68-
name={t('operationalStudies/scenario:pacedTrain.pacedTrain')}
68+
name="paced-train-switch"
6969
checked={userPreferences.showPacedTrains}
7070
onChange={() =>
7171
dispatch(

front/src/modules/trainschedule/components/ManageTrainSchedule/AddTrainScheduleButton.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ const AddTrainScheduleButton = ({
114114
type="button"
115115
disabled={infraState !== 'CACHED'}
116116
onClick={createTrainSchedules}
117-
data-testid="add-train-schedules"
117+
data-testid="add-train"
118118
>
119119
<span className="mr-2">
120120
<Plus size="lg" />

front/src/modules/trainschedule/components/ManageTrainSchedule/TrainSettings.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export default function TrainSettings() {
8787
<span className="text-nowrap">{t('trainScheduleName')}</span>
8888
</>
8989
}
90-
id="trainSchedule-name"
90+
id="train-name"
9191
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setName(e.target.value)}
9292
value={name}
9393
isInvalid={isInvalidTrainScheduleName}
@@ -107,7 +107,7 @@ export default function TrainSettings() {
107107
<small className="text-nowrap">{t('trainScheduleDepartureTime')}</small>
108108
</>
109109
}
110-
id="trainSchedule-startTime"
110+
id="train-start-time"
111111
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setStartTime(e.target.value)}
112112
value={startTime}
113113
isInvalid={!startTime}
@@ -124,7 +124,7 @@ export default function TrainSettings() {
124124
<small className="text-nowrap">{t('trainScheduleInitialSpeed')}</small>
125125
</>
126126
}
127-
id="trainSchedule-initialSpeed"
127+
id="train-initial-speed"
128128
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setInitialSpeed(+e.target.value)}
129129
value={initialSpeed}
130130
min={0}

front/tests/005-operational-studies.spec.ts

+66-4
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,27 @@ import type {
88
Study,
99
} from 'common/api/osrdEditoastApi';
1010

11-
import { electricRollingStockName } from './assets/project-const';
11+
import { NEW_PACED_TRAIN_SETTINGS } from './assets/operational-studies-const';
12+
import { dualModeRollingStockName, electricRollingStockName } from './assets/project-const';
1213
import test from './logging-fixture';
1314
import RoutePage from './pages/op-route-page-model';
1415
import OperationalStudiesPage from './pages/operational-studies-page-model';
1516
import RollingStockSelectorPage from './pages/rollingstock-selector-page-model';
16-
import { waitForInfraStateToBeCached } from './utils';
17+
import { getTranslations, waitForInfraStateToBeCached } from './utils';
1718
import { getInfra, getRollingStock } from './utils/api-setup';
19+
import readJsonFile from './utils/file-utils';
1820
import createScenario from './utils/scenario';
1921
import { deleteScenario } from './utils/teardown-utils';
22+
import type { ManageTrainScheduleTranslations } from './utils/types';
2023

21-
test.describe('Verify simulation configuration in operational studies', () => {
24+
const enTranslations: ManageTrainScheduleTranslations = readJsonFile(
25+
'public/locales/en/operationalStudies/manageTrainSchedule.json'
26+
);
27+
const frTranslations: ManageTrainScheduleTranslations = readJsonFile(
28+
'public/locales/fr/operationalStudies/manageTrainSchedule.json'
29+
);
30+
31+
test.describe('Verify simulation configuration in operational studies for train schedules and paced trains', () => {
2232
test.slow();
2333

2434
let rollingstockPage: RollingStockSelectorPage;
@@ -29,10 +39,15 @@ test.describe('Verify simulation configuration in operational studies', () => {
2939
let scenario: Scenario;
3040
let infra: Infra;
3141
let rollingStock: LightRollingStock;
42+
let translations: ManageTrainScheduleTranslations;
3243

33-
test.beforeAll('Fetch rolling stock and infrastructure ', async () => {
44+
test.beforeAll('Fetch infrastructure and get translations', async () => {
3445
rollingStock = await getRollingStock(electricRollingStockName);
3546
infra = await getInfra();
47+
translations = getTranslations({
48+
en: enTranslations,
49+
fr: frTranslations,
50+
});
3651
});
3752

3853
test.beforeEach('Set up the project, study, and scenario', async ({ page }) => {
@@ -50,6 +65,53 @@ test.describe('Verify simulation configuration in operational studies', () => {
5065
});
5166

5267
/** *************** Test **************** */
68+
test('Add a paced train', async ({ page }) => {
69+
// Navigate to the scenario page for the given project and study
70+
await page.goto(
71+
`/operational-studies/projects/${project.id}/studies/${study.id}/scenarios/${scenario.id}`
72+
);
73+
74+
await operationalStudiesPage.checkPacedTrainSwitch();
75+
76+
// Wait for infra to be in 'CACHED' state before proceeding
77+
await waitForInfraStateToBeCached(infra.id);
78+
79+
// Click the button to add a train schedule or paced train
80+
await operationalStudiesPage.clickOnAddTrainButton();
81+
82+
// Verify that all configuration buttons and inputs are visible and have their proper default values
83+
await operationalStudiesPage.checkInputsAndButtons(translations, scenario.creation_date);
84+
85+
// Verify that all tabs are visible and their default behavior is correct
86+
await operationalStudiesPage.checkTabs();
87+
88+
// Check the define paced train checkbox
89+
await operationalStudiesPage.checkPacedTrainModeAndVerifyInputs(translations);
90+
91+
// Test the paced train mode behavior
92+
await operationalStudiesPage.testPacedTrainMode(translations);
93+
94+
// Set the paced train inputs
95+
await operationalStudiesPage.fillPacedTrainSettings(NEW_PACED_TRAIN_SETTINGS);
96+
97+
// Select a rolling stock
98+
await rollingstockPage.selectRollingStock(dualModeRollingStockName);
99+
100+
// Select an itinerary
101+
await operationalStudiesPage.clickOnRouteTab();
102+
await routePage.performPathfindingByTrigram('MWS', 'NES');
103+
await operationalStudiesPage.checkPathfindingDistance('33.950 km');
104+
105+
// TODO : update this part when paced train endpoints are delivered to find a fine configuration for it
106+
// Change some time and stops
107+
108+
// Adding Train Schedule
109+
await operationalStudiesPage.addTrainSchedule();
110+
111+
// TODO : update the test to verify the newly added paced train (for now nothing happens when clicking on the button)
112+
});
113+
114+
// TODO Paced train : Remove this test in https://github.com/OpenRailAssociation/osrd/issues/10791
53115
test('Pathfinding with rolling stock and composition code', async ({ page }) => {
54116
// Page models
55117

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { PacedTrainSettings } from '../utils/types';
2+
3+
export const DEFAULT_PACED_TRAIN_SETTINGS: Pick<
4+
PacedTrainSettings,
5+
'timeRangeDuration' | 'cadence'
6+
> = {
7+
timeRangeDuration: '120',
8+
cadence: '60',
9+
};
10+
11+
export const PACED_TRAIN_SETTINGS_TEST: Pick<PacedTrainSettings, 'timeRangeDuration' | 'cadence'> =
12+
{
13+
timeRangeDuration: '180',
14+
cadence: '30',
15+
};
16+
17+
export const NEW_PACED_TRAIN_SETTINGS: PacedTrainSettings = {
18+
name: 'Paced train test',
19+
startTime: '08:35:40',
20+
timeRangeDuration: '150',
21+
cadence: '20',
22+
};

front/tests/pages/operational-studies-page-model.ts

+146-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { expect, type Locator, type Page } from '@playwright/test';
22

33
import CommonPage from './common-page-model';
4+
import {
5+
DEFAULT_PACED_TRAIN_SETTINGS,
6+
PACED_TRAIN_SETTINGS_TEST,
7+
} from '../assets/operational-studies-const';
48
import readJsonFile from '../utils/file-utils';
9+
import type { ManageTrainScheduleTranslations, PacedTrainSettings } from '../utils/types';
510

611
const manageTrainScheduleTranslation: { trainAdded: string } = readJsonFile(
712
'public/locales/fr/operationalStudies/manageTrainSchedule.json'
@@ -24,9 +29,29 @@ class OperationalStudiesPage extends CommonPage {
2429

2530
private readonly trainCountInput: Locator;
2631

27-
private readonly trainScheduleNameInput: Locator;
32+
private readonly operationStudiesSettings: Locator;
2833

29-
private readonly addTrainScheduleButton: Locator;
34+
private readonly userSettings: Locator;
35+
36+
private readonly modalCloseButton: Locator;
37+
38+
private readonly pacedTrainSwitch: Locator;
39+
40+
private readonly definePacedTrainCheckbox: Locator;
41+
42+
private readonly definePacedTrainCheckboxLabel: Locator;
43+
44+
private readonly pacedTrainTimeRangeDurationInput: Locator;
45+
46+
private readonly pacedTrainCadenceInput: Locator;
47+
48+
private readonly trainNameInput: Locator;
49+
50+
private readonly trainInitialSpeedInput: Locator;
51+
52+
private readonly trainTagsInput: Locator;
53+
54+
private readonly addTrainButton: Locator;
3055

3156
private readonly trainTimetable: Locator;
3257

@@ -42,11 +67,21 @@ class OperationalStudiesPage extends CommonPage {
4267
this.routeTab = page.getByTestId('tab-pathfinding');
4368
this.simulationSettingsTab = page.getByTestId('tab-simulation-settings');
4469
this.timesAndStopsTab = page.getByTestId('tab-timesStops');
45-
this.startTimeField = page.locator('#trainSchedule-startTime');
70+
this.startTimeField = page.locator('#train-start-time');
4671
this.returnSimulationResultButton = page.getByTestId('return-simulation-result');
4772
this.trainCountInput = page.locator('#osrdconf-traincount');
48-
this.addTrainScheduleButton = page.getByTestId('add-train-schedules');
49-
this.trainScheduleNameInput = page.locator('#trainSchedule-name');
73+
this.operationStudiesSettings = page.getByTestId('dropdown-sncf');
74+
this.userSettings = page.getByTestId('user-settings-btn');
75+
this.modalCloseButton = page.getByTestId('modal-close-button');
76+
this.pacedTrainSwitch = page.getByTestId('paced-train-switch');
77+
this.definePacedTrainCheckbox = page.locator('#define-paced-train');
78+
this.definePacedTrainCheckboxLabel = page.locator('label[for="define-paced-train"]');
79+
this.pacedTrainTimeRangeDurationInput = page.locator('#paced-train-time-range-duration');
80+
this.pacedTrainCadenceInput = page.locator('#paced-train-cadence');
81+
this.addTrainButton = page.getByTestId('add-train');
82+
this.trainNameInput = page.locator('#train-name');
83+
this.trainInitialSpeedInput = page.locator('#train-initial-speed');
84+
this.trainTagsInput = page.getByTestId('chips-input');
5085

5186
this.trainTimetable = page
5287
.locator('.scenario-timetable-trains')
@@ -118,14 +153,117 @@ class OperationalStudiesPage extends CommonPage {
118153
await this.trainCountInput.fill(trainCount);
119154
}
120155

156+
// TODO Paced train : remove this (and all related locator and data-testid) in https://github.com/OpenRailAssociation/osrd/issues/10791
157+
async checkPacedTrainSwitch() {
158+
await expect(this.operationStudiesSettings).toBeVisible();
159+
await this.operationStudiesSettings.click();
160+
161+
await expect(this.userSettings).toBeVisible();
162+
await this.userSettings.click();
163+
164+
await expect(this.pacedTrainSwitch).toBeVisible();
165+
await expect(this.pacedTrainSwitch).not.toBeChecked();
166+
await this.pacedTrainSwitch.click();
167+
await expect(this.pacedTrainSwitch).toBeChecked();
168+
169+
await this.modalCloseButton.click();
170+
}
171+
172+
async checkInputsAndButtons(translations: ManageTrainScheduleTranslations, date: string) {
173+
await expect(this.addTrainButton).toBeVisible();
174+
await expect(this.addTrainButton).toHaveText(translations.addTrainSchedule);
175+
await expect(this.definePacedTrainCheckboxLabel).toBeVisible();
176+
await expect(this.definePacedTrainCheckboxLabel).toHaveText(
177+
translations.pacedTrains.defineService
178+
);
179+
await expect(this.definePacedTrainCheckbox).not.toBeChecked();
180+
await expect(this.returnSimulationResultButton).toBeVisible();
181+
await expect(this.trainNameInput).toBeVisible();
182+
183+
await expect(this.startTimeField).toBeVisible();
184+
const startTimeDate = new Date(await this.startTimeField.inputValue());
185+
const scenarioCreationDate = new Date(date);
186+
const isSameDate =
187+
startTimeDate.getFullYear() === scenarioCreationDate.getFullYear() &&
188+
startTimeDate.getMonth() === scenarioCreationDate.getMonth() &&
189+
startTimeDate.getDate() === scenarioCreationDate.getDate();
190+
expect(isSameDate).toBe(true);
191+
192+
await expect(this.trainInitialSpeedInput).toBeVisible();
193+
await expect(this.trainInitialSpeedInput).toHaveValue('0');
194+
195+
await expect(this.trainTagsInput).toBeVisible();
196+
}
197+
198+
async checkTabs() {
199+
await expect(this.rollingStockTab).toBeVisible();
200+
await expect(this.routeTab).toBeVisible();
201+
await expect(this.timesAndStopsTab).toBeVisible();
202+
await expect(this.simulationSettingsTab).toBeVisible();
203+
204+
await expect(this.rollingStockTab).toHaveClass(/active/);
205+
await this.verifyTabWarningPresence();
206+
}
207+
208+
async checkPacedTrainModeAndVerifyInputs(translations: ManageTrainScheduleTranslations) {
209+
await this.definePacedTrainCheckboxLabel.click();
210+
await expect(this.addTrainButton).toHaveText(translations.addPacedTrain);
211+
await expect(this.pacedTrainTimeRangeDurationInput).toBeVisible();
212+
await expect(this.pacedTrainTimeRangeDurationInput).toHaveValue(
213+
DEFAULT_PACED_TRAIN_SETTINGS.timeRangeDuration
214+
);
215+
await expect(this.pacedTrainCadenceInput).toBeVisible();
216+
await expect(this.pacedTrainCadenceInput).toHaveValue(DEFAULT_PACED_TRAIN_SETTINGS.cadence);
217+
}
218+
219+
async testPacedTrainMode(translations: ManageTrainScheduleTranslations) {
220+
await this.setTimeRangeDuration(PACED_TRAIN_SETTINGS_TEST.timeRangeDuration);
221+
await this.setCadence(PACED_TRAIN_SETTINGS_TEST.cadence);
222+
await this.definePacedTrainCheckboxLabel.click();
223+
await expect(this.addTrainButton).toHaveText(translations.addTrainSchedule);
224+
await expect(this.pacedTrainTimeRangeDurationInput).not.toBeVisible();
225+
await expect(this.pacedTrainCadenceInput).not.toBeVisible();
226+
227+
await this.definePacedTrainCheckboxLabel.click();
228+
await expect(this.addTrainButton).toHaveText(translations.addPacedTrain);
229+
await expect(this.pacedTrainTimeRangeDurationInput).toBeVisible();
230+
await expect(this.pacedTrainTimeRangeDurationInput).toHaveValue(
231+
PACED_TRAIN_SETTINGS_TEST.timeRangeDuration
232+
);
233+
await expect(this.pacedTrainCadenceInput).toBeVisible();
234+
await expect(this.pacedTrainCadenceInput).toHaveValue(PACED_TRAIN_SETTINGS_TEST.cadence);
235+
}
236+
237+
async fillPacedTrainSettings({
238+
name,
239+
startTime,
240+
timeRangeDuration,
241+
cadence,
242+
}: PacedTrainSettings) {
243+
await this.setTrainScheduleName(name);
244+
await this.setTrainStartTime(startTime);
245+
await this.setTimeRangeDuration(timeRangeDuration);
246+
await this.setCadence(cadence);
247+
}
248+
249+
async setTimeRangeDuration(timeRangeDuration: string) {
250+
await this.pacedTrainTimeRangeDurationInput.fill(timeRangeDuration);
251+
await expect(this.pacedTrainTimeRangeDurationInput).toHaveValue(timeRangeDuration);
252+
}
253+
254+
async setCadence(cadence: string) {
255+
await this.pacedTrainCadenceInput.fill(cadence);
256+
await expect(this.pacedTrainCadenceInput).toHaveValue(cadence);
257+
}
258+
121259
async addTrainSchedule() {
122-
await this.addTrainScheduleButton.click();
260+
await this.addTrainButton.click();
123261
await this.closeToastNotification();
124262
}
125263

126264
async setTrainScheduleName(name: string) {
127-
await this.trainScheduleNameInput.fill(name);
128-
await expect(this.trainScheduleNameInput).toHaveValue(name);
265+
await this.trainNameInput.fill(name);
266+
await expect(this.trainNameInput).toHaveValue(name);
129267
}
130268

131269
async checkNumberOfTrains(number: number) {

0 commit comments

Comments
 (0)