fix(dev): WP-37 — dev-switcher resets scenario/role instead of sticking
CI / frontend (push) Successful in 1m49s
CI / storybook-a11y (push) Successful in 4m59s
CI / backend (push) Successful in 1m27s
CI / e2e (push) Successful in 2m59s
CI / semgrep (push) Successful in 59s
CI / api-client-drift (push) Successful in 2m9s

currentScenario()/currentRole() read the URL param before sessionStorage, so a
stale ?scenario=/?role= in the address bar overrode the switcher on reload
("stuck on slow"). The switcher now strips both dev params from the URL
(pure stripDevParams + history.replaceState) before reloading, so the stored
value wins.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
eho
2026-07-23 13:34:01 +02:00
co-authored by Claude Opus 4.8
parent a828e604d1
commit fe9e3121c7
4 changed files with 77 additions and 1 deletions
@@ -0,0 +1,22 @@
import { describe, it, expect } from 'vitest';
import { stripDevParams } from './dev-params';
describe('stripDevParams (WP-37)', () => {
it('removes ?scenario and ?role so the stored dev value wins on reload', () => {
expect(stripDevParams('http://localhost:4200/dashboard?scenario=slow&role=admin')).toBe(
'http://localhost:4200/dashboard',
);
});
it('keeps unrelated query params and the path/hash', () => {
expect(stripDevParams('http://localhost:4200/beheer/zaken?scenario=error&tab=2#top')).toBe(
'http://localhost:4200/beheer/zaken?tab=2#top',
);
});
it('is a no-op when neither param is present', () => {
expect(stripDevParams('http://localhost:4200/dashboard')).toBe(
'http://localhost:4200/dashboard',
);
});
});
@@ -0,0 +1,14 @@
/**
* Remove the dev-only `?scenario=` and `?role=` params from a URL (WP-37). Once the
* dev switcher (debug-state) has been used, sessionStorage is the authoritative source
* for both — `currentScenario()`/`currentRole()` read the URL FIRST, so a stale param
* left in the address bar would override the switcher on reload (the "stuck on slow"
* bug). Stripping the params before reload lets the stored value win. Pure: returns the
* rewritten href, mutates nothing.
*/
export function stripDevParams(href: string): string {
const url = new URL(href);
url.searchParams.delete('scenario');
url.searchParams.delete('role');
return url.toString();
}
@@ -7,6 +7,7 @@ import { map } from '@shared/application/remote-data';
import { Role } from '@shared/domain/role';
import { ROLES, currentRole, setRole } from '@shared/infrastructure/role';
import { Scenario, SCENARIOS, currentScenario, setScenario } from '@shared/infrastructure/scenario';
import { stripDevParams } from '@shared/infrastructure/dev-params';
import { maskBsn, redactProfile } from './mask';
// CIBG-GAP EXTENSION: n/a — devtool, no corresponding CIBG concept; deliberately
@@ -143,10 +144,18 @@ export class DebugStateComponent {
switchRole(r: Role): void {
setRole(r);
location.reload();
this.applyAndReload();
}
switchScenario(s: Scenario): void {
setScenario(s);
this.applyAndReload();
}
// Strip the dev params from the URL before reloading (WP-37) so a stale ?scenario=/?role=
// in the address bar can't override the value the switcher just stored (currentScenario/
// currentRole read the URL first) — otherwise a switch to "default"/"drafter" gets stuck.
private applyAndReload(): void {
history.replaceState({}, '', stripDevParams(window.location.href));
location.reload();
}