Skip to content

Commit

Permalink
front: add times and stops e2e test for operational studies
Browse files Browse the repository at this point in the history
Signed-off-by: maymanaf <med.aymen.naf@gmail.com>
  • Loading branch information
Maymanaf committed Oct 1, 2024
1 parent b54cdb4 commit 2f738ed
Show file tree
Hide file tree
Showing 15 changed files with 801 additions and 8 deletions.
2 changes: 1 addition & 1 deletion front/src/modules/timesStops/TimesStopsInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const createClearViaButton = ({
rowData.onStopSignal === true);
if (isClearBtnShown) {
return (
<button type="button" onClick={removeVia}>
<button data-testid="remove-via-button" type="button" onClick={removeVia}>
</button>
);
Expand Down
234 changes: 234 additions & 0 deletions front/tests/011-op-times-and-stops-tab.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
import { test, expect } from '@playwright/test';

import type { Project, Scenario, Study } from 'common/api/osrdEditoastApi';

import HomePage from './pages/home-page-model';
import OperationalStudiesInputTablePage from './pages/op-input-table-page-model';
import OperationalStudiesOutputTablePage from './pages/op-output-table-page-model';
import OperationalStudiesTimetablePage from './pages/op-timetable-page-model';
import OperationalStudiesPage from './pages/operational-studies-page-model';
import ScenarioPage from './pages/scenario-page-model';
import { readJsonFile, safeClick } from './utils';
import { cleanWhitespace, cleanWhitespaces, type StationData } from './utils/dataNormalizer';
import setupScenario from './utils/scenario';
import scrollContainer from './utils/scrollHelper';
import enTranslations from '../public/locales/en/timesStops.json';
import frTranslations from '../public/locales/fr/timesStops.json';

let project: Project;
let study: Study;
let scenario: Scenario;
let selectedLanguage: string;

const dualRollingStockName = 'dual-mode_rollingstock_test_e2e';

const initialInputsData: CellData[] = readJsonFile(
'./tests/assets/operationStudies/timesAndStops/initialInputs.json'
);
const updatedInputsData: CellData[] = readJsonFile(
'./tests/assets/operationStudies/timesAndStops/updatedInputs.json'
);
const outputExpectedCellData: StationData[] = readJsonFile(
'./tests/assets/operationStudies/timesAndStops/expectedOutputsCellsData.json'
);
const inputExpectedData = readJsonFile(
'./tests/assets/operationStudies/timesAndStops/expectedInputsCellsData.json'
);
const updatedCellData = readJsonFile(
'./tests/assets/operationStudies/timesAndStops/updatedInputsCellsData.json'
);

const expectedViaValues = [
{ name: 'Mid_West_station', ch: 'BV', uic: '3', km: 'KM 11.850' },
{ name: 'Mid_East_station', ch: 'BV', uic: '4', km: 'KM 26.300' },
];

type TranslationKeys = keyof typeof enTranslations;

// Define CellData interface for table cell data
interface CellData {
stationName: string;
header: TranslationKeys;
value: string;
marginForm?: string;
}

test.beforeEach(async ({ page }) => {
// Create a new scenario
({ project, study, scenario } = await setupScenario());

// Navigate to home page and retrieve the language setting
const homePage = new HomePage(page);
await homePage.goToHomePage();
selectedLanguage = await homePage.getOSRDLanguage();

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

test.describe('Times and Stops Tab Verification', () => {
// Set viewport to avoid scrolling issues and ensure elements are attached to the DOM
test.use({ viewport: { width: 1920, height: 1080 } });

test('should correctly set and display times and stops tables', async ({ page }) => {
// Page models
const [
opInputTablePage,
opTimetablePage,
opOutputTablePage,
operationalStudiesPage,
scenarioPage,
] = [
new OperationalStudiesInputTablePage(page),
new OperationalStudiesTimetablePage(page),
new OperationalStudiesOutputTablePage(page),
new OperationalStudiesPage(page),
new ScenarioPage(page),
];

// Setup the initial train configuration and schedule
await scenarioPage.checkInfraLoaded();
await operationalStudiesPage.clickOnAddTrainBtn();
await scenarioPage.setTrainScheduleName('Train-name-e2e-test');
await page.waitForTimeout(500);
await operationalStudiesPage.setTrainStartTime('11:22:40');
await operationalStudiesPage.selectRollingStock(dualRollingStockName);

// Perform pathfinding
await scenarioPage.openTabByDataId('tab-pathfinding');
await operationalStudiesPage.performPathfindingByTrigram('WS', 'NES');

// Navigate to the Times and Stops tab and scroll into view
await scenarioPage.openTabByDataId('tab-timesStops');
await scrollContainer(page, '.time-stops-datasheet .dsg-container');

// Set column names based on the selected language
const translations = selectedLanguage === 'English' ? enTranslations : frTranslations;
const expectedColumnNames = cleanWhitespaces([
translations.name,
'Ch',
translations.arrivalTime,
translations.departureTime,
translations.stopTime,
translations.receptionOnClosedSignal,
translations.theoreticalMargin,
]);

// Verify that the actual column headers match the expected headers
const actualColumnHeaders = cleanWhitespaces(
await opInputTablePage.columnHeaders.allInnerTexts()
);
expect(actualColumnHeaders).toEqual(expectedColumnNames);

// Validate the initial active row count
await opInputTablePage.verifyActiveRowsCount(2);

// Fill in table cells based on the predefined cell data
for (const cell of initialInputsData) {
const translatedHeader = cleanWhitespace(translations[cell.header]);
await opInputTablePage.fillTableCellByStationAndHeader(
cell.stationName,
translatedHeader,
cell.value,
selectedLanguage,
cell.marginForm
);
}

// Verify the table after modification
await opInputTablePage.verifyActiveRowsCount(4);
await opInputTablePage.verifyDeleteButtons(2);
await opInputTablePage.verifyInputTableData(inputExpectedData);

// Switch to Pathfinding tab and validate waypoints
await scenarioPage.openTabByDataId('tab-pathfinding');
for (const [viaIndex, expectedValue] of expectedViaValues.entries()) {
const droppedWaypoint = operationalStudiesPage.droppedWaypoints.nth(viaIndex);
await OperationalStudiesPage.validateAddedWaypoint(
droppedWaypoint,
expectedValue.name,
expectedValue.ch,
expectedValue.uic
);
}

// Add the train schedule and verify simulation results
await scenarioPage.addTrainSchedule();
await scenarioPage.returnSimulationResult();
opTimetablePage.verifyTimeStopsDatasheetVisibility();
// Scroll and extract data from output table
await scrollContainer(page, '.osrd-simulation-container .time-stops-datasheet .dsg-container');
await opOutputTablePage.getOutputTableData(outputExpectedCellData, selectedLanguage);
});

test('should correctly update and clear input table row', async ({ page }) => {
// Page models
const [opInputTablePage, operationalStudiesPage, scenarioPage] = [
new OperationalStudiesInputTablePage(page),
new OperationalStudiesPage(page),
new ScenarioPage(page),
];

// Setup initial train configuration
await scenarioPage.checkInfraLoaded();
await operationalStudiesPage.clickOnAddTrainBtn();
await scenarioPage.setTrainScheduleName('Train-name-e2e-test');
await page.waitForTimeout(500);
await operationalStudiesPage.setTrainStartTime('11:22:40');
await operationalStudiesPage.selectRollingStock(dualRollingStockName);

// Perform pathfinding and navigate to Times and Stops tab
await scenarioPage.openTabByDataId('tab-pathfinding');
await operationalStudiesPage.performPathfindingByTrigram('WS', 'NES');
await scenarioPage.openTabByDataId('tab-timesStops');
await scrollContainer(page, '.time-stops-datasheet .dsg-container');

const translations = selectedLanguage === 'English' ? enTranslations : frTranslations;
// Fill in table cells based on the predefined cell data
for (const cell of initialInputsData) {
const translatedHeader = cleanWhitespace(translations[cell.header]);
await opInputTablePage.fillTableCellByStationAndHeader(
cell.stationName,
translatedHeader,
cell.value,
selectedLanguage,
cell.marginForm
);
}
await opInputTablePage.verifyInputTableData(inputExpectedData);

// Update table inputs
await opInputTablePage.verifyActiveRowsCount(4);
for (const cell of updatedInputsData) {
const translatedHeader = cleanWhitespace(translations[cell.header]);
await opInputTablePage.fillTableCellByStationAndHeader(
cell.stationName,
translatedHeader,
cell.value,
selectedLanguage,
cell.marginForm
);
}

// Delete a row and validate row count
await opInputTablePage.verifyDeleteButtons(2);
await safeClick(opInputTablePage.deleteButtons.nth(0));
await opInputTablePage.verifyActiveRowsCount(4);
await opInputTablePage.verifyDeleteButtons(1);
await opInputTablePage.verifyInputTableData(updatedCellData);

// Switch to Pathfinding tab and validate waypoints
await scenarioPage.openTabByDataId('tab-pathfinding');
for (const [viaIndex, expectedValue] of expectedViaValues.entries()) {
const droppedWaypoint = operationalStudiesPage.droppedWaypoints.nth(viaIndex);
await OperationalStudiesPage.validateAddedWaypoint(
droppedWaypoint,
expectedValue.name,
expectedValue.ch,
expectedValue.uic
);
}
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"row": 1,
"values": ["West_station", "BV", "11:22:40", "", "", "5%"]
},
{
"row": 2,
"values": ["Mid_West_station", "BV", "11:30:40", "11:35:40", "300", "1min/100km"]
},
{
"row": 3,
"values": ["Mid_East_station", "BV", "11:45:21", "11:47:25", "124", ""]
},
{
"row": 4,
"values": ["North_East_station", "BV", "", "", "0", ""]
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
[
{
"stationName": "West_station",
"stationCh": "BV",
"requestedArrival": "11:22:40",
"requestedDeparture": "",
"stopTime": "",
"signalReceptionClosed": false,
"margin": {
"theoretical": "5 %",
"theoreticalS": "23 s",
"actual": "23 s",
"difference": "0 s"
},
"calculatedArrival": "11:22:40",
"calculatedDeparture": ""
},
{
"stationName": "Mid_West_station",
"stationCh": "BV",
"requestedArrival": "11:30:40",
"requestedDeparture": "11:35:40",
"stopTime": "300",
"signalReceptionClosed": true,
"margin": {
"theoretical": "1 min/100km",
"theoreticalS": "9 s",
"actual": "167 s",
"difference": "159 s"
},
"calculatedArrival": "11:30:39",
"calculatedDeparture": "11:35:39"
},
{
"stationName": "Mid_East_station",
"stationCh": "BV",
"requestedArrival": "11:45:21",
"requestedDeparture": "11:47:25",
"stopTime": "124",
"signalReceptionClosed": false,
"margin": {
"theoretical": "",
"theoreticalS": "12 s",
"actual": "12 s",
"difference": "0 s"
},
"calculatedArrival": "11:45:20",
"calculatedDeparture": "11:47:24"
},
{
"stationName": "North_East_station",
"stationCh": "BV",
"requestedArrival": "",
"requestedDeparture": "",
"stopTime": "0",
"signalReceptionClosed": false,
"margin": {
"theoretical": "",
"theoreticalS": "",
"actual": "",
"difference": ""
},
"calculatedArrival": "11:56:23",
"calculatedDeparture": ""
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[
{
"stationName": "West_station",
"header": "theoreticalMargin",
"value": "5%",
"marginForm": "% ou min/100km"
},
{
"stationName": "Mid_West_station",
"header": "theoreticalMargin",
"value": "1min/100km",
"marginForm": "% ou min/100km"
},
{
"stationName": "Mid_West_station",
"header": "arrivalTime",
"value": "11:30:40"
},
{
"stationName": "Mid_West_station",
"header": "stopTime",
"value": "300"
},
{
"stationName": "Mid_East_station",
"header": "arrivalTime",
"value": "11:45:21"
},
{
"stationName": "Mid_East_station",
"header": "stopTime",
"value": "124"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"stationName": "West_station",
"header": "theoreticalMargin",
"value": "3%",
"marginForm": "% ou min/100km"
},
{
"stationName": "Mid_East_station",
"header": "arrivalTime",
"value": "12:58:19"
},
{
"stationName": "Mid_East_station",
"header": "stopTime",
"value": "21"
}
]
Loading

0 comments on commit 2f738ed

Please sign in to comment.