Each browser test file is run with a separate instance of shared-head.js and thus a distinct WebSocket connection to the a11y Python runner. pywebsocket3 is multi-threaded and may thus choose different threads to handle different WebSocket requests. Python comtypes implicitly initialises COM when it is imported, but COM initialisation is thread specific and Python modules are cached, so this only applies to the thread on which comtypes was imported. These factors were causing problems such as event timeouts when running multiple IA2 test files because IA2 relies on COM being initialised. To fix this, add a setup() function to a11y_setup.py which is called when a request is handled. For Windows, this calls CoInitialize once in each thread in which it is run. Differential Revision: https://phabricator.services.mozilla.com/D227143
70 lines
1.9 KiB
Python
70 lines
1.9 KiB
Python
# 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 setup():
|
|
# We do all the setup we need at module level.
|
|
pass
|
|
|
|
|
|
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
|