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

Side by Side 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, 5 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 unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """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
7
8 This file performs Semi-automated tests of Chrome with NVDA
9 (NonVisual Desktop Access), a popular open-source screen reader for
10 visually impaired users on Windows. It works by launching Chrome in a
11 subprocess, then launching NVDA in a special environment that simulates
12 speech rather than actually speaking, and ignores all events coming from
13 processes other than a specific Chrome process ID. Each test automates
14 Chrome with a series of actions and asserts that NVDA gives the expected
15 feedback in response."""
16
17 import os
18 import pywinauto
19 import re
20 import shutil
21 import subprocess
22 import sys
23 import tempfile
24 import time
25 import unittest
26
27 CHROME_PROFILES_PATH = os.path.join(os.getcwd(), 'chrome_profiles')
28 CHROME_PATH = os.path.join(os.environ['USERPROFILE'],
29 'AppData',
30 'Local',
31 'Google',
32 'Chrome SxS',
33 'Application',
34 'chrome.exe')
35 NVDA_PATH = os.path.join(os.getcwd(),
36 'nvdaPortable',
37 'nvda_noUIAccess.exe')
38 NVDA_PROCTEST_PATH = os.path.join(os.getcwd(),
39 'nvda-proctest')
40 NVDA_LOGPATH = os.path.join(os.getcwd(),
41 'nvda_log.txt')
42
43 class NvdaChromeTest(unittest.TestCase):
44 @classmethod
45 def setUpClass(cls):
46 print 'user data: %s' % CHROME_PROFILES_PATH
47 print 'chrome: %s' % CHROME_PATH
48 print 'nvda: %s' % NVDA_PATH
49 print 'nvda_proctest: %s' % NVDA_PROCTEST_PATH
50
51 print
52 print 'Clearing user data directory and log file from previous runs'
53 if os.access(CHROME_PROFILES_PATH, os.F_OK):
54 shutil.rmtree(CHROME_PROFILES_PATH)
55 if os.access(NVDA_LOGPATH, os.F_OK):
56 os.remove(NVDA_LOGPATH)
57 os.mkdir(CHROME_PROFILES_PATH, 0777)
58
59 def setUp(self):
60 user_data_dir = tempfile.mkdtemp(dir = CHROME_PROFILES_PATH)
61 args = [CHROME_PATH,
62 '--user-data-dir=%s' % user_data_dir,
63 '--no-first-run',
64 'about:blank']
65 print
66 print ' '.join(args)
67 self._chrome_proc = subprocess.Popen(args)
68 self._chrome_proc.poll()
69 if self._chrome_proc.returncode is None:
70 print 'Chrome is running'
71 else:
72 print 'Chrome exited with code', self._chrome_proc.returncode
73 sys.exit()
74 print 'Chrome pid: %d' % self._chrome_proc.pid
75 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
76
77 os.environ['NVDA_SPECIFIC_PROCESS'] = str(self._chrome_proc.pid)
78
79 args = [NVDA_PATH,
80 '-m',
81 '-c',
82 NVDA_PROCTEST_PATH,
83 '-f',
84 NVDA_LOGPATH]
85 self._nvda_proc = subprocess.Popen(args)
86 self._nvda_proc.poll()
87 if self._nvda_proc.returncode is None:
88 print 'NVDA is running'
89 else:
90 print 'NVDA exited with code', self._nvda_proc.returncode
91 sys.exit()
92 print 'NVDA pid: %d' % self._nvda_proc.pid
93 time.sleep(1)
David Tseng 2014/06/30 16:55:28 Ditto.
94
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
95 app = pywinauto.application.Application()
96 app.connect_(process = self._chrome_proc.pid)
97 self._pywinauto_window = app.top_window_()
98
99 def tearDown(self):
100 print
101 print 'Shutting down'
102
103 self._chrome_proc.poll()
104 if self._chrome_proc.returncode is None:
105 print 'Killing Chrome subprocess'
106 self._chrome_proc.kill()
107 else:
108 print 'Chrome already died.'
109
110 self._nvda_proc.poll()
111 if self._nvda_proc.returncode is None:
112 print 'Killing Nvda subprocess'
David Tseng 2014/06/30 16:55:29 nit: NVDA
dmazzoni 2014/07/15 06:09:58 Done.
113 self._nvda_proc.kill()
114 else:
115 print 'Nvda already died.'
David Tseng 2014/06/30 16:55:29 Ditto.
dmazzoni 2014/07/15 06:09:58 Done.
116
117 def _GetSpeechFromNvdaLogFile(self):
118 """Return everything NVDA would have spoken as a list of strings.
119
120 Parses lines like this from NVDA's log file:
121 Speaking [LangChangeCommand ('en'), u'Google Chrome', u'window']
122 Speaking character u'slash'
123
124 Returns a single list of strings like this:
125 [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
126 """
127 lines = open(NVDA_LOGPATH).readlines()
128 regex = re.compile(r"u'((?:[^\'\\]|\\.)*)\'")
129 result = []
130 for line in lines:
131 for m in regex.finditer(line):
132 result.append(m.group(1))
133 return result
134
135 #
136 # Tests
137 #
138
139 def testTypingInOmnibox(self):
140 # Ctrl+A: Select all.
141 self._pywinauto_window.TypeKeys("^A")
142 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
143
144 # Type three characters.
145 self._pywinauto_window.TypeKeys("xyz")
146 time.sleep(1)
147
148 # Arrow back over two characters.
149 self._pywinauto_window.TypeKeys("{LEFT}")
150 time.sleep(1)
151 self._pywinauto_window.TypeKeys("{LEFT}")
152 time.sleep(1)
153
154 speech = self._GetSpeechFromNvdaLogFile()
155
156 self.assertIn('Address and search bar edit', speech)
157 speech = speech[speech.index('Address and search bar edit'):]
158
159 self.assertEqual(speech, [
160 'Address and search bar edit',
161 'about:blank',
162 'selecting about:blank',
163 'x',
164 'y',
165 'z',
166 'z',
167 'unselecting ',
168 'y'])
169
170 def testFocusToolbarButton(self):
171 # Alt+Shift+T.
172 self._pywinauto_window.TypeKeys("%+T")
173 time.sleep(1)
174
175 speech = self._GetSpeechFromNvdaLogFile()
176 self.assertIn('Reload button Reload this page', speech)
177
178 def testReadAllOnPageLoad(self):
179 # Ctrl+A: Select all
180 self._pywinauto_window.TypeKeys("^A")
181 time.sleep(1)
182
183 # Load data url.
184 self._pywinauto_window.TypeKeys("data:text/html,Hello<p>World")
185 time.sleep(1)
186 self._pywinauto_window.TypeKeys("{ENTER}")
187 time.sleep(1)
188
189 speech = self._GetSpeechFromNvdaLogFile()
190
191 self.assertIn('document', speech)
192 speech = speech[speech.index('document'):]
193
194 self.assertEqual(speech, [
195 'document',
196 'Hello',
197 'World'])
198
199 if __name__ == '__main__':
200 unittest.main()
201
OLDNEW
« 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