Repository: electron/electron
Pull request: fix: restore AXDocument accessibility attribute for representedFilename on macOS

#### Description of Change

This PR fixes a regression where `setRepresentedFilename()` no longer sets the `AXDocument` accessibility attribute on macOS windows starting from Electron 35.0.0-beta.5.

## Root Cause

Chromium change [crrev.com/c/6187085](https://chromium-review.googlesource.com/c/chromium/src/+/6187085) ([commit ea32bec](https://chromium.googlesource.com/chromium/src/+/ea32bec275a1e3df6fca29caa29353529be1f8bc), first included in Chromium 134.0.6989.0) added an `accessibilityDocument` override to `NativeWidgetMacNSWindow` that returns the web content URL from the accessibility tree. However, this override doesn't fall back to `NSWindow`'s default behavior of returning the `representedFilename` as a file URL when the web content URL is empty.

This broke Electron's `setRepresentedFilename()` API - the file path was still correctly set on the `NSWindow.representedFilename` property, but it was no longer exposed via the `AXDocument` accessibility attribute that screen readers and other assistive technologies use. In particular, my automatic time tracking app Timing relies on this attribute to determine which document the user is currently working on in apps like Visual Studio Code or Cursor.

## Bisect Results

- **Last working version:** 35.0.0-beta.4
- **First broken version:** 35.0.0-beta.5
- **Chromium version that introduced the regression:** 134.0.6989.0

## The Fix

This PR adds an `accessibilityDocument` override in `ElectronNSWindow` that:

1. First checks if `representedFilename` is set (via Electron's `setRepresentedFilename()` API)
2. If set, returns it as a file URL (matching `NSWindow`'s default behavior)
3. Otherwise, falls back to Chromium's implementation for web content URLs

This ensures both use cases work:
- Apps using `setRepresentedFilename()` get proper `AXDocument` values
- Web content URLs are still reported when available

## Checklist

- [x] PR description included
- [x] `npm run lint:js` passes (full test suite requires built Electron binary)
- [x] Tests added/updated (see note below)
- [x] Release notes updated

## Automated Test (on separate branch)

I've written an automated test that verifies the `AXDocument` accessibility attribute is correctly set when `representedFilename` is used. However, per Electron's [Dependencies Upgrades Policy](https://github.com/electron/electron/blob/main/CONTRIBUTING.md#dependencies-upgrades-policy):

> Dependencies in Electron's package.json or yarn.lock files should only be altered by maintainers. For security reasons, we will not accept PRs that alter our package.json or yarn.lock files. We invite contributors to make requests updating these files in our issue tracker. If the change is significantly complicated, draft PRs are welcome, with the understanding that these PRs will be closed in favor of a duplicate PR submitted by an Electron maintainer.

The test requires a new native addon (`@electron-ci/get-ax-document`) which modifies `spec/package.json` and `yarn.lock`. I've pushed the test to a separate branch for maintainers to review if they wish to duplicate it:

**Branch with tests:** [`fix/macos-axdocument-represented-filename-with-tests`](https://github.com/MrMage/electron/tree/fix/macos-axdocument-represented-filename-with-tests)

I validated the test against precompiled Electron binaries:

```bash
# Electron 34 (before regression) - PASSES
$ npm test -- --electronVersion 34.0.0 --files spec/api-browser-window-spec.ts --grep "AXDocument"
Only running: [ 'main' ]
Running against Electron undefined

Running: Main process specs
Running: /Users/daniel/Library/Application Support/fiddle-core/electron/current/Electron.app/Contents/MacOS/Electron electron/spec --files spec/api-browser-window-spec.ts --grep AXDocument
ok 1 BrowserWindow module window states (excluding Linux) representedFilename AXDocument accessibility attribute is set to file URL when representedFilename is set
ok 2 BrowserWindow module window states (excluding Linux) representedFilename AXDocument accessibility attribute is empty when representedFilename is not set
# tests 2
# pass 2
# fail 0
1..2
✓ Electron main process tests passed.

# Electron 35 (regression introduced) - FAILS
$ npm test -- --electronVersion 35.0.0 --files spec/api-browser-window-spec.ts --grep "AXDocument"
Running against Electron undefined

Running: Main process specs
Running: /Users/daniel/Library/Application Support/fiddle-core/electron/current/Electron.app/Contents/MacOS/Electron electron/spec --files spec/api-browser-window-spec.ts --grep AXDocument
not ok 1 BrowserWindow module window states (excluding Linux) representedFilename AXDocument accessibility attribute is set to file URL when representedFilename is set
  expected '' to equal 'file:///tmp/test-represented-file.txt'
  AssertionError: expected '' to equal 'file:///tmp/test-represented-file.txt'
      at Context.<anonymous> (electron-fork/spec/api-browser-window-spec.ts:5737:33)
      at processImmediate (node:internal/timers:491:21)
ok 2 BrowserWindow module window states (excluding Linux) representedFilename AXDocument accessibility attribute is empty when representedFilename is not set
# tests 2
# pass 1
# fail 1
1..2
✗ Electron tests failed with code 1.
```

| Version | Test 1 (file URL set) | Test 2 (empty when unset) |
|---------|----------------------|---------------------------|
| 34.0.0  | PASS                 | PASS                      |
| 35.0.0  | FAIL (`''` instead of `file://...`) | PASS       |

This confirms the test correctly detects the regression.

## Manual Test Instructions

1. Clone the demo app: https://github.com/MrMage/Electron-RepresentedFilename-Demo
2. Run with the patched Electron build
3. Use one of the following methods to verify the window's `AXDocument` attribute:

**Option A: Swift test script**

The demo repo includes a Swift script that checks the `AXDocument` attribute:

```bash
swift check_axdocument.swift
```

See the [demo repo README](https://github.com/MrMage/Electron-RepresentedFilename-Demo#readme) for more details, including troubleshooting steps if you encounter permission issues.

**Option B: Terminal command**

```bash
osascript -e 'tell application "System Events" to get value of attribute "AXDocument" of window 1 of (first process whose frontmost is true)'
```

**Option C: Accessibility Inspector**

Use Xcode's Accessibility Inspector to inspect the Electron window.

**Expected result:** `file:///path/to/package.json`

#### Release Notes

Notes: Fixed `setRepresentedFilename()` not setting `AXDocument` accessibility attribute on macOS.

#### Backport

This bug affects all currently supported Electron versions (38, 39, 40) since it was introduced in 35.0.0-beta.5. Backports to supported branches are requested.

Changed files:
filename: shell/browser/ui/cocoa/electron_ns_window.mm
patch: @@ -285,6 +285,19 @@ - (NSString*)accessibilityTitle {
   return base::SysUTF8ToNSString(shell_ ? shell_->GetTitle() : "");
 }
 
+- (NSString*)accessibilityDocument {
+  // Prefer representedFilename set via Electron's setRepresentedFilename API.
+  // This works around a Chromium change (https://crrev.com/c/6187085) where
+  // NativeWidgetMacNSWindow's accessibilityDocument override doesn't fall back
+  // to NSWindow's default behavior of returning the representedFilename.
+  NSString* representedFilename = [self representedFilename];
+  if (representedFilename.length > 0) {
+    return [[NSURL fileURLWithPath:representedFilename] absoluteString];
+  }
+  // Fall back to Chromium's implementation for web content URLs.
+  return [super accessibilityDocument];
+}
+
 - (BOOL)canBecomeMainWindow {
   return !self.disableKeyOrMainWindow;
 }