forked from mirrors/gecko-dev
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
This commit is contained in:
parent
c5503d7f3e
commit
a8d36840cb
10 changed files with 152 additions and 6 deletions
|
|
@ -32,6 +32,7 @@ DIRS += [
|
|||
TEST_DIRS += ["tests/mochitest"]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
"tests/browser/atk/browser.toml",
|
||||
"tests/browser/bounds/browser.toml",
|
||||
"tests/browser/browser.toml",
|
||||
"tests/browser/e10s/browser.toml",
|
||||
|
|
|
|||
64
accessible/tests/browser/atk/a11y_setup.py
Normal file
64
accessible/tests/browser/atk/a11y_setup.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
"""Python environment for ATK a11y browser tests.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import psutil
|
||||
|
||||
# pyatspi can't be installed using pip. Rely on the system installation.
|
||||
# Get the path to the system installation of pyatspi.
|
||||
pyatspiFile = subprocess.check_output(
|
||||
(
|
||||
os.path.join(sys.base_prefix, "bin", "python3"),
|
||||
"-c",
|
||||
"import pyatspi; print(pyatspi.__file__)",
|
||||
),
|
||||
encoding="utf-8",
|
||||
).rstrip()
|
||||
sys.path.append(os.path.dirname(os.path.dirname(pyatspiFile)))
|
||||
import pyatspi
|
||||
|
||||
sys.path.pop()
|
||||
del pyatspiFile
|
||||
|
||||
|
||||
def getDoc():
|
||||
"""Get the Accessible for the document being tested."""
|
||||
# We can compare the parent process ids to find the Firefox started by the
|
||||
# test harness.
|
||||
commonPid = psutil.Process().ppid()
|
||||
for app in pyatspi.Registry.getDesktop(0):
|
||||
if (
|
||||
app.name == "Firefox"
|
||||
and psutil.Process(app.get_process_id()).ppid() == commonPid
|
||||
):
|
||||
break
|
||||
else:
|
||||
raise LookupError("Couldn't find Firefox application Accessible")
|
||||
root = app[0]
|
||||
for embeds in root.getRelationSet():
|
||||
if embeds.getRelationType() == pyatspi.RELATION_EMBEDS:
|
||||
break
|
||||
else:
|
||||
raise LookupError("Firefox root doesn't have RELATION_EMBEDS")
|
||||
doc = embeds.getTarget(0)
|
||||
child = doc[0]
|
||||
if child.get_attributes().get("id") == "default-iframe-id":
|
||||
# This is an iframe or remoteIframe test.
|
||||
doc = child[0]
|
||||
return doc
|
||||
|
||||
|
||||
def findByDomId(root, id):
|
||||
for child in root:
|
||||
if child.get_attributes().get("id") == id:
|
||||
return child
|
||||
descendant = findByDomId(child, id)
|
||||
if descendant:
|
||||
return descendant
|
||||
15
accessible/tests/browser/atk/browser.toml
Normal file
15
accessible/tests/browser/atk/browser.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[DEFAULT]
|
||||
subsuite = "a11y"
|
||||
skip-if = [
|
||||
"os != 'linux'",
|
||||
"headless",
|
||||
]
|
||||
support-files = ["head.js"]
|
||||
prefs = [
|
||||
# Enabling the a11y service from XPCOM doesn't seem to be enough to get ATK
|
||||
# working correctly. Force enable it before the test starts.
|
||||
"accessibility.force_disabled=-1",
|
||||
"javascript.options.asyncstack_capture_debuggee_only=false",
|
||||
]
|
||||
|
||||
["browser_role.js"]
|
||||
33
accessible/tests/browser/atk/browser_role.js
Normal file
33
accessible/tests/browser/atk/browser_role.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const ATSPI_ROLE_DOCUMENT_WEB = 95;
|
||||
const ATSPI_ROLE_PARAGRAPH = 73;
|
||||
|
||||
addAccessibleTask(
|
||||
`
|
||||
<p id="p">p</p>
|
||||
`,
|
||||
async function (browser, docAcc) {
|
||||
let role = await runPython(`
|
||||
global doc
|
||||
doc = getDoc()
|
||||
return doc.getRole()
|
||||
`);
|
||||
is(role, ATSPI_ROLE_DOCUMENT_WEB, "doc has correct ATSPI role");
|
||||
ok(
|
||||
await runPython(`
|
||||
global p
|
||||
p = findByDomId(doc, "p")
|
||||
return p == doc[0]
|
||||
`),
|
||||
"doc's first child is p"
|
||||
);
|
||||
role = await runPython(`p.getRole()`);
|
||||
is(role, ATSPI_ROLE_PARAGRAPH, "p has correct ATSPI role");
|
||||
},
|
||||
{ chrome: true, topLevel: true, iframe: true, remoteIframe: true }
|
||||
);
|
||||
18
accessible/tests/browser/atk/head.js
Normal file
18
accessible/tests/browser/atk/head.js
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Load the shared-head file first.
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
|
||||
this
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as promisified-events.js.
|
||||
loadScripts(
|
||||
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
|
@ -4,6 +4,7 @@ subsuite = "a11y"
|
|||
support-files = [
|
||||
"!/accessible/tests/mochitest/*.js",
|
||||
"*.sys.mjs",
|
||||
"atk/a11y_setup.py",
|
||||
"head.js",
|
||||
"python_runner_wsh.py",
|
||||
"shared-head.js",
|
||||
|
|
|
|||
|
|
@ -30,8 +30,7 @@ def web_socket_transfer_data(request):
|
|||
if sys.platform == "win32":
|
||||
testDir = "windows"
|
||||
elif sys.platform == "linux":
|
||||
# XXX ATK code goes here.
|
||||
pass
|
||||
testDir = "atk"
|
||||
if testDir:
|
||||
sys.path.append(
|
||||
os.path.join(
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ apt_packages+=('pulseaudio-module-gconf')
|
|||
apt_packages+=('python-dev')
|
||||
apt_packages+=('python-pip')
|
||||
apt_packages+=('python3-pip')
|
||||
apt_packages+=('python3-pyatspi')
|
||||
apt_packages+=('qemu-kvm')
|
||||
apt_packages+=('rlwrap')
|
||||
apt_packages+=('screen')
|
||||
|
|
@ -158,4 +159,14 @@ rm -rf /usr/share/locale/ /usr/share/locale-langpack/ /usr/share/locales/
|
|||
# Further cleanup
|
||||
apt-get autoremove
|
||||
|
||||
# We've changed python3 to use 3.7, but binary modules are only installed for
|
||||
# the distribution's default which is 3.6. Symlink a module we need for 3.7.
|
||||
ln -s /usr/lib/python3/dist-packages/gi/_gi.cpython-{36m,37m}-x86_64-linux-gnu.so
|
||||
|
||||
# The packaged version of pyatspi is not compatible with Python 3.7. Hack it to
|
||||
# be compatible, since there's no package for 3.7 in this distribution.
|
||||
# Specifically, rename variables named "async" to "asynchronous", since "async"
|
||||
# is a reserved keyword in Python 3.7.
|
||||
sed -i 's/\basync\b/asynchronous/' /usr/lib/python3/dist-packages/pyatspi/registry.py
|
||||
|
||||
rm -f "$0"
|
||||
|
|
|
|||
|
|
@ -1217,7 +1217,7 @@ Tester.prototype = {
|
|||
|
||||
this.SimpleTest.reset();
|
||||
// Reset accessibility environment.
|
||||
this.AccessibilityUtils.reset(this.a11y_checks);
|
||||
this.AccessibilityUtils.reset(this.a11y_checks, this.currentTest.path);
|
||||
|
||||
// Load the tests into a testscope
|
||||
let currentScope = (this.currentTest.scope = new testScope(
|
||||
|
|
|
|||
|
|
@ -697,13 +697,17 @@ this.AccessibilityUtils = (function () {
|
|||
gEnv = { ...DEFAULT_ENV };
|
||||
},
|
||||
|
||||
reset(a11yChecks = false) {
|
||||
reset(a11yChecks = false, testPath = "") {
|
||||
gA11YChecks = a11yChecks;
|
||||
|
||||
const { Services } = SpecialPowers;
|
||||
// Disable accessibility service if it is running and if a11y checks are
|
||||
// disabled.
|
||||
if (!gA11YChecks && Services.appinfo.accessibilityEnabled) {
|
||||
// disabled. However, don't do this for accessibility engine tests.
|
||||
if (
|
||||
!gA11YChecks &&
|
||||
Services.appinfo.accessibilityEnabled &&
|
||||
!testPath.startsWith("chrome://mochitests/content/browser/accessible/")
|
||||
) {
|
||||
Services.prefs.setIntPref(FORCE_DISABLE_ACCESSIBILITY_PREF, 1);
|
||||
Services.prefs.clearUserPref(FORCE_DISABLE_ACCESSIBILITY_PREF);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue