diff --git a/src/context/SimulationContext.tsx b/src/context/SimulationContext.tsx index ec8155c..cdaa41c 100644 --- a/src/context/SimulationContext.tsx +++ b/src/context/SimulationContext.tsx @@ -36,6 +36,17 @@ import { loadTemperaturesFromCSV, } from '@/utils/temperatures'; +type SpeedState = { + text: string; + multiply: number; +}; + +const SPEED_STATES: SpeedState[] = [ + { text: 'x1', multiply: 1 }, + { text: 'x3', multiply: 3 }, + { text: 'x5', multiply: 5 }, +]; + // TODO: regroup by type like windowSize: { value, update }... type SimulationContextType = UseHouseComponentsReturnType & { status: SimulationStatus; @@ -69,6 +80,8 @@ type SimulationContextType = UseHouseComponentsReturnType & { numberOfFloors: number; updateNumberOfFloors: (numberOfFloors: number) => void; houseComponentsConfigurator: HouseComponentsConfigurator; + speed: string; + nextSpeed: () => void; }; const SimulationContext = createContext(null); @@ -99,6 +112,7 @@ export const SimulationProvider = ({ const [simulationStatus, setSimulationStatus] = useState( SimulationStatus.LOADING, // waiting for the temperatures... ); + const [simulationSpeedIdx, setSimulationSpeedIdx] = useState(0); // Computed states const csv = @@ -209,7 +223,7 @@ export const SimulationProvider = ({ } else { setSimulationStatus(SimulationStatus.FINISHED); } - }, simulationFrameMS); + }, simulationFrameMS / SPEED_STATES[simulationSpeedIdx].multiply); } return () => { @@ -224,6 +238,7 @@ export const SimulationProvider = ({ simulationFrameMS, dispatchHistory, currentDayIdx, + simulationSpeedIdx, ]); // Update simulation's current state @@ -317,6 +332,9 @@ export const SimulationProvider = ({ numberOfFloors: simulationSettings.numberOfFloors, updateNumberOfFloors, houseComponentsConfigurator: simulationSettings.houseConfigurator, + speed: SPEED_STATES[simulationSpeedIdx].text, + nextSpeed: () => + setSimulationSpeedIdx((curr) => (curr + 1) % SPEED_STATES.length), ...houseComponentsHook, }), [ @@ -344,6 +362,7 @@ export const SimulationProvider = ({ gotToDay, updateWindowSize, updateNumberOfFloors, + simulationSpeedIdx, houseComponentsHook, ], ); diff --git a/src/modules/common/SimulationControl.tsx b/src/modules/common/SimulationControl.tsx index 027f18f..aec4040 100644 --- a/src/modules/common/SimulationControl.tsx +++ b/src/modules/common/SimulationControl.tsx @@ -6,6 +6,7 @@ import { useSimulation } from '@/context/SimulationContext'; import { SimulationStatus } from '@/types/simulation'; import { LabelledSlider } from './LabelledSlider'; +import { SpeedButton } from './SpeedButton'; export const SimulationControl = (): JSX.Element => { const { @@ -26,18 +27,21 @@ export const SimulationControl = (): JSX.Element => { return ( - handleGoToDay(v)} - min={0} - max={numberOfDays - 1} - hideValue - hideLabels={status === SimulationStatus.LOADING} - formatValue={(v) => getDateOf(v).toLocaleDateString()} - disabled={status === SimulationStatus.LOADING} - /> + + + handleGoToDay(v)} + min={0} + max={numberOfDays - 1} + hideValue + hideLabels={status === SimulationStatus.LOADING} + formatValue={(v) => getDateOf(v).toLocaleDateString()} + disabled={status === SimulationStatus.LOADING} + /> + { + const { speed, nextSpeed } = useSimulation(); + + return ( + + ); +}; diff --git a/tests/player/SimulationControlPage.ts b/tests/player/SimulationControlPage.ts index ef56a65..aa83620 100644 --- a/tests/player/SimulationControlPage.ts +++ b/tests/player/SimulationControlPage.ts @@ -25,10 +25,14 @@ export class SimulationControlPage { this.lastDate = this.page.getByTestId(`${this.testId}-max`); } - getButton(action: 'start' | 'pause'): Locator { + getControlButton(action: 'start' | 'pause'): Locator { return this.page.getByTestId(`simulation-control-button-${action}`); } + getSpeedButton(speed: number): Locator { + return this.page.getByTestId(`speed-button-x${speed}`); + } + async startSimulation(): Promise { await clickOnButton( this.page.getByTestId('simulation-control-button-start'), diff --git a/tests/player/simulation-control.spec.ts b/tests/player/simulation-control.spec.ts index d0ab5e7..f90a940 100644 --- a/tests/player/simulation-control.spec.ts +++ b/tests/player/simulation-control.spec.ts @@ -11,7 +11,7 @@ test('clicking on start should run the simulation', async ({ page }) => { // Wait for *any* change in the current date await page.waitForTimeout(1_000); - await expect(control.getButton('pause')).toBeVisible(); + await expect(control.getControlButton('pause')).toBeVisible(); await control.pauseSimulation(); const date = await info.dateInfo.textContent(); @@ -21,7 +21,7 @@ test('clicking on start should run the simulation', async ({ page }) => { const totElectricityCost = await info.totElectricityCostInfo.textContent(); expect(date).toBeDefined(); - await expect(control.getButton('start')).toBeVisible(); + await expect(control.getControlButton('start')).toBeVisible(); await control.startSimulation(); // Wait for *any* change in the current date @@ -71,7 +71,7 @@ test('moving in the futur should work when the simulation is not runned', async // the user should be able to resume the simulation await control.startSimulation(); await page.waitForTimeout(1_000); - await expect(control.getButton('pause')).toBeVisible(); + await expect(control.getControlButton('pause')).toBeVisible(); const finalDate = await info.dateInfo.textContent(); expect(finalDate).toBeDefined(); expect(new Date(finalDate!).getTime()).toBeGreaterThan( @@ -88,18 +88,18 @@ test('moving in the futur should pause the simulation when running', async ({ await control.startSimulation(); // Wait for *any* change in the current date await page.waitForTimeout(1_000); - await expect(control.getButton('pause')).toBeVisible(); + await expect(control.getControlButton('pause')).toBeVisible(); await control.moveDateSlider(50); const date = await info.dateInfo.textContent(); expect(date).toBeDefined(); - await expect(control.getButton('start')).toBeVisible(); + await expect(control.getControlButton('start')).toBeVisible(); // the user should be able to resume the simulation await control.startSimulation(); await page.waitForTimeout(1_000); - await expect(control.getButton('pause')).toBeVisible(); + await expect(control.getControlButton('pause')).toBeVisible(); const newDate = await info.dateInfo.textContent(); expect(newDate).toBeDefined(); expect(new Date(newDate!).getTime()).toBeGreaterThan( @@ -121,7 +121,7 @@ test('should move in the futur and in the past', async ({ page }) => { await control.startSimulation(); // Wait for *any* change in the current date await page.waitForTimeout(1_000); - await expect(control.getButton('pause')).toBeVisible(); + await expect(control.getControlButton('pause')).toBeVisible(); const newDate = await info.dateInfo.textContent(); expect(newDate).toBeDefined(); @@ -131,7 +131,7 @@ test('should move in the futur and in the past', async ({ page }) => { // move to the past await control.moveDateSlider(10); - await expect(control.getButton('start')).toBeVisible(); + await expect(control.getControlButton('start')).toBeVisible(); const dateInThePast = await info.dateInfo.textContent(); expect(dateInThePast).toBeDefined(); expect(new Date(dateInThePast!).getTime()).toBeLessThan( @@ -141,10 +141,54 @@ test('should move in the futur and in the past', async ({ page }) => { // the user should be able to resume the simulation await control.startSimulation(); await page.waitForTimeout(1_000); - await expect(control.getButton('pause')).toBeVisible(); + await expect(control.getControlButton('pause')).toBeVisible(); const finalDate = await info.dateInfo.textContent(); expect(finalDate).toBeDefined(); expect(new Date(finalDate!).getTime()).toBeGreaterThan( new Date(dateInThePast!).getTime(), ); }); + +test('increasing speed should reach a greater date after 1 second', async ({ + page, +}) => { + const housePage = new HousePage(page); + const { info, control } = housePage; + await housePage.goto(); + + // start the simulation in normal speed (x1) + await control.startSimulation(); + await page.waitForTimeout(1_000); + await control.pauseSimulation(); + + const x1Date = await info.dateInfo.textContent(); + expect(x1Date).toBeDefined(); + + // set speed from x1 to x3 and restart the simulation + await control.getSpeedButton(1).click(); + expect(await control.getSpeedButton(3).textContent()).toBe('x3'); + await control.moveDateSlider(0); + await control.startSimulation(); + await page.waitForTimeout(1_000); + await control.pauseSimulation(); + + const x3Date = await info.dateInfo.textContent(); + expect(x3Date).toBeDefined(); + expect(new Date(x3Date!).getTime()).toBeGreaterThan( + new Date(x1Date!).getTime(), + ); + + // set speed from x3 to x5 and restart the simulation + await control.getSpeedButton(3).click(); + expect(await control.getSpeedButton(5).textContent()).toBe('x5'); + await control.moveDateSlider(0); + await control.startSimulation(); + await page.waitForTimeout(1_000); + await control.pauseSimulation(); + + const x5Date = await info.dateInfo.textContent(); + expect(x5Date).toBeDefined(); + expect(new Date(x5Date!).getTime()).toBeGreaterThan( + new Date(x3Date!).getTime(), + ); +}); diff --git a/tests/player/simulation-duration.spec.ts b/tests/player/simulation-duration.spec.ts index d87e3be..7586eec 100644 --- a/tests/player/simulation-duration.spec.ts +++ b/tests/player/simulation-duration.spec.ts @@ -9,7 +9,7 @@ test('simulation duration should be disabled when simulation is running', async const { settings, control } = housePage; await housePage.goto(); await settings.setSimulationDuration(25); - await control.getButton('start').click(); + await control.getControlButton('start').click(); await expect(settings.simulationDuration).toBeDisabled(); });