diff --git a/front/src/modules/rollingStock/components/RollingStockSelector/SearchRollingStock.tsx b/front/src/modules/rollingStock/components/RollingStockSelector/SearchRollingStock.tsx index 8c988af148a..4f612fcaff8 100644 --- a/front/src/modules/rollingStock/components/RollingStockSelector/SearchRollingStock.tsx +++ b/front/src/modules/rollingStock/components/RollingStockSelector/SearchRollingStock.tsx @@ -114,7 +114,7 @@ const SearchRollingStock = ({
- + {filteredRollingStockList.length > 0 ? `${filteredRollingStockList.length} ${t('resultsFound')}` : t('noResultFound')} diff --git a/front/tests/008-allowances.spec.ts b/front/tests/008-allowances.spec.ts index 12449995bd1..3bba4106aec 100644 --- a/front/tests/008-allowances.spec.ts +++ b/front/tests/008-allowances.spec.ts @@ -1,7 +1,7 @@ import { test } from '@playwright/test'; import { v4 as uuidv4 } from 'uuid'; -import createCompleteScenario, { allowancesManagement } from './assets/utils'; +import createCompleteScenario, { allowancesManagement } from './assets/scenario-utlis'; import PlaywrightScenarioPage from './pages/scenario-page-model'; let scenarioName: string; diff --git a/front/tests/009-rollingstock-editor.spec.ts b/front/tests/009-rollingstock-editor.spec.ts index 8799aec2234..fd327231fc4 100644 --- a/front/tests/009-rollingstock-editor.spec.ts +++ b/front/tests/009-rollingstock-editor.spec.ts @@ -4,11 +4,13 @@ import path from 'path'; import { test, expect } from '@playwright/test'; import { - findAndDeleteRollingStock, + findAndDeleteRollingStocks, generateUniqueName, verifyAndCheckInputById, fillAndCheckInputById, + addRollingStock, } from './assets/utils'; +import RollingStockSelectorPage from './pages/rolling-stock-selector-page'; import PlaywrightRollingstockEditorPage from './pages/rollingstock-editor-page-model'; // Correct path to load rolling stock details from JSON @@ -16,7 +18,14 @@ const rollingstockDetailsPath = path.resolve( __dirname, '../tests/assets/rollingStock/rollingstockDetails.json' ); +// Correct path to load electrical and themal rolling stock from JSON +const rollingstockPath = path.resolve( + __dirname, + '../tests/assets/rollingStock/thermal-electric_rolling_stock.json' +); const rollingstockDetails = JSON.parse(fs.readFileSync(rollingstockDetailsPath, 'utf-8')); +const rollingStockJson = JSON.parse(fs.readFileSync(rollingstockPath, 'utf8')); +const thermalElectricRollingStockName = 'thermal-electric_rolling_stock'; test.describe('Rollingstock editor page', () => { let uniqueRollingStockName: string; @@ -29,16 +38,22 @@ test.describe('Rollingstock editor page', () => { uniqueDeletedRollingStockName = await generateUniqueName('D_RSN'); // Check and delete the specified rolling stocks if they exist - await findAndDeleteRollingStock(uniqueRollingStockName); - await findAndDeleteRollingStock(uniqueUpdatedRollingStockName); - await findAndDeleteRollingStock(uniqueDeletedRollingStockName); + await findAndDeleteRollingStocks([ + uniqueRollingStockName, + uniqueUpdatedRollingStockName, + uniqueDeletedRollingStockName, + thermalElectricRollingStockName, + ]); }); test.afterEach(async () => { // Clean up by deleting the created or updated rolling stock - await findAndDeleteRollingStock(uniqueRollingStockName); - await findAndDeleteRollingStock(uniqueUpdatedRollingStockName); - await findAndDeleteRollingStock(uniqueDeletedRollingStockName); + await findAndDeleteRollingStocks([ + uniqueRollingStockName, + uniqueUpdatedRollingStockName, + uniqueDeletedRollingStockName, + thermalElectricRollingStockName, + ]); }); test('should correctly create a new rolling stock', async ({ page }) => { @@ -189,4 +204,92 @@ test.describe('Rollingstock editor page', () => { rollingStockEditorPage.page.getByTestId(uniqueDeletedRollingStockName) ).toBeHidden(); }); + test('should correctly filter a rolling stock', async ({ page }) => { + const rollingStockEditorPage = new PlaywrightRollingstockEditorPage(page); + const rollingStockSelectorPage = new RollingStockSelectorPage(page); + // Navigate to rolling stock editor page + await rollingStockEditorPage.navigateToPage(); + + // Extract and check the initial count of rolling stock + const initialRollingStockFoundNumber = + await rollingStockSelectorPage.getRollingStockSearchNumber(); + + // Perform a filtering action for electric rolling stock + await rollingStockSelectorPage.electricRollingStockFilter(); + + // Verify that filtering reduces the count and all the RS have electic icons + expect(await rollingStockSelectorPage.getElectricRollingStockIcons.count()).toEqual( + await rollingStockSelectorPage.getRollingStockSearchNumber() + ); + + // Clear electric filter + await rollingStockSelectorPage.electricRollingStockFilter(); + + // Perform a filtering action for thermal rolling stock + await rollingStockSelectorPage.thermalRollingStockFilter(); + + // Verify that filtering reduces the count and all the RS have thermal icons + expect(await rollingStockSelectorPage.getThermalRollingStockIcons.count()).toEqual( + await rollingStockSelectorPage.getRollingStockSearchNumber() + ); + + // Perform a filtering action for combined thermal-electric rolling stock + await rollingStockSelectorPage.electricRollingStockFilter(); + + // Verify that filtering reduces the count and all the RS have thermal and electric icons + expect(await rollingStockSelectorPage.getThermalElectricRollingStockIcons.count()).toEqual( + await rollingStockSelectorPage.getRollingStockSearchNumber() + ); + + // Clear filters + await rollingStockSelectorPage.electricRollingStockFilter(); + await rollingStockSelectorPage.thermalRollingStockFilter(); + + // Verify that the count of rolling stock is back to the initial number + expect(await rollingStockSelectorPage.getRollingStockList.count()).toEqual( + initialRollingStockFoundNumber + ); + }); + + test('should correctly search for a rolling stock', async ({ page }) => { + const rollingStockEditorPage = new PlaywrightRollingstockEditorPage(page); + const rollingStockSelectorPage = new RollingStockSelectorPage(page); + // Add a rolling stock via postAPI + await addRollingStock(thermalElectricRollingStockName, rollingStockJson); + + // Navigate to rolling stock editor page + await rollingStockEditorPage.navigateToPage(); + + // Extract and check the initial count of rolling stock + const initialRollingStockFoundNumber = + await rollingStockSelectorPage.getRollingStockSearchNumber(); + + // Search for the specific rolling stock + await rollingStockEditorPage.searchRollingStock(thermalElectricRollingStockName); + expect( + rollingStockEditorPage.page.getByTestId( + `rollingstock-thermal-${thermalElectricRollingStockName}` + ) + ).toBeDefined(); + + // Verify that the first rolling stock has the thermal and electric icon + await expect(rollingStockSelectorPage.getThermalRollingStockFirstIcon).toBeVisible(); + await expect(rollingStockSelectorPage.getElectricRollingStockFirstIcon).toBeVisible(); + + // Clear the search + await rollingStockEditorPage.clearSearchRollingStock(); + + // Verify that the count of rolling stock is back to the initial number + expect(await rollingStockSelectorPage.getRollingStockList.count()).toEqual( + initialRollingStockFoundNumber + ); + // Search for a non existing rolling stock + await rollingStockEditorPage.searchRollingStock( + `${thermalElectricRollingStockName}-no-results` + ); + + // Verify that the count of rolling stock is 0 (No results Found) + await expect(rollingStockSelectorPage.getNoRollingStockResult).toBeVisible(); + expect(await rollingStockSelectorPage.getRollingStockSearchNumber()).toEqual(0); + }); }); diff --git a/front/tests/assets/rollingStock/thermal-electric_rolling_stock.json b/front/tests/assets/rollingStock/thermal-electric_rolling_stock.json new file mode 100644 index 00000000000..33b21da0a70 --- /dev/null +++ b/front/tests/assets/rollingStock/thermal-electric_rolling_stock.json @@ -0,0 +1,447 @@ +{ + "railjson_version": "3.2", + "name": "thermal-electric_rolling_stock", + "effort_curves": { + "modes": { + "25000V": { + "curves": [ + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": "25000V", + "power_restriction_code": "C1" + }, + "curve": { + "speeds": [ + 0.0, 5.294117647058823, 10.588235294117649, 15.882352941176473, 21.176470588235293, + 26.470588235294116, 31.764705882352946, 37.05882352941176, 42.35294117647059, + 47.64705882352941, 52.94117647058823, 58.23529411764706, 63.52941176470589, + 68.82352941176471, 74.11764705882352, 79.41176470588235, 84.70588235294117, 90.0 + ], + "max_efforts": [ + 450000.0, 445235.2941176471, 440470.5882352941, 435705.8823529412, + 430411.7647058823, 423264.70588235295, 416117.6470588235, 408970.5882352941, + 398484.1628959276, 383823.5294117647, 369162.89592760184, 348806.7226890756, + 328386.55462184874, 288330.8823529411, 210904.411764706, 192705.88235294115, + 186352.9411764706, 180000.0 + ] + } + }, + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": "25000V", + "power_restriction_code": "C2" + }, + "curve": { + "speeds": [ + 0.0, 5.294117647058823, 10.588235294117649, 15.882352941176473, 21.176470588235293, + 26.470588235294116, 31.764705882352946, 37.05882352941176, 42.35294117647059, + 47.64705882352941, 52.94117647058823, 58.23529411764706, 63.52941176470589, + 68.82352941176471, 74.11764705882352, 79.41176470588235, 84.70588235294117, 90.0 + ], + "max_efforts": [ + 400000.0, 395764.705882353, 391529.4117647059, 387294.11764705885, + 382588.2352941177, 376235.29411764705, 369882.3529411765, 363529.4117647059, + 354208.1447963801, 341176.4705882353, 328144.7963800905, 310050.42016806727, + 291899.1596638655, 256294.11764705877, 187470.5882352942, 171294.11764705885, + 165647.05882352943, 160000.0 + ] + } + }, + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": "22500V", + "power_restriction_code": "C1" + }, + "curve": { + "speeds": [ + 0.0, 5.294117647058823, 10.588235294117649, 15.882352941176473, 21.176470588235293, + 26.470588235294116, 31.764705882352946, 37.05882352941176, 42.35294117647059, + 47.64705882352941, 52.94117647058823, 58.23529411764706, 63.52941176470589, + 68.82352941176471, 74.11764705882352, 79.41176470588235, 84.70588235294117, 90.0 + ], + "max_efforts": [ + 405000.0, 400711.7647058824, 396423.5294117647, 392135.2941176471, + 387370.5882352941, 380938.2352941177, 374505.8823529412, 368073.5294117647, + 358635.74660633487, 345441.17647058825, 332246.6063348417, 313926.0504201681, + 295547.8991596639, 259497.794117647, 189813.9705882354, 173435.29411764705, + 167717.64705882355, 162000.0 + ] + } + }, + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": "22500V", + "power_restriction_code": "C2" + }, + "curve": { + "speeds": [ + 0.0, 5.294117647058823, 10.588235294117649, 15.882352941176473, 21.176470588235293, + 26.470588235294116, 31.764705882352946, 37.05882352941176, 42.35294117647059, + 47.64705882352941, 52.94117647058823, 58.23529411764706, 63.52941176470589, + 68.82352941176471, 74.11764705882352, 79.41176470588235, 84.70588235294117, 90.0 + ], + "max_efforts": [ + 360000.0, 356188.2352941177, 352376.4705882353, 348564.705882353, 344329.4117647059, + 338611.7647058824, 332894.11764705885, 327176.4705882353, 318787.3303167421, + 307058.82352941175, 295330.3167420815, 279045.3781512605, 262709.243697479, + 230664.7058823529, 168723.52941176482, 154164.70588235295, 149082.35294117648, + 144000.0 + ] + } + }, + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": "20000V", + "power_restriction_code": "C1" + }, + "curve": { + "speeds": [ + 0.0, 5.294117647058823, 10.588235294117649, 15.882352941176473, 21.176470588235293, + 26.470588235294116, 31.764705882352946, 37.05882352941176, 42.35294117647059, + 47.64705882352941, 52.94117647058823, 58.23529411764706, 63.52941176470589, + 68.82352941176471, 74.11764705882352, 79.41176470588235, 84.70588235294117, 90.0 + ], + "max_efforts": [ + 360000.0, 356188.2352941177, 352376.4705882353, 348564.70588235295, + 344329.4117647059, 338611.76470588235, 332894.11764705885, 327176.4705882353, + 318787.33031674207, 307058.8235294118, 295330.3167420815, 279045.37815126055, + 262709.24369747896, 230664.7058823529, 168723.5294117648, 154164.70588235295, + 149082.35294117648, 144000.0 + ] + } + }, + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": "20000V", + "power_restriction_code": "C2" + }, + "curve": { + "speeds": [ + 0.0, 5.294117647058823, 10.588235294117649, 15.882352941176473, 21.176470588235293, + 26.470588235294116, 31.764705882352946, 37.05882352941176, 42.35294117647059, + 47.64705882352941, 52.94117647058823, 58.23529411764706, 63.52941176470589, + 68.82352941176471, 74.11764705882352, 79.41176470588235, 84.70588235294117, 90.0 + ], + "max_efforts": [ + 320000.0, 316611.7647058824, 313223.52941176476, 309835.2941176471, + 306070.58823529416, 300988.23529411765, 295905.8823529412, 290823.52941176476, + 283366.51583710406, 272941.17647058825, 262515.83710407245, 248040.33613445383, + 233519.32773109243, 205035.29411764705, 149976.4705882354, 137035.29411764708, + 132517.64705882355, 128000.0 + ] + } + }, + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": null, + "power_restriction_code": "C1" + }, + "curve": { + "speeds": [ + 0.0, 5.294117647058823, 10.588235294117649, 15.882352941176473, 21.176470588235293, + 26.470588235294116, 31.764705882352946, 37.05882352941176, 42.35294117647059, + 47.64705882352941, 52.94117647058823, 58.23529411764706, 63.52941176470589, + 68.82352941176471, 74.11764705882352, 79.41176470588235, 84.70588235294117, 90.0 + ], + "max_efforts": [ + 450000.0, 445235.2941176471, 440470.5882352941, 435705.8823529412, + 430411.7647058823, 423264.70588235295, 416117.6470588235, 408970.5882352941, + 398484.1628959276, 383823.5294117647, 369162.89592760184, 348806.7226890756, + 328386.55462184874, 288330.8823529411, 210904.411764706, 192705.88235294115, + 186352.9411764706, 180000.0 + ] + } + }, + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": null, + "power_restriction_code": "C2" + }, + "curve": { + "speeds": [ + 0.0, 5.294117647058823, 10.588235294117649, 15.882352941176473, 21.176470588235293, + 26.470588235294116, 31.764705882352946, 37.05882352941176, 42.35294117647059, + 47.64705882352941, 52.94117647058823, 58.23529411764706, 63.52941176470589, + 68.82352941176471, 74.11764705882352, 79.41176470588235, 84.70588235294117, 90.0 + ], + "max_efforts": [ + 400000.0, 395764.705882353, 391529.4117647059, 387294.11764705885, + 382588.2352941177, 376235.29411764705, 369882.3529411765, 363529.4117647059, + 354208.1447963801, 341176.4705882353, 328144.7963800905, 310050.42016806727, + 291899.1596638655, 256294.11764705877, 187470.5882352942, 171294.11764705885, + 165647.05882352943, 160000.0 + ] + } + }, + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": "25000V", + "power_restriction_code": null + }, + "curve": { + "speeds": [ + 0.0, 5.294117647058823, 10.588235294117649, 15.882352941176473, 21.176470588235293, + 26.470588235294116, 31.764705882352946, 37.05882352941176, 42.35294117647059, + 47.64705882352941, 52.94117647058823, 58.23529411764706, 63.52941176470589, + 68.82352941176471, 74.11764705882352, 79.41176470588235, 84.70588235294117, 90.0 + ], + "max_efforts": [ + 500000.0, 494705.8823529412, 489411.7647058823, 484117.6470588235, + 478235.29411764705, 470294.1176470588, 462352.9411764706, 454411.7647058823, + 442760.1809954751, 426470.5882352941, 410180.9954751131, 387563.025210084, + 364873.9495798319, 320367.64705882344, 234338.23529411777, 214117.64705882352, + 207058.82352941175, 200000.0 + ] + } + }, + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": "22500V", + "power_restriction_code": null + }, + "curve": { + "speeds": [ + 0.0, 5.294117647058823, 10.588235294117649, 15.882352941176473, 21.176470588235293, + 26.470588235294116, 31.764705882352946, 37.05882352941176, 42.35294117647059, + 47.64705882352941, 52.94117647058823, 58.23529411764706, 63.52941176470589, + 68.82352941176471, 74.11764705882352, 79.41176470588235, 84.70588235294117, 90.0 + ], + "max_efforts": [ + 450000.0, 445235.2941176471, 440470.5882352941, 435705.8823529412, + 430411.7647058823, 423264.70588235295, 416117.6470588235, 408970.5882352941, + 398484.1628959276, 383823.5294117647, 369162.89592760184, 348806.7226890756, + 328386.55462184874, 288330.8823529411, 210904.411764706, 192705.88235294115, + 186352.9411764706, 180000.0 + ] + } + }, + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": "20000V", + "power_restriction_code": null + }, + "curve": { + "speeds": [ + 0.0, 5.294117647058823, 10.588235294117649, 15.882352941176473, 21.176470588235293, + 26.470588235294116, 31.764705882352946, 37.05882352941176, 42.35294117647059, + 47.64705882352941, 52.94117647058823, 58.23529411764706, 63.52941176470589, + 68.82352941176471, 74.11764705882352, 79.41176470588235, 84.70588235294117, 90.0 + ], + "max_efforts": [ + 400000.0, 395764.705882353, 391529.4117647059, 387294.11764705885, + 382588.2352941177, 376235.29411764705, 369882.3529411765, 363529.4117647059, + 354208.1447963801, 341176.4705882353, 328144.7963800905, 310050.42016806727, + 291899.1596638655, 256294.11764705877, 187470.5882352942, 171294.11764705885, + 165647.05882352943, 160000.0 + ] + } + }, + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": null, + "power_restriction_code": null + }, + "curve": { + "speeds": [ + 0.0, 5.277777777777778, 10.555555555555555, 15.833333333333332, 21.11111111111111, + 26.38888888888889, 31.666666666666664, 36.94444444444444, 42.22222222222222, + 47.77777777777778, 53.05555555555556, 58.33333333333333, 63.61111111111111, + 68.88888888888889, 74.16666666666667, 79.44444444444444, 84.72222222222221, 90.0 + ], + "max_efforts": [ + 500000.0, 494705.8823529412, 489411.7647058823, 484117.6470588235, + 478235.29411764705, 470294.1176470588, 462352.9411764706, 454411.7647058823, + 442760.1809954751, 426470.5882352941, 410180.9954751131, 387563.025210084, + 364873.9495798319, 320367.64705882344, 234338.23529411777, 214117.64705882352, + 207058.82352941175, 200000.0 + ] + } + }, + { + "cond": { + "comfort": "AC", + "electrical_profile_level": null, + "power_restriction_code": null + }, + "curve": { + "speeds": [ + 0.0, 5.277777777777778, 10.555555555555555, 15.833333333333332, 21.11111111111111, + 26.38888888888889, 31.666666666666664, 36.94444444444444, 42.22222222222222, + 47.77777777777778, 53.05555555555556, 58.33333333333333, 63.61111111111111, + 68.88888888888889, 74.16666666666667, 79.44444444444444, 84.72222222222221, 90.0 + ], + "max_efforts": [ + 510000.0, 504705.8823529412, 499411.7647058823, 494117.6470588235, + 488235.29411764705, 480294.1176470588, 472352.9411764706, 464411.7647058823, + 452760.1809954751, 436470.5882352941, 420180.9954751131, 397563.025210084, + 374873.9495798319, 330367.64705882344, 244338.23529411777, 224117.64705882352, + 217058.82352941175, 210000.0 + ] + } + }, + { + "cond": { + "comfort": "HEATING", + "electrical_profile_level": null, + "power_restriction_code": null + }, + "curve": { + "speeds": [ + 0.0, 5.277777777777778, 10.555555555555555, 15.833333333333332, 21.11111111111111, + 26.38888888888889, 31.666666666666664, 36.94444444444444, 42.22222222222222, + 47.77777777777778, 53.05555555555556, 58.33333333333333, 63.61111111111111, + 68.88888888888889, 74.16666666666667, 79.44444444444444, 84.72222222222221, 90.0 + ], + "max_efforts": [ + 490000.0, 484705.8823529412, 469411.7647058823, 474117.6470588235, + 468235.29411764705, 460294.1176470588, 452352.9411764706, 444411.7647058823, + 452760.1809954751, 416470.5882352941, 400180.9954751131, 377563.025210084, + 354873.9495798319, 310367.64705882344, 224338.23529411777, 204117.64705882352, + 197058.82352941175, 199000.0 + ] + } + } + ], + "default_curve": { + "speeds": [ + 0.0, 5.277777777777778, 10.555555555555555, 15.833333333333332, 21.11111111111111, + 26.38888888888889, 31.666666666666664, 36.94444444444444, 42.22222222222222, + 47.77777777777778, 53.05555555555556, 58.33333333333333, 63.61111111111111, + 68.88888888888889, 74.16666666666667, 79.44444444444444, 84.72222222222221, 90.0 + ], + "max_efforts": [ + 500000.0, 494705.8823529412, 489411.7647058823, 484117.6470588235, 478235.29411764705, + 470294.1176470588, 462352.9411764706, 454411.7647058823, 442760.1809954751, + 426470.5882352941, 410180.9954751131, 387563.025210084, 364873.9495798319, + 320367.64705882344, 234338.23529411777, 214117.64705882352, 207058.82352941175, 200000.0 + ] + }, + "is_electric": true + }, + "thermal": { + "curves": [ + { + "cond": { + "comfort": "STANDARD", + "electrical_profile_level": null, + "power_restriction_code": null + }, + "curve": { + "speeds": [ + 0.0, 2.7777777777777777, 5.555555555555555, 8.333333333333334, 11.11111111111111, + 13.88888888888889, 16.666666666666668, 19.444444444444443, 22.22222222222222, 25.0, + 27.77777777777778, 30.555555555555554, 33.333333333333336 + ], + "max_efforts": [ + 126000.0, 126000.0, 126000.0, 102750.0, 80340.0, 65379.99999999999, 54900.0, + 47210.0, 41360.0, 36790.0, 33120.0, 30110.0, 27600.0 + ] + } + }, + { + "cond": { + "comfort": "AC", + "electrical_profile_level": null, + "power_restriction_code": null + }, + "curve": { + "speeds": [ + 0.0, 1.3888888888888888, 5.555555555555555, 8.333333333333334, 11.11111111111111, + 13.88888888888889, 16.666666666666668, 19.444444444444443, 22.77777777777778, 25.0, + 27.77777777777778, 30.555555555555554, 33.333333333333336 + ], + "max_efforts": [ + 235000.0, 232500.0, 224000.0, 219000.0, 213500.0, 208000.0, 203000.0, 198000.0, + 192000.0, 175000.0, 157500.0, 143000.0, 131000.0 + ] + } + }, + { + "cond": { + "comfort": "HEATING", + "electrical_profile_level": null, + "power_restriction_code": null + }, + "curve": { + "speeds": [ + 0.0, 1.3888888888888888, 5.555555555555555, 8.333333333333334, 11.11111111111111, + 13.88888888888889, 16.666666666666668, 19.444444444444443, 22.77777777777778, 25.0, + 27.77777777777778, 30.555555555555554 + ], + "max_efforts": [ + 235000.0, 232500.0, 224000.0, 219000.0, 213500.0, 208000.0, 203000.0, 198000.0, + 192000.0, 175000.0, 157500.0, 143000.0 + ] + } + } + ], + "default_curve": { + "speeds": [ + 0.0, 2.7777777777777777, 5.555555555555555, 8.333333333333334, 11.11111111111111, + 13.88888888888889, 16.666666666666668, 19.444444444444443, 22.22222222222222, 25.0, + 27.77777777777778, 30.555555555555554, 33.333333333333336 + ], + "max_efforts": [ + 126000.0, 126000.0, 126000.0, 102750.0, 80340.0, 65379.99999999999, 54900.0, 47210.0, + 41360.0, 36790.0, 33120.0, 30110.0, 27600.0 + ] + }, + "is_electric": false + } + }, + "default_mode": "thermal" + }, + "metadata": { + "detail": "thermo-electric", + "family": "", + "type": "", + "grouping": "", + "series": "", + "subseries": "", + "unit": "", + "number": "", + "reference": "thermo-electric" + }, + "length": 350.0, + "max_speed": 44.44444444444444, + "startup_time": 12.0, + "startup_acceleration": 0.06, + "comfort_acceleration": 0.54, + "gamma": { + "type": "CONST", + "value": 0.5 + }, + "inertia_coefficient": 1.05, + "base_power_class": "5", + "mass": 900000.0, + "rolling_resistance": { + "type": "davis", + "A": 4400.0, + "B": 195.67674, + "C": 12.00002688 + }, + "loading_gauge": "G1", + "power_restrictions": { + "C2": "1", + "C1": "3" + }, + "energy_sources": [], + "locked": false, + "electrical_power_startup_time": 6.0, + "raise_pantograph_time": 16.0, + "version": 1, + "supported_signaling_systems": ["BAL", "BAPR", "TVM300", "TVM430"], + "liveries": [] +} diff --git a/front/tests/assets/scenario-utlis.ts b/front/tests/assets/scenario-utlis.ts new file mode 100644 index 00000000000..f28bc6b2953 --- /dev/null +++ b/front/tests/assets/scenario-utlis.ts @@ -0,0 +1,95 @@ +import { type Page, expect } from '@playwright/test'; +import { v4 as uuidv4 } from 'uuid'; + +import scenarioData from './operationStudies/scenario.json'; +import { getInfra, getProject, getRollingStock, getStudy, postApiRequest } from './utils'; +import { PlaywrightHomePage } from '../pages/home-page-model'; +import RollingStockSelectorPage from '../pages/rolling-stock-selector-page'; +import PlaywrightScenarioPage from '../pages/scenario-page-model'; + +// Scenario creation +export default async function createCompleteScenario( + page: Page, + trainScheduleName: string, + trainCount: string, + delta: string +) { + const smallInfra = await getInfra(); + const project = await getProject(); + const study = await getStudy(project.id); + const rollingStock = await getRollingStock(); + + const scenario = await postApiRequest( + `/api/projects/${project.id}/studies/${study.id}/scenarios`, + { + ...scenarioData, + name: `${scenarioData.name} ${uuidv4()}`, + study_id: study.id, + infra_id: smallInfra.id, + } + ); + + const playwrightHomePage = new PlaywrightHomePage(page); + const scenarioPage = new PlaywrightScenarioPage(page); + + await page.goto( + `/operational-studies/projects/${project.id}/studies/${study.id}/scenarios/${scenario.id}` + ); + + await playwrightHomePage.page.getByTestId('scenarios-add-train-schedule-button').click(); + + await scenarioPage.setTrainScheduleName(trainScheduleName); + await scenarioPage.setNumberOfTrains(trainCount); + await scenarioPage.setDelta(delta); + + // ***************** Select Rolling Stock ***************** + const playwrightRollingstockModalPage = new RollingStockSelectorPage(playwrightHomePage.page); + await playwrightRollingstockModalPage.openRollingstockModal(); + + await playwrightRollingstockModalPage.searchRollingstock('rollingstock_1500_25000_test_e2e'); + + const rollingstockCard = playwrightRollingstockModalPage.getRollingstockCardByTestID( + `rollingstock-${rollingStock.name}` + ); + + await rollingstockCard.click(); + await rollingstockCard.locator('button').click(); + + // ***************** Select Origin/Destination ***************** + await scenarioPage.openTabByDataId('tab-pathfinding'); + await scenarioPage.getPathfindingByTriGramSearch('MWS', 'NES'); + + // ***************** Create train ***************** + await scenarioPage.addTrainSchedule(); + await scenarioPage.page.waitForSelector('.dots-loader', { state: 'hidden' }); + await scenarioPage.checkTrainHasBeenAdded(); + await scenarioPage.returnSimulationResult(); +} + +// Allowances management + +export async function allowancesManagement( + scenarioPage: PlaywrightScenarioPage, + scenarioName: string, + allowanceType: 'standard' | 'engineering' +) { + await expect(scenarioPage.getTimetableList).toBeVisible(); + + await scenarioPage.getBtnByName(scenarioName).hover(); + await scenarioPage.page.getByTestId('edit-train').click(); + + await scenarioPage.openAllowancesModule(); + await expect(scenarioPage.getAllowancesModule).toBeVisible(); + + if (allowanceType === 'standard') { + await scenarioPage.setStandardAllowance(); + } else { + await scenarioPage.setEngineeringAllowance(); + await scenarioPage.clickSuccessBtn(); + await expect(scenarioPage.getAllowancesEngineeringSettings).toHaveAttribute('disabled'); + } + + await scenarioPage.page.getByTestId('submit-edit-train-schedule').click(); + await scenarioPage.page.waitForSelector('.scenario-details-name'); + expect(await scenarioPage.isAllowanceWorking()).toEqual(true); +} diff --git a/front/tests/assets/utils.ts b/front/tests/assets/utils.ts index f0a2e117eb4..6ced3ad24b4 100644 --- a/front/tests/assets/utils.ts +++ b/front/tests/assets/utils.ts @@ -3,10 +3,6 @@ import { v4 as uuidv4 } from 'uuid'; import type { Project, Scenario, Study, RollingStock, Infra } from 'common/api/osrdEditoastApi'; -import scenarioData from './operationStudies/scenario.json'; -import { PlaywrightHomePage } from '../pages/home-page-model'; -import RollingStockSelectorPage from '../pages/rolling-stock-selector-page'; -import PlaywrightScenarioPage from '../pages/scenario-page-model'; // API requests const getApiContext = async () => @@ -78,17 +74,25 @@ export const getRollingStock = async () => { ) as RollingStock; return rollingStock; }; - +// Add a rolling Stock +export async function addRollingStock(rollingStockName: string, rollingStockJson: JSON) { + await postApiRequest('/api/rolling_stock/', { + ...rollingStockJson, + name: rollingStockName, + }); +} // Find and delete rolling stock with the given name -export async function findAndDeleteRollingStock(rollingStockName: string) { +export async function findAndDeleteRollingStocks(rollingStockNames: string[]) { const rollingStocks = await getApiRequest(`/api/light_rolling_stock/`, { page_size: 500 }); - const rollingStockToDeleteCreated = rollingStocks.results.find( - (r: RollingStock) => r.name === rollingStockName - ); - if (rollingStockToDeleteCreated) { - await deleteApiRequest(`/api/rolling_stock/${rollingStockToDeleteCreated.id}/`); - } + const deleteRequests = rollingStockNames.map(async (name) => { + const rollingStockToDelete = rollingStocks.results.find((r: RollingStock) => r.name === name); + if (rollingStockToDelete) { + await deleteApiRequest(`/api/rolling_stock/${rollingStockToDelete.id}/`); + } + }); + + await Promise.all(deleteRequests); } // Fill and check input by ID @@ -125,91 +129,9 @@ export const generateUniqueName = async (baseName: string) => { const uuidSegment = uuidv4().slice(0, 6); return `${baseName}-${uuidSegment}`; }; -// Scenario creation -export default async function createCompleteScenario( - page: Page, - trainScheduleName: string, - trainCount: string, - delta: string -) { - const smallInfra = (await getInfra()) as Infra; - const project = await getProject(); - const study = await getStudy(project.id); - const rollingStock = await getRollingStock(); - - const scenario = await postApiRequest( - `/api/projects/${project.id}/studies/${study.id}/scenarios`, - { - ...scenarioData, - name: `${scenarioData.name} ${uuidv4()}`, - study_id: study.id, - infra_id: smallInfra.id, - } - ); - - const playwrightHomePage = new PlaywrightHomePage(page); - const scenarioPage = new PlaywrightScenarioPage(page); - - await page.goto( - `/operational-studies/projects/${project.id}/studies/${study.id}/scenarios/${scenario.id}` - ); - - await playwrightHomePage.page.getByTestId('scenarios-add-train-schedule-button').click(); - - await scenarioPage.setTrainScheduleName(trainScheduleName); - await scenarioPage.setNumberOfTrains(trainCount); - await scenarioPage.setDelta(delta); - - // ***************** Select Rolling Stock ***************** - const playwrightRollingstockModalPage = new RollingStockSelectorPage(playwrightHomePage.page); - await playwrightRollingstockModalPage.openRollingstockModal(); - - await playwrightRollingstockModalPage.searchRollingstock('rollingstock_1500_25000_test_e2e'); - - const rollingstockCard = playwrightRollingstockModalPage.getRollingstockCardByTestID( - `rollingstock-${rollingStock.name}` - ); - - await rollingstockCard.click(); - await rollingstockCard.locator('button').click(); - - // ***************** Select Origin/Destination ***************** - await scenarioPage.openTabByDataId('tab-pathfinding'); - await scenarioPage.getPathfindingByTriGramSearch('MWS', 'NES'); - - // ***************** Create train ***************** - await scenarioPage.addTrainSchedule(); - await scenarioPage.page.waitForSelector('.dots-loader', { state: 'hidden' }); - await scenarioPage.checkTrainHasBeenAdded(); - await scenarioPage.returnSimulationResult(); -} - -// Allowances management - -export async function allowancesManagement( - scenarioPage: PlaywrightScenarioPage, - scenarioName: string, - allowanceType: 'standard' | 'engineering' -) { - await expect(scenarioPage.getTimetableList).toBeVisible(); - - await scenarioPage.getBtnByName(scenarioName).hover(); - await scenarioPage.page.getByTestId('edit-train').click(); - - await scenarioPage.openAllowancesModule(); - await expect(scenarioPage.getAllowancesModule).toBeVisible(); - - if (allowanceType === 'standard') { - await scenarioPage.setStandardAllowance(); - } else { - await scenarioPage.setEngineeringAllowance(); - await scenarioPage.clickSuccessBtn(); - await expect(scenarioPage.getAllowancesEngineeringSettings).toHaveAttribute('disabled'); - } - - await scenarioPage.page.getByTestId('submit-edit-train-schedule').click(); - await scenarioPage.page.waitForSelector('.scenario-details-name'); - expect(await scenarioPage.isAllowanceWorking()).toEqual(true); - // TODO: check if the allowances are taken into account in the scenario page (waiting for issue # 6695 to be fixed) +// Extracts the first sequence of digits found in the input string and returns it as a number or return 0 if no digits found +export async function extractNumberFromString(input: string): Promise { + const match = input.match(/\d+/); + return match ? parseInt(match[0], 10) : 0; } diff --git a/front/tests/pages/rolling-stock-selector-page.ts b/front/tests/pages/rolling-stock-selector-page.ts index 68c5f9bf6a4..7bad7b71369 100644 --- a/front/tests/pages/rolling-stock-selector-page.ts +++ b/front/tests/pages/rolling-stock-selector-page.ts @@ -1,9 +1,7 @@ import { type Locator, type Page, expect } from '@playwright/test'; import BasePage from './base-page'; -import rollingstockTranslation from '../../public/locales/fr/rollingstock.json'; - -const electricCheckboxTranslation = rollingstockTranslation.electric; +import { extractNumberFromString } from '../assets/utils'; export default class RollingStockSelectorPage extends BasePage { readonly rollingStockSelectorButton: Locator; @@ -16,15 +14,31 @@ export default class RollingStockSelectorPage extends BasePage { readonly rollingStockListItem: Locator; - readonly getRollingStockSearch: Locator; - - readonly getRollingStockSearchFilter: Locator; + readonly getRollingStockModalSearch: Locator; readonly rollingStockMiniCards: Locator; readonly getRollingstockSpanNames: Locator; - readonly electricalCheckbox: Locator; + readonly getElectricRollingStockFilter: Locator; + + readonly getThermalRollingStockFilter: Locator; + + readonly getRollingStockSearchResult: Locator; + + readonly getThermalRollingStockIcons: Locator; + + readonly getElectricRollingStockIcons: Locator; + + readonly getElectricRollingStockFirstIcon: Locator; + + readonly getThermalRollingStockFirstIcon: Locator; + + readonly getRollingStockList: Locator; + + readonly getThermalElectricRollingStockIcons: Locator; + + readonly getNoRollingStockResult: Locator; constructor(page: Page) { super(page); @@ -35,13 +49,23 @@ export default class RollingStockSelectorPage extends BasePage { this.rollingStockListItem = page.locator('.rollingstock-container'); this.getResultsFound = page.locator('.modal-dialog').locator('small').first(); - this.getRollingStockSearch = this.rollingStockSelectorModal.locator('#searchfilter'); - this.getRollingStockSearchFilter = page.locator('.rollingstock-search-filters'); + this.getRollingStockModalSearch = this.rollingStockSelectorModal.locator('#searchfilter'); this.rollingStockMiniCards = page.locator('.rollingstock-selector-minicard'); this.getRollingstockSpanNames = page.locator('.rollingstock-minicard-name'); - this.electricalCheckbox = this.rollingStockSelectorModal.locator('label').filter({ - hasText: electricCheckboxTranslation, - }); + this.getElectricRollingStockFilter = page.locator('label[for="elec"]'); + this.getThermalRollingStockFilter = page.locator('label[for="thermal"]'); + this.getRollingStockSearchResult = page.getByTestId('search-results-text'); + this.getThermalRollingStockIcons = page.locator('.rollingstock-footer-specs .text-pink'); + this.getElectricRollingStockIcons = page.locator('.rollingstock-footer-specs .text-primary'); + this.getThermalElectricRollingStockIcons = page + .locator('.rollingstock-footer-specs .rollingstock-tractionmode:has(.text-pink)') + .filter({ + has: page.locator('.text-primary'), + }); + this.getElectricRollingStockFirstIcon = this.getElectricRollingStockIcons.first(); + this.getThermalRollingStockFirstIcon = this.getThermalRollingStockIcons.first(); + this.getRollingStockList = page.locator('.rollingstock-editor-list .rollingstock-title'); + this.getNoRollingStockResult = page.locator('.rollingstock-empty'); } async openRollingstockModal() { @@ -54,11 +78,11 @@ export default class RollingStockSelectorPage extends BasePage { } async searchRollingstock(rollingstockName: string) { - await this.getRollingStockSearch.fill(rollingstockName); + await this.getRollingStockModalSearch.fill(rollingstockName); } async selectRollingStock(rollingStockName: string) { - await this.getRollingStockSearch.fill(rollingStockName); + await this.getRollingStockModalSearch.fill(rollingStockName); const rollingstockItem = this.rollingStockList.getByTestId(`rollingstock-${rollingStockName}`); await rollingstockItem.click(); await rollingstockItem.locator('.rollingstock-footer-buttons > button').click(); @@ -79,4 +103,19 @@ export default class RollingStockSelectorPage extends BasePage { async closeRollingstockModal() { await this.rollingStockSelectorModal.locator('.close').click(); } + + // Select Combustion engine RS filter + async thermalRollingStockFilter() { + await this.getThermalRollingStockFilter.click(); + } + + // Select Electic RS filter + async electricRollingStockFilter() { + await this.getElectricRollingStockFilter.click(); + } + + // Get the number of RS from the search result text + async getRollingStockSearchNumber(): Promise { + return extractNumberFromString(await this.getRollingStockSearchResult.innerText()); + } } diff --git a/front/tests/pages/rollingstock-editor-page-model.ts b/front/tests/pages/rollingstock-editor-page-model.ts index ad41570d65e..4168e21b24e 100644 --- a/front/tests/pages/rollingstock-editor-page-model.ts +++ b/front/tests/pages/rollingstock-editor-page-model.ts @@ -71,6 +71,8 @@ export default class PlaywrightRollingstockEditorPage extends PlaywrightCommonPa // Navigate to the Rolling Stock Editor Page async navigateToPage() { await this.page.goto('/rolling-stock-editor/'); + // Wait for the page to reach the network idle state + await this.page.waitForLoadState('networkidle'); await this.removeViteOverlay(); } @@ -162,6 +164,7 @@ export default class PlaywrightRollingstockEditorPage extends PlaywrightCommonPa } // Set spreadsheet row value + // TODO: Refactor to eliminate ESLint errors async setSpreadsheetRow(data: { row: number; velocity: string; effort: string }[]) { for (const { row, effort, velocity } of data) { const velocityCell = this.getVelocityCellByRow(row); @@ -222,6 +225,7 @@ export default class PlaywrightRollingstockEditorPage extends PlaywrightCommonPa .getByTitle(powerRestrictionValue, { exact: true }) .click(); } + // TODO: Refactor to eliminate ESLint errors for (const rowData of data) { const rowIndex = data.indexOf(rowData) + 1; const velocityCell = this.getVelocityCellByRow(rowIndex); @@ -242,7 +246,7 @@ export default class PlaywrightRollingstockEditorPage extends PlaywrightCommonPa .getByRole('button', { name: powerRestrictionValue }) .click(); } - + // TODO: Refactor to eliminate ESLint errors for (const rowData of expectedData) { const rowIndex = expectedData.indexOf(rowData) + 1; const velocityCell = await this.getVelocityCellByRowValue(rowIndex);