Flaky under load: keycloak-admin user-list spec settles resources with a fixed hop count (reddens full-suite SonarQube scan); 9 sibling specs share the pattern
#830
The component gates its httpResources on an async admin-permission check, so the chain is: permission promise → request computation updates → loader promise → value. Two hops is enough on an idle machine. Under the Sonar job (81 projects, --coverage, parallel) the chain does not complete within the allotted hops, so assertions run against an empty list. Passes in isolation and in a full single-project run locally — only the loaded full-suite run trips it.
Fix
Make settle() accept a predicate and keep hopping (bounded, then throw) until the awaited state actually arrives, e.g.:
Waiting on the observable outcome rather than a hop count removes the timing dependence entirely.
Related — latent, not yet failing
Nine sibling specs in libraries/keycloak-admin/src/lib/components/ carry the identical fixed-hop settle() helper (realm-events, realm-settings, clients-list, groups-list, roles-list, user-consents, user-federated-identity, user-detail, user-roles). They have the same latent flake; user-list is simply the one that lost the race first. Worth a follow-up sweep to the predicate form — I have deliberately NOT swept them in the fixing PR to keep it reviewable, so this ticket should stay open for that sweep even after user-list is fixed.
## Symptom
Second failure reddening the `SonarQube Scan` job (the only job running the full `nx run-many --target=test --coverage` suite — see #829 for the first):
```
FAIL keycloak-admin libraries/keycloak-admin/src/lib/components/user-list/user-list.component.spec.ts
> UserListComponent > stays idle until the admin permission check passes, then loads users and count
AssertionError: expected [] to deeply equal [ { id: 'u1', … }, … ]
```
Unlike #829 this one is a **test-harness flake, not an app bug** — the component is fine.
## Root cause
The spec settles resources with a FIXED number of macrotask hops:
```ts
async function settle(): Promise<void> {
TestBed.tick();
await new Promise((r) => setTimeout(r, 0));
TestBed.tick();
}
...
await settle(); // permission promise resolves -> resources fire
await settle(); // loader promises resolve
```
The component gates its `httpResource`s on an async admin-permission check, so the chain is: permission promise → request computation updates → loader promise → value. Two hops is enough on an idle machine. Under the Sonar job (81 projects, `--coverage`, parallel) the chain does not complete within the allotted hops, so assertions run against an empty list. Passes in isolation and in a full single-project run locally — only the loaded full-suite run trips it.
## Fix
Make `settle()` accept a predicate and keep hopping (bounded, then throw) until the awaited state actually arrives, e.g.:
```ts
await settle(() => fixture.componentInstance.users().length > 0);
```
Waiting on the observable outcome rather than a hop count removes the timing dependence entirely.
## Related — latent, not yet failing
**Nine sibling specs in `libraries/keycloak-admin/src/lib/components/` carry the identical fixed-hop `settle()` helper** (realm-events, realm-settings, clients-list, groups-list, roles-list, user-consents, user-federated-identity, user-detail, user-roles). They have the same latent flake; user-list is simply the one that lost the race first. Worth a follow-up sweep to the predicate form — I have deliberately NOT swept them in the fixing PR to keep it reviewable, so this ticket should stay open for that sweep even after user-list is fixed.
Fix for the user-list spec is up in spikersoft-angular PR #570 (fix/sonar-suite-red-jwt-race), alongside #829 since both were reddening the same job.
settle() now takes an optional predicate and hops (bounded at 50, then throws with a clear message) until the awaited state arrives — await settle(() => fixture.componentInstance.users().length > 0) instead of two blind hops. The negative/error cases wait on snackBar.open having been called, and the pagination/force-refresh cases wait on the specific follow-up call landing.
Leaving this ticket OPEN on purpose. PR #570 only fixes user-list.component.spec.ts — the one that actually lost the race. The nine sibling specs listed above still carry the identical fixed-hop helper and remain latent flakes; this ticket tracks that sweep. Closing it when #570 merges would lose that.
Full local nx run-many --target=test is green across all 81 projects, so user-list was the only sibling failing today.
— Opus 5 Agent
Fix for the user-list spec is up in spikersoft-angular **PR #570** (`fix/sonar-suite-red-jwt-race`), alongside #829 since both were reddening the same job.
`settle()` now takes an optional predicate and hops (bounded at 50, then throws with a clear message) until the awaited state arrives — `await settle(() => fixture.componentInstance.users().length > 0)` instead of two blind hops. The negative/error cases wait on `snackBar.open` having been called, and the pagination/force-refresh cases wait on the specific follow-up call landing.
**Leaving this ticket OPEN on purpose.** PR #570 only fixes `user-list.component.spec.ts` — the one that actually lost the race. The nine sibling specs listed above still carry the identical fixed-hop helper and remain latent flakes; this ticket tracks that sweep. Closing it when #570 merges would lose that.
Full local `nx run-many --target=test` is green across all 81 projects, so user-list was the only sibling failing today.
— Opus 5 Agent
CI evidence: SonarQube Scan passed on PR #570 — first green scan today. That covers the user-list spec.
Reminder that this ticket stays open for the remaining sweep: nine sibling keycloak-admin specs still use the fixed-hop settle() and are latent flakes under a loaded full-suite run.
— Opus 5 Agent
CI evidence: `SonarQube Scan` passed on PR #570 — first green scan today. That covers the user-list spec.
Reminder that this ticket stays open for the remaining sweep: nine sibling keycloak-admin specs still use the fixed-hop `settle()` and are latent flakes under a loaded full-suite run.
— Opus 5 Agent
Status: the user-list half is merged to master (PR #570, b3626e69) and master's full-suite SonarQube Scan is green again (run 18137 on 721d171b).
This ticket stays open for the remaining sweep. Nine sibling specs in libraries/keycloak-admin/src/lib/components/ still settle promise-loader resources with a fixed hop count and carry the same latent flake: realm-events, realm-settings, clients-list, groups-list, roles-list, user-consents, user-federated-identity, user-detail, user-roles.
They pass today, so this is not urgent — but the failure mode is nasty when it does hit: the only job running the full suite is the Sonar scan, which does not gate publish, so a flake there reddens master quietly and stales the Sonar metrics rather than blocking anything loudly. The fix is mechanical (predicate-based settle(), as in user-list) and would be one small PR.
— Opus 5 Agent
Status: the user-list half is merged to master (PR #570, `b3626e69`) and master's full-suite `SonarQube Scan` is green again (run 18137 on `721d171b`).
**This ticket stays open for the remaining sweep.** Nine sibling specs in `libraries/keycloak-admin/src/lib/components/` still settle promise-loader resources with a fixed hop count and carry the same latent flake: realm-events, realm-settings, clients-list, groups-list, roles-list, user-consents, user-federated-identity, user-detail, user-roles.
They pass today, so this is not urgent — but the failure mode is nasty when it does hit: the only job running the full suite is the Sonar scan, which does not gate `publish`, so a flake there reddens master quietly and stales the Sonar metrics rather than blocking anything loudly. The fix is mechanical (predicate-based `settle()`, as in user-list) and would be one small PR.
— Opus 5 Agent
Re-verified against origin/master — only the named spec was fixed; all nine siblings still carry the blind two-hop helper. Staying open, which matches what you asked for in comments 12842/12874.
Fixed (angular PR #570, b3626e69): libraries/keycloak-admin/src/lib/components/user-list/user-list.component.spec.ts:36-44 — settle(until?) with a predicate, bounded at 50 hops, throwing on timeout.
Still on the fixed-hop helper, with line numbers so the sweep is mechanical:
All nine are the same shape as the pre-fix user-list helper, so this is a copy of the same edit nine times rather than nine separate investigations. Until they're swept, the full-suite SonarQube scan stays exposed to the same load-dependent flake — the fix so far removes one of ten instances.
Tangentially: user-roles.component.spec.ts is also the spec for #762 (both role-search boxes wired to nothing), so whoever picks up either could reasonably do both in one pass.
Re-verified against `origin/master` — **only the named spec was fixed; all nine siblings still carry the blind two-hop helper.** Staying open, which matches what you asked for in comments 12842/12874.
**Fixed** (angular PR #570, `b3626e69`): `libraries/keycloak-admin/src/lib/components/user-list/user-list.component.spec.ts:36-44` — `settle(until?)` with a predicate, bounded at 50 hops, throwing on timeout.
**Still on the fixed-hop helper**, with line numbers so the sweep is mechanical:
- `realm-settings/realm-events.component.spec.ts:22-26`
- `realm-settings/realm-settings.component.spec.ts:27-31`
- `clients-list/clients-list.component.spec.ts:25-29`
- `groups-list/groups-list.component.spec.ts:25-29`
- `roles-list/roles-list.component.spec.ts:31-35`
- `user-consents/user-consents.component.spec.ts:24-28`
- `user-federated-identity/user-federated-identity.component.spec.ts:26-30`
- `user-detail/user-detail.component.spec.ts:27-31`
- `user-roles/user-roles.component.spec.ts:28-32`
All nine are the same shape as the pre-fix `user-list` helper, so this is a copy of the same edit nine times rather than nine separate investigations. Until they're swept, the full-suite SonarQube scan stays exposed to the same load-dependent flake — the fix so far removes one of ten instances.
Tangentially: `user-roles.component.spec.ts` is also the spec for #762 (both role-search boxes wired to nothing), so whoever picks up either could reasonably do both in one pass.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Symptom
Second failure reddening the
SonarQube Scanjob (the only job running the fullnx run-many --target=test --coveragesuite — see #829 for the first):Unlike #829 this one is a test-harness flake, not an app bug — the component is fine.
Root cause
The spec settles resources with a FIXED number of macrotask hops:
The component gates its
httpResources on an async admin-permission check, so the chain is: permission promise → request computation updates → loader promise → value. Two hops is enough on an idle machine. Under the Sonar job (81 projects,--coverage, parallel) the chain does not complete within the allotted hops, so assertions run against an empty list. Passes in isolation and in a full single-project run locally — only the loaded full-suite run trips it.Fix
Make
settle()accept a predicate and keep hopping (bounded, then throw) until the awaited state actually arrives, e.g.:Waiting on the observable outcome rather than a hop count removes the timing dependence entirely.
Related — latent, not yet failing
Nine sibling specs in
libraries/keycloak-admin/src/lib/components/carry the identical fixed-hopsettle()helper (realm-events, realm-settings, clients-list, groups-list, roles-list, user-consents, user-federated-identity, user-detail, user-roles). They have the same latent flake; user-list is simply the one that lost the race first. Worth a follow-up sweep to the predicate form — I have deliberately NOT swept them in the fixing PR to keep it reviewable, so this ticket should stay open for that sweep even after user-list is fixed.Fix for the user-list spec is up in spikersoft-angular PR #570 (
fix/sonar-suite-red-jwt-race), alongside #829 since both were reddening the same job.settle()now takes an optional predicate and hops (bounded at 50, then throws with a clear message) until the awaited state arrives —await settle(() => fixture.componentInstance.users().length > 0)instead of two blind hops. The negative/error cases wait onsnackBar.openhaving been called, and the pagination/force-refresh cases wait on the specific follow-up call landing.Leaving this ticket OPEN on purpose. PR #570 only fixes
user-list.component.spec.ts— the one that actually lost the race. The nine sibling specs listed above still carry the identical fixed-hop helper and remain latent flakes; this ticket tracks that sweep. Closing it when #570 merges would lose that.Full local
nx run-many --target=testis green across all 81 projects, so user-list was the only sibling failing today.— Opus 5 Agent
CI evidence:
SonarQube Scanpassed on PR #570 — first green scan today. That covers the user-list spec.Reminder that this ticket stays open for the remaining sweep: nine sibling keycloak-admin specs still use the fixed-hop
settle()and are latent flakes under a loaded full-suite run.— Opus 5 Agent
Status: the user-list half is merged to master (PR #570,
b3626e69) and master's full-suiteSonarQube Scanis green again (run 18137 on721d171b).This ticket stays open for the remaining sweep. Nine sibling specs in
libraries/keycloak-admin/src/lib/components/still settle promise-loader resources with a fixed hop count and carry the same latent flake: realm-events, realm-settings, clients-list, groups-list, roles-list, user-consents, user-federated-identity, user-detail, user-roles.They pass today, so this is not urgent — but the failure mode is nasty when it does hit: the only job running the full suite is the Sonar scan, which does not gate
publish, so a flake there reddens master quietly and stales the Sonar metrics rather than blocking anything loudly. The fix is mechanical (predicate-basedsettle(), as in user-list) and would be one small PR.— Opus 5 Agent
Re-verified against
origin/master— only the named spec was fixed; all nine siblings still carry the blind two-hop helper. Staying open, which matches what you asked for in comments 12842/12874.Fixed (angular PR #570,
b3626e69):libraries/keycloak-admin/src/lib/components/user-list/user-list.component.spec.ts:36-44—settle(until?)with a predicate, bounded at 50 hops, throwing on timeout.Still on the fixed-hop helper, with line numbers so the sweep is mechanical:
realm-settings/realm-events.component.spec.ts:22-26realm-settings/realm-settings.component.spec.ts:27-31clients-list/clients-list.component.spec.ts:25-29groups-list/groups-list.component.spec.ts:25-29roles-list/roles-list.component.spec.ts:31-35user-consents/user-consents.component.spec.ts:24-28user-federated-identity/user-federated-identity.component.spec.ts:26-30user-detail/user-detail.component.spec.ts:27-31user-roles/user-roles.component.spec.ts:28-32All nine are the same shape as the pre-fix
user-listhelper, so this is a copy of the same edit nine times rather than nine separate investigations. Until they're swept, the full-suite SonarQube scan stays exposed to the same load-dependent flake — the fix so far removes one of ten instances.Tangentially:
user-roles.component.spec.tsis also the spec for #762 (both role-search boxes wired to nothing), so whoever picks up either could reasonably do both in one pass.