Remove accessible_disabled_button feature flag

What this MR does

Removes the accessible_disabled_button feature flag, making the accessible disabled-button behavior permanent: GlButton renders aria-disabled="true" while disabled instead of the native disabled attribute, keeping the button focusable and letting assistive technology announce it. The flag has been at 100% in production for a while, so this is pure cleanup. Milestone 19.3.

Scope

The 4-file flag removal is the substance. Everything else is test fallout from the render change.

The MR is much smaller than it started: master merged !249618 (merged) ("Treat aria-disabled buttons as disabled in Capybara"), which teaches Capybara's built-in disabled: filter, on the :button and :link_or_button selectors, to treat aria-disabled="true" as disabled globally. That superseded this MR's original custom aria_disabled filter and its ~84 call-site edits — all reverted, and 27 of the 31 touched Ruby spec files are now byte-identical to master. A previously-included quarantine inside ee/spec/features/work_items/okr_spec.rb was also dropped: master has since quarantined that whole file as flaky (https://gitlab.com/gitlab-org/quality/test-failure-issues/-/issues/43758), making the inner quarantine redundant.

Net: 75 files changed, +190 / −140. The Ruby side is 7 files, 3 of which are comment-only or a stub removal.

What survives, and why each one is real

  1. The flag removal itself — the four files in the table below.
  2. spec/frontend/ci/pipeline_details/graph/components/job_item_spec.js — job_item.vue passes a bare disabled attribute to ActionComponent, which declares no such prop. Vue 2 applies it straight to the DOM node (stays native, never reaches GlButton's prop); Vue 3 resolves it into the prop, so GlButton renders aria-disabled. A new isActionComponentDisabled() helper accepts either signal, so the spec passes under both Vue versions.
  3. ee/spec/features/explore/ai_catalog/ai_catalog_agent_enable_spec.rb and ai_catalog_flow_enable_spec.rb — both asserted expect(page).not_to have_button('Enable'), which passed for the wrong reason: the button is rendered, just disabled, and Capybara's default disabled: false filter simply didn't match it. Now assert what's true: expect(page).to have_button('Enable', disabled: true).
  4. Jest specs + snapshots — genuinely required, not incidental: Jest asserts on rendered DOM, and GlButton really does render aria-disabled in place of disabled now.

Files changed

File Change
config/feature_flags/gitlab_com_derisk/accessible_disabled_button.yml Deleted the flag definition.
lib/gitlab/gon_helper.rb Removed the push_frontend_feature_flag call.
app/assets/javascripts/commons/gitlab_ui.js accessibleDisabledButton hard-set to true instead of read from gon.features.
spec/spec_helper.rb Removed the suite-wide stub_feature_flags(accessible_disabled_button: false) stub.
spec/support/capybara.rb Comment only — master's filter comment referenced the behavior applying "once accessible_disabled_button is on"; it's unconditional now.
qa/qa/page/component/aria_disabled_button.rb Comment only, same stale flag conditional removed.
spec/features/work_items/detail/work_item_children_spec.rb Dropped stub_feature_flags(accessible_disabled_button: true). Master added it mid-rollout; with the flag deleted the stub does nothing.
ee/spec/features/explore/ai_catalog/*_enable_spec.rb Negative-assertion rewrites (see above).
spec/frontend/ci/pipeline_details/graph/components/job_item_spec.js Vue 2 / Vue 3 version-agnostic assertion (see above).
Jest specs + snapshots 39 spec files and 26 snapshot files, asserting aria-disabled in place of disabled.

Why the config key stays

accessibleDisabledButton in app/assets/javascripts/commons/gitlab_ui.js is kept deliberately and set to true rather than deleted. @gitlab/ui 136.1.0 still derives the GlButton accessibleDisabled prop default from glButtonConfig.accessibleDisabledButton (src/components/base/button/button.vue line 131). Deleting the key would leave the prop defaulting to undefined, regressing every disabled GlButton back to the inaccessible native attribute. Removal is tracked in #607085 and is blocked on a future @gitlab/ui bump that drops the prop entirely.

Verification

Jest — 63 changed specs (39 changed spec files plus the 24 that own the changed snapshots) pass on both configs:

Config Suites Tests Snapshots
default 63 / 63 pass 1276 pass, 38 skipped 41 pass
VUE_VERSION=3 63 / 63 pass 1276 pass, 38 skipped 41 pass

Identical on both configs, which is the point of the job_item change.

RSpec — CI is the verifier for the Ruby side, not local. This GDK is too flaky to be an oracle: unmodified master fails ~49 of the same 66 feature examples here, and re-running identical master code produces a different failure set each time. The two suspected regressions (assignees, labels) were proven to fail on plain master with none of this branch's changes applied, so the earlier guard removal isn't the cause. Only 7 Ruby files differ from master (3 comment-only or a stub removal), and the substantive ones — work_item_children_spec.rb (stub removal) and the two ai_catalog specs (negative-assertion rewrites) — pass locally. The Capybara built-in filter this relies on was verified with a control: on infrastructure_registry_spec.rb, a DOM probe confirmed the button renders aria-disabled="true" with no native attribute; have_button(..., disabled: true) matched with the filter active and failed with it neutralized, confirming the match depends on the built-in filter. RuboCop clean on all 7 Ruby files.

Reviewer note: run yarn install after pulling

Run yarn install as well as bundle install after checking out this branch. Master bumped @gitlab/ui to 136.1.0, and a stale node_modules silently invalidates local :js verification — an older @gitlab/ui keeps GlButton rendering the native disabled attribute, so assertions pass for the wrong reason.

Also worth knowing: pages that don't load commons/index.js never call applyGitLabUIConfig, and accessibleDisabledButton defaults to false inside @gitlab/ui, so GlButton still renders the native disabled attribute there (the standalone jira_connect layout is one example). That's why feature specs should assert with the attribute-agnostic disabled: filter rather than asserting aria-disabled directly.

Not affected, deliberately untouched

Server-rendered buttons don't change. Pajamas::ButtonComponent#base_attributes sets both disabled and aria-disabled unconditionally, with no flag check, so non-:js feature specs and all view specs are unaffected. The disabled CSS class is also applied unconditionally, so class-selector assertions don't change. Shallow-mounted GlButton is stubbed by Vue Test Utils and serialises the prop rather than the real render, so only full-mount assertions needed converting. (Making server-rendered buttons accessible-when-disabled is tracked as a follow-up in #612142.)

References

Edited by Adam Ferch

Merge request reports

Loading
Loading