LearnNewsExamplesServices
Frontmatter
id19276
titleTabHeaderActionsNL still expects a withdrawn action to be a hidden node, where #18069 gives it none
stateClosed
labels
bugaitest
assigneesneo-opus-grace
createdAtSep 26, 2026, 2:30 PM
updatedAtSep 26, 2026, 2:59 PM
githubUrlhttps://github.com/neomjs/neo/issues/19276
authorneo-opus-grace
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 26, 2026, 2:59 PM

TabHeaderActionsNL still expects a withdrawn action to be a hidden node, where #18069 gives it none

neo-opus-grace
neo-opus-grace commented on Sep 26, 2026, 2:30 PM

Context

TabHeaderActionsNL › actions stay semantic, focus-aware, overflow-safe, and outside tab sorting has been red in #17844's censuses (the 21, the 28, the 22) and at dev 08a84ef3be:

expect(locator('#neo-button-2')).toHaveCSS('visibility', 'hidden')   :65
Error: element(s) not found

#neo-button-2 is the previous-tab action's queried id, not a hard-coded one: the node does not exist.

The Problem

#18069 (Resolves #18042, 09-02) made a withdrawn, focus-gated action a node-less instance. applyContextualActionState stamps vdom.removeDom, and component.Base#domWithheld keeps it out on every show() path, so no consumer stylesheet can resurrect it. That PR moved its dock and ContainerUi witnesses to read absence (toHaveCount(0)). This NL spec, which CI does not select, still reads the old contract in six places:

  • :65-70: visibility: hidden plus aria-hidden / inert / tabIndex on the node;
  • :100, :220 and :295: visibility: hidden after the focus leaves again;
  • :305-313: the runtime-replaced runtime-contextual action withdrawn, read as a present, hidden node with node-level ARIA (Vega's review; past the drain residual below, so no run reaches it today).

The Architectural Reality

  • The revealed-state assertions (visibility: visible, the ARIA of a present node) still hold: #18069 reinserts the same instance on reveal.
  • The getByRole('button', {name: 'previous tab'}) counts beside them already read presence and stay.

The Fix

The six withdrawn-state assertions read absence: toHaveCount(0) on the action's locator. The node-level ARIA check for the withdrawn state goes, since there is no node to carry it. No engine change.

Acceptance Criteria

  • AC-1: at the head (headless, --workers=1, runtime root bound), the spec passes the withdrawn-state assertions a run reaches (:65, :100, :220). It then fails at the overflow-drain arm (:268, "the queued projection drains after SortZone restores natural layout": no "More tabs" control). With this fix overlaid, that arm already fails at ab2ae8c73c (09-05, the spec's last edit) and at e66b6f8142. That failure is recorded on #17844 and is not this ticket's.
  • AC-2: red-first: dev's spec at the same head fails at :65 on the missing node.

Out of Scope

  • #18069's contract, which is correct.

Related

#17844 (census) · #18042 / #18069 (the node-less withdrawn action) · #17418 / #17423 (the spec's origin)

Origin Session ID: 81d1894c-d8fd-4192-8350-42e32eb0101e Retrieval Hint: "TabHeaderActionsNL withdrawn action no DOM node domWithheld visibility hidden #18069"

tobiu referenced in commit e3d83f1 - "test(tab): a withdrawn header action is read as absent, as #18069 made it (#19276) (#19277) on Sep 26, 2026, 2:59 PM
tobiu closed this issue on Sep 26, 2026, 2:59 PM