commit bb2eefe4703708103f9bf7204bf06816c68b1f6d Author: Mat Hare Date: Sat Jul 10 17:58:17 2021 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dc4af9d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +.pytest_cache/ \ No newline at end of file diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..47b8048 --- /dev/null +++ b/Pipfile @@ -0,0 +1,16 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +selenium = "*" +pytest = "*" +pytest-bdd = "*" +webdriver-manager = "*" +sttable = "*" + +[dev-packages] + +[requires] +python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..d59e3fd --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,262 @@ +{ + "_meta": { + "hash": { + "sha256": "ffac70183633b651a15be3d779fb1d1017f5de3e4647b2f78ebe0f213954fe05" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.8" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "atomicwrites": { + "hashes": [ + "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197", + "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a" + ], + "markers": "sys_platform == 'win32'", + "version": "==1.4.0" + }, + "attrs": { + "hashes": [ + "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", + "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==21.2.0" + }, + "certifi": { + "hashes": [ + "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee", + "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8" + ], + "version": "==2021.5.30" + }, + "chardet": { + "hashes": [ + "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", + "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==4.0.0" + }, + "colorama": { + "hashes": [ + "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b", + "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.4.4" + }, + "configparser": { + "hashes": [ + "sha256:85d5de102cfe6d14a5172676f09d19c465ce63d6019cf0a4ef13385fc535e828", + "sha256:af59f2cdd7efbdd5d111c1976ecd0b82db9066653362f0962d7bf1d3ab89a1fa" + ], + "markers": "python_version >= '3.6'", + "version": "==5.0.2" + }, + "crayons": { + "hashes": [ + "sha256:bd33b7547800f2cfbd26b38431f9e64b487a7de74a947b0fafc89b45a601813f", + "sha256:e73ad105c78935d71fe454dd4b85c5c437ba199294e7ffd3341842bc683654b1" + ], + "version": "==0.4.0" + }, + "glob2": { + "hashes": [ + "sha256:85c3dbd07c8aa26d63d7aacee34fa86e9a91a3873bc30bf62ec46e531f92ab8c" + ], + "version": "==0.7" + }, + "idna": { + "hashes": [ + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.10" + }, + "iniconfig": { + "hashes": [ + "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", + "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" + ], + "version": "==1.1.1" + }, + "mako": { + "hashes": [ + "sha256:17831f0b7087c313c0ffae2bcbbd3c1d5ba9eeac9c38f2eb7b50e8c99fe9d5ab", + "sha256:aea166356da44b9b830c8023cd9b557fa856bd8b4035d6de771ca027dfc5cc6e" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.1.4" + }, + "markupsafe": { + "hashes": [ + "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298", + "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64", + "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b", + "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567", + "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff", + "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74", + "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35", + "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26", + "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7", + "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75", + "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f", + "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135", + "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8", + "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", + "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914", + "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18", + "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8", + "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2", + "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d", + "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b", + "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f", + "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb", + "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833", + "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415", + "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902", + "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9", + "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d", + "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066", + "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f", + "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5", + "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94", + "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509", + "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", + "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" + ], + "markers": "python_version >= '3.6'", + "version": "==2.0.1" + }, + "packaging": { + "hashes": [ + "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7", + "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14" + ], + "markers": "python_version >= '3.6'", + "version": "==21.0" + }, + "parse": { + "hashes": [ + "sha256:9ff82852bcb65d139813e2a5197627a94966245c897796760a3a2a8eb66f020b" + ], + "version": "==1.19.0" + }, + "parse-type": { + "hashes": [ + "sha256:089a471b06327103865dfec2dd844230c3c658a4a1b5b4c8b6c16c8f77577f9e", + "sha256:7f690b18d35048c15438d6d0571f9045cffbec5907e0b1ccf006f889e3a38c0b" + ], + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.5.2" + }, + "pluggy": { + "hashes": [ + "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", + "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.13.1" + }, + "py": { + "hashes": [ + "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", + "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.10.0" + }, + "pyparsing": { + "hashes": [ + "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", + "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" + ], + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.4.7" + }, + "pytest": { + "hashes": [ + "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b", + "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890" + ], + "index": "pypi", + "version": "==6.2.4" + }, + "pytest-bdd": { + "hashes": [ + "sha256:304cd2b09923b838d0c2f08331d1f4236a14ef3594efa94e3bdae0f384d3fa5d", + "sha256:7c5221680cec9a97630e1fae6132f4a97c2f86a90914206ee06a55ae1a409fe5" + ], + "index": "pypi", + "version": "==4.1.0" + }, + "requests": { + "hashes": [ + "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", + "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==2.25.1" + }, + "selenium": { + "hashes": [ + "sha256:2d7131d7bc5a5b99a2d9b04aaf2612c411b03b8ca1b1ee8d3de5845a9be2cb3c", + "sha256:deaf32b60ad91a4611b98d8002757f29e6f2c2d5fcaf202e1c9ad06d6772300d" + ], + "index": "pypi", + "version": "==3.141.0" + }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, + "sttable": { + "hashes": [ + "sha256:305d75b48e409993a766f3c1322bb7244c9c3729a377b98d21aba8047a0f669c", + "sha256:46653f283fc0482f338db54d2d8f5d2c4d558eafd565a155acb5e3fbcf3e7b33" + ], + "index": "pypi", + "version": "==0.0.1" + }, + "toml": { + "hashes": [ + "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", + "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" + ], + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.10.2" + }, + "urllib3": { + "hashes": [ + "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4", + "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.26.6" + }, + "webdriver-manager": { + "hashes": [ + "sha256:50a6e174106542f5335cacc387cec7ada26812babc1aeca61c208a1bab2ac2c5", + "sha256:c6d81590aae6fc0fb10cf7dd20c8c1b9bb043501f9cf62c316a854a0de841e32" + ], + "index": "pypi", + "version": "==3.4.2" + } + }, + "develop": {} +} diff --git a/config.json b/config.json new file mode 100644 index 0000000..10176c6 --- /dev/null +++ b/config.json @@ -0,0 +1,5 @@ +{ + "browser": "Chrome", + "headless": true, + "implicit_wait": 10 +} \ No newline at end of file diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..a1532b2 --- /dev/null +++ b/conftest.py @@ -0,0 +1,117 @@ +import pytest +import selenium.webdriver +import json +from selenium import webdriver +from webdriver_manager.chrome import ChromeDriverManager +from webdriver_manager.firefox import GeckoDriverManager +from pytest_bdd import given, then, parsers +from pages.base import BasePage + + +@pytest.fixture +def config(scope='session'): + + BROWSERS = ['Chrome', 'Firefox'] + + # Read config file + with open('config.json') as config_file: + config = json.load(config_file) + + # Assert values are acceptable + assert config['browser'] in BROWSERS + assert isinstance(config['headless'], bool) + assert isinstance(config['implicit_wait'], int) + assert config['implicit_wait'] > 0 + + # Return config so it can be used + return config + + +@pytest.fixture +def browser(config): + + # Initialize the WebDriver instance + if config['browser'] == 'Chrome': + opts = webdriver.ChromeOptions() + if config['headless']: + opts.add_argument('headless') + b = webdriver.Chrome(ChromeDriverManager().install(), options=opts) + elif config['browser'] == 'Firefox': + opts = webdriver.FirefoxOptions() + if config['headless']: + opts.headless = True + b = webdriver.Firefox( + executable_path=GeckoDriverManager().install(), options=opts) + else: + raise Exception(f'Browser "{config["browser"]}" is not supported') + + # Make call wait up to 10 seconds for elements to appear + b.implicitly_wait(config['implicit_wait']) + + # Return the WebDriver instance for the setup + yield b + + # Quit the WebDriver instance for the teardown + b.quit() + + +@pytest.fixture() +def datatable(): + return DataTable() + + +class DataTable(object): + + def __init__(self): + pass + + def __str__(self): + dt_str = '' + for field, value in self.__dict__.items(): + dt_str = f'{dt_str}\n{field} = {value}' + return dt_str + + def __repr__(self) -> str: + return self.__str__() + + +@given(parsers.parse('I have navigated to the \'the-internet\' "{page_name}" page'), target_fixture='navigate_to') +def navigate_to(browser, page_name): + + BASE_URL = "https://the-internet.herokuapp.com" + + PAGE_URLS = { + "home": BASE_URL + "/", + "checkboxes": BASE_URL + "/checkboxes", + "dropdown": BASE_URL + "/dropdown", + "dynamic controls": BASE_URL + "/dynamic_controls", + "form authentication": BASE_URL + "/login", + "inputs": BASE_URL + "/inputs", + "secure area": BASE_URL + "/secure" + } + browser.get(PAGE_URLS.get(page_name.lower())) + + +@then(parsers.parse('a "{text}" banner is displayed in the top-right corner of the page')) +def verify_banner_text(browser, text): + url = 'https://github.com/tourdedave/the-internet' + assert text == BasePage(browser).get_github_fork_banner_text() + assert url == BasePage(browser).get_github_fork_banner_link() + styleAttrs = BasePage(browser).get_github_fork_banner_position().split(";") + for attr in styleAttrs: + if attr.startswith("position"): + assert "absolute" == attr.split(": ")[1] + if attr.startswith("top"): + assert "0px" == attr.split(": ")[1] + if attr.startswith("right"): + assert "0px" == attr.split(": ")[1] + if attr.startswith("border"): + assert "0px" == attr.split(": ")[1] + +@then(parsers.parse('the page has a footer containing "{text}"')) +def verify_footer_text(browser, text): + pass + +@then(parsers.parse('the link in the page footer goes to "{url}"')) +def verify_footer_link_url(browser, url): + pass diff --git a/features/home_page.feature b/features/home_page.feature new file mode 100644 index 0000000..48c2c60 --- /dev/null +++ b/features/home_page.feature @@ -0,0 +1,69 @@ +Feature: Home Page + Tests for the 'https://the-internet.herokuapp.com/' home page + + Background: Open home page + Given I have navigated to the 'the-internet' "home" page + @focus + Scenario: Verify home page contents are correct + Then the page title is "Welcome to the-internet" + And the sub-header text is "Available Examples" + And a list of the following sub-pages is displayed + | name | + | A/B Testing | + | Add/Remove Elements | + | Basic Auth | + | Broken Images | + | Challenging DOM | + | Checkboxes | + | Context Menu | + | Digest Authentication | + | Disappearing Elements | + | Drag and Drop | + | Dropdown | + | Dynamic Content | + | Dynamic Controls | + | Dynamic Loading | + | Entry Ad | + | Exit Intent | + | File Download | + | File Upload | + | Floating Menu | + | Forgot Password | + | Form Authentication | + | Frames | + | Geolocation | + | Horizontal Slider | + | Hovers | + | Infinite Scroll | + | Inputs | + | JQuery UI Menus | + | JavaScript Alerts | + | JavaScript onload event error | + | Key Presses | + | Large & Deep DOM | + | Multiple Windows | + | Nested Frames | + | Notification Messages | + | Redirect Link | + | Secure File Download | + | Shadow DOM | + | Shifting Content | + | Slow Resources | + | Sortable Data Tables | + | Status Codes | + | Typos | + | WYSIWYG Editor | + And a "Fork me on GitHub" banner is displayed in the top-right corner of the page + And the page has a footer containing "Powered by Elemental Selenium" + And the link in the page footer goes to "http://elementalselenium.com/" + +# Scenario Outline: Open page +# When I click on the "" link +# Then the "" page opens +# Examples: +# | page | +# | Checkboxes | +# | Dropdown | +# | Dynamic Controls | +# | Form Authentication | +# | Inputs | \ No newline at end of file diff --git a/pages/base.py b/pages/base.py new file mode 100644 index 0000000..f0859bf --- /dev/null +++ b/pages/base.py @@ -0,0 +1,49 @@ +from abc import ABC, abstractmethod +from selenium.webdriver.common.by import By + +class BasePage(): + + # public static WebDriver driver; + + # BASE_URL = "https://the-internet.herokuapp.com"; + + # PAGE_URLS = { + # "home": BASE_URL + "/", + # "checkboxes": BASE_URL + "/checkboxes", + # "dropdown": BASE_URL + "/dropdown", + # "dynamic controls": BASE_URL + "/dynamic_controls", + # "form authentication": BASE_URL + "/login", + # "inputs": BASE_URL + "/inputs", + # "secure area": BASE_URL + "/secure" + # } + + @property + @abstractmethod + def PAGE_TITLE(self): + pass + + @abstractmethod + def get_page_title_text(self): + pass + + FORK_LINK = (By.XPATH, "/html/body/div[2]/a") + FORK_LINK_IMG = (By.XPATH, "/html/body/div[2]/a/img") + FOOTER = (By.ID, "page-footer") + + def __init__(self, browser): + self.browser = browser + + def get_github_fork_banner_text(self): + return self.browser.find_element(*self.FORK_LINK_IMG).get_attribute("alt") + + def get_github_fork_banner_link(self): + return self.browser.find_element(*self.FORK_LINK).get_attribute("href") + + def get_github_fork_banner_position(self): + return self.browser.find_element(*self.FORK_LINK_IMG).get_attribute("style") + + def get_page_footer_text(self): + return self.browser.find_element(*self.FOOTER).text + + def get_page_footer_link_url(self): + return self.browser.find_element(*self.FOOTER).get_attribute("href") \ No newline at end of file diff --git a/pages/home.py b/pages/home.py new file mode 100644 index 0000000..994edc8 --- /dev/null +++ b/pages/home.py @@ -0,0 +1,42 @@ +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from pages.base import BasePage + + +class HomePage(BasePage): + + @property + def PAGE_TITLE(self): + return (By.TAG_NAME, 'h1') + SUBHEADER = (By.TAG_NAME, 'h2') + SUBPAGE_LINKS = (By.XPATH, '//*[@id="content"]/ul/li') + + def __init__(self, browser): + self.browser = browser + + def get_page_title_text(self): + return self.browser.find_element(*self.PAGE_TITLE).text + + def get_subheader_text(self): + return self.browser.find_element(*self.SUBHEADER).text + + def get_subpage_list(self): + links = self.browser.find_elements(*self.SUBPAGE_LINKS) + titles = [link.text.split(" (")[0] for link in links] + return titles + + + + # URL = "https://www.duckduckgo.com" + + # SEARCH_INPUT = (By.ID, 'search_form_input_homepage') + + # def __init__(self, browser): + # self.browser = browser + + # def load(self): + # self.browser.get(self.URL) + + # def search(self, phrase): + # search_input = self.browser.find_element(*self.SEARCH_INPUT) + # search_input.send_keys(phrase + Keys.RETURN) diff --git a/step_defs/test_home_page_steps.py b/step_defs/test_home_page_steps.py new file mode 100644 index 0000000..600594f --- /dev/null +++ b/step_defs/test_home_page_steps.py @@ -0,0 +1,22 @@ +from pytest_bdd import scenarios, given, when, then, parsers +from pages.home import HomePage as page +from sttable import parse_str_table + +scenarios('../features/home_page.feature') + + +@then(parsers.parse('the page title is "{title}"')) +def verify_page_title(browser, title): + assert title == page(browser).get_page_title_text() + + +@then(parsers.parse('the sub-header text is "{text}"')) +def verify_subheader_text(browser, text): + assert text == page(browser).get_subheader_text() + + +@then(parsers.parse('a list of the following sub-pages is displayed\n{subpages}')) +def verify_subpage_list(browser, datatable, subpages): + expected = parse_str_table(subpages) + for field in expected.fields: + assert expected.columns[field] == page(browser).get_subpage_list()