Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2733)

Unified Diff: tools/accessibility/nvda/nvda_chrome_tests.py

Issue 331363004: Add a script to test Chrome with the NVDA screen reader. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« tools/accessibility/nvda/README.txt ('K') | « tools/accessibility/nvda/README.txt ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/accessibility/nvda/nvda_chrome_tests.py
diff --git a/tools/accessibility/nvda/nvda_chrome_tests.py b/tools/accessibility/nvda/nvda_chrome_tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..2061377d4bac583fe7eeeb796f98bc5ab555031d
--- /dev/null
+++ b/tools/accessibility/nvda/nvda_chrome_tests.py
@@ -0,0 +1,201 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Semi-automated tests of Chrome with NVDA.
David Tseng 2014/06/30 16:55:28 What does it mean to be semi automated?
dmazzoni 2014/07/15 06:09:58 Clarified in comments. I basically mean that it's
+
+This file performs Semi-automated tests of Chrome with NVDA
+(NonVisual Desktop Access), a popular open-source screen reader for
+visually impaired users on Windows. It works by launching Chrome in a
+subprocess, then launching NVDA in a special environment that simulates
+speech rather than actually speaking, and ignores all events coming from
+processes other than a specific Chrome process ID. Each test automates
+Chrome with a series of actions and asserts that NVDA gives the expected
+feedback in response."""
+
+import os
+import pywinauto
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+import time
+import unittest
+
+CHROME_PROFILES_PATH = os.path.join(os.getcwd(), 'chrome_profiles')
+CHROME_PATH = os.path.join(os.environ['USERPROFILE'],
+ 'AppData',
+ 'Local',
+ 'Google',
+ 'Chrome SxS',
+ 'Application',
+ 'chrome.exe')
+NVDA_PATH = os.path.join(os.getcwd(),
+ 'nvdaPortable',
+ 'nvda_noUIAccess.exe')
+NVDA_PROCTEST_PATH = os.path.join(os.getcwd(),
+ 'nvda-proctest')
+NVDA_LOGPATH = os.path.join(os.getcwd(),
+ 'nvda_log.txt')
+
+class NvdaChromeTest(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ print 'user data: %s' % CHROME_PROFILES_PATH
+ print 'chrome: %s' % CHROME_PATH
+ print 'nvda: %s' % NVDA_PATH
+ print 'nvda_proctest: %s' % NVDA_PROCTEST_PATH
+
+ print
+ print 'Clearing user data directory and log file from previous runs'
+ if os.access(CHROME_PROFILES_PATH, os.F_OK):
+ shutil.rmtree(CHROME_PROFILES_PATH)
+ if os.access(NVDA_LOGPATH, os.F_OK):
+ os.remove(NVDA_LOGPATH)
+ os.mkdir(CHROME_PROFILES_PATH, 0777)
+
+ def setUp(self):
+ user_data_dir = tempfile.mkdtemp(dir = CHROME_PROFILES_PATH)
+ args = [CHROME_PATH,
+ '--user-data-dir=%s' % user_data_dir,
+ '--no-first-run',
+ 'about:blank']
+ print
+ print ' '.join(args)
+ self._chrome_proc = subprocess.Popen(args)
+ self._chrome_proc.poll()
+ if self._chrome_proc.returncode is None:
+ print 'Chrome is running'
+ else:
+ print 'Chrome exited with code', self._chrome_proc.returncode
+ sys.exit()
+ print 'Chrome pid: %d' % self._chrome_proc.pid
+ time.sleep(1)
David Tseng 2014/06/30 16:55:28 Is this needed? Looks flakey.
dmazzoni 2014/07/15 06:09:58 OK, I successfully removed this and replaced it wi
+
+ os.environ['NVDA_SPECIFIC_PROCESS'] = str(self._chrome_proc.pid)
+
+ args = [NVDA_PATH,
+ '-m',
+ '-c',
+ NVDA_PROCTEST_PATH,
+ '-f',
+ NVDA_LOGPATH]
+ self._nvda_proc = subprocess.Popen(args)
+ self._nvda_proc.poll()
+ if self._nvda_proc.returncode is None:
+ print 'NVDA is running'
+ else:
+ print 'NVDA exited with code', self._nvda_proc.returncode
+ sys.exit()
+ print 'NVDA pid: %d' % self._nvda_proc.pid
+ time.sleep(1)
David Tseng 2014/06/30 16:55:28 Ditto.
+
David Tseng 2014/06/30 16:55:29 Wrt ordering, do we ever want to test Chrome initi
dmazzoni 2014/07/15 06:09:58 Sure. My guess is that opening a new browser windo
dmazzoni 2014/07/15 15:41:18 Oh, I almost forgot - one big reason I did it in t
+ app = pywinauto.application.Application()
+ app.connect_(process = self._chrome_proc.pid)
+ self._pywinauto_window = app.top_window_()
+
+ def tearDown(self):
+ print
+ print 'Shutting down'
+
+ self._chrome_proc.poll()
+ if self._chrome_proc.returncode is None:
+ print 'Killing Chrome subprocess'
+ self._chrome_proc.kill()
+ else:
+ print 'Chrome already died.'
+
+ self._nvda_proc.poll()
+ if self._nvda_proc.returncode is None:
+ print 'Killing Nvda subprocess'
David Tseng 2014/06/30 16:55:29 nit: NVDA
dmazzoni 2014/07/15 06:09:58 Done.
+ self._nvda_proc.kill()
+ else:
+ print 'Nvda already died.'
David Tseng 2014/06/30 16:55:29 Ditto.
dmazzoni 2014/07/15 06:09:58 Done.
+
+ def _GetSpeechFromNvdaLogFile(self):
+ """Return everything NVDA would have spoken as a list of strings.
+
+ Parses lines like this from NVDA's log file:
+ Speaking [LangChangeCommand ('en'), u'Google Chrome', u'window']
+ Speaking character u'slash'
+
+ Returns a single list of strings like this:
+ [u'Google Chrome', u'window', u'slash']
David Tseng 2014/06/30 16:55:28 Any chance NVDA could just use json for the log fo
dmazzoni 2014/07/15 06:09:58 Happy to ask - but this seems robust enough for wh
+ """
+ lines = open(NVDA_LOGPATH).readlines()
+ regex = re.compile(r"u'((?:[^\'\\]|\\.)*)\'")
+ result = []
+ for line in lines:
+ for m in regex.finditer(line):
+ result.append(m.group(1))
+ return result
+
+ #
+ # Tests
+ #
+
+ def testTypingInOmnibox(self):
+ # Ctrl+A: Select all.
+ self._pywinauto_window.TypeKeys("^A")
+ time.sleep(1)
David Tseng 2014/06/30 16:55:29 Going to be flakey; any way we could just listen t
dmazzoni 2014/07/15 06:09:58 I think I've removed the flakiness. I really like
+
+ # Type three characters.
+ self._pywinauto_window.TypeKeys("xyz")
+ time.sleep(1)
+
+ # Arrow back over two characters.
+ self._pywinauto_window.TypeKeys("{LEFT}")
+ time.sleep(1)
+ self._pywinauto_window.TypeKeys("{LEFT}")
+ time.sleep(1)
+
+ speech = self._GetSpeechFromNvdaLogFile()
+
+ self.assertIn('Address and search bar edit', speech)
+ speech = speech[speech.index('Address and search bar edit'):]
+
+ self.assertEqual(speech, [
+ 'Address and search bar edit',
+ 'about:blank',
+ 'selecting about:blank',
+ 'x',
+ 'y',
+ 'z',
+ 'z',
+ 'unselecting ',
+ 'y'])
+
+ def testFocusToolbarButton(self):
+ # Alt+Shift+T.
+ self._pywinauto_window.TypeKeys("%+T")
+ time.sleep(1)
+
+ speech = self._GetSpeechFromNvdaLogFile()
+ self.assertIn('Reload button Reload this page', speech)
+
+ def testReadAllOnPageLoad(self):
+ # Ctrl+A: Select all
+ self._pywinauto_window.TypeKeys("^A")
+ time.sleep(1)
+
+ # Load data url.
+ self._pywinauto_window.TypeKeys("data:text/html,Hello<p>World")
+ time.sleep(1)
+ self._pywinauto_window.TypeKeys("{ENTER}")
+ time.sleep(1)
+
+ speech = self._GetSpeechFromNvdaLogFile()
+
+ self.assertIn('document', speech)
+ speech = speech[speech.index('document'):]
+
+ self.assertEqual(speech, [
+ 'document',
+ 'Hello',
+ 'World'])
+
+if __name__ == '__main__':
+ unittest.main()
+
« tools/accessibility/nvda/README.txt ('K') | « tools/accessibility/nvda/README.txt ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698