Skip to content
This repository has been archived by the owner on Aug 20, 2018. It is now read-only.

Commit

Permalink
Migrate to pytest-selenium
Browse files Browse the repository at this point in the history
  • Loading branch information
davehunt committed Jan 22, 2016
1 parent 2df475d commit 88beda9
Show file tree
Hide file tree
Showing 27 changed files with 154 additions and 138 deletions.
18 changes: 10 additions & 8 deletions README.md
Expand Up @@ -106,30 +106,30 @@ Before each test run, clean up the repo:

To run tests locally it's a simple case of calling the command below from this directory:

py.test --driver=firefox --destructive --variables=/full/path/to/variables.json .
py.test --driver Firefox --variables /full/path/to/variables.json .

__Output__
Output of a test run should look like this:

============================= test session starts ==============================
platform darwin -- Python 2.6.1 -- pytest-2.2.3
collected 35 items
collected 35 items

tests/desktop/test_kb_article.py .X....
tests/desktop/test_new_user_registration.py .
tests/desktop/test_questions.py ....
tests/desktop/test_rewrites.py .....................
tests/desktop/test_search.py ..X

==================== 33 passed, 2 xpassed in 172.03 seconds ====================

__Note__
"~" will not resolve to the home directory when used in the py.test command line.

Some options for py.test are pre-specified by the file sumo_tests/mozwebqa.cfg

The mozwebqa plugin has advanced command line options for reporting and using browsers. See the documentation on [pytest mozwebqa github][pymozwebqa]:
[pymozwebqa]: https://github.com/mozilla/pytest-mozwebqa
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-selenium].

__Troubleshooting__

Expand Down Expand Up @@ -159,3 +159,5 @@ This software is licensed under the [MPL] 2.0:
file, You can obtain one at http://mozilla.org/MPL/2.0/.

[MPL]: http://www.mozilla.org/MPL/2.0/

[pytest-selenium]: http://pytest-selenium.readthedocs.org/
4 changes: 0 additions & 4 deletions mozwebqa.cfg

This file was deleted.

12 changes: 6 additions & 6 deletions pages/desktop/base.py
Expand Up @@ -9,8 +9,8 @@

class Base(Page):

def __init__(self, testsetup):
super(Base, self).__init__(testsetup)
def __init__(self, base_url, selenium):
super(Base, self).__init__(base_url, selenium)
self.header.dismiss_staging_site_warning_if_present()

def click_card_grid(self, locator):
Expand All @@ -21,11 +21,11 @@ def click_card_grid(self, locator):

@property
def footer(self):
return self.FooterRegion(self.testsetup)
return self.FooterRegion(self.base_url, self.selenium)

@property
def header(self):
return self.HeaderRegion(self.testsetup)
return self.HeaderRegion(self.base_url, self.selenium)

def sign_in(self, username, password):
login = self.header.click_login()
Expand All @@ -34,7 +34,7 @@ def sign_in(self, username, password):
def sign_out(self):
self.header.click_logout()
from pages.desktop.register_page import RegisterPage
return RegisterPage(self.testsetup)
return RegisterPage(self.base_url, self.selenium)

def switch_to_mobile_view(self):
self.footer.click_switch_to_mobile_view()
Expand Down Expand Up @@ -81,7 +81,7 @@ class HeaderRegion(Page):
def click_login(self):
self.selenium.find_element(*self._login_locator).click()
from pages.desktop.login_page import LoginPage
return LoginPage(self.testsetup)
return LoginPage(self.base_url, self.selenium)

def click_logout(self):
self.dismiss_staging_site_warning_if_present()
Expand Down
14 changes: 7 additions & 7 deletions pages/desktop/knowledge_base_article.py
Expand Up @@ -12,7 +12,7 @@ class KnowledgeBase(Base):

@property
def navigation(self):
return self.Navigation(self.testsetup)
return self.Navigation(self.base_url, self.selenium)

@property
def is_the_current_page(self):
Expand All @@ -36,21 +36,21 @@ def show_editing_tools(self):
def click_article(self):
self.show_editing_tools()
self.selenium.find_element(*self._article_locator).click()
return KnowledgeBaseArticle(self.testsetup)
return KnowledgeBaseArticle(self.base_url, self.selenium)

def click_edit_article(self):
self.selenium.find_element(*self._edit_article_locator).click()
return KnowledgeBaseEditArticle(self.testsetup)
return KnowledgeBaseEditArticle(self.base_url, self.selenium)

def click_translate_article(self):
self.show_editing_tools()
self.selenium.find_element(*self._translate_article_locator).click()
return KnowledgeBaseTranslate(self.testsetup)
return KnowledgeBaseTranslate(self.base_url, self.selenium)

def click_show_history(self):
self.show_editing_tools()
self.selenium.find_element(*self._show_history_locator).click()
return KnowledgeBaseShowHistory(self.testsetup)
return KnowledgeBaseShowHistory(self.base_url, self.selenium)


class KnowledgeBaseArticle(KnowledgeBase):
Expand Down Expand Up @@ -141,7 +141,7 @@ def check_article_product(self, index):
def set_article_comment_box(self, comment='default comment'):
self.selenium.find_element(*self._comment_box_locator).send_keys(comment)
self.selenium.find_element(*self._comment_submit_btn_locator).click()
kb_article_history = KnowledgeBaseShowHistory(self.testsetup)
kb_article_history = KnowledgeBaseShowHistory(self.base_url, self.selenium)
kb_article_history.is_the_current_page
return kb_article_history

Expand Down Expand Up @@ -187,7 +187,7 @@ def type_modal_describe_changes(self, text):

def click_modal_submit_changes_button(self):
self.selenium.find_element(*self._submit_changes_button_locator).click()
return KnowledgeBaseShowHistory(self.testsetup)
return KnowledgeBaseShowHistory(self.base_url, self.selenium)


class KnowledgeBaseShowHistory(KnowledgeBase):
Expand Down
2 changes: 1 addition & 1 deletion pages/desktop/knowledge_base_new_article.py
Expand Up @@ -95,7 +95,7 @@ def set_article_content(self, content):
def set_article_comment_box(self, comment='automated test'):
self.selenium.find_element(*self._comment_box_locator).send_keys(comment)
self.selenium.find_element(*self._comment_submit_btn_locator).click()
kb_article_history = KnowledgeBaseShowHistory(self.testsetup)
kb_article_history = KnowledgeBaseShowHistory(self.base_url, self.selenium)
kb_article_history.is_the_current_page
return kb_article_history

Expand Down
23 changes: 11 additions & 12 deletions pages/desktop/page_provider.py
Expand Up @@ -6,10 +6,9 @@
class PageProvider():
''' internal methods '''

def __init__(self, testsetup):
self.testsetup = testsetup
self.base_url = testsetup.base_url
self.selenium = testsetup.selenium
def __init__(self, base_url, selenium):
self.base_url = base_url
self.selenium = selenium

def _set_window_size(self):
# SUMO requires a minimum window width
Expand All @@ -30,7 +29,7 @@ def _go_to_page_with_login_redirect(self, page_object, username, password):
self._set_window_size()
from pages.desktop.login_page import LoginPage
self.selenium.get(self.base_url + page_object._page_url)
login_page = LoginPage(self.testsetup)
login_page = LoginPage(self.base_url, self.selenium)
login_page.log_in(username, password)
page_object.is_the_current_page
page_object.header.dismiss_staging_site_warning_if_present()
Expand All @@ -40,32 +39,32 @@ def _go_to_page_with_login_redirect(self, page_object, username, password):

def new_user_registration_page(self):
from pages.desktop.register_page import RegisterPage
return self._go_to_page(RegisterPage(self.testsetup))
return self._go_to_page(RegisterPage(self.base_url, self.selenium))

''' pages for which login is optional '''

def home_page(self, username=None, password=None):
from pages.desktop.support_home_page import SupportHomePage
return self._go_to_page(SupportHomePage(self.testsetup), username, password)
return self._go_to_page(SupportHomePage(self.base_url, self.selenium), username, password)

def new_question_page(self, username=None, password=None):
from pages.desktop.questions_page import AskNewQuestionsPage
return self._go_to_page(AskNewQuestionsPage(self.testsetup), username, password)
return self._go_to_page(AskNewQuestionsPage(self.base_url, self.selenium), username, password)

def questions_page(self, username=None, password=None):
from pages.desktop.questions_page import QuestionsPage
return self._go_to_page(QuestionsPage(self.testsetup), username, password)
return self._go_to_page(QuestionsPage(self.base_url, self.selenium), username, password)

def refine_search_page(self, username=None, password=None):
from pages.desktop.refine_search_page import RefineSearchPage
return self._go_to_page(RefineSearchPage(self.testsetup), username, password)
return self._go_to_page(RefineSearchPage(self.base_url, self.selenium), username, password)

def search_page(self, username=None, password=None):
from pages.desktop.search_page import SearchPage
return self._go_to_page(SearchPage(self.testsetup), username, password)
return self._go_to_page(SearchPage(self.base_url, self.selenium), username, password)

''' pages for which login is required '''

def new_kb_article_page(self, username, password):
from pages.desktop.knowledge_base_new_article import KnowledgeBaseNewArticle
return self._go_to_page_with_login_redirect(KnowledgeBaseNewArticle(self.testsetup), username, password)
return self._go_to_page_with_login_redirect(KnowledgeBaseNewArticle(self.base_url, self.selenium), username, password)
12 changes: 6 additions & 6 deletions pages/desktop/questions_page.py
Expand Up @@ -27,7 +27,7 @@ class QuestionsPage(Base):

def click_ask_new_questions_link(self):
self.selenium.find_element(*self._ask_question_link_locator).click()
return AskNewQuestionsPage(self.testsetup)
return AskNewQuestionsPage(self.base_url, self.selenium)

def go_to_thread(self, url):
self.open(url)
Expand Down Expand Up @@ -68,7 +68,7 @@ def questions_count(self):

@property
def questions(self):
return [self.Question(self.testsetup, web_element) for web_element in self.selenium.find_elements(*self._questions_list_locator)]
return [self.Question(self.base_url, self.selenium, web_element) for web_element in self.selenium.find_elements(*self._questions_list_locator)]

class Question(Page):

Expand All @@ -77,8 +77,8 @@ class Question(Page):
_question_link_locator = (By.CSS_SELECTOR, 'a')
_product_name_locator = (By.CSS_SELECTOR, '.content ul.tag-list li:nth-child(1)')

def __init__(self, testsetup, element):
Page.__init__(self, testsetup)
def __init__(self, base_url, selenium, element):
Page.__init__(self, base_url, selenium)
self._root_element = element

@property
Expand All @@ -101,7 +101,7 @@ def click_question_link(self):
element = self._root_element.find_element(*self._question_link_locator)
self.selenium.execute_script('arguments[0].scrollIntoView(false);', element)
element.click()
view_question_pg = ViewQuestionPage(self.testsetup)
view_question_pg = ViewQuestionPage(self.base_url, self.selenium)
view_question_pg.is_the_current_page(question_title, product_name)
return view_question_pg

Expand Down Expand Up @@ -155,7 +155,7 @@ def fill_up_questions_form(self, question_to_ask, q_text='details', q_site='www.
self.selenium.find_element(*self._q_post_button_locator).click()
WebDriverWait(self.selenium, self.timeout).until(
lambda s: not self.is_element_present(*self._q_post_button_locator))
view_question_pg = ViewQuestionPage(self.testsetup)
view_question_pg = ViewQuestionPage(self.base_url, self.selenium)
view_question_pg.is_the_current_page(question_to_ask, selected_product)
return view_question_pg

Expand Down
2 changes: 1 addition & 1 deletion pages/desktop/support_home_page.py
Expand Up @@ -28,7 +28,7 @@ def do_search_on_main_search_box(self, search_query):
search_box.type_keys(search_query)
self.selenium.find_element(*self._search_button).click()
from search_page import SearchPage
return SearchPage(self.testsetup)
return SearchPage(self.base_url, self.selenium)

def click_top_common_content_link(self):
self.selenium.find_element(*self._top_helpful_content_locator).click()
Expand Down
8 changes: 4 additions & 4 deletions pages/mobile/article.py
Expand Up @@ -14,16 +14,16 @@ class Article(Base):
_helpful_header_text_locator = (By.CSS_SELECTOR, 'div.vote-bar header')
_vote_message_text_locator = (By.CSS_SELECTOR, 'div.vote-bar p')

def __init__(self, testsetup):
Base.__init__(self, testsetup)
def __init__(self, base_url, selenium):
Base.__init__(self, base_url, selenium)

@property
def helpful_header_text(self):
return self.selenium.find_element(*self._helpful_header_text_locator).text

def wait_for_vote_message_text(self, text):
vote_message = self.selenium.find_element(*self._vote_message_text_locator)
WebDriverWait(self.selenium, self.timeout).until(lambda s: vote_message.text == text)
WebDriverWait(self.selenium, self.timeout).until(
lambda s: s.find_element(*self._vote_message_text_locator).text == text)

def click_helpful_button(self):
self.selenium.find_element(*self._helpful_button_locator).click()
6 changes: 3 additions & 3 deletions pages/mobile/base.py
Expand Up @@ -20,7 +20,7 @@ def is_menu_exposed(self):

@property
def menu_items(self):
return [self.MenuItem(self.testsetup, element)
return [self.MenuItem(self.base_url, self.selenium, element)
for element in self.selenium.find_elements(*self._menu_items_locator)]

@property
Expand All @@ -40,8 +40,8 @@ def open_menu(self):

class MenuItem(Page):

def __init__(self, testsetup, element):
Page.__init__(self, testsetup)
def __init__(self, base_url, selenium, element):
Page.__init__(self, base_url, selenium)
self._root_element = element

@property
Expand Down
6 changes: 3 additions & 3 deletions pages/mobile/home.py
Expand Up @@ -15,8 +15,8 @@ class Home(Base):
_header_locator = (By.CSS_SELECTOR, 'header h1')
_search_box_locator = (By.CSS_SELECTOR, '#search input')

def __init__(self, testsetup):
Base.__init__(self, testsetup)
def __init__(self, base_url, selenium):
Base.__init__(self, base_url, selenium)

@property
def header_text(self):
Expand All @@ -29,4 +29,4 @@ def search_for(self, search_term):
search_box.submit()

from pages.mobile.search import Search
return Search(self.testsetup)
return Search(self.base_url, self.selenium)
2 changes: 1 addition & 1 deletion pages/mobile/page_provider.py
Expand Up @@ -14,4 +14,4 @@ def _go_to_page(self, page_object):

def home_page(self):
from pages.mobile.home import Home
return self._go_to_page(Home(self.testsetup))
return self._go_to_page(Home(self.base_url, self.selenium))
12 changes: 6 additions & 6 deletions pages/mobile/search.py
Expand Up @@ -12,21 +12,21 @@ class Search(Base):

_results_locator = (By.CSS_SELECTOR, 'ol.search-results li')

def __init__(self, testsetup):
Base.__init__(self, testsetup)
def __init__(self, base_url, selenium):
Base.__init__(self, base_url, selenium)
self._page_title = 'Search | Mozilla Support'

@property
def results(self):
return [self.SearchResult(self.testsetup, element)
return [self.SearchResult(self.base_url, self.selenium, element)
for element in self.selenium.find_elements(*self._results_locator)]

class SearchResult(Page):
def __init__(self, testsetup, element):
Page.__init__(self, testsetup)
def __init__(self, base_url, selenium, element):
Page.__init__(self, base_url, selenium)
self._root_element = element

def click(self):
self._root_element.click()
from pages.mobile.article import Article
return Article(self.testsetup)
return Article(self.base_url, self.selenium)
11 changes: 5 additions & 6 deletions pages/page.py
Expand Up @@ -20,11 +20,10 @@ 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
def __init__(self, base_url, selenium):
self.base_url = base_url
self.selenium = selenium
self.timeout = 10

@property
def is_the_current_page(self):
Expand Down Expand Up @@ -56,7 +55,7 @@ def is_element_present(self, *locator):
return False
finally:
# set back to where you once belonged
self.selenium.implicitly_wait(self.testsetup.default_implicit_wait)
self.selenium.implicitly_wait(10)

def is_element_visible(self, *locator):
try:
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
@@ -1,4 +1,4 @@
pytest==2.7.3
pytest-mozwebqa
pytest-selenium
pytest-variables
requests==2.9.1

0 comments on commit 88beda9

Please sign in to comment.