Skip to content

Commit a8d3684

Browse files
committed
Bug 1862534: Groundwork for ATK accessibility API tests. r=eeejay,jmaher
This adds setup code and utility functions for ATK to the Python environment. I also needed to prevent front-end accessibility checks (AccessibilityUtils) from force disabling accessibility for a11y engine tests. Although the tests re-enabled it anyway, this seems to break AT-SPI's interaction with our ApplicationAccessible. Disabling it really doesn't make sense in this case anyway. This patch includes a simple role test to show all of this working. Differential Revision: https://phabricator.services.mozilla.com/D192911
1 parent c5503d7 commit a8d3684

File tree

10 files changed

+152
-6
lines changed

10 files changed

+152
-6
lines changed

accessible/moz.build

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ DIRS += [
3232
TEST_DIRS += ["tests/mochitest"]
3333

3434
BROWSER_CHROME_MANIFESTS += [
35+
"tests/browser/atk/browser.toml",
3536
"tests/browser/bounds/browser.toml",
3637
"tests/browser/browser.toml",
3738
"tests/browser/e10s/browser.toml",
+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this
3+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
5+
"""Python environment for ATK a11y browser tests.
6+
"""
7+
8+
import os
9+
import subprocess
10+
import sys
11+
12+
import psutil
13+
14+
# pyatspi can't be installed using pip. Rely on the system installation.
15+
# Get the path to the system installation of pyatspi.
16+
pyatspiFile = subprocess.check_output(
17+
(
18+
os.path.join(sys.base_prefix, "bin", "python3"),
19+
"-c",
20+
"import pyatspi; print(pyatspi.__file__)",
21+
),
22+
encoding="utf-8",
23+
).rstrip()
24+
sys.path.append(os.path.dirname(os.path.dirname(pyatspiFile)))
25+
import pyatspi
26+
27+
sys.path.pop()
28+
del pyatspiFile
29+
30+
31+
def getDoc():
32+
"""Get the Accessible for the document being tested."""
33+
# We can compare the parent process ids to find the Firefox started by the
34+
# test harness.
35+
commonPid = psutil.Process().ppid()
36+
for app in pyatspi.Registry.getDesktop(0):
37+
if (
38+
app.name == "Firefox"
39+
and psutil.Process(app.get_process_id()).ppid() == commonPid
40+
):
41+
break
42+
else:
43+
raise LookupError("Couldn't find Firefox application Accessible")
44+
root = app[0]
45+
for embeds in root.getRelationSet():
46+
if embeds.getRelationType() == pyatspi.RELATION_EMBEDS:
47+
break
48+
else:
49+
raise LookupError("Firefox root doesn't have RELATION_EMBEDS")
50+
doc = embeds.getTarget(0)
51+
child = doc[0]
52+
if child.get_attributes().get("id") == "default-iframe-id":
53+
# This is an iframe or remoteIframe test.
54+
doc = child[0]
55+
return doc
56+
57+
58+
def findByDomId(root, id):
59+
for child in root:
60+
if child.get_attributes().get("id") == id:
61+
return child
62+
descendant = findByDomId(child, id)
63+
if descendant:
64+
return descendant
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[DEFAULT]
2+
subsuite = "a11y"
3+
skip-if = [
4+
"os != 'linux'",
5+
"headless",
6+
]
7+
support-files = ["head.js"]
8+
prefs = [
9+
# Enabling the a11y service from XPCOM doesn't seem to be enough to get ATK
10+
# working correctly. Force enable it before the test starts.
11+
"accessibility.force_disabled=-1",
12+
"javascript.options.asyncstack_capture_debuggee_only=false",
13+
]
14+
15+
["browser_role.js"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
"use strict";
6+
7+
const ATSPI_ROLE_DOCUMENT_WEB = 95;
8+
const ATSPI_ROLE_PARAGRAPH = 73;
9+
10+
addAccessibleTask(
11+
`
12+
<p id="p">p</p>
13+
`,
14+
async function (browser, docAcc) {
15+
let role = await runPython(`
16+
global doc
17+
doc = getDoc()
18+
return doc.getRole()
19+
`);
20+
is(role, ATSPI_ROLE_DOCUMENT_WEB, "doc has correct ATSPI role");
21+
ok(
22+
await runPython(`
23+
global p
24+
p = findByDomId(doc, "p")
25+
return p == doc[0]
26+
`),
27+
"doc's first child is p"
28+
);
29+
role = await runPython(`p.getRole()`);
30+
is(role, ATSPI_ROLE_PARAGRAPH, "p has correct ATSPI role");
31+
},
32+
{ chrome: true, topLevel: true, iframe: true, remoteIframe: true }
33+
);

accessible/tests/browser/atk/head.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
"use strict";
6+
7+
// Load the shared-head file first.
8+
Services.scriptloader.loadSubScript(
9+
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
10+
this
11+
);
12+
13+
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
14+
// well as promisified-events.js.
15+
loadScripts(
16+
{ name: "common.js", dir: MOCHITESTS_DIR },
17+
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
18+
);

accessible/tests/browser/browser.toml

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ subsuite = "a11y"
44
support-files = [
55
"!/accessible/tests/mochitest/*.js",
66
"*.sys.mjs",
7+
"atk/a11y_setup.py",
78
"head.js",
89
"python_runner_wsh.py",
910
"shared-head.js",

accessible/tests/browser/python_runner_wsh.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ def send(*args):
3030
if sys.platform == "win32":
3131
testDir = "windows"
3232
elif sys.platform == "linux":
33-
# XXX ATK code goes here.
34-
pass
33+
testDir = "atk"
3534
if testDir:
3635
sys.path.append(
3736
os.path.join(

taskcluster/docker/recipes/ubuntu1804-test-system-setup-base.sh

+11
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ apt_packages+=('pulseaudio-module-gconf')
7474
apt_packages+=('python-dev')
7575
apt_packages+=('python-pip')
7676
apt_packages+=('python3-pip')
77+
apt_packages+=('python3-pyatspi')
7778
apt_packages+=('qemu-kvm')
7879
apt_packages+=('rlwrap')
7980
apt_packages+=('screen')
@@ -158,4 +159,14 @@ rm -rf /usr/share/locale/ /usr/share/locale-langpack/ /usr/share/locales/
158159
# Further cleanup
159160
apt-get autoremove
160161

162+
# We've changed python3 to use 3.7, but binary modules are only installed for
163+
# the distribution's default which is 3.6. Symlink a module we need for 3.7.
164+
ln -s /usr/lib/python3/dist-packages/gi/_gi.cpython-{36m,37m}-x86_64-linux-gnu.so
165+
166+
# The packaged version of pyatspi is not compatible with Python 3.7. Hack it to
167+
# be compatible, since there's no package for 3.7 in this distribution.
168+
# Specifically, rename variables named "async" to "asynchronous", since "async"
169+
# is a reserved keyword in Python 3.7.
170+
sed -i 's/\basync\b/asynchronous/' /usr/lib/python3/dist-packages/pyatspi/registry.py
171+
161172
rm -f "$0"

testing/mochitest/browser-test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1217,7 +1217,7 @@ Tester.prototype = {
12171217

12181218
this.SimpleTest.reset();
12191219
// Reset accessibility environment.
1220-
this.AccessibilityUtils.reset(this.a11y_checks);
1220+
this.AccessibilityUtils.reset(this.a11y_checks, this.currentTest.path);
12211221

12221222
// Load the tests into a testscope
12231223
let currentScope = (this.currentTest.scope = new testScope(

testing/mochitest/tests/SimpleTest/AccessibilityUtils.js

+7-3
Original file line numberDiff line numberDiff line change
@@ -697,13 +697,17 @@ this.AccessibilityUtils = (function () {
697697
gEnv = { ...DEFAULT_ENV };
698698
},
699699

700-
reset(a11yChecks = false) {
700+
reset(a11yChecks = false, testPath = "") {
701701
gA11YChecks = a11yChecks;
702702

703703
const { Services } = SpecialPowers;
704704
// Disable accessibility service if it is running and if a11y checks are
705-
// disabled.
706-
if (!gA11YChecks && Services.appinfo.accessibilityEnabled) {
705+
// disabled. However, don't do this for accessibility engine tests.
706+
if (
707+
!gA11YChecks &&
708+
Services.appinfo.accessibilityEnabled &&
709+
!testPath.startsWith("chrome://mochitests/content/browser/accessible/")
710+
) {
707711
Services.prefs.setIntPref(FORCE_DISABLE_ACCESSIBILITY_PREF, 1);
708712
Services.prefs.clearUserPref(FORCE_DISABLE_ACCESSIBILITY_PREF);
709713
}

0 commit comments

Comments
 (0)