Skip to content

Commit 7368173

Browse files
authored
Merge pull request #537 from seleniumbase/offline-methods
Add methods and examples for offline testing
2 parents 998655d + 3b4972a commit 7368173

File tree

9 files changed

+744
-83
lines changed

9 files changed

+744
-83
lines changed

examples/offline_examples/demo_page.html

Lines changed: 482 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from seleniumbase import BaseCase
2+
3+
4+
class MyTestClass(BaseCase):
5+
6+
def test_demo_page(self):
7+
# Load a local html file into the browser
8+
self.load_html_file("demo_page.html")
9+
10+
# Assert that the element is visible on the page
11+
self.assert_element("tbody#tbodyId")
12+
13+
# Assert that the text appears within a given element
14+
self.assert_text("Demo Page", "h1")
15+
16+
# Update the text of various text fields on the page
17+
self.update_text("#myTextInput", "This is Automated")
18+
self.update_text("textarea.area1", "Testing Time!\n")
19+
self.update_text('[name="preText2"]', "Typing Text!")
20+
21+
# Verify that a button click changes text on the page
22+
self.assert_text("This Text is Green", "#pText")
23+
self.click("#myButton")
24+
self.assert_text("This Text is Purple", "#pText")
25+
26+
# Verify that the hover dropdown option changes text
27+
self.assert_text("Automation Practice", "h3")
28+
self.hover_and_click("#myDropdown", "#dropOption2")
29+
self.assert_text("Link Two Selected", "h3")
30+
31+
# Verify that the "select" option updates a meter bar
32+
self.assert_element('meter[value="0.25"]')
33+
self.select_option_by_text("#mySelect", "Set to 75%")
34+
self.assert_element('meter[value="0.75"]')
35+
36+
# Assert an element located inside an iFrame
37+
self.assert_false(self.is_element_visible("img"))
38+
self.switch_to_frame("#myFrame1")
39+
self.assert_true(self.is_element_visible("img"))
40+
self.switch_to_default_content()
41+
42+
# Assert text located inside an iFrame
43+
self.assert_false(self.is_text_visible("Frame Text"))
44+
self.switch_to_frame("#myFrame2")
45+
self.assert_true(self.is_text_visible("Frame Text"))
46+
self.switch_to_default_content()
47+
48+
# Verify that clicking a checkbox makes it selected
49+
self.assert_false(self.is_selected("#checkBox1"))
50+
self.click("#checkBox1")
51+
self.assert_true(self.is_selected("#checkBox1"))
52+
53+
# Verify that clicking a radio button selects it
54+
self.assert_false(self.is_selected("#radioButton2"))
55+
self.click("#radioButton2")
56+
self.assert_true(self.is_selected("#radioButton2"))
57+
58+
# Assert that the SVG is visible on the page
59+
self.assert_element('svg[name="svgName"]')
60+
61+
# Assert the title of the current web page
62+
self.assert_title("Web Testing Page")

help_docs/method_summary.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ self.select_option_by_value(dropdown_selector, option,
126126
dropdown_by=By.CSS_SELECTOR,
127127
timeout=None)
128128

129+
self.load_html_string(html_string, new_page=True)
130+
131+
self.load_html_file(html_file, new_page=True)
132+
133+
self.open_html_file(html_file)
134+
129135
self.execute_script(script)
130136

131137
self.execute_async_script(script, timeout=None)
@@ -262,6 +268,8 @@ self.assert_equal(first, second, msg=None)
262268

263269
self.assert_not_equal(first, second, msg=None)
264270

271+
self.assert_raises(*args, **kwargs)
272+
265273
self.assert_title(title)
266274

267275
self.assert_no_js_errors()
@@ -294,6 +302,8 @@ self.add_css_style(css_style)
294302

295303
self.add_js_code_from_link(js_link)
296304

305+
self.add_js_code(js_code)
306+
297307
self.add_meta_tag(http_equiv=None, content=None)
298308

299309
########

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pytest-xdist==1.31.0
2727
parameterized==0.7.1
2828
soupsieve==1.9.5;python_version<"3.5"
2929
soupsieve==2.0;python_version>="3.5"
30-
beautifulsoup4==4.8.2
30+
beautifulsoup4==4.9.0
3131
atomicwrites==1.3.0
3232
portalocker==1.6.0
3333
cryptography==2.8
@@ -44,6 +44,6 @@ boto==2.49.0
4444
cffi==1.14.0
4545
tqdm==4.45.0
4646
flake8==3.7.9
47-
certifi>=2019.11.28
47+
certifi>=2020.4.5.1
4848
pdfminer.six==20191110;python_version<"3.5"
4949
pdfminer.six==20200402;python_version>="3.5"

seleniumbase/fixtures/base_case.py

Lines changed: 105 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,88 @@ def select_option_by_value(self, dropdown_selector, option,
13721372
dropdown_by=dropdown_by, option_by="value",
13731373
timeout=timeout)
13741374

1375+
def load_html_string(self, html_string, new_page=True):
1376+
""" Loads an HTML string into the web browser.
1377+
If new_page==True, the page will switch to: "data:text/html,"
1378+
If new_page==False, will load HTML into the current page. """
1379+
1380+
soup = self.get_beautiful_soup(html_string)
1381+
scripts = soup.findAll("script")
1382+
for script in scripts:
1383+
html_string = html_string.replace(str(script), "")
1384+
soup = self.get_beautiful_soup(html_string)
1385+
1386+
found_head = False
1387+
found_body = False
1388+
html_head = None
1389+
html_body = None
1390+
if soup.head and len(str(soup.head)) > 12:
1391+
found_head = True
1392+
html_head = str(soup.head)
1393+
html_head = re.escape(html_head)
1394+
html_head = self.__escape_quotes_if_needed(html_head)
1395+
html_head = html_head.replace('\\ ', ' ')
1396+
if soup.body and len(str(soup.body)) > 12:
1397+
found_body = True
1398+
html_body = str(soup.body)
1399+
html_body = re.escape(html_body)
1400+
html_body = self.__escape_quotes_if_needed(html_body)
1401+
html_body = html_body.replace('\\ ', ' ')
1402+
html_string = re.escape(html_string)
1403+
html_string = self.__escape_quotes_if_needed(html_string)
1404+
html_string = html_string.replace('\\ ', ' ')
1405+
1406+
if new_page:
1407+
self.open("data:text/html,")
1408+
inner_head = '''document.getElementsByTagName("head")[0].innerHTML'''
1409+
inner_body = '''document.getElementsByTagName("body")[0].innerHTML'''
1410+
if not found_body:
1411+
self.execute_script(
1412+
'''%s = \"%s\"''' % (inner_body, html_string))
1413+
elif found_body and not found_head:
1414+
self.execute_script(
1415+
'''%s = \"%s\"''' % (inner_body, html_body))
1416+
elif found_body and found_head:
1417+
self.execute_script(
1418+
'''%s = \"%s\"''' % (inner_head, html_head))
1419+
self.execute_script(
1420+
'''%s = \"%s\"''' % (inner_body, html_body))
1421+
else:
1422+
raise Exception("Logic Error!")
1423+
1424+
for script in scripts:
1425+
js_code = script.string
1426+
js_code_lines = js_code.split('\n')
1427+
new_lines = []
1428+
for line in js_code_lines:
1429+
line = line.strip()
1430+
new_lines.append(line)
1431+
js_code = '\n'.join(new_lines)
1432+
js_utils.add_js_code(self.driver, js_code)
1433+
1434+
def load_html_file(self, html_file, new_page=True):
1435+
""" Loads a local html file into the browser from a relative file path.
1436+
If new_page==True, the page will switch to: "data:text/html,"
1437+
If new_page==False, will load HTML into the current page.
1438+
Local images and other local src content WILL BE IGNORED. """
1439+
if len(html_file) < 6 or not html_file.endswith(".html"):
1440+
raise Exception('Expecting a ".html" file!')
1441+
abs_path = os.path.abspath('.')
1442+
file_path = abs_path + "/%s" % html_file
1443+
f = open(file_path, 'r')
1444+
html_string = f.read().strip()
1445+
f.close()
1446+
self.load_html_string(html_string, new_page)
1447+
1448+
def open_html_file(self, html_file):
1449+
""" Opens a local html file into the browser from a relative file path.
1450+
The URL displayed in the web browser will start with "file://". """
1451+
if len(html_file) < 6 or not html_file.endswith(".html"):
1452+
raise Exception('Expecting a ".html" file!')
1453+
abs_path = os.path.abspath('.')
1454+
file_path = abs_path + "/%s" % html_file
1455+
self.open("file://" + file_path)
1456+
13751457
def execute_script(self, script):
13761458
return self.driver.execute_script(script)
13771459

@@ -1753,6 +1835,7 @@ def activate_jquery(self):
17531835
""" If "jQuery is not defined", use this method to activate it for use.
17541836
This happens because jQuery is not always defined on web sites. """
17551837
js_utils.activate_jquery(self.driver)
1838+
self.wait_for_ready_state_complete()
17561839

17571840
def __are_quotes_escaped(self, string):
17581841
return js_utils.are_quotes_escaped(string)
@@ -1776,7 +1859,7 @@ def bring_to_front(self, selector, by=By.CSS_SELECTOR):
17761859
return
17771860
selector = re.escape(selector)
17781861
selector = self.__escape_quotes_if_needed(selector)
1779-
script = ("""document.querySelector('%s').style.zIndex = '9999';"""
1862+
script = ("""document.querySelector('%s').style.zIndex = '999999';"""
17801863
% selector)
17811864
self.execute_script(script)
17821865

@@ -2340,32 +2423,34 @@ def assert_downloaded_file(self, file):
23402423
self.driver, messenger_post, self.message_duration)
23412424

23422425
def assert_true(self, expr, msg=None):
2426+
""" Asserts that the expression is True.
2427+
Will raise an exception if the statement if False. """
23432428
self.assertTrue(expr, msg=msg)
2344-
'''if self.demo_mode:
2345-
messenger_post = ("ASSERT TRUE (See code)")
2346-
js_utils.post_messenger_success_message(
2347-
self.driver, messenger_post, self.message_duration)'''
23482429

23492430
def assert_false(self, expr, msg=None):
2431+
""" Asserts that the expression is False.
2432+
Will raise an exception if the statement if True. """
23502433
self.assertFalse(expr, msg=msg)
2351-
'''if self.demo_mode:
2352-
messenger_post = ("ASSERT FALSE (See code)")
2353-
js_utils.post_messenger_success_message(
2354-
self.driver, messenger_post, self.message_duration)'''
23552434

23562435
def assert_equal(self, first, second, msg=None):
2436+
""" Asserts that the two values are equal.
2437+
Will raise an exception if the values are not equal. """
23572438
self.assertEqual(first, second, msg=msg)
2358-
'''if self.demo_mode:
2359-
messenger_post = ("ASSERT EQUAL: {%s == %s}" % (first, second))
2360-
js_utils.post_messenger_success_message(
2361-
self.driver, messenger_post, self.message_duration)'''
23622439

23632440
def assert_not_equal(self, first, second, msg=None):
2441+
""" Asserts that the two values are not equal.
2442+
Will raise an exception if the values are equal. """
23642443
self.assertNotEqual(first, second, msg=msg)
2365-
'''if self.demo_mode:
2366-
messenger_post = ("ASSERT NOT EQUAL: {%s != %s}" % (first, second))
2367-
js_utils.post_messenger_success_message(
2368-
self.driver, messenger_post, self.message_duration)'''
2444+
2445+
def assert_raises(self, *args, **kwargs):
2446+
""" Asserts that the following block of code raises an exception.
2447+
Will raise an exception if the block of code has no exception.
2448+
Usage Example =>
2449+
# Verify that the expected exception is raised.
2450+
with self.assert_raises(Exception):
2451+
raise Exception("Expected Exception!")
2452+
"""
2453+
self.assertRaises(*args, **kwargs)
23692454

23702455
def assert_title(self, title):
23712456
""" Asserts that the web page title matches the expected title. """
@@ -2610,6 +2695,9 @@ def add_css_style(self, css_style):
26102695
def add_js_code_from_link(self, js_link):
26112696
js_utils.add_js_code_from_link(self.driver, js_link)
26122697

2698+
def add_js_code(self, js_code):
2699+
js_utils.add_js_code(self.driver, js_code)
2700+
26132701
def add_meta_tag(self, http_equiv=None, content=None):
26142702
js_utils.add_meta_tag(
26152703
self.driver, http_equiv=http_equiv, content=content)

0 commit comments

Comments
 (0)