From 10d516e93ef9fecfc9bfdb1630d57c144068597b Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Thu, 1 Oct 2026 20:39:23 +0200 Subject: [PATCH] fix(frontend): preserve ladder form selections when editing Clone the form before populating its controls so editing retains the provider, approval mode and cadence in the submitted configuration. Cover the Edit and submit path in Jest and the production browser, including repeated opens, defaults, Cancel/Close and mobile behavior. --- frontend/src/__tests__/ladder.test.ts | 29 +++++- frontend/src/ladder.ts | 32 +++--- frontend/tests-e2e/ladder-config.spec.ts | 125 +++++++++++++++++++++++ 3 files changed, 166 insertions(+), 20 deletions(-) create mode 100644 frontend/tests-e2e/ladder-config.spec.ts diff --git a/frontend/src/__tests__/ladder.test.ts b/frontend/src/__tests__/ladder.test.ts index 03b39960..cb1aca3a 100644 --- a/frontend/src/__tests__/ladder.test.ts +++ b/frontend/src/__tests__/ladder.test.ts @@ -9,6 +9,7 @@ */ import { initLadderingSettings, renderConfigTable, saveLadderConfig } from '../ladder'; import type { LadderConfig } from '../api'; +import { waitFor } from '@testing-library/dom'; jest.mock('../api', () => ({ getLadderConfigs: jest.fn(), @@ -50,9 +51,9 @@ function baseConfig(overrides: Partial = {}): LadderConfig { // Render the full section (incl. the modal form) into the DOM so the exported // helpers have the elements they read. -async function renderSection(): Promise { +async function renderSection(configs: LadderConfig[] = []): Promise { document.body.innerHTML = '
'; - (api.getLadderConfigs as jest.Mock).mockResolvedValue([]); + (api.getLadderConfigs as jest.Mock).mockResolvedValue(configs); await initLadderingSettings(false); } @@ -62,6 +63,30 @@ describe('ladder.ts', () => { mockShowToast.mockReset(); }); + test.each([ + ['aws', 'email_approval', 'daily'], + ['azure', 'auto_approve', 'weekly'], + ['gcp', 'auto_approve', 'weekly'], + ] as const)('editing %s preserves the selected values in the submitted config', async (provider, mode, cadence) => { + const config = baseConfig({ id: 'config-1', provider, mode, cadence, target_coverage: 80 }); + await renderSection([config]); + (api.upsertLadderConfig as jest.Mock).mockImplementation(async (cfg: LadderConfig) => cfg); + + document.querySelector('.ladder-edit-btn')!.click(); + expect(document.getElementById('ladder-cfg-provider')).toHaveValue(provider); + expect(document.getElementById('ladder-cfg-mode')).toHaveValue(mode); + expect(document.getElementById('ladder-cfg-cadence')).toHaveValue(cadence); + expect(document.getElementById('ladder-cfg-provider')).toBeDisabled(); + expect(document.getElementById('ladder-cfg-account')).toHaveAttribute('readonly'); + + (document.getElementById('ladder-cfg-target-coverage') as HTMLInputElement).value = '75'; + document.getElementById('ladder-config-form')!.dispatchEvent(new Event('submit', { cancelable: true })); + await waitFor(() => expect(document.getElementById('ladder-config-modal')).toHaveClass('hidden')); + expect(api.upsertLadderConfig).toHaveBeenCalledTimes(1); + const { updated_at: _updatedAt, ...expected } = config; + expect(api.upsertLadderConfig).toHaveBeenCalledWith({ ...expected, target_coverage: 75 }); + }); + describe('renderLadderingSection: toggle label accessibility (issue #1412 row 3.1)', () => { // Regression guard: the Enable Commitment Laddering label text must NOT be // a