├── README.md
├── autoitdriverserver_python
├── __init__.py
├── autoit_options.cfg
├── favicon.ico
├── requirements.txt
└── server.py
└── sample-code
├── CalculatorTest.java
├── SeleniumIntegrationTest.java
├── SeleniumIntegrationWithAutoItDriver.py
├── calculator.py
├── demo.au3
├── notepad.py
└── run_au3_script_demo.py
/README.md:
--------------------------------------------------------------------------------
1 | AutoItDriverServer
2 | =========
3 |
4 | AutoItDriverServer is a server interface wrapper to [AutoIt](https://www.autoitscript.com) that provides a Selenium WebDriver API via the webdriver JSON wire protocol to drive AutoIt (using AutoItX COM/DLL API).
5 |
6 | There are 3 benefits to testing with AutoItDriverServer:
7 |
8 | 1: you are able to write your test in your choice of programming language, using the Selenium WebDriver API and language-specific client libraries.
9 |
10 | 2: is remote execution enabled, and perhaps Selenium Grid compatible in the future. See [Why use AutoItDriverServer](https://github.com/daluu/AutoItDriverServer/wiki/Why-use-AutoItDriverServer) for more details.
11 |
12 | 3: uses the well known AutoIt tool for Windows GUI manipulation. If you already use AutoIt, this will be a nice benefit.
13 |
14 | Quick Start & server/implementation notes
15 | ------------------------------------------
16 |
17 | The server is currently implemented in Python, calling AutoItX over COM (or optionally/alternatively DLL). There is a plan to do a .NET/C# version that is more standalone than Python in the future. Both implementations have the goal of working with all off the shelf Selenium client libraries.
18 |
19 | Python implementation is adapted from the [old Appium server Python implementation](https://github.com/hugs/appium-old), and uses the [Bottle micro web-framework](http://www.bottlepy.org). The .NET/C# implementation will be adapted from [Strontium server](https://github.com/jimevans/strontium).
20 |
21 | To get started, clone the repo:
22 | `git clone git://github.com/daluu/AutoItDriverServer`
23 |
24 | Next, change into the 'autoitdriverserver_python' directory, and install dependencies:
25 | `pip install -r partial_requirements.txt`
26 |
27 | The partial_requirements file doesn't necessarily specify all requirements. You'll need to have the Python win32com.client module (or Python for Windows extensions, win32 extensions for Python, etc.). That may already be installed with your Python installation. If not, you can install from here for example: http://sourceforge.net/projects/pywin32. You can test first yourself to see if executing "import win32com.client" will return an exception or not in Python, with no errors meaning it's already installed. Alternatively, the server code was initially written to also work with https://github.com/jacexh/pyautoit as well (if you swap out the commented code with the current code).
28 |
29 | Additionally, you'll need to have AutoIt installed, or register the appropriate version of AutoItX DLL (x86 vs x64). When installing AutoIt or registering DLL, the version to register/use depends on the platform you're using with. For Python it would depend on whether you run the 32 or 64 bit version of Python not whether your OS is 32 or 64 bit.
30 |
31 | To launch the webdriver-compatible AutoItDriverServer to use AutoIt via WebDriver client API, run (from 'autoitdriverserver_python' directory):
32 | `python server.py`
33 |
34 | For additional parameter info, append the `--help` parameter
35 |
36 | Example WebDriver API/client test usage against this server tool can be found in `sample-code` folder. To run the test, startup the server (with customized parameters as needed, recommend set address to 127.0.0.1) and review the example files' code before executing those scripts. Examples use Python WebDriver binding, but any language binding will actually do.
37 |
38 | NOTES/Caveats
39 | -------------
40 |
41 | AutoItDriverServer is simply a WebDriver server interface to AutoIt. Issues you experience may usually be the result of an issue with AutoIt rather than AutoItDriverServer itself. It would be wise to test your issue/scenario using AutoIt (via native AutoIt script compiled to executable or not) or AutoItX to confirm whether the issue is with AutoIt or AutoItDriverServer. The source code of AutoItDriverServer will point you to the appropriate AutoItX API or see the wiki documentation [here](https://github.com/daluu/AutoItDriverServer/wiki/WebDriver-API-command-support-and-mapping-to-AutoItX-API) and [here](https://github.com/daluu/AutoItDriverServer/wiki/Debugging-tests-and-issues-regarding-AutoIt-and-AutoItDriverServer).
42 |
43 | WebDriver API/command support and mapping to AutoItX API
44 | -------------------------------------------------------
45 |
46 | See [WebDriver API command support and mapping to AutoItX API](https://github.com/daluu/AutoItDriverServer/wiki/WebDriver-API-command-support-and-mapping-to-AutoItX-API)
47 |
48 | Contributing
49 | ------------
50 |
51 | Fork the project, make a change, and send a pull request!
52 |
53 | Or as a user, try it out, provide your feedback, submit bugs/enhancement requests.
54 |
--------------------------------------------------------------------------------
/autoitdriverserver_python/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2012 Appium Committers
2 | #
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 |
--------------------------------------------------------------------------------
/autoitdriverserver_python/autoit_options.cfg:
--------------------------------------------------------------------------------
1 | [AutoIt Options]
2 | CaretCoordMode=1
3 | ExpandEnvStrings=0
4 | MouseClickDelay=10
5 | MouseClickDownDelay=10
6 | MouseClickDragDelay=250
7 | MouseCoordinateMode=1
8 | SendAttachMode=0
9 | SendCapslockMode=1
10 | SendKeyDelay=5
11 | SendKeyDownDelay=5
12 | WinDetectHiddenText=0
13 | WinSearchChildren=0
14 | WinTextMatchMode=1
15 | WinTitleMatchMode=1
16 | WinWaitDelay=250
17 | AutoItScriptExecuteScriptAsCompiledBinary=False
18 | AutoIt32BitExecutablePath="C:\Program Files\AutoIt3\AutoIt3.exe"
19 | AutoIt64BitOSOnInstallUse32Bit=True
20 | AutoIt64BitOS32BitExecutablePath="C:\Program Files (x86)\AutoIt3\AutoIt3.exe"
21 | AutoIt64BitOS64BitExecutablePath="C:\Program Files (x86)\AutoIt3\AutoIt3_x64.exe"
--------------------------------------------------------------------------------
/autoitdriverserver_python/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daluu/AutoItDriverServer/331ef82d824d15da4a171004ef6bd740829851de/autoitdriverserver_python/favicon.ico
--------------------------------------------------------------------------------
/autoitdriverserver_python/requirements.txt:
--------------------------------------------------------------------------------
1 | bottle>=0.10.11
2 |
--------------------------------------------------------------------------------
/autoitdriverserver_python/server.py:
--------------------------------------------------------------------------------
1 | # Source code is modified from and based off of
2 | # old/original Appium Python implementation at
3 | #
4 | # https://github.com/hugs/appium-old
5 | #
6 | # Licensed to the Apache Software Foundation (ASF) under one
7 | # or more contributor license agreements. See the NOTICE file
8 | # distributed with this work for additional information
9 | # regarding copyright ownership. The ASF licenses this file
10 | # to you under the Apache License, Version 2.0 (the
11 | # "License"); you may not use this file except in compliance
12 | # with the License. You may obtain a copy of the License at
13 | #
14 | # http://www.apache.org/licenses/LICENSE-2.0
15 | #
16 | # Unless required by applicable law or agreed to in writing,
17 | # software distributed under the License is distributed on an
18 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19 | # KIND, either express or implied. See the License for the
20 | # specific language governing permissions and limitations
21 | # under the License.
22 |
23 | from __future__ import print_function
24 | from bottle import Bottle, request, response, redirect
25 | from bottle import run, static_file
26 | import json
27 | import socket
28 | import sys
29 | import platform
30 | import os
31 | import subprocess
32 | import tempfile
33 | import base64
34 | import urllib
35 | #import autoit
36 | import win32com.client
37 | from time import time
38 | from time import sleep
39 | try:
40 | import configparser
41 | except ImportError:
42 | import ConfigParser as configparser
43 |
44 | app = Bottle()
45 |
46 | @app.get('/favicon.ico')
47 | def get_favicon():
48 | return static_file('favicon.ico', root='.')
49 |
50 | def get_platform():
51 | if sys.platform == "win32":
52 | if platform.release() == "Vista":
53 | wd_platform = "VISTA"
54 | elif platform.release() == "XP": #?
55 | wd_platform = "XP"
56 | else:
57 | wd_platform = "WINDOWS"
58 | else:
59 | wd_platform = "WINDOWS"
60 | return wd_platform
61 |
62 | @app.route('/wd/hub/status', method='GET')
63 | def status():
64 | status = {'sessionId': app.SESSION_ID if app.started else None,
65 | 'status': 0,
66 | 'value': {'build': {'version': 'AutoItDriverServer 0.1'},
67 | 'os': {'arch':platform.machine(),'name':'windows','version':platform.release()}}}
68 | return status
69 |
70 | @app.route('/wd/hub/session', method='POST')
71 | def create_session():
72 | #app.oAutoItX = win32com.client.Dispatch("AutoItX3.Control")
73 |
74 | #process desired capabilities
75 | request_data = request.body.read()
76 | dc = json.loads(request_data.decode()).get('desiredCapabilities')
77 | if dc is not None:
78 | app.caretCoordMode = dc.get('caretCoordMode') if dc.get('caretCoordMode') is not None else app.caretCoordMode
79 | app.expandEnvStrings = dc.get('expandEnvStrings') if dc.get('expandEnvStrings') is not None else app.expandEnvStrings
80 | app.mouseClickDelay = dc.get('mouseClickDelay') if dc.get('mouseClickDelay') is not None else app.mouseClickDelay
81 | app.mouseClickDownDelay = dc.get('mouseClickDownDelay') if dc.get('mouseClickDownDelay') is not None else app.mouseClickDownDelay
82 | app.mouseClickDragDelay = dc.get('mouseClickDragDelay') if dc.get('mouseClickDragDelay') is not None else app.mouseClickDragDelay
83 | app.mouseCoordinateMode = dc.get('mouseCoordinateMode') if dc.get('mouseCoordinateMode') is not None else app.mouseCoordinateMode
84 | app.sendAttachMode = dc.get('sendAttachMode') if dc.get('sendAttachMode') is not None else app.sendAttachMode
85 | app.sendCapslockMode = dc.get('sendCapslockMode') if dc.get('sendCapslockMode') is not None else app.sendCapslockMode
86 | app.sendKeyDelay = dc.get('sendKeyDelay') if dc.get('sendKeyDelay') is not None else app.sendKeyDelay
87 | app.sendKeyDownDelay = dc.get('sendKeyDownDelay') if dc.get('sendKeyDownDelay') is not None else app.sendKeyDownDelay
88 | app.winDetectHiddenText = dc.get('winDetectHiddenText') if dc.get('winDetectHiddenText') is not None else app.winDetectHiddenText
89 | app.winSearchChildren = dc.get('winSearchChildren') if dc.get('winSearchChildren') is not None else app.winSearchChildren
90 | app.winTextMatchMode = dc.get('winTextMatchMode') if dc.get('winTextMatchMode') is not None else app.winTextMatchMode
91 | app.winTitleMatchMode = dc.get('winTitleMatchMode') if dc.get('winTitleMatchMode') is not None else app.winTitleMatchMode
92 | app.winWaitDelay = dc.get('winWaitDelay') if dc.get('winWaitDelay') is not None else app.winWaitDelay
93 |
94 | #autoit.option.caret_coord_mode = app.caretCoordMode
95 | app.oAutoItX.Opt("CaretCoordMode", app.caretCoordMode)
96 | #autoit.option.expand_env_strings = app.expandEnvStrings
97 | app.oAutoItX.Opt("ExpandEnvStrings", app.expandEnvStrings)
98 | #autoit.option.mouse_click_delay = app.mouseClickDelay
99 | app.oAutoItX.Opt("MouseClickDelay", app.mouseClickDelay)
100 | #autoit.option.mouse_click_down_delay = app.mouseClickDownDelay
101 | app.oAutoItX.Opt("MouseClickDownDelay", app.mouseClickDownDelay)
102 | #autoit.option.mouse_click_drag_delay = app.mouseClickDragDelay
103 | app.oAutoItX.Opt("MouseClickDragDelay", app.mouseClickDragDelay)
104 | #autoit.option.mouse_coordinate_mode = app.mouseCoordinateMode
105 | app.oAutoItX.Opt("MouseCoordinateMode", app.mouseCoordinateMode)
106 | #autoit.option.send_attach_mode = app.sendAttachMode
107 | app.oAutoItX.Opt("SendAttachMode", app.sendAttachMode)
108 | #autoit.option.send_capslock_mode = app.sendCapslockMode
109 | app.oAutoItX.Opt("SendCapslockMode", app.sendCapslockMode)
110 | #autoit.option.send_key_delay = app.sendKeyDelay
111 | app.oAutoItX.Opt("SendKeyDelay", app.sendKeyDelay)
112 | #autoit.option.send_key_down_delay = app.sendKeyDownDelay
113 | app.oAutoItX.Opt("SendKeyDownDelay", app.sendKeyDownDelay)
114 | #autoit.option.win_detect_hidden_text = app.winDetectHiddenText
115 | app.oAutoItX.Opt("WinDetectHiddenText", app.winDetectHiddenText)
116 | #autoit.option.win_search_children = app.winSearchChildren
117 | app.oAutoItX.Opt("WinSearchChildren", app.winSearchChildren)
118 | #autoit.option.win_text_match_mode = app.winTextMatchMode
119 | app.oAutoItX.Opt("WinTextMatchMode", app.winTextMatchMode)
120 | #autoit.option.win_title_match_mode = app.winTitleMatchMode
121 | app.oAutoItX.Opt("WinTitleMatchMode", app.winTitleMatchMode)
122 | #autoit.option.win_wait_delay = app.winWaitDelay
123 | app.oAutoItX.Opt("WinWaitDelay", app.winWaitDelay)
124 |
125 | #setup session
126 | app.started = True
127 | redirect('/wd/hub/session/%s' % app.SESSION_ID)
128 |
129 | @app.route('/wd/hub/session/', method='GET')
130 | def get_session(session_id=''):
131 | wd_platform = get_platform()
132 | app_response = {'sessionId': session_id,
133 | 'status': 0,
134 | 'value': {"version":"0.1",
135 | "browserName":"AutoIt",
136 | "platform":wd_platform,
137 | "takesScreenshot":False,
138 | "caretCoordMode":app.caretCoordMode,
139 | "expandEnvStrings":app.expandEnvStrings,
140 | "mouseClickDelay":app.mouseClickDelay,
141 | "mouseClickDownDelay":app.mouseClickDownDelay,
142 | "mouseClickDragDelay":app.mouseClickDragDelay,
143 | "mouseCoordinateMode":app.mouseCoordinateMode,
144 | "sendAttachMode":app.sendAttachMode,
145 | "sendCapslockMode":app.sendCapslockMode,
146 | "sendKeyDelay":app.sendKeyDelay,
147 | "sendKeyDownDelay":app.sendKeyDownDelay,
148 | "winDetectHiddenText":app.winDetectHiddenText,
149 | "winSearchChildren":app.winSearchChildren,
150 | "winTextMatchMode":app.winTextMatchMode,
151 | "winTitleMatchMode":app.winTitleMatchMode,
152 | "winWaitDelay":app.winWaitDelay}}
153 | return app_response
154 |
155 | @app.route('/wd/hub/session/', method='DELETE')
156 | def delete_session(session_id=''):
157 | app.started = False
158 | # any need to dispose of/clean up COM connection to AutoIt for win32com?
159 | # if we instantiated from create session (rather than at server startup)
160 | #app.oAutoItX = None # for example
161 | app_response = {'sessionId': session_id,
162 | 'status': 0,
163 | 'value': {}}
164 | return app_response
165 |
166 | @app.route('/wd/hub/session//execute', method='POST')
167 | def execute_script(session_id=''):
168 | request_data = request.body.read()
169 | try:
170 | script = json.loads(request_data.decode()).get('script')
171 | args = json.loads(request_data.decode()).get('args')
172 |
173 | if config.get("AutoIt Options",'AutoItScriptExecuteScriptAsCompiledBinary') == "False":
174 | if platform.machine() == "AMD64":
175 | if config.get("AutoIt Options",'AutoIt64BitOSOnInstallUse32Bit') == "True":
176 | au3Runner = config.get("AutoIt Options",'AutoIt64BitOS32BitExecutablePath')
177 | else:
178 | au3Runner = config.get("AutoIt Options",'AutoIt64BitOS64BitExecutablePath')
179 | else: # platform.machine() == "i386"
180 | au3Runner = config.get("AutoIt Options",'AutoIt32BitExecutablePath')
181 | script_call = "%s %s" % (au3Runner,script)
182 | else:
183 | script_call = script
184 | if args is not None:
185 | for arg in args:
186 | script_call = "%s %s" % (script_call,arg)
187 | print("script2exec: ",script_call)
188 | os.system(script_call)
189 | except:
190 | response.status = 400
191 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
192 |
193 | app_response = {'sessionId': session_id,
194 | 'status': 0,
195 | 'value': {}}
196 | return app_response
197 |
198 | @app.route('/wd/hub/session//element//click', method='POST')
199 | def element_click(session_id='', element_id=''):
200 | try:
201 | element = decode_value_from_wire(element_id)
202 | #result = autoit.control_click("[active]", element)
203 | result = app.oAutoItX.ControlClick("[active]", "", element)
204 | if result == 0:
205 | raise Exception("AutoIt failed to click element %s." % element)
206 | except:
207 | response.status = 400
208 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
209 |
210 | app_response = {'sessionId': session_id,
211 | 'status': 0,
212 | 'value': {}}
213 | return app_response
214 |
215 | @app.route('/wd/hub/session//click', method='POST')
216 | def mouse_click(session_id=''):
217 | request_data = request.body.read()
218 | if request_data == None or request_data == '' or request_data == "{}":
219 | button = 0
220 | else:
221 | button = json.loads(request_data.decode()).get('button')
222 | try:
223 | if button == 1:
224 | btn_type = "middle"
225 | elif button == 2:
226 | btn_type = "right"
227 | else:
228 | btn_type = "left"
229 | #autoit.mouse_click(btn_type)
230 | app.oAutoItX.MouseClick(btn_type)
231 | except:
232 | response.status = 400
233 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[0])}
234 |
235 | app_response = {'sessionId': session_id,
236 | 'status': 0,
237 | 'value': {}}
238 | return app_response
239 |
240 | @app.route('/wd/hub/session//doubleclick', method='POST')
241 | def double_click(session_id=''):
242 | try:
243 | #src = autoit.mouse_get_pos()
244 | #autoit.mouse_click("left",src.x,src.y,2)
245 | x = app.oAutoItX.MouseGetPosX()
246 | y = app.oAutoItX.MouseGetPosY()
247 | app.oAutoItX.MouseClick("left",x,y,2)
248 | except:
249 | response.status = 400
250 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[0])}
251 |
252 | app_response = {'sessionId': session_id,
253 | 'status': 0,
254 | 'value': {}}
255 | return app_response
256 |
257 | @app.route('/wd/hub/session//buttonup', method='POST')
258 | def mouse_up(session_id=''):
259 | request_data = request.body.read()
260 | if request_data == None or request_data == '' or request_data == "{}":
261 | button = 0
262 | else:
263 | button = json.loads(request_data.decode()).get('button')
264 | try:
265 | if button == 1:
266 | btn_type = "middle"
267 | elif button == 2:
268 | btn_type = "right"
269 | else:
270 | btn_type = "left"
271 | #autoit.mouse_up(btn_type)
272 | app.oAutoItX.MouseUp(btn_type)
273 | except:
274 | response.status = 400
275 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[0])}
276 |
277 | app_response = {'sessionId': session_id,
278 | 'status': 0,
279 | 'value': {}}
280 | return app_response
281 |
282 | @app.route('/wd/hub/session//buttondown', method='POST')
283 | def mouse_down(session_id=''):
284 | request_data = request.body.read()
285 | if request_data == None or request_data == '' or request_data == "{}":
286 | button = 0
287 | else:
288 | button = json.loads(request_data.decode()).get('button')
289 | try:
290 | if button == 1:
291 | btn_type = "middle"
292 | elif button == 2:
293 | btn_type = "right"
294 | else:
295 | btn_type = "left"
296 | #autoit.mouse_down(btn_type)
297 | app.oAutoItX.MouseDown(btn_type)
298 | except:
299 | response.status = 400
300 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[0])}
301 |
302 | app_response = {'sessionId': session_id,
303 | 'status': 0,
304 | 'value': {}}
305 | return app_response
306 |
307 | @app.route('/wd/hub/session//moveto', method='POST')
308 | def move_to(session_id=''):
309 | request_data = request.body.read()
310 | if request_data == None or request_data == '' or request_data == "{}":
311 | element_id = None
312 | xoffset = None
313 | yoffset = None
314 | else:
315 | element_id = json.loads(request_data.decode()).get('element')
316 | xoffset = json.loads(request_data.decode()).get('xoffset')
317 | yoffset = json.loads(request_data.decode()).get('yoffset')
318 | try:
319 | if element_id == None and (xoffset != None or yoffset != None):
320 | #src = autoit.mouse_get_pos()
321 | #autoit.mouse_move(src.x+xoffset,src.y+yoffset)
322 | x = app.oAutoItX.MouseGetPosX()
323 | y = app.oAutoItX.MouseGetPosY()
324 | app.oAutoItX.MouseMove(x+xoffset,y+yoffset)
325 | else:
326 | if xoffset != None or yoffset != None:
327 | control_id = decode_value_from_wire(element_id)
328 | #pos = autoit.control_get_pos("[active]",control_id)
329 | x = app.oAutoItX.ControlGetPosX("[active]","",control_id)
330 | y = app.oAutoItX.ControlGetPosY("[active]","",control_id)
331 | #if autoit._has_error():
332 | if app.oAutoItX.error == 1:
333 | raise Exception("AutoIt failed to get element %s location to move to." % control_id)
334 | #autoit.mouse_move(pos.left+xoffset,pos.top+yoffset)
335 | app.oAutoItX.MouseMove(x+xoffset,y+yoffset)
336 | else: # just go to center of element
337 | control_id = decode_value_from_wire(element_id)
338 | #pos = autoit.control_get_pos("[active]",control_id)
339 | x = app.oAutoItX.ControlGetPosX("[active]","",control_id)
340 | y = app.oAutoItX.ControlGetPosY("[active]","",control_id)
341 | width = app.oAutoItX.ControlGetPosWidth("[active]","",control_id)
342 | height = app.oAutoItX.ControlGetPosHeight("[active]","",control_id)
343 | #if autoit._has_error():
344 | if app.oAutoItX.error == 1:
345 | raise Exception("AutoIt failed to get element %s location to move to." % control_id)
346 | #autoit.mouse_move(pos.left+(pos.right/2),pos.top+(pos.bottom/2))
347 | app.oAutoItX.MouseMove(x+(width/2),y+(height/2))
348 | except:
349 | response.status = 400
350 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
351 |
352 | app_response = {'sessionId': session_id,
353 | 'status': 0,
354 | 'value': {}}
355 | return app_response
356 |
357 | @app.route('/wd/hub/session//element//value', method='POST')
358 | def set_value(session_id='', element_id=''):
359 | request_data = request.body.read()
360 | try:
361 | value_to_set = json.loads(request_data.decode()).get('value')
362 | value_to_set = ''.join(value_to_set)
363 | control_id = decode_value_from_wire(element_id)
364 | #result = autoit.control_set_text("[active]",control_id,value_to_set)
365 | result = app.oAutoItX.ControlSetText("[active]","",control_id,value_to_set)
366 | if result == 0:
367 | raise Exception("AutoIt failed to set text of element %s, element or window not found." % control_id)
368 | except:
369 | response.status = 400
370 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
371 |
372 | app_response = {'sessionId': session_id,
373 | 'status': 0,
374 | 'value': {}}
375 | return app_response
376 |
377 | @app.route('/wd/hub/session//element//clear', method='POST')
378 | def clear(session_id='', element_id=''):
379 | try:
380 | control_id = decode_value_from_wire(element_id)
381 | #result = autoit.control_set_text("[active]",control_id,"")
382 | result = app.oAutoItX.ControlSetText("[active]","",control_id,"")
383 | if result == 0:
384 | raise Exception("AutoIt failed to clear text of element %s, element or window not found." % control_id)
385 | except:
386 | response.status = 400
387 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
388 |
389 | app_response = {'sessionId': session_id,
390 | 'status': 0,
391 | 'value': {}}
392 | return app_response
393 |
394 | @app.route('/wd/hub/session//element//element', method='POST')
395 | def element_find_element(session_id='', element_id=''):
396 | return _find_element(session_id, element_id)
397 |
398 | @app.route('/wd/hub/session//element', method='POST')
399 | def find_element(session_id=''):
400 | return _find_element(session_id, "root")
401 |
402 | def _find_element(session_id, context, many=False):
403 | try:
404 | json_request_data = json.loads(request.body.read().decode())
405 | locator_strategy = json_request_data.get('using')
406 | value = json_request_data.get('value')
407 |
408 | if locator_strategy == "id":
409 | control_id = "[ID:%s]" % value
410 | elif locator_strategy == "link text":
411 | control_id = "[TEXT:%s]" % value
412 | elif locator_strategy == "tag name":
413 | control_id = "[CLASS:%s]" % value
414 | elif locator_strategy == "class name":
415 | control_id = "[CLASSNN:%s]" % value
416 | elif locator_strategy == "name":
417 | control_id = "[NAME:%s]" % value
418 | elif locator_strategy == "xpath":
419 | control_id = "[REGEXPCLASS:%s]" % value
420 | elif locator_strategy == "css selector":
421 | control_id = value
422 | else:
423 | control_id = value
424 |
425 | # AutoIt has no concept of finding elements/controls and checking if it
426 | # exists or not. Therefore, we just pass back the location strategy value
427 | # and let the individual WebElement methods fail when control/element not found
428 | found_elements = {'ELEMENT':encode_value_4_wire(control_id)}
429 | return {'sessionId': session_id, 'status': 0, 'value': found_elements}
430 | except:
431 | response.status = 400
432 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[0])}
433 |
434 | @app.route('/wd/hub/session//keys', method='POST')
435 | def keys(session_id=''):
436 | try:
437 | request_data = request.body.read()
438 | wired_keys = json.loads(request_data.decode()).get('value')
439 | keys = "".join(wired_keys)
440 | #autoit.send(keys)
441 | app.oAutoItX.Send(keys)
442 | return {'sessionId': session_id, 'status': 0}
443 | except:
444 | response.status = 400
445 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[0])}
446 |
447 | @app.route('/wd/hub/session//element//location', method='GET')
448 | def element_location(session_id='', element_id=''):
449 | try:
450 | control_id = decode_value_from_wire(element_id)
451 | #pos = autoit.control_get_pos("[active]",control_id)
452 | #location = {'x': pos.left, 'y': pos.top}
453 | x = app.oAutoItX.ControlGetPosX("[active]","",control_id)
454 | y = app.oAutoItX.ControlGetPosY("[active]","",control_id)
455 | location = {'x': x, 'y': y}
456 | #if autoit._has_error():
457 | if app.oAutoItX.error == 1:
458 | raise Exception("AutoIt failed to get element %s location coordinates." % control_id)
459 | return {'sessionId': session_id, 'status': 0, 'value': location}
460 | except:
461 | response.status = 400
462 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
463 |
464 | @app.route('/wd/hub/session//element//size', method='GET')
465 | def element_size(session_id='', element_id=''):
466 | try:
467 | control_id = decode_value_from_wire(element_id)
468 | #pos = autoit.control_get_pos("[active]",control_id)
469 | #size = {'width': pos.right, 'height': pos.bottom}
470 | width = app.oAutoItX.ControlGetPosWidth("[active]","",control_id)
471 | height = app.oAutoItX.ControlGetPosWidth("[active]","",control_id)
472 | size = {'width': width, 'height': height}
473 | #if autoit._has_error():
474 | if app.oAutoItX.error == 1:
475 | raise Exception("AutoIt failed to get element %s width & height size." % control_id)
476 | return {'sessionId': session_id, 'status': 0, 'value': size}
477 | except:
478 | response.status = 400
479 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
480 |
481 | @app.route('/wd/hub/session//element//displayed', method='GET')
482 | def element_displayed(session_id='', element_id=''):
483 | try:
484 | control_id = decode_value_from_wire(element_id)
485 | #result = autoit.control_command("[active]",control_id,"IsVisible")
486 | result = app.oAutoItX.ControlCommand("[active]","",control_id,"IsVisible")
487 | displayed = True if result == 1 else False
488 | #if autoit._has_error():
489 | if app.oAutoItX.error == 1:
490 | raise Exception("AutoIt failed to find element %s." % control_id)
491 | return {'sessionId': session_id, 'status': 0, 'value': displayed}
492 | except:
493 | response.status = 400
494 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
495 |
496 | @app.route('/wd/hub/session//element//enabled', method='GET')
497 | def element_enabled(session_id='', element_id=''):
498 | try:
499 | control_id = decode_value_from_wire(element_id)
500 | #result = autoit.control_command("[active]",control_id,"IsEnabled")
501 | result = app.oAutoItX.ControlCommand("[active]","",control_id,"IsEnabled")
502 | enabled = True if result == 1 else False
503 | #if autoit._has_error():
504 | if app.oAutoItX.error == 1:
505 | raise Exception("AutoIt failed to find element %s." % control_id)
506 | return {'sessionId': session_id, 'status': 0, 'value': enabled}
507 | except:
508 | response.status = 400
509 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
510 |
511 | @app.route('/wd/hub/session//element//selected', method='GET')
512 | def element_selected(session_id='', element_id=''):
513 | try:
514 | control_id = decode_value_from_wire(element_id)
515 | #result = autoit.control_command("[active]",control_id,"IsChecked")
516 | result = app.oAutoItX.ControlCommand("[active]","",control_id,"IsChecked")
517 | selected = True if result == 1 else False
518 | #if autoit._has_error():
519 | if app.oAutoItX.error == 1:
520 | raise Exception("AutoIt failed to find element %s." % control_id)
521 | return {'sessionId': session_id, 'status': 0, 'value': selected}
522 | except:
523 | response.status = 400
524 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
525 |
526 | @app.route('/wd/hub/session//element//text', method='GET')
527 | def get_text(session_id='', element_id=''):
528 | try:
529 | control_id = decode_value_from_wire(element_id)
530 | #text = autoit.control_get_text("[active]",control_id)
531 | text = app.oAutoItX.ControlGetText("[active]","",control_id)
532 | #if autoit._has_error() and text == "":
533 | if app.oAutoItX.error == 1 and text == "":
534 | raise Exception("AutoIt failed to find element %s, and get it's text" % control_id)
535 | except:
536 | response.status = 400
537 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
538 |
539 | app_response = {'sessionId': session_id,
540 | 'status': 0,
541 | 'value': text}
542 | return app_response
543 |
544 | @app.route('/wd/hub/session//element//attribute/', method='GET')
545 | def get_attribute(session_id='', element_id='', attribute=''):
546 | try:
547 | control_id = decode_value_from_wire(element_id)
548 | #result = autoit.control_command("[active]",control_id,attribute)
549 | result = app.oAutoItX.ControlCommand("[active]","",control_id,attribute)
550 | #if autoit._has_error():
551 | if app.oAutoItX.error == 1:
552 | raise Exception("AutoIt failed to find element %s or extract the specified attribute/command '%s'." % (control_id,attribute))
553 | except:
554 | response.status = 400
555 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
556 |
557 | app_response = {'sessionId': session_id,
558 | 'status': 0,
559 | 'value': str(result)}
560 | return app_response
561 |
562 | @app.route('/wd/hub/session//element//css/', method='GET')
563 | def get_property(session_id='', element_id='', property_name=''):
564 | try:
565 | control_id = decode_value_from_wire(element_id)
566 | #result = autoit.control_command("[active]",control_id,property_name)
567 | result = app.oAutoItX.ControlCommand("[active]","",control_id,property_name)
568 | #if autoit._has_error():
569 | if app.oAutoItX.error == 1:
570 | raise Exception("AutoIt failed to find element %s or extract the specified property/command '%s'." % (control_id,property_name))
571 | except:
572 | response.status = 400
573 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
574 |
575 | app_response = {'sessionId': session_id,
576 | 'status': 0,
577 | 'value': str(result)}
578 | return app_response
579 |
580 | @app.route('/wd/hub/session//title', method='GET')
581 | def get_window_title(session_id=''):
582 | try:
583 | #text = autoit.win_get_title("[active]")
584 | text = app.oAutoItX.WinGetTitle("[active]")
585 | if text == 0:
586 | raise Exception("AutoIt failed to get window title of current window.")
587 | except:
588 | response.status = 400
589 | return {'sessionId': session_id, 'status': 23, 'value': str(sys.exc_info()[1])}
590 |
591 | app_response = {'sessionId': session_id,
592 | 'status': 0,
593 | 'value': text}
594 | return app_response
595 |
596 | @app.route('/wd/hub/session//window_handle', method='GET')
597 | def get_current_window_handle(session_id=''):
598 | try:
599 | #handle = autoit.win_get_handle("[active]")
600 | handle = app.oAutoItX.WinGetHandle("[active]")
601 | #if autoit._has_error() and handle == "":
602 | if app.oAutoItX.error == 1 and handle == "":
603 | raise Exception("AutoIt failed to get current window handle.")
604 | except:
605 | response.status = 400
606 | return {'sessionId': session_id, 'status': 23, 'value': str(sys.exc_info()[1])}
607 |
608 | app_response = {'sessionId': session_id,
609 | 'status': 0,
610 | 'value': handle}
611 | return app_response
612 |
613 | @app.route('/wd/hub/session//window', method='POST')
614 | def select_window(session_id=''):
615 | request_data = request.body.read()
616 | try:
617 | win_name_or_handle = json.loads(request_data.decode()).get('name')
618 | #try:
619 | #autoit.win_activate_by_handle(win_name_or_handle)
620 | #except:
621 | #autoit.win_activate(win_name_or_handle)
622 | app.oAutoItX.WinActivate(win_name_or_handle)
623 | except:
624 | response.status = 400
625 | return {'sessionId': session_id, 'status': 23, 'value': str(sys.exc_info()[0])}
626 |
627 | app_response = {'sessionId': session_id,
628 | 'status': 0,
629 | 'value': {}}
630 | return app_response
631 |
632 | @app.route('/wd/hub/session//window', method='DELETE')
633 | def close_window(session_id=''):
634 | try:
635 | #autoit.win_close("[active]")
636 | app.oAutoItX.WinClose("[active]")
637 | except:
638 | response.status = 400
639 | return {'sessionId': session_id, 'status': 23, 'value': str(sys.exc_info()[0])}
640 |
641 | app_response = {'sessionId': session_id,
642 | 'status': 0,
643 | 'value': {}}
644 | return app_response
645 |
646 | @app.route('/wd/hub/session//window//size', method='POST')
647 | def resize_window(session_id='', window_handle=''):
648 | try:
649 | request_data = request.body.read()
650 | width = json.loads(request_data.decode()).get('width')
651 | height = json.loads(request_data.decode()).get('height')
652 |
653 | if window_handle == "current":
654 | window = "[active]"
655 | #pos = autoit.win_get_pos(window)
656 | #if autoit._has_error():
657 | #raise Exception("Window handle %s not found for resizing." % window_handle)
658 | #autoit.win_move(window,pos.left,pos.top,width,height)
659 | else:
660 | window = window_handle
661 | #pos = autoit.win_get_pos_by_handle(window)
662 | #if autoit._has_error():
663 | #raise Exception("Window handle %s not found for resizing." % window_handle)
664 | #autoit.win_move_by_handle(window,pos.left,pos.top,width,height)
665 |
666 | x = app.oAutoItX.WinGetPosX(window)
667 | y = app.oAutoItX.WinGetPosX(window)
668 | if app.oAutoItX.error == 1:
669 | raise Exception("Window handle %s not found for resizing." % window_handle)
670 | app.oAutoItX.WinMove(window,x,y,width,height)
671 |
672 | except:
673 | response.status = 400
674 | return {'sessionId': session_id, 'status': 23, 'value': str(sys.exc_info()[1])}
675 |
676 | app_response = {'sessionId': session_id,
677 | 'status': 0,
678 | 'value': {}}
679 | return app_response
680 |
681 | @app.route('/wd/hub/session//window//size', method='GET')
682 | def get_window_size(session_id='', window_handle=''):
683 | try:
684 | if window_handle == "current":
685 | window = "[active]"
686 | #pos = autoit.win_get_pos(window)
687 | else:
688 | window = window_handle
689 | #pos = autoit.win_get_pos_by_handle(window)
690 |
691 | #size = {'width': pos.right, 'height': pos.bottom}
692 | width = app.oAutoItX.WinGetPosWidth(window)
693 | height = app.oAutoItX.WinGetPosHeight(window)
694 | size = {'width': width, 'height': height}
695 | #if autoit._has_error():
696 | if app.oAutoItX.error == 1:
697 | raise Exception("Window handle %s not found for getting window size." % window_handle)
698 | except:
699 | response.status = 400
700 | return {'sessionId': session_id, 'status': 23, 'value': str(sys.exc_info()[1])}
701 |
702 | app_response = {'sessionId': session_id,
703 | 'status': 0,
704 | 'value': size}
705 | return app_response
706 |
707 | @app.route('/wd/hub/session//window//position', method='POST')
708 | def move_window(session_id='', window_handle=''):
709 | try:
710 | request_data = request.body.read()
711 | x = json.loads(request_data.decode()).get('x')
712 | y = json.loads(request_data.decode()).get('y')
713 |
714 | if window_handle == "current":
715 | window = "[active]"
716 | #autoit.win_move(window,x,y)
717 | else:
718 | window = window_handle
719 | #autoit.win_move_by_handle(window,x,y)
720 |
721 | app.oAutoItX.WinMove(window,x,y)
722 | except:
723 | response.status = 400
724 | return {'sessionId': session_id, 'status': 23, 'value': str(sys.exc_info()[0])}
725 |
726 | app_response = {'sessionId': session_id,
727 | 'status': 0,
728 | 'value': {}}
729 | return app_response
730 |
731 | @app.route('/wd/hub/session//window//position', method='GET')
732 | def get_window_position(session_id='', window_handle=''):
733 | try:
734 | if window_handle == "current":
735 | window = "[active]"
736 | #pos = autoit.win_get_pos(window)
737 | else:
738 | window = window_handle
739 | #pos = autoit.win_get_pos_by_handle(window)
740 |
741 | #size = {'x': pos.left, 'y': pos.top}
742 | x = app.oAutoItX.WinGetPosX(window)
743 | y = app.oAutoItX.WinGetPosY(window)
744 | size = {'x': x, 'y': y}
745 | #if autoit._has_error():
746 | if app.oAutoItX.error == 1:
747 | raise Exception("Window handle %s not found for getting window position." % window_handle)
748 | except:
749 | response.status = 400
750 | return {'sessionId': session_id, 'status': 23, 'value': str(sys.exc_info()[1])}
751 |
752 | app_response = {'sessionId': session_id,
753 | 'status': 0,
754 | 'value': size}
755 | return app_response
756 |
757 | @app.route('/wd/hub/session//window//maximize', method='POST')
758 | def max_window(session_id='', window_handle=''):
759 | try:
760 | if window_handle == "current":
761 | window = "[active]"
762 | #pos = autoit.win_set_state(window,autoit.properties.SW_MAXIMIZE)
763 | else:
764 | window = window_handle
765 | #pos = autoit.win_set_state_by_handle(window,autoit.properties.SW_MAXIMIZE)
766 |
767 | # FYI, @SW_MAXIMIZE = 3, per https://github.com/jacexh/pyautoit/blob/master/autoit/autoit.py#L111
768 | app.oAutoItX.WinSetState(window,app.oAutoItX.SW_MAXIMIZE)
769 | except:
770 | response.status = 400
771 | return {'sessionId': session_id, 'status': 23, 'value': str(sys.exc_info()[0])}
772 |
773 | app_response = {'sessionId': session_id,
774 | 'status': 0,
775 | 'value': {}}
776 | return app_response
777 |
778 | @app.route('/wd/hub/session//url', method='POST')
779 | def run_autoit_app(session_id=''):
780 | try:
781 | request_data = request.body.read()
782 | app2run = json.loads(request_data.decode()).get('url')
783 | #autoit.run(app2run)
784 | app.oAutoItX.Run(app2run)
785 | #if autoit._has_error():
786 | if app.oAutoItX.error == 1:
787 | raise Exception("Failed to run the application/executable: %s." % app2run)
788 | except:
789 | response.status = 400
790 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[1])}
791 |
792 | app_response = {'sessionId': session_id,
793 | 'status': 0,
794 | 'value': {}}
795 | return app_response
796 |
797 | @app.route('/wd/hub/session//file', method='POST')
798 | def upload_file(session_id=''):
799 | try:
800 | request_data = request.body.read()
801 | b64data = json.loads(request_data.decode()).get('file')
802 | byteContent = base64.b64decode(b64data)
803 | path = ""
804 | with tempfile.NamedTemporaryFile(delete=False) as f:
805 | f.write(byteContent)
806 | path = f.name
807 | extracted_files = unzip(path,os.path.dirname(path))
808 | except:
809 | response.status = 400
810 | return {'sessionId': session_id, 'status': 13, 'value': str(sys.exc_info()[0])}
811 |
812 | # For (remote) file uploads - well currently AutoItDriverServer will always be "remote"
813 | # we can't formally/technically support multiple file uploads yet, due to Selenium issue 2239
814 | # as the WebDriver/JSONWireProtocol spec doesn't define how to handle request/response
815 | # of multiple files uploaded. Therefore, we assume user upload single file for now
816 | result = "".join(extracted_files)
817 | app_response = {'sessionId': session_id,
818 | 'status': 0,
819 | 'value': result}
820 | return app_response
821 |
822 | def unzip(source_filename, dest_dir):
823 | import zipfile,os.path
824 | files_in_zip = []
825 | with zipfile.ZipFile(source_filename) as zf:
826 | for member in zf.infolist():
827 | words = member.filename.split('/')
828 | path = dest_dir
829 | for word in words[:-1]:
830 | drive, word = os.path.splitdrive(word)
831 | head, word = os.path.split(word)
832 | if word in (os.curdir, os.pardir, ''): continue
833 | path = os.path.join(path, word)
834 | zf.extract(member, path)
835 | unzipped_file = os.path.join(dest_dir,member.filename)
836 | print("Unzipped a file: ",unzipped_file)
837 | files_in_zip.append(unzipped_file)
838 | return files_in_zip
839 |
840 | @app.error(404)
841 | def unsupported_command(error):
842 | response.content_type = 'text/plain'
843 | return 'Unrecognized command, or AutoItDriverServer does not support/implement this: %s %s' % (request.method, request.path)
844 |
845 | def encode_value_4_wire(value):
846 | try:
847 | return urllib.parse.quote(base64.b64encode(value.encode("utf-8")))
848 | except:
849 | return urllib.quote(base64.b64encode(value.encode("utf-8")))
850 |
851 | def decode_value_from_wire(value):
852 | try:
853 | return base64.b64decode(urllib.parse.unquote(value)).decode("utf-8")
854 | except:
855 | return base64.b64decode(urllib.unquote(value)).decode("utf-8")
856 |
857 | if __name__ == '__main__':
858 | import argparse
859 |
860 | parser = argparse.ArgumentParser(description='AutoItDriverServer - a webdriver-compatible server for use with desktop GUI automation via AutoIt COM/DLL interface.')
861 | #parser.add_argument('-v', dest='verbose', action="store_true", default=False, help='verbose mode')
862 | parser.add_argument('-a', '--address', type=str, default=None, help='ip address to listen on')
863 | parser.add_argument('-p', '--port', type=int, default=4723, help='port to listen on')
864 | parser.add_argument('-c', '--autoit_options_file', type=str, default=None, help='config file defining the AutoIt options to use, see default sample config file in the app/server directory')
865 |
866 | args = parser.parse_args()
867 |
868 | if args.address is None:
869 | try:
870 | args.address = socket.gethostbyname(socket.gethostname())
871 | except:
872 | args.address = '127.0.0.1'
873 |
874 | if args.autoit_options_file is not None:
875 | options_file = args.autoit_options_file
876 | else:
877 | options_file = os.path.join(os.path.curdir,'autoit_options.cfg')
878 | config = configparser.RawConfigParser()
879 | config.read(options_file)
880 | app.caretCoordMode = config.get("AutoIt Options",'CaretCoordMode')
881 | app.expandEnvStrings = config.get("AutoIt Options",'ExpandEnvStrings')
882 | app.mouseClickDelay = config.get("AutoIt Options",'MouseClickDelay')
883 | app.mouseClickDownDelay = config.get("AutoIt Options",'MouseClickDownDelay')
884 | app.mouseClickDragDelay = config.get("AutoIt Options",'MouseClickDragDelay')
885 | app.mouseCoordinateMode = config.get("AutoIt Options",'MouseCoordinateMode')
886 | app.sendAttachMode = config.get("AutoIt Options",'SendAttachMode')
887 | app.sendCapslockMode = config.get("AutoIt Options",'SendCapslockMode')
888 | app.sendKeyDelay = config.get("AutoIt Options",'SendKeyDelay')
889 | app.sendKeyDownDelay = config.get("AutoIt Options",'SendKeyDownDelay')
890 | app.winDetectHiddenText = config.get("AutoIt Options",'WinDetectHiddenText')
891 | app.winSearchChildren = config.get("AutoIt Options",'WinSearchChildren')
892 | app.winTextMatchMode = config.get("AutoIt Options",'WinTextMatchMode')
893 | app.winTitleMatchMode = config.get("AutoIt Options",'WinTitleMatchMode')
894 | app.winWaitDelay = config.get("AutoIt Options",'WinWaitDelay')
895 |
896 | # for win32com, if we choose to instantiate AutoIt COM connection here
897 | # instead of per session basis
898 | app.oAutoItX = win32com.client.Dispatch("AutoItX3.Control")
899 |
900 | app.SESSION_ID = "%s:%d" % (args.address, args.port)
901 | app.started = False
902 | run(app, host=args.address, port=args.port)
--------------------------------------------------------------------------------
/sample-code/CalculatorTest.java:
--------------------------------------------------------------------------------
1 | import org.junit.*;
2 | import org.openqa.selenium.*;
3 | import org.openqa.selenium.remote.DesiredCapabilities;
4 | import org.openqa.selenium.remote.RemoteWebDriver;
5 | import java.net.URL;
6 |
7 | public class CalculatorTest {
8 |
9 | public WebDriver driver;
10 | public DesiredCapabilities capabilities;
11 |
12 | @Before
13 | public void setUp() throws Exception {
14 | capabilities = new DesiredCapabilities();
15 | capabilities.setCapability("browserName", "AutoIt");
16 | driver = new RemoteWebDriver(new URL("http://localhost:4723/wd/hub" ), capabilities);
17 | }
18 |
19 | @After
20 | public void tearDown() throws Exception {
21 | driver.quit();
22 | }
23 |
24 | @Test
25 | public void test() throws Exception{
26 | // demo adapted from
27 | // http://www.joecolantonio.com/2014/07/02/selenium-autoit-how-to-automate-non-browser-based-functionality/
28 | driver.get("calc.exe");
29 | driver.switchTo().window("Calculator");
30 | Thread.sleep(1000);
31 | driver.findElement(By.id("133")).click(); // 3
32 | Thread.sleep(1000);
33 | driver.findElement(By.id("93")).click(); // +
34 | Thread.sleep(1000);
35 | driver.findElement(By.id("133")).click(); // 3
36 | Thread.sleep(1000);
37 | driver.findElement(By.id("121")).click(); // =
38 | Thread.sleep(1000);
39 | Assert.assertEquals("3 + 3 did not produce 6 as expected.", "6", driver.findElement(By.id("150")).getText());
40 | driver.findElement(By.id("81")).click(); // Clear "C" button
41 | Thread.sleep(1000);
42 | driver.close();
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/sample-code/SeleniumIntegrationTest.java:
--------------------------------------------------------------------------------
1 | import org.junit.*;
2 | import org.openqa.selenium.*;
3 | import org.openqa.selenium.firefox.*;
4 | import org.openqa.selenium.remote.*;
5 | import org.openqa.selenium.interactions.*;
6 | import java.net.URL;
7 |
8 | public class SeleniumIntegrationTest {
9 |
10 | public WebDriver webDriver, autoitDriver;
11 | public DesiredCapabilities autoItCapabilities;
12 |
13 | @Before
14 | public void setUp() throws Exception {
15 | webDriver = new FirefoxDriver();
16 | autoItCapabilities = new DesiredCapabilities();
17 | autoItCapabilities.setCapability("browserName", "AutoIt");
18 | autoitDriver = new RemoteWebDriver(new URL("http://localhost:4723/wd/hub" ), autoItCapabilities);
19 | }
20 |
21 | @After
22 | public void tearDown() throws Exception {
23 | webDriver.quit();
24 | autoitDriver.quit();
25 | }
26 |
27 | @Test
28 | public void test() throws Exception {
29 | // ### HTTP authentication dialog popup demo ###
30 | webDriver.get("http://www.httpwatch.com/httpgallery/authentication/");
31 | Thread.sleep(1000);
32 | // check state that img is "unauthenticated" at start
33 | String imgSrc = webDriver.findElement(By.id("downloadImg")).getAttribute("src");
34 | Assert.assertTrue("HTTP demo test fail because test site not started with correct default unauthenticated state.",imgSrc.contains("/images/spacer.gif"));
35 |
36 | // now test authentication
37 | webDriver.findElement(By.id("displayImage")).click(); // trigger the popup
38 | Thread.sleep(5000); // wait for popup to appear
39 | autoitDriver.switchTo().window("Authentication Required");
40 | new Actions(autoitDriver).sendKeys("httpwatch{TAB}AutoItDriverServerAndSeleniumIntegrationDemo{TAB}{ENTER}").build().perform();
41 | Thread.sleep(5000);
42 |
43 | // now check img is authenticated or changed
44 | imgSrc = webDriver.findElement(By.id("downloadImg")).getAttribute("src");
45 | Assert.assertFalse("HTTP demo failed, image didn't authenticate/change after logging in.",imgSrc.contains("/images/spacer.gif"));
46 |
47 | // ### file upload demo, also adapted from sample code of the test/target site ###
48 | webDriver.get("http://www.toolsqa.com/automation-practice-form");
49 | // webDriver.findElement(By.id("photo")).click(); // this doesn't seem to trigger file upload to popup
50 | WebElement elem = webDriver.findElement(By.id("photo"));
51 | ((JavascriptExecutor) webDriver).executeScript("arguments[0].click();",elem);
52 | Thread.sleep(5000); // wait for file upload dialog to appear
53 | autoitDriver.switchTo().window("File Upload");
54 |
55 | /* FYI, on FF, Opera, (Windows Safari) filename field control ID may be 1152
56 | * but on IE, Chrome, and Windows in general, should be control ID should be 1148
57 | */
58 | //uncomment line below if want to transfer file from Selenium code execution machine A to remote node B before typing in actual file path at target node B
59 | //((RemoteWebDriver) autoitDriver).setFileDetector(new LocalFileDetector());
60 | autoitDriver.findElement(By.className("Edit1")).sendKeys("C:\\ReplaceWith\\PathTo\\AnActualFileOnRemoteNode.txt");
61 | Thread.sleep(2000);
62 | autoitDriver.findElement(By.className("Button1")).click();
63 | //new Actions(autoitDriver).sendKeys("{ENTER}").perform(); // another option to "click" Open/Upload
64 | //new Actions(autoitDriver).sendKeys("!o").perform(); // another option to invoke Open/Upload via keyboard shortcut ALT + O
65 | Thread.sleep(5000);
66 |
67 | // execute an AutoIt script from WebDriver
68 | ((JavascriptExecutor) autoitDriver).executeScript("C:\\PathOnAutoItDriverServerHostMachineTo\\demo.au3","Hello","World");
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/sample-code/SeleniumIntegrationWithAutoItDriver.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | from selenium import webdriver
3 | from selenium.webdriver import ActionChains
4 | import time
5 |
6 | wd = webdriver.Firefox()
7 | ad = webdriver.Remote( command_executor='http://127.0.0.1:4723/wd/hub', desired_capabilities={'browserName':'AutoIt'})
8 | print("Desired Capabilities returned by server:\n")
9 | print(ad.desired_capabilities)
10 | print("")
11 |
12 | action1 = ActionChains(ad)
13 |
14 | ### HTTP authentication dialog popup demo ###
15 | wd.get("http://www.httpwatch.com/httpgallery/authentication/")
16 | time.sleep(1)
17 | # check state that img is "unauthenticated" at start
18 | img_src = wd.find_element_by_id("downloadImg").get_attribute("src")
19 | if not img_src.endswith("/images/spacer.gif"):
20 | print("HTTP demo test fail because test site not started with correct default unauthenticated state.")
21 |
22 | # now test authentication
23 | wd.find_element_by_id("displayImage").click() # trigger the popup
24 | time.sleep(5) # wait for popup to appear
25 | ad.switch_to_window("Authentication Required")
26 | action1.send_keys("httpwatch{TAB}AutoItDriverServerAndSeleniumIntegrationDemo{TAB}{ENTER}").perform()
27 | time.sleep(5)
28 |
29 | # now check img is authenticated or changed
30 | img_src = wd.find_element_by_id("downloadImg").get_attribute("src")
31 | if img_src.endswith("/images/spacer.gif"):
32 | print("HTTP demo failed, image didn't authenticate/change after logging in.")
33 |
34 | ### file upload demo, also adapted from sample code of the test/target site ###
35 | wd.get("http://www.toolsqa.com/automation-practice-form")
36 | # wd.find_element_by_id("photo").click() # this doesn't seem to trigger file upload to popup
37 | elem = wd.find_element_by_id("photo")
38 | wd.execute_script("arguments[0].click();",elem)
39 | time.sleep(10) # wait for file upload dialog to appear
40 | ad.switch_to_window("File Upload")
41 |
42 | # FYI, on FF, Opera, (Windows Safari) filename field control ID may be 1152
43 | # but on IE, Chrome, and Windows in general, should be control ID should be 1148
44 |
45 | ad.find_element_by_class_name("Edit1").send_keys("C:\\ReplaceWith\\PathTo\\AnActualFile.txt")
46 | # due to remote file upload (via local file detector), you may notice actual path typed
47 | # may differ from what you fill in above, but that path is still valid for the original file
48 | # it's just a copy in a temp directory. This is the nature of file uploads over RemoteWebDriver
49 | # instead of a local driver.
50 | time.sleep(2)
51 | ad.find_element_by_class_name("Button1").click()
52 | #actions.send_keys("{ENTER}").perform() # another option to "click" Open/Upload
53 | #actions.send_keys("!o").perform() # another option to invoke Open/Upload via keyboard shortcut ALT + O
54 | time.sleep(5)
55 |
56 | ### handle browser's print dialog popup demo? to come... ###
57 | # Print dialog popup may hang Selenium code,
58 | # so may want to fire off a separate thread for AutoIt(DriverServer)
59 | # to monitor for popup when it shows up (i.e. Selenium then hung)
60 | # and have AutoIt print or cancel the popup to then resume Selenium main thread code
61 |
62 | # file download popup handling demo? to come...
63 |
64 | # handle Adobe Acrobat PDF loaded inside browser demo? e.g. click save, print, etc. to come...
65 |
66 | # handle Flash or embedded streaming video controls demo? e.g. play, stop, etc. to come...
67 |
68 | wd.quit()
69 | ad.quit()
--------------------------------------------------------------------------------
/sample-code/calculator.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | from selenium import webdriver
3 | from selenium.webdriver import ActionChains
4 | import time
5 |
6 | driver = webdriver.Remote( command_executor='http://127.0.0.1:4723/wd/hub', desired_capabilities={'browserName':'AutoIt'})
7 | print("Desired Capabilities returned by server:\n")
8 | print(driver.desired_capabilities)
9 | print("")
10 |
11 | # demo adapted from
12 | # http://www.joecolantonio.com/2014/07/02/selenium-autoit-how-to-automate-non-browser-based-functionality/
13 | driver.get("calc.exe")
14 | driver.switch_to_window("Calculator")
15 | time.sleep(1)
16 | driver.find_element_by_id("133").click() # 3
17 | time.sleep(1)
18 | driver.find_element_by_id("93").click() # +
19 | time.sleep(1)
20 | driver.find_element_by_id("133").click() # 3
21 | time.sleep(1)
22 | driver.find_element_by_id("121").click() # =
23 | time.sleep(1)
24 | if driver.find_element_by_id("150").text != "6":
25 | print("3 + 3 did not produce 6 as expected.")
26 | driver.find_element_by_id("81").click() # Clear "C" button
27 | time.sleep(1)
28 |
29 | # demo adapted from AutoItX VBScript example that comes with AutoIt installation
30 | action1 = ActionChains(driver)
31 | action2 = ActionChains(driver)
32 | action3 = ActionChains(driver)
33 | action1.send_keys("2*2=").perform()
34 | time.sleep(1)
35 | if driver.find_element_by_id("150").text != "4":
36 | print("2 x 2 did not produce 4 as expected.")
37 | driver.find_element_by_id("81").click() # Clear "C" button
38 | time.sleep(1)
39 | action2.send_keys("4*4=").perform()
40 | time.sleep(1)
41 | if driver.find_element_by_id("150").text != "16":
42 | print("4 x 4 did not produce 16 as expected.")
43 | driver.find_element_by_id("81").click() # Clear "C" button
44 | time.sleep(1)
45 | action3.send_keys("8*8=").perform()
46 | time.sleep(1)
47 | if driver.find_element_by_id("150").text != "64":
48 | print("8 x 8 did not produce 64 as expected.")
49 | driver.find_element_by_id("81").click() # Clear "C" button
50 | time.sleep(1)
51 | driver.close()
52 | driver.quit()
--------------------------------------------------------------------------------
/sample-code/demo.au3:
--------------------------------------------------------------------------------
1 | Local $myArgs = ""
2 | If $CmdLine[0] > 0 Then
3 | For $i = 1 To $CmdLine[0] Step 1
4 | $myArgs &= " " & $CmdLine[$i]
5 | Next
6 | EndIf
7 | MsgBox(64, "Demo", "An AutoIt au3 script was ran, with arguments (if any) of: " & $myArgs)
--------------------------------------------------------------------------------
/sample-code/notepad.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | from selenium import webdriver
3 | from selenium.webdriver import ActionChains
4 | import time
5 |
6 | driver = webdriver.Remote( command_executor='http://127.0.0.1:4723/wd/hub', desired_capabilities={'browserName':'AutoIt'})
7 | print("Desired Capabilities returned by server:\n")
8 | print(driver.desired_capabilities)
9 | print("")
10 |
11 | # demo adapted from AutoItX VBScript example that comes with AutoIt installation
12 | driver.get("notepad.exe")
13 | driver.switch_to_window("Untitled - Notepad")
14 | time.sleep(1)
15 | action1 = ActionChains(driver)
16 | action2 = ActionChains(driver)
17 | action3 = ActionChains(driver)
18 | action4 = ActionChains(driver)
19 | action1.send_keys("Hello, this is line 1{ENTER}").perform()
20 | time.sleep(1)
21 | action2.send_keys("This is line 2{ENTER}This is line 3").perform()
22 | time.sleep(1)
23 | action3.send_keys("!{F4}").perform()
24 | time.sleep(1)
25 | action4.send_keys("!n").perform()
26 | driver.quit()
--------------------------------------------------------------------------------
/sample-code/run_au3_script_demo.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | from selenium import webdriver
3 | import os
4 |
5 | driver = webdriver.Remote( command_executor='http://127.0.0.1:4723/wd/hub', desired_capabilities={'browserName':'AutoIt'})
6 | print("Desired Capabilities returned by server:\n")
7 | print(driver.desired_capabilities)
8 | print("")
9 |
10 | # execute an AutoIt script file (rather than call specific AutoItX API commands)
11 | # supply path to AutoIt script file followed by optional arguments
12 | driver.execute_script("C:\\PathOnAutoItDriverServerHostMachineTo\\demo.au3","Hello","World")
13 |
14 | # or if using compiled binary option
15 | # (but need to set AutoItScriptExecuteScriptAsCompiledBinary to True in autoit_options.cfg first
16 | # before starting the server).
17 | #driver.execute_script("C:\\PathOnAutoItDriverServerHostMachineTo\\demo.exe","Hello","World")
18 |
19 | driver.quit()
--------------------------------------------------------------------------------