forked from sauce-archives/Python-Robot-Appium-Android
-
Notifications
You must be signed in to change notification settings - Fork 0
/
RobotAppEyes.py
491 lines (400 loc) · 31.8 KB
/
RobotAppEyes.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
#!/usr/bin/env python
# Copyright 2013-2014 NaviNet Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import httplib
import base64
from selenium.webdriver.common.by import By
from selenium.common.exceptions import InvalidElementStateException
from robot.libraries.BuiltIn import BuiltIn
from applitools import logger
from applitools.logger import StdoutLogger
from applitools.geometry import Region
from applitools.eyes import Eyes, BatchInfo
from applitools.utils import _image_utils
from applitools._webdriver import EyesScreenshot
from version import VERSION
from applitools.target import Target, IgnoreRegionBySelector, FloatingRegion, FloatingBounds
from applitools.target import IgnoreRegionBySelector, FloatingRegion, FloatingBounds
from applitools.common import StitchMode
_version_ = VERSION
class RobotAppEyes:
"""
Robot-AppEyes is a visual verfication library for Robot Framework that leverages
the Eyes-Selenium and Selenium2 libraries.
*Before running tests*
Prior to running tests, RobotAppEyes must first be imported into your Robot test suite.
Example:
| Library | RobotAppEyes |
In order to run the Robot-AppEyes library and return results, you have to create a free account https://applitools.com/sign-up/ with Applitools.
You can retreive your API key from the applitools website and that will need to be passed in your Open Eyes Session keyword.
*Using Selectors*
Using the keyword Check Eyes Region By Element. The first four strategies are supported: _CSS SELECTOR_, _XPATH_, _ID_ and _CLASS NAME_.
Using the keyword Check Eyes Region By Selector. *All* the following strategies are supported:
| *Strategy* | *Example* | *Description* |
| CSS SELECTOR | Check Eyes Region By Selector `|` CSS SELECTOR `|` .first.expanded.dropdown `|` CssElement | Matches by CSS Selector |
| XPATH | Check Eyes Region By Selector `|` XPATH `|` //div[@id='my_element'] `|` XpathElement | Matches with arbitrary XPath expression |
| ID | Check Eyes Region By Selector `|` ID `|` my_element `|` IdElement | Matches by @id attribute |
| CLASS NAME | Check Eyes Region By Selector `|` CLASS NAME `|` element-search `|` ClassElement | Matches by @class attribute |
| LINK TEXT | Check Eyes Region By Selector `|` LINK TEXT `|` My Link `|` LinkTextElement | Matches anchor elements by their link text |
| PARTIAL LINK TEXT | Check Eyes Region By Selector `|` PARTIAL LINK TEXT `|` My Li `|` PartialLinkTextElement | Matches anchor elements by partial link text |
| NAME | Check Eyes Region By Selector `|` NAME `|` my_element `|` NameElement | Matches by @name attribute |
| TAG NAME | Check Eyes Region By Selector `|` TAG NAME `|` div `|` TagNameElement | Matches by HTML tag name |
"""
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
ROBOT_LIBRARY_VERSION = VERSION
BatchDic=dict()
def _eyes_set_batch(self,batchName,ApplitoolsJenkinsPlugin):
batch = BatchInfo(batchName)
if ApplitoolsJenkinsPlugin is True:
batch.id = os.environ('APPLITOOLS_BATCH_ID')
if batchName is None:
batch.name = os.environ('JOB_NAME')
if batchName not in self.BatchDic.keys():
self.BatchDic[batchName]=batch
eyes.batch=self.BatchDic[batchName]
def open_eyes_session(self,
appname,
testname,
apikey,
width=None,
height=None,
osname=None,
browsername=None,
matchlevel=None,
includeEyesLog=False,
httpDebugLog=False,
baselineName=None,
batchName=None,
ApplitoolsJenkinsPlugin=False,
branchname=None,
parentbranch=None,
hideScrollBar=False,
fullPageScreenshot=False,
matchTimeout=None,
cssStitch=None):
"""
Starts a session with the Applitools Eyes Website.
Arguments:
| Application Name (string) | The name of the application under test. |
| Test Name (string) | The test name. |
| API Key (string) | User's Applitools Eyes key. |
| (Optional) Width (int) | The width of the browser window e.g. 1280 |
| (Optional) Height (int) | The height of the browser window e.g. 1000 |
| (Optional) Operating System (string) | The operating system of the test, can be used to override the OS name to allow cross OS verfication |
| (Optional) Browser Name (string) | The browser name for the test, can be used to override the browser name to allow cross browser verfication |
| (Optional) Match Level (string) | The match level for the comparison - can be STRICT, LAYOUT or CONTENT |
| Include Eyes Log (default=False) | The Eyes logs will not be included by default. To activate, pass 'True' in the variable. |
| HTTP Debug Log (default=False) | The HTTP Debug logs will not be included by default. To activate, pass 'True' in the variable. |
| (Optional) Branch Name (default=None) | The branch to use to check test | For further information - http://support.applitools.com/customer/portal/articles/2142886
| (Optional)Parent Branch (default=None) | Parent Branch to base the new Branch on | For further information - http://support.applitools.com/customer/portal/articles/2142886
| (Optional) fullPageScrennshot (default=False) | Will force the browser to take a screenshot of whole page. |
| (Optional) matchTimeout | The amount of time that Eyes will wait for an image to stabilize to a point that it is similar to the baseline image | For further information - http://support.applitools.com/customer/portal/articles/2099488
| (Optional) ApplitoolsJenkinsPlugin (Boolean) | Integration with Applitools Jenkins Plugin | For further information - http://support.applitools.com/customer/portal/articles/2689601
| (Optional) cssStitch (string) | Scrolling option either Scroll or CSS | For further information - http://support.applitools.com/customer/portal/articles/2249374
Creates an instance of the Selenium2Library webdriver.
Defines a global driver and sets the Selenium2Library webdriver to the global driver.
Checks if there has been a width or height value passed in.
If there no are values passed in, eyes calls the method open without the width and height values.
Otherwise eyes calls open with the width and height values defined.
The Height resolution should not be greater than 1000, this is currently Applitools maximum setting.
Starts a session with the Applitools Eyes Website. See https://eyes.applitools.com/app/sessions/
Example:
| *Keywords* | *Parameters* |
| Open Browser | http://www.navinet.net/ | gc | | | | | | | | | |
| Open Eyes Session | RobotAppEyes_Test | NaviNet_RobotAppEyes_Test | YourApplitoolsKey | 1024 | 768 | OSOverrideName | BrowserOverrideName | matchlevel=LAYOUT | includeEyesLog=True | httpDebugLog=True |
| Check Eyes Window | NaviNet Home | | | | | | | | | | |
| Close Eyes Session | False | | | | | | | | | | |
"""
global driver
global eyes
eyes = Eyes()
eyes.api_key = apikey
self._eyes_set_batch(batchName,ApplitoolsJenkinsPlugin)
eyes.force_full_page_screenshot = fullPageScreenshot
eyes.hide_scrollbars = hideScrollBar
if baselineName is not None:
eyes.baseline_name = baselineName # (str)
s2l = BuiltIn().get_library_instance('Selenium2Library')
webdriver = s2l._current_browser()
driver = webdriver
if includeEyesLog is True:
logger.set_logger(StdoutLogger())
logger.open_()
if httpDebugLog is True:
httplib.HTTPConnection.debuglevel = 1
if osname is not None:
eyes.host_os = osname # (str)
if browsername is not None:
eyes.host_app = browsername # (str)
if matchTimeout is not None:
eyes._match_timeout= int(matchTimeout)
if baselineName is not None:
eyes.baseline_name = baselineName # (str)
if matchlevel is not None:
eyes.match_level = matchlevel
if parentbranch is not None:
eyes.parent_branch_name = parentbranch # (str)
if branchname is not None:
eyes.branch_name = branchname # (str)
if cssStitch is not None:
if cssStitch == 'CSS':
eyes.stitch_mode = StitchMode.CSS
elif cssStitch == 'Scroll':
eyes.stitch_mode = StitchMode.Scroll
if width is None and height is None:
eyes.open(driver, appname, testname)
else:
intwidth = int(width)
intheight = int(height)
eyes.open(driver, appname, testname, {'width': intwidth, 'height': intheight})
def check_eyes_window_with_ignore_region_by_selector(self, name, selector, selector_value, includeEyesLog=False, httpDebugLog=False):
"""
Takes a snapshot from the browser using the web driver and matches it with
the expected output.
Arguments:
| Name (string) | Name that will be given to region in Eyes. |
| Include Eyes Log (default=False) | The Eyes logs will not be included by default. To activate, pass 'True' in the variable. |
| HTTP Debug Log (default=False) | The HTTP Debug logs will not be included by default. To activate, pass 'True' in the variable. |
Example:
| *Keywords* | *Parameters* |
| Open Browser | http://www.navinet.net/ | gc | | | | |
| Open Eyes Session | http://www.navinet.net/ | RobotAppEyes_Test | NaviNet_RobotAppEyes_Test | YourApplitoolsKey | 1024 | 768 |
| Check Eyes Window | NaviNet Home | True | | | | |
| Close Eyes Session | False | | | | | |
"""
if includeEyesLog is True:
logger.set_logger(StdoutLogger())
logger.open_()
if httpDebugLog is True:
httplib.HTTPConnection.debuglevel = 1
eyes.check_window(name)
searchElement = None
if selector.upper() == 'CSS_SELECTOR':
searchElement = By.CSS_SELECTOR
elif selector.upper() == 'XPATH':
searchElement = By.XPATH
elif selector.upper() == 'ID':
searchElement = By.ID
elif selector.upper() == 'LINK TEXT':
searchElement = By.LINK_TEXT
elif selector.upper() == 'PARTIAL LINK TEXT':
searchElement = By.PARTIAL_LINK_TEXT
elif selector.upper() == 'NAME':
searchElement = By.NAME
elif selector.upper() == 'TAG NAME':
searchElement = By.TAG_NAME
elif selector.upper() == 'CLASS NAME':
searchElement = By.CLASS_NAME
else:
raise InvalidElementStateException(
'Please select a valid selector: CSS SELECTOR, XPATH, ID, LINK TEXT, PARTIAL LINK TEXT, NAME, TAG NAME, CLASS NAME')
eyes.check_window(tag=name, target=Target().ignore(IgnoreRegionBySelector(searchElement, selector_value)))
def check_eyes_window(self, name,
includeEyesLog=False, httpDebugLog=False):
"""
Takes a snapshot from the browser using the web driver and matches it with
the expected output.
Arguments:
| Name (string) | Name that will be given to region in Eyes. |
| Include Eyes Log (default=False) | The Eyes logs will not be included by default. To activate, pass 'True' in the variable. |
| HTTP Debug Log (default=False) | The HTTP Debug logs will not be included by default. To activate, pass 'True' in the variable. |
Example:
| *Keywords* | *Parameters* |
| Open Browser | http://www.navinet.net/ | gc | | | | |
| Open Eyes Session | http://www.navinet.net/ | RobotAppEyes_Test | NaviNet_RobotAppEyes_Test | YourApplitoolsKey | 1024 | 768 |
| Check Eyes Window | NaviNet Home | True | | | | |
| Close Eyes Session | False | | | | | |
"""
if includeEyesLog is True:
logger.set_logger(StdoutLogger())
logger.open_()
if httpDebugLog is True:
httplib.HTTPConnection.debuglevel = 1
eyes.check_window(name)
def check_eyes_region(self, element, width, height, name, includeEyesLog=False, httpDebugLog=False):
"""
Takes a snapshot of the given region from the browser using the web driver to locate an xpath element
with a certain width and height and matches it with the expected output.
The width and the height cannot be greater than the width and the height specified in the open_eyes_session keyword.
Arguments:
| Element (string) | This needs to be passed in as an xpath e.g. //*[@id="navbar"]/div/div |
| Width (int) | The width of the region that is tested e.g. 500 |
| Height (int) | The height of the region that is tested e.g. 120 |
| Name (string) | Name that will be given to region in Eyes. |
| Include Eyes Log (default=False) | The Eyes logs will not be included by default. To activate, pass 'True' in the variable. |
| HTTP Debug Log (default=False) | The HTTP Debug logs will not be included by default. To activate, pass 'True' in the variable. |
Example:
| *Keywords* | *Parameters* |
| Open Browser | http://www.navinet.net/ | gc | | | | |
| Open Eyes Session | http://www.navinet.net/ | RobotAppEyes_Test | NaviNet_RobotAppEyes_Test | YourApplitoolsKey | 1024 | 768 |
| Check Eyes Region | //*[@id="navbar"]/div/div | 500 | 120 | NaviNet Navbar | | |
| Close Eyes Session | False | | | | | |
"""
if includeEyesLog is True:
logger.set_logger(StdoutLogger())
logger.open_()
if httpDebugLog is True:
httplib.HTTPConnection.debuglevel = 1
intwidth = int(width)
intheight = int(height)
searchElement = driver.find_element_by_xpath(element)
location = searchElement.location
region = Region(location["x"], location["y"], intwidth, intheight)
eyes.check_region(region, name)
def check_eyes_region_by_element(self, selector, value, name, includeEyesLog=False, httpDebugLog=False):
"""
Takes a snapshot of the region of the given selector and element value from the browser using the web driver
and matches it with the expected output. With a choice from four selectors, listed below, to check by.
Arguments:
| Selector (string) | This will decide what element will be located. The supported selectors include: XPATH, ID, CLASS NAME, CSS SELECTOR |
| Value (string) | The specific value of the selector. e.g. an xpath value //*[@id="navbar"]/div/div |
| Name (string) | Name that will be given to region in Eyes. |
| Include Eyes Log (default=False) | The Eyes logs will not be included by default. To activate, pass 'True' in the variable. |
| HTTP Debug Log (default=False) | The HTTP Debug logs will not be included by default. To activate, pass 'True' in the variable. |
Example:
| *Keywords* | *Parameters* |
| Open Browser | http://www.navinet.net/ | gc | | | | |
| Open Eyes Session | http://www.navinet.net/ | RobotAppEyes_Test | NaviNet_RobotAppEyes_Test | YourApplitoolsKey | 1024 | 768 |
| Check Eyes Region By Element | CLASS NAME | container | NaviNetClassElement | | | |
| Close Eyes Session | False | | | | | |
"""
if includeEyesLog is True:
logger.set_logger(StdoutLogger())
logger.open_()
if httpDebugLog is True:
httplib.HTTPConnection.debuglevel = 1
searchElement = None
if selector.upper() == 'XPATH':
searchElement = driver.find_element_by_xpath(value)
elif selector.upper() == 'ID':
searchElement = driver.find_element_by_id(value)
elif selector.upper() == 'CLASS NAME':
searchElement = driver.find_element_by_class_name(value)
elif selector.upper() == 'CSS SELECTOR':
searchElement = driver.find_element_by_css_selector(value)
else:
raise InvalidElementStateException('Please select a valid selector: XPATH, ID, CLASS NAME, CSS SELECTOR')
eyes.check_region_by_element(searchElement, name)
def check_eyes_region_by_selector(self, selector, value, name, includeEyesLog=False, httpDebugLog=False):
"""
Takes a snapshot of the region of the element found by calling find_element(by, value) from the browser using the web driver
and matches it with the expected output. With a choice from eight selectors, listed below to check by.
Arguments:
| Selector (string) | This will decide what element will be located. The supported selectors include: CSS SELECTOR, XPATH, ID, LINK TEXT, PARTIAL LINK TEXT, NAME, TAG NAME, CLASS NAME. |
| Value (string) | The specific value of the selector. e.g. a CSS SELECTOR value .first.expanded.dropdown |
| Name (string) | Name that will be given to region in Eyes. |
| Include Eyes Log (default=False) | The Eyes logs will not be included by default. To activate, pass 'True' in the variable. |
| HTTP Debug Log (default=False) | The HTTP Debug logs will not be included by default. To activate, pass 'True' in the variable. |
Example:
| *Keywords* | *Parameters* |
| Open Browser | http://www.navinet.net/ | gc | | | | |
| Open Eyes Session | http://www.navinet.net/ | RobotAppEyes_Test | NaviNet_RobotAppEyes_Test | YourApplitoolsKey | 1024 | 768 |
| Check Eyes Region By Selector | CSS SELECTOR | .first.expanded.dropdown | NaviNetCssElement | | | |
| Close Eyes Session | False | | | | | |
"""
if includeEyesLog is True:
logger.set_logger(StdoutLogger())
logger.open_()
if httpDebugLog is True:
httplib.HTTPConnection.debuglevel = 1
searchElement = None
if selector.upper() == 'CSS SELECTOR':
searchElement = By.CSS_SELECTOR
elif selector.upper() == 'XPATH':
searchElement = By.XPATH
elif selector.upper() == 'ID':
searchElement = By.ID
elif selector.upper() == 'LINK TEXT':
searchElement = By.LINK_TEXT
elif selector.upper() == 'PARTIAL LINK TEXT':
searchElement = By.PARTIAL_LINK_TEXT
elif selector.upper() == 'NAME':
searchElement = By.NAME
elif selector.upper() == 'TAG NAME':
searchElement = By.TAG_NAME
elif selector.upper() == 'CLASS NAME':
searchElement = By.CLASS_NAME
else:
raise InvalidElementStateException('Please select a valid selector: CSS SELECTOR, XPATH, ID, LINK TEXT, PARTIAL LINK TEXT, NAME, TAG NAME, CLASS NAME')
eyes.check_region_by_selector(searchElement, value, name)
def compare_image(self, path, imagename=None, ignore_mismatch=False, includeEyesLog=False, httpDebugLog=False):
"""
Select an image and send it to Eyes for comparison. A name can be used in place of the image's file name.
Arguments:
| Path | Path of the image to send to eyes for visual comparison. |
| imagename (default=None) | Can manually set the name desired for the image passed in. If no name is passed in it will default file name of the image. |
| Include Eyes Log (default=False) | The Eyes logs will not be included by default. To activate, pass 'True' in the variable. |
| HTTP Debug Log (default=False) | The HTTP Debug logs will not be included by default. To activate, pass 'True' in the variable. |
Example:
| *Keywords* | *Parameters* |
| Open Browser | http://www.navinet.net/ | gc | | | | |
| Open Eyes Session | http://www.navinet.net/ | RobotAppEyes_Test | NaviNet_RobotAppEyes_Test | YourApplitoolsKey | 1024 | 768 |
| Compare Image | selenium-screenshot-1.png | Image Name Example | | | | |
| Close Eyes Session | | | | | | |
"""
if imagename is None:
tag = os.path.basename(path)
else:
tag = imagename
eyes._prepare_to_check()
if includeEyesLog is True:
logger.set_logger(StdoutLogger())
logger.open_()
if httpDebugLog is True:
httplib.HTTPConnection.debuglevel = 1
with open(path, 'rb') as image_file:
screenshot64 = image_file.read().encode('base64')
screenshot = _image_utils.png_image_from_bytes(base64.b64decode(screenshot64))
screenshotBytes = EyesScreenshot.create_from_image(screenshot, eyes._driver)
title = eyes.get_title()
app_output = {'title': title, 'screenshot64': None}
user_inputs = []
prepare_match_data = eyes._match_window_task._create_match_data_bytes(
app_output, user_inputs, tag, ignore_mismatch, screenshotBytes, default_match_settings)
eyes._match_window_task._agent_connector.match_window(
eyes._match_window_task._running_session, prepare_match_data)
def close_eyes_session(self, includeEyesLog=False, httpDebugLog=False):
"""
Closes a session and returns the results of the session.
If a test is running, aborts it. Otherwise, does nothing.
The RobotAppEyesTest.txt test will fail after the first run, this is because a baseline is being created and will be accepted automatically by Applitools Eyes.
A second test run will show a successful comparison between screens and the test will pass.
Arguments:
| Include Eyes Log (default=False) | The Eyes logs will not be included by default. To activate, pass 'True' in the variable. |
| HTTP Debug Log (default=False) | The HTTP Debug logs will not be included by default. To activate, pass 'True' in the variable. |
Example:
| *Keywords* | *Parameters* |
| Open Browser | http://www.navinet.net/ | gc | | | | |
| Open Eyes Session | http://www.navinet.net/ | RobotAppEyes_Test | NaviNet_RobotAppEyes_Test | YourApplitoolsKey | 1024 | 768 |
| Check Eyes Region By Selector | LINK TEXT | RESOURCES | NaviNetLinkTextElement | | | |
| Close Eyes Session | | | | | | |
"""
if includeEyesLog is True:
logger.set_logger(StdoutLogger())
logger.open_()
if httpDebugLog is True:
httplib.HTTPConnection.debuglevel = 1
eyes.close()
eyes.abort_if_not_closed()
def eyes_session_is_open(self):
"""
Returns True if an Applitools Eyes session is currently running, otherwise it will return False.
| *Keywords* | *Parameters* |
| Open Browser | http://www.navinet.net/ | gc | | | | |
| Open Eyes Session | http://www.navinet.net/ | RobotAppEyes_Test | NaviNet_RobotAppEyes_Test | YourApplitoolsKey | 1024 | 768 |
| ${isOpen}= | Eyes Session Is Open | | | | | |
| Run Keyword If | ${isOpen}==True | Close Eyes Session | | | | |
"""
return eyes.is_open()