Skip to content

fix(e2e): target the description field, not its helper button - #1635

Merged
rubenvdlinde merged 1 commit into
developmentfrom
fix/description-selector-must-match-the-field-not-its-helper
Aug 28, 2026
Merged

fix(e2e): target the description field, not its helper button#1635
rubenvdlinde merged 1 commit into
developmentfrom
fix/description-selector-must-match-the-field-not-its-helper

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Fixes the E2E failure on development (1 failed, 178 passed).

The failure

Source — full CRUD with persistence › create → row appears → view → edit persists → delete
  locator.fill: Element is not an <input>, <textarea>, <select> or [contenteditable]
  locator resolved to <button class="cn-field-helper__trigger"
                       aria-label="Show the full description">

Cause

CnFieldHelper renders a "Show the full description" button beside the field. Its aria-label matches /description/i too, so getByLabel(/description/i).first() resolved to the button instead of the input, and fill() died.

This is the selector-as-contract shape: a shared component grew an affordance whose accessible name collides with the field's, and every consumer targeting the field by label silently starts targeting the button.

The change

Both call sites move from getByLabel to getByRole('textbox', …), which only a real field can satisfy:

-.getByLabel(/description/i)
+.getByRole('textbox', { name: /description/i })

The create path had the same bug and was hiding it

Line 184 does the same lookup, but its fill is wrapped in .catch(() => { /* description optional */ }). So there the helper button swallowed the value silently — the create simply never set a description, and nothing failed. Only the edit path, which has no catch, surfaced it.

Fixed both rather than only the one that was red, since they are the same defect and one of them cannot report itself.

Deliberately not changed

The .catch() on the create path. Removing it is a separate judgement about whether description is genuinely optional there, and this PR is about the selector.

Verified: node --experimental-strip-types --check clean; no getByLabel(/description/i) remains in the file; pushed file byte-identical to the intended patch.

Surfaced once development runs started completing again — see ConductionNL/.github#597 and #625.

E2E fails on development:

  Source — full CRUD with persistence
  locator.fill: Element is not an <input>, <textarea>, <select>
  locator resolved to <button class="cn-field-helper__trigger"
                        aria-label="Show the full description">

CnFieldHelper renders a Show the full description button beside the
field. Its aria-label matches /description/i as well, and getByLabel
resolved to the button rather than the input.

Both call sites move to getByRole(textbox), which only a real field can
satisfy. The create path had the same bug and was hiding it: its fill is
wrapped in .catch() as description optional, so the helper button
swallowed the value silently instead of failing.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/integriq @ 9df1dfb

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
build
check-specs
test-l10n
format
check-schema-l10n
check-l10n-js
composer ✅ 145/145
npm ✅ 551/551
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright 🚨 NO VERDICT — enabled but never ran
Hydra gates

Quality workflow — 2026-08-28 13:23 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde merged commit d4ff275 into development Aug 28, 2026
47 checks passed
@rubenvdlinde
rubenvdlinde deleted the fix/description-selector-must-match-the-field-not-its-helper branch August 28, 2026 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant