Permalink
Browse files

Migrate to pytest-selenium

  • Loading branch information...
1 parent c2393b9 commit 39d9839cbe8cfce04d011e38ca5e74e7e6b641c7 @davehunt davehunt committed Nov 7, 2015
Showing with 110 additions and 118 deletions.
  1. +5 −4 README.md
  2. +19 −0 expected.py
  3. +0 −3 mozwebqa.cfg
  4. +0 −50 page.py
  5. +0 −20 pages/base.py
  6. +34 −0 pages/page.py
  7. +24 −22 pages/resultset.py
  8. +2 −3 requirements.txt
  9. +4 −0 setup.cfg
  10. +17 −0 tests/conftest.py
  11. +5 −16 tests/test_unclassified_job.py
View
@@ -65,22 +65,23 @@ To run all of the desktop tests against the default environment:
$ py.test --driver firefox
```
-To run against a different environment, pass in a value for --baseurl, like so:
+To run against a different environment, pass in a value for `--base-url`, like
+so:
```bash
-$ py.test --baseurl https://treeherder.mozilla.org --driver firefox
+$ py.test --base-url https://treeherder.mozilla.org --driver Firefox
```
The pytest plugin that we use for running tests has a number of advanced
command line options available. To see the options available, run
`py.test --help`. The full documentation for the plugin can be found
-[here][pytest-mozwebqa].
+[here][pytest-selenium].
[contributors]: https://github.com/mozilla/treeherder-tests/contributors
[git-clone]: https://help.github.com/articles/cloning-a-repository/
[git-fork]: https://help.github.com/articles/fork-a-repo/
[irc]: http://widget01.mibbit.com/?settings=1b10107157e79b08f2bf99a11f521973&server=irc.mozilla.org&channel=%23mozwebqa
[list]: https://mail.mozilla.org/listinfo/mozwebqa
-[pytest-mozwebqa]: https://github.com/mozilla/pytest-mozwebqa
+[pytest-selenium]: http://pytest-selenium.readthedocs.org/
[running-tests]: https://developer.mozilla.org/en-US/docs/Mozilla/QA/Running_Web_QA_automated_tests
[virtualenv]: https://wiki.mozilla.org/QA/Execution/Web_Testing/Automation/Virtual_Environments
View
@@ -0,0 +1,19 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+class window_with_title(object):
+ """An expectation for checking that a window exists with the specified title.
+
+ :returns: window handle if window exists, False otherwise
+ """
+
+ def __init__(self, title):
+ self.title = title
+
+ def __call__(self, selenium):
+ for w in selenium.window_handles:
+ selenium.switch_to.window(w)
+ if self.title in selenium.title:
+ return w
View
@@ -1,3 +0,0 @@
-[DEFAULT]
-api = webdriver
-baseurl = https://treeherder.allizom.org
View
@@ -1,50 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from unittestzero import Assert
-
-from selenium.webdriver.support.ui import WebDriverWait
-from selenium.common.exceptions import NoSuchElementException
-from selenium.common.exceptions import ElementNotVisibleException
-
-
-class Page(object):
- """
- Base class for all Pages
- """
-
- def __init__(self, testsetup):
- self.testsetup = testsetup
- self.base_url = testsetup.base_url
- self.selenium = testsetup.selenium
- self.timeout = testsetup.timeout
-
- @property
- def is_the_current_page(self):
- WebDriverWait(self.selenium, 10).until(lambda s: self.selenium.title)
- Assert.equal(self.selenium.title, self._page_title,
- 'Expected page title: %s. Actual page title: %s' % (self._page_title, self.selenium.title))
- return True
-
- @property
- def current_page_url(self):
- WebDriverWait(self.selenium, self.timeout).until(lambda s: self.selenium.title)
- return(self.selenium.current_url)
-
- @property
- def page_title(self):
- WebDriverWait(self.selenium, self.timeout).until(lambda s: s.title)
- return self.selenium.title
-
- def is_element_visible(self, *locator):
- try:
- self.selenium.find_element(*locator).is_displayed()
- return True
- except (ElementNotVisibleException, NoSuchElementException):
- # this will return a snapshot, which takes time.
- return False
-
- def open(self, url_fragment):
- self.selenium.get(self.base_url + url_fragment)
- self.selenium.maximize_window()
View
@@ -1,20 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-from selenium.webdriver.support.ui import WebDriverWait
-
-from page import Page
-
-
-class Base(Page):
-
- @property
- def page_title(self):
- WebDriverWait(self.selenium, self.timeout).until(lambda s: self.selenium.title)
- return self.selenium.title
-
- def _go_to_page(self, path_to_page):
- self.selenium.maximize_window()
- self.selenium.get(self.base_url + path_to_page)
- self.is_the_current_page
View
@@ -0,0 +1,34 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from selenium.common.exceptions import NoSuchElementException
+
+
+class Page(object):
+
+ _url = None
+
+ def __init__(self, base_url, selenium):
+ self.base_url = base_url
+ self.selenium = selenium
+ self.timeout = 10
+
+ def open(self):
+ self.selenium.get(self.url)
+ return self.wait_for_page_to_load()
+
+ @property
+ def url(self):
+ if self._url is not None:
+ return self._url.format(base_url=self.base_url)
+ return self.base_url
+
+ def wait_for_page_to_load(self):
+ return self
+
+ def is_element_visible(self, locator):
+ try:
+ return self.selenium.find_element(*locator).is_displayed()
+ except (NoSuchElementException):
+ return False
View
@@ -3,12 +3,14 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from selenium.webdriver.common.by import By
-from selenium.webdriver.support.ui import WebDriverWait
+from selenium.webdriver.support import expected_conditions as EC
+from selenium.webdriver.support.ui import WebDriverWait as Wait
-from pages.base import Base
+import expected
+from pages.page import Page
-class ResultsetPage(Base):
+class ResultsetPage(Page):
_job_details_actionbar_locator = (By.ID, 'job-details-actionbar')
_job_result_status_locator = (By.CSS_SELECTOR, '#result-status-pane > div:nth-child(1) > span')
@@ -17,6 +19,11 @@ class ResultsetPage(Base):
_result_status_locator = (By.ID, 'job-details-panel')
_unclassified_failure_count_locator = (By.ID, 'unclassified-failure-count')
+ def wait_for_page_to_load(self):
+ Wait(self.selenium, self.timeout).until(
+ lambda s: self.unclassified_failure_count > 0)
+ return self
+
@property
def job_result_status(self):
return self.selenium.find_element(*self._job_result_status_locator).text
@@ -25,33 +32,28 @@ def job_result_status(self):
def unclassified_failure_count(self):
return int(self.selenium.find_element(*self._unclassified_failure_count_locator).text)
- def go_to_page(self):
- self.open('')
-
def open_next_unclassified_failure(self):
- WebDriverWait(self.selenium, self.timeout).until(lambda s: self.selenium.find_element(*self._resultset_locator).is_displayed())
- self.selenium.find_element(*self._resultset_locator).send_keys("n")
+ el = self.selenium.find_element(*self._resultset_locator)
+ Wait(self.selenium, self.timeout).until(EC.visibility_of(el))
+ el.send_keys('n')
+ Wait(self.selenium, self.timeout).until(lambda s: self.job_result_status)
def open_logviewer(self):
- WebDriverWait(self.selenium, self.timeout).until(lambda s: self.selenium.find_element(*self._job_details_actionbar_locator).is_displayed())
- self.selenium.find_element(*self._resultset_locator).send_keys("l")
+ Wait(self.selenium, self.timeout).until(
+ EC.visibility_of_element_located(self._job_details_actionbar_locator))
+ self.selenium.find_element(*self._resultset_locator).send_keys('l')
+ return LogviewerPage(self.base_url, self.selenium)
-class LogviewerPage(Base):
+class LogviewerPage(Page):
- _page_title = 'Log for'
_job_header_locator = (By.CSS_SELECTOR, 'div.job-header')
- def __init__(self, testsetup):
- Base.__init__(self, testsetup)
-
- if self.selenium.title != self._page_title:
- for handle in self.selenium.window_handles:
- self.selenium.switch_to_window(handle)
- WebDriverWait(self.selenium, self.timeout).until(lambda s: s.title)
- else:
- raise Exception('Page has not loaded')
+ def __init__(self, base_url, selenium):
+ Page.__init__(self, base_url, selenium)
+ Wait(self.selenium, self.timeout).until(
+ expected.window_with_title('Log for'))
@property
def is_job_status_visible(self):
- return self.is_element_visible(*self._job_header_locator)
+ return self.is_element_visible(self._job_header_locator)
View
@@ -1,4 +1,3 @@
-pytest==2.7.2
-pytest-mozwebqa
-selenium
+pytest==2.7.2
+pytest-selenium
UnittestZero
View
@@ -1,2 +1,6 @@
[flake8]
ignore=E501
+
+[pytest]
+base_url=https://treeherder.allizom.org
+sensitive_url=mozilla\.org
View
@@ -0,0 +1,17 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import pytest
+
+
+@pytest.fixture(scope='session')
+def capabilities(capabilities):
+ capabilities.setdefault('tags', []).append('treeherder')
+ return capabilities
+
+
+@pytest.fixture
+def selenium(selenium):
+ selenium.maximize_window()
+ return selenium
@@ -7,35 +7,24 @@
from unittestzero import Assert
from pages.resultset import ResultsetPage
-from pages.resultset import LogviewerPage
class TestUnclassifiedJobs:
@pytest.mark.nondestructive
- def test_unclassified_failure(self, mozwebqa):
+ def test_unclassified_failure(self, base_url, selenium):
# Open resultset page and search for next unclassified failure
- resultset_page = ResultsetPage(mozwebqa)
- resultset_page.go_to_page()
+ resultset_page = ResultsetPage(base_url, selenium).open()
Assert.greater_equal(resultset_page.unclassified_failure_count, 1)
-
resultset_page.open_next_unclassified_failure()
-
teststatus = resultset_page.job_result_status
- jobstatus = ["busted", "testfailed", "exception"]
-
- for i in range(len(jobstatus)):
- assert jobstatus in teststatus
+ assert teststatus in ['busted', 'testfailed', 'exception']
@pytest.mark.nondestructive
- def test_open_unclassified_failure_log(self, mozwebqa):
+ def test_open_unclassified_failure_log(self, base_url, selenium):
# Open the job log and verify there is content
- resultset_page = ResultsetPage(mozwebqa)
- resultset_page.go_to_page()
+ resultset_page = ResultsetPage(base_url, selenium).open()
Assert.greater_equal(resultset_page.unclassified_failure_count, 1)
-
resultset_page.open_next_unclassified_failure()
logviewer_page = resultset_page.open_logviewer()
- logviewer_page = LogviewerPage(mozwebqa)
-
Assert.true(logviewer_page.is_job_status_visible)

0 comments on commit 39d9839

Please sign in to comment.