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
- The flag removal itself — the four files in the table below.
spec/frontend/ci/pipeline_details/graph/components/job_item_spec.js—job_item.vuepasses a baredisabledattribute toActionComponent, which declares no such prop. Vue 2 applies it straight to the DOM node (stays native, never reachesGlButton's prop); Vue 3 resolves it into the prop, soGlButtonrendersaria-disabled. A newisActionComponentDisabled()helper accepts either signal, so the spec passes under both Vue versions.ee/spec/features/explore/ai_catalog/ai_catalog_agent_enable_spec.rbandai_catalog_flow_enable_spec.rb— both assertedexpect(page).not_to have_button('Enable'), which passed for the wrong reason: the button is rendered, just disabled, and Capybara's defaultdisabled: falsefilter simply didn't match it. Now assert what's true:expect(page).to have_button('Enable', disabled: true).- Jest specs + snapshots — genuinely required, not incidental: Jest asserts on rendered DOM, and
GlButtonreally does renderaria-disabledin place ofdisablednow.
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
- Rollout issue: #600158 (closed)
- Follow-up (config key + prop removal): #607085
- Follow-up (server-rendered Pajamas buttons): #612142
- Supersedes this MR's test churn: !249618 (merged)
- OKR spec flakiness (why the okr_spec change was dropped): https://gitlab.com/gitlab-org/quality/test-failure-issues/-/issues/43758