-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
front: add, get and delete paced trains #10966
base: dev
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## dev #10966 +/- ##
==========================================
+ Coverage 80.86% 80.90% +0.03%
==========================================
Files 1118 1119 +1
Lines 112736 113119 +383
Branches 759 759
==========================================
+ Hits 91164 91517 +353
- Misses 21517 21547 +30
Partials 55 55
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
5cf88dd
to
77ebbd0
Compare
77ebbd0
to
9d5a8e6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've looked at the first two commits! Will continue the review later.
...c/modules/trainschedule/components/ManageTrainSchedule/helpers/formatTimetableItemPayload.ts
Outdated
Show resolved
Hide resolved
...c/modules/trainschedule/components/ManageTrainSchedule/helpers/formatTimetableItemPayload.ts
Outdated
Show resolved
Hide resolved
...c/modules/trainschedule/components/ManageTrainSchedule/helpers/formatTimetableItemPayload.ts
Outdated
Show resolved
Hide resolved
front/src/modules/trainschedule/components/ManageTrainSchedule/AddTrainScheduleButton.tsx
Outdated
Show resolved
Hide resolved
front/src/modules/trainschedule/components/ManageTrainSchedule/AddTrainScheduleButton.tsx
Outdated
Show resolved
Hide resolved
front/src/modules/trainschedule/components/ManageTrainSchedule/helpers/checkCurrentConfig.ts
Show resolved
Hide resolved
front/src/applications/operationalStudies/hooks/useScenarioData.ts
Outdated
Show resolved
Hide resolved
front/src/applications/operationalStudies/hooks/useScenarioData.ts
Outdated
Show resolved
Hide resolved
front/src/applications/operationalStudies/hooks/useScenarioData.ts
Outdated
Show resolved
Hide resolved
front/src/applications/operationalStudies/hooks/useScenarioData.ts
Outdated
Show resolved
Hide resolved
d37c225
to
9f154eb
Compare
46934e7
to
b6811f7
Compare
const trainScheduleIds = useMemo( | ||
() => (fetchedTrainSchedulesResults || []).map((t) => t.id), | ||
[fetchedTrainSchedulesResults] | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const trainScheduleIds = useMemo( | |
() => (fetchedTrainSchedulesResults || []).map((t) => t.id), | |
[fetchedTrainSchedulesResults] | |
); | |
const trainScheduleIds = useMemo( | |
() => (fetchedTrainSchedulesResults || []).map((trainSchedule) => trainSchedule.id), | |
[fetchedTrainSchedulesResults] | |
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's another round of reviews :P
front/src/utils/trainId.ts
Outdated
@@ -11,6 +17,10 @@ export const isOccurrence = (id: string): id is OccurrenceId => { | |||
export const isTrainSchedule = (id: string): id is TrainScheduleId => | |||
id.startsWith('trainschedule-'); | |||
|
|||
export const isPacedTrainResultWithPacedTrainId = ( | |||
timetableITem: TimetableItemWithTimetableId |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: "timetableItem"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥷
front/src/utils/trainId.ts
Outdated
@@ -11,6 +17,10 @@ export const isOccurrence = (id: string): id is OccurrenceId => { | |||
export const isTrainSchedule = (id: string): id is TrainScheduleId => | |||
id.startsWith('trainschedule-'); | |||
|
|||
export const isPacedTrainResultWithPacedTrainId = ( | |||
timetableITem: TimetableItemWithTimetableId | |||
): timetableITem is PacedTrainResultWithPacedTrainId => 'paced' in timetableITem; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd slightly prefer to check isPacedTrain(timetableItem.id)
here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
duration: Duration.parse(formattedItem.paced.duration), | ||
step: Duration.parse(formattedItem.paced.step), | ||
}, | ||
} as PacedTrainWithDetails; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of casting, could we set the type of the variable?
const formattedPacedTrains: PacedTrainWithDetails = …
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, done.
} as PacedTrainWithDetails; | ||
acc[1].push(formattedPacedTrains); | ||
} else { | ||
acc[0].push(formattedItem as TrainScheduleWithDetails); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this cast really necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not, you're right.
const result: PacedTrainResult[] = []; | ||
while (!reachEnd) { | ||
const promise = dispatch( | ||
// TODO : update the endpoint with the proper one when back is ready |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this TODO can be dropped now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch
...otherProps, | ||
}; | ||
|
||
if (isPacedTrainResultWithPacedTrainId(formattedItem)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This passes a partially constructed train result to the function. In particular, formattedItem
will not yet have a paced
field, so the function will always return false here?
Seems safer to check the timetableItem.id
instead of operating on an incomplete value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the change in this comment, it should be fine I think ?
); | ||
|
||
const [trainScheduleWithDetails, pacedTrainWithDetails] = relevantTimetableItems.reduce< | ||
[TrainScheduleWithDetails[], PacedTrainWithDetails[]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reduce()
is tricky to read for me. I would prefer a for
loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥲
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥲
* This function formats the timetable items with their simulation summaries. | ||
* Mapping the simulation results to the timetable items needs to be done in a second part | ||
* because otherwise typescript doesn't understand that a PacedTrainWithDetails will necessarily | ||
* be mapped with a PacedTrainId and not a TrainScheduleId (same for TrainScheduleWithDetails) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, curious. The following snippet works for me:
const formatTimetableItemSummaries = (
timetableItemIds: TimetableItemId[],
rawSummaries: Map<TimetableItemId, SimulationSummaryResult>,
rawTimetableItems: Map<TimetableItemId, TimetableItemWithTimetableId>,
rollingStocks: LightRollingStockWithLiveries[]
): Map<TimetableItemId, TimetableItemWithDetails> => {
const relevantTimetableItems = compact(
timetableItemIds.map((timetableItemId) => rawTimetableItems.get(timetableItemId))
);
const items = relevantTimetableItems.map((timetableItem): TimetableItemWithDetails | null => {
const rollingStock = rollingStocks.find((rs) => rs.name === timetableItem.rolling_stock_name);
const timetableItemSummary = rawSummaries.get(timetableItem.id);
if (!timetableItemSummary) return null;
let notHonoredReason: TimetableItemWithDetails['notHonoredReason'];
if (timetableItemSummary.status === 'success') {
if (isTooFast(timetableItem, timetableItemSummary)) notHonoredReason = 'trainTooFast';
if (isScheduledPointsNotHonored(timetableItem, timetableItemSummary))
notHonoredReason = 'scheduleNotHonored';
}
const startTime = new Date(timetableItem.start_time);
const otherProps =
timetableItemSummary.status === 'success'
? {
isValid: true,
arrivalTime: new Date(startTime.getTime() + timetableItemSummary.time),
duration: new Duration({ milliseconds: timetableItemSummary.time }),
pathLength: formatKmValue(timetableItemSummary.length, 'millimeters', 1),
mechanicalEnergyConsumed: jouleToKwh(timetableItemSummary.energy_consumption, true),
pathItemTimes: {
base: timetableItemSummary.path_item_times_base,
provisional: timetableItemSummary.path_item_times_provisional,
final: timetableItemSummary.path_item_times_final,
},
}
: {
isValid: false,
arrivalTime: null,
duration: null,
pathLength: '',
mechanicalEnergyConsumed: 0,
invalidReason:
timetableItemSummary.status === 'pathfinding_not_found' ||
timetableItemSummary.status === 'pathfinding_input_error'
? timetableItemSummary.error_type
: timetableItemSummary.status,
};
const formattedItem = {
...timetableItem,
name: timetableItem.train_name,
startTime,
stopsCount:
(timetableItem.schedule?.filter(
(step) => step.stop_for && Duration.parse(step.stop_for).ms > 0
).length ?? 0) + 1, // +1 to take the final stop (destination) into account
speedLimitTag: timetableItem.speed_limit_tag ?? null,
labels: timetableItem.labels ?? [],
rollingStock,
scheduledPointsNotHonored: notHonoredReason !== undefined,
notHonoredReason,
...otherProps,
};
if (isPacedTrainResultWithPacedTrainId(formattedItem)) {
return {
...formattedItem,
paced: {
duration: Duration.parse(formattedItem.paced.duration),
step: Duration.parse(formattedItem.paced.step),
},
};
}
return formattedItem;
});
return mapBy(compact(items), 'id');
};
Does this map()
approach not work on your machine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yes you're right. Not sure what I did before that made typescript complain.
[[], []] | ||
); | ||
|
||
const rawTrainScheduleSummaries = await postTrainScheduleSimulationSummary({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: would be slightly nicer to fetch these in parallel, without waiting for the train schedule request to complete before sending the paced train request.
const trainSchedulesPromise = postTrainScheduleSimulationSummary(…);
const pacedTrainsPromise = postPacedTrainSimulationSummary(…);
const rawTrainScheduleSummaries = await trainSchedulesPromise;
const rawPacedTrainSummaries = await pacedTrainsPromise;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
const rawTrainScheduleSummaries = await postTrainScheduleSimulationSummary({ | ||
body: { | ||
infra_id: _infraId, | ||
ids: editoastTrainScheduleIds, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The list can be empty, would be nicer to skip sending an HTTP request when there is nothing to fetch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
front/src/applications/operationalStudies/hooks/useScenarioData.ts
Outdated
Show resolved
Hide resolved
front/src/applications/operationalStudies/hooks/useScenarioData.ts
Outdated
Show resolved
Hide resolved
front/src/applications/operationalStudies/hooks/useScenarioData.ts
Outdated
Show resolved
Hide resolved
front/src/applications/operationalStudies/hooks/useLazyLoadTimatableItems.ts
Outdated
Show resolved
Hide resolved
front/src/applications/operationalStudies/hooks/useLazyLoadTimatableItems.ts
Outdated
Show resolved
Hide resolved
front/src/applications/operationalStudies/hooks/useLazyLoadTimatableItems.ts
Outdated
Show resolved
Hide resolved
front/src/applications/operationalStudies/hooks/useLazyLoadTimatableItems.ts
Outdated
Show resolved
Hide resolved
front/src/applications/operationalStudies/hooks/useLazyLoadTimatableItems.ts
Outdated
Show resolved
Hide resolved
c1396d9
to
d1851e9
Compare
setProjectedTrainsById((prev) => { | ||
const newProjectedTrainsById = new Map(prev); | ||
trainSchedulesToUpsert.forEach((trainSchedule) => { | ||
timetableItemsToUpsert.forEach((trainSchedule) => { | ||
newProjectedTrainsById.delete(trainSchedule.id); | ||
}); | ||
return newProjectedTrainsById; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setProjectedItemsById((prev) => {
const newProjectedItemsById = new Map(prev);
timetableItemsToUpsert.forEach((timetableItem) => {
newProjectedTrainsById.delete(timetableItem.id);
});
return newProjectedItemsById;
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kept trainSchedule
inside for now to remember that we manipulate only train schedule and not paced train. I planned that we would change this when dealing with projection in the related issue. Is that ok for you ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job !
Left some comments
await this.verifyOccurrencesCount(totalOccurrences, index); | ||
|
||
await expect(this.hideOccurrencesButton.nth(index)).not.toBeVisible(); | ||
await expect(pacedTrainItem.locator('.toggle-icon')).toBeVisible(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not use data-testid
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why but with the data-testid
, playwright doesn't find the Locator
🤔
const formattedDuration = dayjs.duration(pacedTrainDuration).asMinutes(); | ||
const formattedStep = dayjs.duration(step).asMinutes(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's better to use the values directly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
await expect(pacedTrainCadenceLocator).toHaveText( | ||
`${String.fromCodePoint(0x2014)} ${formattedStep}min` | ||
); // UI format: "- 20min" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can directly check for 20min
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm the displayed text is "- 20min" so I have to deal with the special character no ? Or you want me to test a .toEqual('20min')
and pass this hardcoded value when calling the function ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
toHaveText()
check if 20min is in the text so the format is not needed
If you keep the format change it to toEqual()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
|
||
async clickOnEditTrainSchedule() { | ||
await this.editTrainScheduleButton.click(); | ||
await this.closeToastNotification(); | ||
} | ||
|
||
async verifyPacedTrainItemDetails( | ||
pacedTrainData: Pick<PacedTrainBase, 'train_name' | 'start_time' | 'labels' | 'paced'>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can avoid using the project types and create a new type for the tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} = pacedTrainData; | ||
|
||
const pacedTrainItem = this.timetableTrains.nth(pacedTrainIndex); | ||
const occurrenceItem = pacedTrainItem.getByTestId('occurrence-item').nth(occurrenceIndex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const occurrenceItem = pacedTrainItem.getByTestId('occurrence-item').nth(occurrenceIndex); | |
getOccurrenceItem(occurrenceIndex: number): Locator { | |
return this.page.getByTestId('occurrence-item').nth(occurrenceIndex); | |
} |
await occurrenceItem.hover(); | ||
await expect(occurrenceItem.getByTestId('project-item')).not.toBeVisible(); | ||
await expect(occurrenceItem.getByTestId('duplicate-item')).not.toBeVisible(); | ||
await expect(occurrenceItem.getByTestId('edit-item')).not.toBeVisible(); | ||
await expect(occurrenceItem.getByTestId('delete-item')).not.toBeVisible(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
await occurrenceItem.hover(); | |
await expect(occurrenceItem.getByTestId('project-item')).not.toBeVisible(); | |
await expect(occurrenceItem.getByTestId('duplicate-item')).not.toBeVisible(); | |
await expect(occurrenceItem.getByTestId('edit-item')).not.toBeVisible(); | |
await expect(occurrenceItem.getByTestId('delete-item')).not.toBeVisible(); | |
getOccurrenceItem(occurrenceIndex: number): Locator { | |
return this.page.getByTestId('occurrence-item').nth(occurrenceIndex); | |
} | |
async getActionButtonsLocators(occurrenceIndex: number): Record<string, Locator> { | |
const occurrenceItem = this.getOccurrenceItem(occurrenceIndex); | |
await occurrenceItem.hover(); | |
return { | |
projectItem: occurrenceItem.getByTestId('project-item'), | |
duplicateItem: occurrenceItem.getByTestId('duplicate-item'), | |
editItem: occurrenceItem.getByTestId('edit-item'), | |
deleteItem: occurrenceItem.getByTestId('delete-item'), | |
}; | |
} | |
async verifyItemsNotVisible(occurrenceIndex: number): Promise<void> { | |
const actionButtonsLocators = this.getActionButtonsLocators(occurrenceIndex); | |
await Promise.all( | |
Object.values(actionButtonsLocators).map(locator => expect(locator).not.toBeVisible()) | |
); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getOccurrenceItem(occurrenceIndex: number): Locator {
return this.page.getByTestId('occurrence-item').nth(occurrenceIndex);
}
This won't work because even if they aren't displayed, occurence items still exist in the DOM, so doing page.get...
will always return the first group of occurrence. We need to locate them relatively to the current paced train we are testing.
Also regarding this comment, It seems like you want me to fetch occurrenceItem
only once but by calling it inside the getActionButtonsLocators
method (and the one I'll be creating for name, startTime etc) means we will call it multiple times.
So instead of calling getOccurrenceItem
in each method I could pass the current occurrence Locator
we are looping on that we would fetch only once at the beginning of verifyOccurrenceDetails
.
But if I do that (for example with the name)
async verifyOccurrenceName(currentPacedTrainLocator: Locator, expectedName: string) {
const occurrenceNameLocator = currentPacedTrainLocator.locator('.occurrence-item-name');
await expect(occurrenceNameLocator).toHaveText(expectedName);
}
I have this eslint warning for each method : Expected 'this' to be used by class async method 'verifyOccurrenceName'.
So best solution seems to be the actual one. Or do you think of something else ?
duration: 'PT90M', | ||
step: 'PT20M', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It better to hard code the values 90 and 20
const formattedTimeRangeDuration = dayjs | ||
.duration(DEFAULT_PACED_TRAIN_SETTINGS.paced.duration) | ||
.asMinutes() | ||
.toString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use hardcoded values
const formattedCadence = dayjs | ||
.duration(DEFAULT_PACED_TRAIN_SETTINGS.paced.step) | ||
.asMinutes() | ||
.toString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same use hardcoded values
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because multiple locators are scoped within occurrenceItem, you can move all of them in a new page model paced-train-section.ts
and it's best to store them in a reusable function so that you only fetch occurrenceItem once and reuse it
18590e6
to
ce6ee25
Compare
@@ -103,10 +103,12 @@ const ScenarioContent = ({ | |||
timeTableId: scenario.timetable_id, | |||
netzgrafikDto, | |||
addUpsertedTrainSchedules: (upsertedTrainSchedules: TrainScheduleResultWithTrainId[]) => { | |||
upsertTrainSchedules(upsertedTrainSchedules); | |||
// TODO Paced trains : update this in https://github.com/OpenRailAssociation/osrd/issues/10612 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove the 2 comments, since there is nothing to change here (everything will by in the functions ;) )
// TODO Paced trains : update this in https://github.com/OpenRailAssociation/osrd/issues/10612 |
); | ||
|
||
const [trainScheduleWithDetails, pacedTrainWithDetails] = relevantTimetableItems.reduce< | ||
[TrainScheduleWithDetails[], PacedTrainWithDetails[]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥲
@@ -55,6 +59,7 @@ const SimulationResults = ({ | |||
infraId, | |||
projectionData, | |||
trainScheduleSummaries, | |||
// timetableItemsWithDetails, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// timetableItemsWithDetails, |
{ forceRefetch: true, subscribe: false } | ||
) | ||
); | ||
// need to unsubscribe on get call to avoid cache issue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm have you unsubscribe here ? Or it is not necessary ?
if (validTrainConfig) { | ||
const { timetableId, firstStartTime, trainCount, trainDelta, trainStep, baseTrainName } = | ||
validTrainConfig; | ||
const { timetableId, firstStartTime, trainCount, trainDelta, trainStep, baseTrainName } = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should setIsWorking(true) here
if (showPacedTrains) { | ||
try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move the try above the test showPacedTrains
if (showPacedTrains) { | |
try { | |
try { | |
if (showPacedTrains) { | |
... |
This extra useEffect introduced a bug in end to end tests. The only way to reproduce it was to set the train name and start time in less that 500ms (the debounce used for these fields) which the e2e tests do. At this speed, after filling the name, a useEffect is fired after 500ms after to update the store, but since the test is also filling the start time a few ms later, the useEffect was called because nameFromStore had been updated resulting in setting the start time back at its original value. A workaround had been done for tests 011 and 012 to insert the selection of the rolling stock between the name and start time filling. Signed-off-by: SharglutDev <[email protected]>
Signed-off-by: SharglutDev <[email protected]>
Signed-off-by: SharglutDev <[email protected]>
ce6ee25
to
362f2b0
Compare
See commits (will be merged all together)
part of #10615
Note
PR is now testable !
As some logic from train schedule has been reused for the pace train mode, be sure to check that all previous behavior when paced train mode is off are still working (add/edit/get/delete, duplicate, import/export, nge, drag, selecting/projecting a train, stdcm)
E2E Tests :