diff --git a/assets/js/components/ChargingPlans/PlanStaticSettings.vue b/assets/js/components/ChargingPlans/PlanStaticSettings.vue index 0598bfbfb..6704ef620 100644 --- a/assets/js/components/ChargingPlans/PlanStaticSettings.vue +++ b/assets/js/components/ChargingPlans/PlanStaticSettings.vue @@ -225,9 +225,17 @@ export default defineComponent({ }, socOptions() { // a list of entries from 5 to 100 with a step of 5 - return Array.from(Array(20).keys()) + const options = Array.from(Array(20).keys()) .map((i) => 5 + i * 5) .map(this.socOption); + + // add current soc value if it's not in the list + if (this.selectedSoc && !options.find((o) => o.value === this.selectedSoc)) { + options.push(this.socOption(this.selectedSoc)); + options.sort((a, b) => a.value - b.value); + } + + return options; }, energyOptions() { const options = energyOptions( @@ -236,7 +244,8 @@ export default defineComponent({ this.fmtWh, this.fmtPercentage, "-", - this.socPerKwh + this.socPerKwh, + this.selectedEnergy ); // remove the first entry (0) return options.slice(1); diff --git a/assets/js/utils/energyOptions.ts b/assets/js/utils/energyOptions.ts index 264fcb412..d4645f0c8 100644 --- a/assets/js/utils/energyOptions.ts +++ b/assets/js/utils/energyOptions.ts @@ -36,11 +36,14 @@ export function energyOptions( fmtWh: InstanceType["fmtWh"], fmtPercentage: InstanceType["fmtPercentage"], zeroText: string, - socPerKwh?: number + socPerKwh?: number, + selectedValue?: number ) { const step = optionStep(maxEnergy); const result = []; - for (let energy = 0; energy <= maxEnergy; energy += step) { + + // helper to create option + const makeOption = (energy: number) => { let text = fmtEnergy(energy, step, fmtWh, zeroText); const disabled = energy < fromEnergy / 1e3 && energy !== 0; const soc = estimatedSoc(energy, socPerKwh); @@ -49,7 +52,19 @@ export function energyOptions( } // prevent rounding errors const energyNormal = parseFloat(energy.toFixed(3)); - result.push({ energy: energyNormal, text, disabled }); + return { energy: energyNormal, text, disabled }; + }; + + // add standard increments + for (let energy = 0; energy <= maxEnergy; energy += step) { + result.push(makeOption(energy)); } + + // add selected value if it's not in the list + if (selectedValue && !result.find((o) => o.energy === selectedValue)) { + result.push(makeOption(selectedValue)); + result.sort((a, b) => a.energy - b.energy); + } + return result; } diff --git a/tests/plan.spec.ts b/tests/plan.spec.ts index dcbab92f9..89566d9ec 100644 --- a/tests/plan.spec.ts +++ b/tests/plan.spec.ts @@ -120,6 +120,35 @@ test.describe("vehicle variations", async () => { // no repeating plans option await verifyRepeatingPlanAvailable(page, lp1, false); }); + + test("non-standard energy values are visible in dropdown", async ({ page }) => { + await page.goto("/"); + const lp1 = await page.getByTestId("loadpoint").first(); + + // verify guest vehicle + await expect(lp1.getByTestId("vehicle-name")).toHaveText("Guest vehicle"); + + // create plan with non-standard energy value via API + const response = await page.request.post( + `/api/loadpoints/1/plan/energy/32/2050-09-04T05:00:00.000Z` + ); + expect(response.status()).toBe(200); + + // verify plan is shown + const plan = await lp1.getByTestId("charging-plan"); + await expect(plan).toContainText("32 kWh"); + + // open modal and verify dropdown + await plan.getByRole("button").click(); + const modal = await page.getByTestId("charging-plan-modal").first(); + const energySelect = modal.getByTestId("static-plan-energy"); + await expect(energySelect).toBeVisible(); + + // verify non-standard value is selected + await expect(energySelect).toHaveValue("32"); + await energySelect.selectOption("70"); + await expect(energySelect).toHaveValue("70"); + }); }); test.describe("vehicle no soc no capacity", async () => { @@ -212,6 +241,35 @@ test.describe("vehicle variations", async () => { // repeating plans option await verifyRepeatingPlanAvailable(page, lp1, true); }); + + test("non-standard soc values are visible in dropdown", async ({ page }) => { + await page.goto("/"); + const lp1 = await page.getByTestId("loadpoint").first(); + await lp1 + .getByTestId("change-vehicle") + .locator("select") + .selectOption("Vehicle with SoC with Capacity"); + + // create plan with non-standard SoC value via API + const response = await page.request.post( + `/api/vehicles/vehicleSocCapacity/plan/soc/72/2050-09-04T05:00:00.000Z` + ); + expect(response.status()).toBe(200); + + // verify plan is shown + const plan = await lp1.getByTestId("charging-plan"); + await expect(plan).toContainText("72%"); + + // open modal and verify dropdown + plan.getByRole("button").click(); + const modal = await page.getByTestId("charging-plan-modal").first(); + const socSelect = modal.getByTestId("static-plan-soc"); + + // verify non-standard value is selected + await expect(socSelect).toHaveValue("72"); + await socSelect.selectOption("80%"); + await expect(socSelect).toHaveValue("80"); + }); }); test.describe("loadpoint with soc, guest vehicle", async () => {