Skip to content

Commit a02f54d

Browse files
authored
Merge pull request #236 from seleniumbase/masterqa-updates
MasterQA Updates
2 parents 9ea6f6e + 66c6c18 commit a02f54d

File tree

5 files changed

+101
-82
lines changed

5 files changed

+101
-82
lines changed

seleniumbase/config/settings.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@
7676
# The default message that appears when you don't specify a custom message
7777
MASTERQA_DEFAULT_VALIDATION_MESSAGE = "Does the page look good?"
7878

79-
# The time delay (in seconds) before the validation pop-up appears
80-
# This value can be overwritten on the command line. Ex: --verify_delay=0.5
81-
MASTERQA_WAIT_TIME_BEFORE_VERIFY = 0.75
79+
# The time delay (in seconds) before the MasterQA validation pop-up appears.
80+
# This value can be overwritten on the command line. Ex: --verify_delay=1.0
81+
MASTERQA_WAIT_TIME_BEFORE_VERIFY = 0.5
8282

8383
# If True, the automation will start in full-screen mode
8484
MASTERQA_START_IN_FULL_SCREEN_MODE = False

seleniumbase/fixtures/js_utils.py

Lines changed: 81 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,69 @@
1010
from seleniumbase.fixtures import constants
1111

1212

13+
def wait_for_ready_state_complete(driver, timeout=settings.EXTREME_TIMEOUT):
14+
"""
15+
The DOM (Document Object Model) has a property called "readyState".
16+
When the value of this becomes "complete", page resources are considered
17+
fully loaded (although AJAX and other loads might still be happening).
18+
This method will wait until document.readyState == "complete".
19+
"""
20+
21+
start_ms = time.time() * 1000.0
22+
stop_ms = start_ms + (timeout * 1000.0)
23+
for x in range(int(timeout * 10)):
24+
try:
25+
ready_state = driver.execute_script("return document.readyState")
26+
except WebDriverException:
27+
# Bug fix for: [Permission denied to access property "document"]
28+
time.sleep(0.03)
29+
return True
30+
if ready_state == u'complete':
31+
time.sleep(0.01) # Better be sure everything is done loading
32+
return True
33+
else:
34+
now_ms = time.time() * 1000.0
35+
if now_ms >= stop_ms:
36+
break
37+
time.sleep(0.1)
38+
raise Exception(
39+
"Page elements never fully loaded after %s seconds!" % timeout)
40+
41+
42+
def execute_async_script(driver, script, timeout=settings.EXTREME_TIMEOUT):
43+
driver.set_script_timeout(timeout)
44+
return driver.execute_async_script(script)
45+
46+
47+
def wait_for_angularjs(driver, timeout=settings.LARGE_TIMEOUT, **kwargs):
48+
if not settings.WAIT_FOR_ANGULARJS:
49+
return
50+
51+
NG_WRAPPER = '%(prefix)s' \
52+
'var $elm=document.querySelector(' \
53+
'\'[data-ng-app],[ng-app],.ng-scope\')||document;' \
54+
'if(window.angular && angular.getTestability){' \
55+
'angular.getTestability($elm).whenStable(%(handler)s)' \
56+
'}else{' \
57+
'var $inj;try{$inj=angular.element($elm).injector()||' \
58+
'angular.injector([\'ng\'])}catch(ex){' \
59+
'$inj=angular.injector([\'ng\'])};$inj.get=$inj.get||' \
60+
'$inj;$inj.get(\'$browser\').' \
61+
'notifyWhenNoOutstandingRequests(%(handler)s)}' \
62+
'%(suffix)s'
63+
def_pre = 'var cb=arguments[arguments.length-1];if(window.angular){'
64+
prefix = kwargs.pop('prefix', def_pre)
65+
handler = kwargs.pop('handler', 'function(){cb(true)}')
66+
suffix = kwargs.pop('suffix', '}else{cb(false)}')
67+
script = NG_WRAPPER % {'prefix': prefix,
68+
'handler': handler,
69+
'suffix': suffix}
70+
try:
71+
execute_async_script(driver, script, timeout=timeout)
72+
except Exception:
73+
time.sleep(0.05)
74+
75+
1376
def is_jquery_activated(driver):
1477
try:
1578
driver.execute_script("jQuery('html')") # Fails if jq is not defined
@@ -18,6 +81,22 @@ def is_jquery_activated(driver):
1881
return False
1982

2083

84+
def wait_for_jquery_active(driver, timeout=None):
85+
if not timeout:
86+
timeout = int(settings.MINI_TIMEOUT * 10.0)
87+
else:
88+
timeout = int(timeout * 10.0)
89+
for x in range(timeout):
90+
# jQuery needs a small amount of time to activate.
91+
try:
92+
driver.execute_script("jQuery('html')")
93+
wait_for_ready_state_complete(driver)
94+
wait_for_angularjs(driver)
95+
return
96+
except Exception:
97+
time.sleep(0.1)
98+
99+
21100
def activate_jquery(driver):
22101
""" If "jQuery is not defined", use this method to activate it for use.
23102
This happens because jQuery is not always defined on web sites. """
@@ -92,69 +171,6 @@ def safe_execute_script(driver, script):
92171
driver.execute_script(script)
93172

94173

95-
def wait_for_ready_state_complete(driver, timeout=settings.EXTREME_TIMEOUT):
96-
"""
97-
The DOM (Document Object Model) has a property called "readyState".
98-
When the value of this becomes "complete", page resources are considered
99-
fully loaded (although AJAX and other loads might still be happening).
100-
This method will wait until document.readyState == "complete".
101-
"""
102-
103-
start_ms = time.time() * 1000.0
104-
stop_ms = start_ms + (timeout * 1000.0)
105-
for x in range(int(timeout * 10)):
106-
try:
107-
ready_state = driver.execute_script("return document.readyState")
108-
except WebDriverException:
109-
# Bug fix for: [Permission denied to access property "document"]
110-
time.sleep(0.03)
111-
return True
112-
if ready_state == u'complete':
113-
time.sleep(0.01) # Better be sure everything is done loading
114-
return True
115-
else:
116-
now_ms = time.time() * 1000.0
117-
if now_ms >= stop_ms:
118-
break
119-
time.sleep(0.1)
120-
raise Exception(
121-
"Page elements never fully loaded after %s seconds!" % timeout)
122-
123-
124-
def execute_async_script(driver, script, timeout=settings.EXTREME_TIMEOUT):
125-
driver.set_script_timeout(timeout)
126-
return driver.execute_async_script(script)
127-
128-
129-
def wait_for_angularjs(driver, timeout=settings.LARGE_TIMEOUT, **kwargs):
130-
if not settings.WAIT_FOR_ANGULARJS:
131-
return
132-
133-
NG_WRAPPER = '%(prefix)s' \
134-
'var $elm=document.querySelector(' \
135-
'\'[data-ng-app],[ng-app],.ng-scope\')||document;' \
136-
'if(window.angular && angular.getTestability){' \
137-
'angular.getTestability($elm).whenStable(%(handler)s)' \
138-
'}else{' \
139-
'var $inj;try{$inj=angular.element($elm).injector()||' \
140-
'angular.injector([\'ng\'])}catch(ex){' \
141-
'$inj=angular.injector([\'ng\'])};$inj.get=$inj.get||' \
142-
'$inj;$inj.get(\'$browser\').' \
143-
'notifyWhenNoOutstandingRequests(%(handler)s)}' \
144-
'%(suffix)s'
145-
def_pre = 'var cb=arguments[arguments.length-1];if(window.angular){'
146-
prefix = kwargs.pop('prefix', def_pre)
147-
handler = kwargs.pop('handler', 'function(){cb(true)}')
148-
suffix = kwargs.pop('suffix', '}else{cb(false)}')
149-
script = NG_WRAPPER % {'prefix': prefix,
150-
'handler': handler,
151-
'suffix': suffix}
152-
try:
153-
execute_async_script(driver, script, timeout=timeout)
154-
except Exception:
155-
time.sleep(0.05)
156-
157-
158174
def wait_for_css_query_selector(
159175
driver, selector, timeout=settings.SMALL_TIMEOUT):
160176
element = None
@@ -352,10 +368,11 @@ def activate_jquery_confirm(driver):
352368

353369
if not is_jquery_activated(driver):
354370
add_js_link(driver, jquery_js)
371+
wait_for_jquery_active(driver, timeout=0.6)
355372
add_css_link(driver, jq_confirm_css)
356373
add_js_link(driver, jq_confirm_js)
357374

358-
for x in range(int(settings.MINI_TIMEOUT * 10.0)):
375+
for x in range(7):
359376
# jQuery-Confirm needs a small amount of time to load & activate.
360377
try:
361378
driver.execute_script("jconfirm")

seleniumbase/masterqa/ReadMe.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
### MasterQA bridges the gap between manual QA and automated QA by combining manual verification steps with SeleniumBase automation scripts.
44

5-
![](https://cdn2.hubspot.net/hubfs/100006/images/masterqa3.gif "MasterQA")
5+
![](https://cdn2.hubspot.net/hubfs/100006/images/masterqa6.gif "MasterQA")
66

77
Here's some example code from [basic_masterqa_test.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/basic_masterqa_test.py):
88

seleniumbase/masterqa/master_qa.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,24 @@ def clear_out_old_logs(self, archive_past_runs=True, get_log_folder=False):
6060

6161
def jq_confirm_dialog(self, question):
6262
count = self.manual_check_count + 1
63-
question = js_utils.escape_quotes_if_needed(question)
63+
title_content = ('<center><font color="#7700bb">Manual Check #%s:'
64+
'</font></center><hr><font color="#0066ff">%s</font>'
65+
'' % (count, question))
66+
title_content = js_utils.escape_quotes_if_needed(title_content)
6467
jqcd = ("""jconfirm({
65-
boxWidth: '30%%',
68+
boxWidth: '32.5%%',
6669
useBootstrap: false,
6770
containerFluid: false,
68-
theme: 'light',
71+
animationBounce: 1,
72+
type: 'default',
73+
theme: 'bootstrap',
74+
typeAnimated: true,
6975
animation: 'scale',
7076
draggable: true,
71-
dragWindowGap: 0,
77+
dragWindowGap: 1,
7278
container: 'body',
73-
title: 'Manual Check #%s:',
74-
content: '<h3><b>%s</b></h3>',
79+
title: '%s',
80+
content: '',
7581
buttons: {
7682
fail_button: {
7783
btnClass: 'btn-red',
@@ -88,7 +94,7 @@ def jq_confirm_dialog(self, question):
8894
}
8995
}
9096
}
91-
});""" % (count, question))
97+
});""" % title_content)
9298
self.execute_script(jqcd)
9399

94100
def manual_page_check(self, *args):
@@ -106,11 +112,10 @@ def manual_page_check(self, *args):
106112
question = instructions
107113

108114
use_jqc = False
115+
self.wait_for_ready_state_complete()
109116
if js_utils.is_jquery_confirm_activated(self.driver):
110117
use_jqc = True
111118
else:
112-
if self.browser == "firefox":
113-
js_utils.activate_jquery(self.driver)
114119
js_utils.activate_jquery_confirm(self.driver)
115120
get_jqc = None
116121
try:
@@ -374,10 +379,7 @@ def process_manual_check_results(self, auto_close_results_page=False):
374379
self.open("file://%s" % archived_results_file)
375380
if auto_close_results_page:
376381
# Long enough to notice the results before closing the page
377-
wait_time_before_verify = WAIT_TIME_BEFORE_VERIFY
378-
if self.verify_delay:
379-
wait_time_before_verify = float(self.verify_delay)
380-
time.sleep(wait_time_before_verify)
382+
time.sleep(1.0)
381383
else:
382384
# The user can decide when to close the results page
383385
print("\n*** Close the html report window to continue ***")

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
setup(
1919
name='seleniumbase',
20-
version='1.17.0',
20+
version='1.17.1',
2121
description='All-in-One Test Automation Framework',
2222
long_description=long_description,
2323
long_description_content_type='text/markdown',

0 commit comments

Comments
 (0)