fix(e2e): resolve the 29 'dead' lasuite selectors — 2 real defects, 27 a blind survey - #259
Merged
Merged
Conversation
…d survey
The selector-liveness sweep reported 29 selectors in element-overrides.css as
matching nothing. Probed against real Nextcloud 32.0.12 and 34.0.2 instances
with lasuite active, only 2 are dead:
.navigation-list__link.active (+ ::before) — nc-vue's settings-dialog
navigation emits only the BEM --active spelling, on both versions. Deleted.
The other 27 are the survey judging a stylesheet it could not see:
11 live on both versions but probed before the nav/bell bundles rendered —
the sweep waited on the header, then on the nav CONTAINER with its
failure swallowed. It now waits for the ITEM, and an anchor that never
arrives is a named, fatal MEASUREMENT failure.
12 NC33+ header markup, absent on the stable32 CI surveys — deferred via
SINCE, which refuses to defer anything once the survey reaches the app's
declared max-version.
1 owned by the notifications app, which is not in CI's fixture — deferred
via REQUIRES_APP, checked against OC.appswebroots so installing the app
re-arms the assertion.
3 live only on /login, a public share page, and under dark theme — three
surfaces the union was missing, now surveyed.
Anonymous surfaces build their context with storageState: undefined and the
login surface asserts its own body id, so an inherited admin session cannot
pass unnoticed. Counts are printed and floored so a survey over empty pages
cannot report PASS.
Contributor
Quality Report — ConductionNL/nldesign @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| test-l10n | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 2/2 | |||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-10 15:39 UTC
Download the full PDF report from the workflow artifacts.
storageState: undefined is not an empty session. Playwright merges context
options over the config's use block and reads undefined as 'not specified',
so the root use.storageState (tests/e2e/.auth/admin.json) was inherited and
the 'anonymous' context browsed as admin. CI proved it: /login came back with
body id body-user.
It was caught only because the login surface asserts its own body id — the
selector verdict itself would have been green, since token gating does not
depend on the caller. Replaced with an explicit { cookies: [], origins: [] },
which cannot be merged away.
Contributor
Quality Report — ConductionNL/nldesign @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| test-l10n | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 2/2 | |||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-10 16:41 UTC
Download the full PDF report from the workflow artifacts.
…enders that state CI's instance is a nextcloud/server stable32 checkout served by php -S. Its Files navigation renders its entries — the bare .app-navigation-entry and :hover rules are live there — but no entry is ever marked .active, on any surface, even after waiting 60s. A released Nextcloud has one: probed at rest on 32.0.12 and 34.0.2, #app-navigation-vue .app-navigation-entry.active matches exactly 1 node. So the ten active-row selectors are correct CSS this fixture cannot exercise. REQUIRES_RENDERED defers them on that measured fact and nothing else: the anchor is a selector the survey actively waits for and records, so the day the navigation marks an active entry they are required live again. Proven in both directions — with the anchor rendering, a planted dead nav-active selector still fails the run. A missing anchor is no longer fatal in itself; a missing PAGE still is, via chromeless and the live-count floor.
Contributor
Quality Report — ConductionNL/nldesign @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| test-l10n | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 2/2 | |||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-10 17:09 UTC
Download the full PDF report from the workflow artifacts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was red
development's Code Quality push run 31381545314 failed one real job —E2E Tests (Playwright)— plusQuality Report, a pure aggregator red only because E2E was. 27 jobs, 110 tests passed, 1 failed:selector-liveness.spec.ts › every element-overrides selector matches something on at least one surface, reporting 29 selectors incss/systems/lasuite/element-overrides.cssas matching nothing anywhere.That message invites the reader to "fix them against the real DOM" — which, acted on, means deleting theme CSS to satisfy a measurement. The previous round already recorded in the file that a timing fix cleared none of them and that the honest reading was still open. So the first job was to find out which of the 29 are really dead.
Measured, not reasoned about
Two disposable Nextcloud instances (32.0.12 and 34.0.2, official images,
lasuiteactive,nldesigninstalled) probed withdocument.querySelectorAllfor every one of the 29. Every claim below is a count from a live DOM.#app-navigation-vue .app-navigation-entry.active…and the.active.activevariants#header .notifications-button__icon svg.app-menu__waffle,.app-menu__current-app-*,.unified-search-input*,.header-start ….guest-box.login-box/login— a surface the survey never visitsbody#body-publicbody[data-theme-dark],body[data-themes*="dark"].navigation-list__link.active,…::beforeSo 2 of 29 were a product defect. The other 27 were the survey judging a stylesheet it could not see.
The product fix
.navigation-list__link.activeis deleted. Opened on the settings dialog on both 32 and 34, nc-vue emitsnavigation-list__link navigation-list__link--active(1 node) andnavigation-list__link(5 nodes) — never the bare.active. The block carried both spellings on the general principle that this file had been bitten four times by naming one of two live spellings; sound principle, wrong application — that component has only ever had one spelling.--active, which is observed, stays.The measurement fixes
Wait for the item, not the container. The survey waited on
CHROME_READY(proves only the header app mounted) and thenwaitForSelector('#app-navigation-vue').catch(() => {})— a container check whose failure was swallowed. The nav is a different bundle on a different clock, and#app-navigation-vueis attached long before the router marks an entry.active. The CI failure list corroborates this exactly: the bare.app-navigation-entryselector was not reported dead, only the.activevariants — the entries had rendered, the active state had not. It now waits for#app-navigation-vue .app-navigation-entry.activeitself, and an anchor that never arrives is a named, fatal measurement failure saying "do not fix the CSS on this".Three surfaces the union was missing —
/login, a public link share, and a dark-theme pass over Files. The share is minted inbeforeAlland dropped inafterAll; dark goes on immediately before its surface and off immediately after.The anonymous surfaces are genuinely anonymous.
use.storageStateis inherited by every context created inside a test, so a plainbrowser.newContext()would have carried admin's cookies,/loginwould have redirected to the dashboard, and the survey would have measured an app page while reporting it had measured the login screen — green, about the wrong page. Contexts are built withstorageState: undefined, and the login surface assertsdocument.body.id === 'body-login'so a regression cannot pass unnoticed.Two deferrals that expire by themselves, kept separate from
ALLOWEDprecisely because an allowance does not expire:SINCE— markup a newer Nextcloud renders. Deferred only while the surveyed major is belowsince, and an explicit assertion refuses to defer anything once the survey reaches the app's declaredmax-version(34). Raisingnextcloud-test-refstherefore cannot silently carry the exemption forward.REQUIRES_APP— markup owned by an app the fixture does not install.notifications-button__iconappears nowhere in a Nextcloud release exceptapps/notifications/, which lives in its own repository and is absent from thenextcloud/servercheckout CI builds from. The check is againstOC.appswebroots, the instance's own list of enabled apps, so installing the app puts the selector straight back under the main assertion.Counts are printed. Nextcloud major, distinct selectors parsed, selectors proven live, per-surface live/probed, deferrals, unreachable and chromeless surfaces. There are hard floors on "selectors parsed" and "selectors proven live" so a survey that measured empty pages cannot report PASS — this is the repo where thirteen a11y gates once passed planted true positives because every one of them globbed
src/**/*.vueand nldesign ships zero.Both directions, one mutation at a time
Each mutation applied alone and reverted, against Nextcloud 32 — the version CI runs.
.navigation-list__link.activebackloginsurface.guest-box.login-boxpublic-sharesurfacebody#body-publicfiles-darksurfacenotifications, add a deadnotifications-button__icon-*selectorbody-loginpositive controlUnmutated, on a CI-shaped fixture (
notificationsdisabled): 2 passed, 179 selectors parsed, 123 proven live, 13 deferred and named, 0 unexplained.Run on Nextcloud 34 the suite goes red on three different selectors — the NC32-only header classes — which is the mirror image working: the guard catches whatever is dead on the version it is actually looking at.
What I could not prove
The container-only wait mutation still passes locally. Reverting the readiness fix does not turn my local run red, because this box wins the race the CI runner loses. So the timing fix is justified by the CI evidence (bare
.app-navigation-entrylive,.activedead — the signature of probing mid-render) and by the failure mode it removes, not by a local mutation. If CI still reports those eleven dead, the new assertion now says so as a measurement failure and names the anchor, instead of accusing the stylesheet.Left alone deliberately
The La Suite header treatment does not reach Nextcloud 32 at all — the twelve deferred selectors have no NC32 counterparts in this file, so on the version CI runs the header is unstyled by this theme. That is a real gap, it is recorded in the
SINCEcomment, and it wants its own change rather than being smuggled into a red-to-green fix.