Permalink
Browse files

partially address #73

* fix wait_for_ajax
* MozTrapEditRunPage
* treat runs in manage runs list as sub-objects
* treat suits in create/edit run as sub-objects
* allow for both addition and removal of suites in runs

TODO:
figure out how to drag-n-drop
  • Loading branch information...
1 parent 2c7da5a commit 7a010580d0b9e24c27a2c0c3f2511d6c8876a459 @klrmn committed Oct 24, 2012
Showing with 262 additions and 52 deletions.
  1. +5 −3 pages/base_test.py
  2. +172 −27 pages/create_run_page.py
  3. +30 −17 pages/manage_runs_page.py
  4. +3 −2 pages/page.py
  5. +52 −3 tests/test_manage_runs_page.py
View
@@ -82,16 +82,18 @@ def create_run(self, mozwebqa, activate=False, product=None, version=None, suite
if activate:
manage_runs_pg = MozTrapManageRunsPage(mozwebqa)
manage_runs_pg.filter_runs_by_name(name=run['name'])
- manage_runs_pg.activate_run(name=run['name'])
-
+ runs = manage_runs_pg.get_runs
+ runs[0].activate()
+
return run
def delete_run(self, mozwebqa, run, delete_version=False, delete_product=False):
manage_runs_pg = MozTrapManageRunsPage(mozwebqa)
manage_runs_pg.go_to_manage_runs_page()
manage_runs_pg.filter_runs_by_name(name=run['name'])
- manage_runs_pg.delete_run(name=run['name'])
+ runs = manage_runs_pg.get_runs
+ runs[0].delete()
if delete_version:
self.delete_version(mozwebqa, version=run['version'], delete_product=delete_product)
View
@@ -9,30 +9,186 @@
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
+from pages.page import Page
from pages.base_page import MozTrapBasePage
-
-class MozTrapCreateRunPage(MozTrapBasePage):
-
- _page_title = 'MozTrap'
-
+class MozTrapEditRunPage(MozTrapBasePage):
+ _known_kwargs = ['name', 'desc', 'start_date', 'end_date', 'suite_list']
+ _product_version_readonly_locator = (By.CSS_SELECTOR, 'div.formfield.product-version-field.readonly > span')
_name_locator = (By.ID, 'id_name')
- _product_version_select_locator = (By.ID, 'id_productversion')
_description_locator = (By.ID, 'id_description')
_start_date_locator = (By.ID, 'id_start')
_end_date_locator = (By.ID, 'id_end')
- _suite_select_locator = (By.CSS_SELECTOR, '#run-add-form .multiunselected .itemlist article.selectitem[data-title="%(suite_name)s"] input.bulk-value')
- _include_selected_suites_locator = (By.CSS_SELECTOR, '#run-add-form .multiselect .include-exclude .action-include')
+ _available_suites_locator = (By.CSS_SELECTOR, '.multiunselected .itemlist article.selectitem')
+ _included_suites_locator = (By.CSS_SELECTOR, '.multiselected .itemlist article.selectitem')
+ _include_selected_suites_locator = (By.CSS_SELECTOR, '.multiselect .include-exclude .action-include')
+ _remove_selected_suites_locator = (By.CSS_SELECTOR, '.multiselect .include-exclude .action-exclude')
_submit_locator = (By.CSS_SELECTOR, '#run-add-form .form-actions > button')
+
+ # Note on __init__: it fails with 'ReferenceError: jQuery is not defined'
+ # if you try to wait_for_ajax
+
+ def fill_fields(self, **kwargs):
+ '''
+ ::keyword args::
+ name
+ desc
+ start_date
+ end_date
+ suite_list
+ '''
+
+ for key in kwargs.keys():
+ if not key in self._known_kwargs:
+ raise Exception("%s unrecognized, use only recognized kwargs:\n%s" %
+ (key, "\n".join(self._known_kwargs)))
+
+ if kwargs.has_key('name'):
+ name_field = self.selenium.find_element(*self._name_locator)
+ name_field.send_keys(kwargs['name'])
+ if kwargs.has_key('desc'):
+ self.selenium.find_element(*self._description_locator).send_keys(kwargs['desc'])
+ if kwargs.has_key('start_date'):
+ self.type_in_element(self._start_date_locator, kwargs['start_date'])
+ if kwargs.has_key('end_date'):
+ self.selenium.find_element(*self._end_date_locator).send_keys(kwargs['end_date'])
+
+ if kwargs.has_key('suite_list') and kwargs['suite_list']:
+ # remove unwanted
+ for suite in self.included_suites:
+ print 'included has %s' % suite.name
+ if not suite.name in kwargs['suite_list']:
+ print 'selecting for removal'
+ suite.select()
+ self.remove_selected_suites()
+ # add wanted
+ for suite in self.available_suites:
+ print 'available has %s' % suite.name
+ if suite.name in kwargs['suite_list']:
+ print 'selecting for addition'
+ suite.select()
+ self.add_selected_suites()
+ # check for strays
+ included_suite_names = self.included_suite_names
+ for suite_name in kwargs['suite_list']:
+ if not suite_name in included_suite_names:
+ raise Exception('suite %s not found' % suite_name)
+
+ self.selenium.find_element(*self._submit_locator).click()
+
+ @property
+ def product_version(self):
+ return self.selenium.find_element(*self._product_version_readonly_locator).text
+
+ @property
+ def included_suites(self):
+ '''this method only works if run is in draft mode.'''
+ suites = self.selenium.find_elements(*self._included_suites_locator)
+ included_suites = [self.Suite(self.testsetup, loc) for loc in suites]
+ print 'included_suites:\n%s' % included_suites
+ return included_suites
+
+ @property
+ def included_suite_names(self):
+ # XXX fix this so that it returns something when run is active
+ included_suite_names = [suite.name for suite in self.included_suites]
+ print 'included_suite_names:\n%s' % included_suite_names
+ return included_suite_names
+
+ def remove_selected_suites(self):
+ '''this method only works if run is in draft mode.'''
+ self.selenium.find_element(*self._remove_selected_suites_locator).click()
+
+ @property
+ def available_suites(self):
+ '''this method only works if run is in draft mode.'''
+ suites = self.selenium.find_elements(*self._available_suites_locator)
+ return [self.Suite(self.testsetup, loc) for loc in suites]
+
+ @property
+ def available_suite_names(self):
+ '''this method only works if run is in draft mode.'''
+ return [suite.name for suite in self.available_suites]
+
+ def add_selected_suites(self):
+ '''this method only works if run is in draft mode.'''
+ self.selenium.find_element(*self._include_selected_suites_locator).click()
+
+ class Suite(Page):
+ _name_locator = (By.CSS_SELECTOR, 'div.name > h5.title')
+ _checkbox_locator = (By.CSS_SELECTOR, 'label.bulk-type')
+ _drag_locator = (By.CSS_SELECTOR, )
+
+ def __init__(self, testsetup, webelement):
+ Page.__init__(self, testsetup)
+ self.webelement = webelement
+
+ @property
+ def name(self):
+ return self.webelement.find_element(*self._name_locator).text
+
+ @property
+ def position(self):
+ pass
+
+ def select(self):
+ self.webelement.find_element(*self._checkbox_locator).click()
+
+ def drag_to(self, position):
+ pass
+
+
+class MozTrapCreateRunPage(MozTrapEditRunPage):
+
+ _page_title = 'MozTrap'
+
+ _product_version_select_locator = (By.ID, 'id_productversion')
_run_manage_locator = (By.CSS_SELECTOR, '#manageruns .itemlist .listitem .title[title="%(run_name)s"]')
_run_homepage_locator = (By.CSS_SELECTOR, '.runsdrill .runsfinder .runs .colcontent .title[title="%(run_name)s"]')
_run_tests_button_locator = (By.CSS_SELECTOR, 'div.form-actions > button')
+ def __init__(self, testsetup):
+ MozTrapEditRunPage.__init__(self, testsetup)
+ self._known_kwargs.append('product_version')
+
def go_to_create_run_page(self):
self.selenium.get(self.base_url + '/manage/run/add/')
self.is_the_current_page
- def create_run(self, name='Test Run', product_version='Test Product Test Version', desc='This is a test run', start_date='2011-01-01', end_date='2012-12-31', suite_list=None):
+ def fill_fields(self, **kwargs):
+ '''
+ ::keyword args::
+ name
+ product_version
+ desc
+ start_date
+ end_date
+ suite_list
+ '''
+
+ if kwargs.has_key('product_version'):
+ product_version_select = Select(self.selenium.find_element(*self._product_version_select_locator))
+ product_version_select.select_by_visible_text(kwargs['product_version'])
+
+ MozTrapEditRunPage.fill_fields(self, **kwargs)
+
+
+ def create_run(self,
+ name='Test Run',
+ product_version='Test Product Test Version',
+ desc='This is a test run',
+ start_date='2011-01-01',
+ end_date='2012-12-31',
+ suite_list=None):
+ '''
+ ::keyword args::
+ name
+ product_version
+ desc
+ start_date
+ end_date
+ suite_list
+ '''
dt_string = datetime.utcnow().isoformat()
run = {}
run['name'] = u'%(name)s %(dt_string)s' % {'name': name, 'dt_string': dt_string}
@@ -41,23 +197,12 @@ def create_run(self, name='Test Run', product_version='Test Product Test Version
run['homepage_locator'] = (self._run_homepage_locator[0], self._run_homepage_locator[1] % {'run_name': run['name']})
run['run_tests_locator'] = self._run_tests_button_locator
- name_field = self.selenium.find_element(*self._name_locator)
- name_field.send_keys(run['name'])
-
- product_version_select = Select(self.selenium.find_element(*self._product_version_select_locator))
- product_version_select.select_by_visible_text(product_version)
-
- self.selenium.find_element(*self._description_locator).send_keys(run['desc'])
-
- self.type_in_element(self._start_date_locator, start_date)
- self.selenium.find_element(*self._end_date_locator).send_keys(end_date)
-
- if suite_list:
-
- for suite in suite_list:
- suite_input_element = self.selenium.find_element(By.XPATH, "//article[@data-title='%s']//label" % suite)
- suite_input_element.click()
- self.selenium.find_element(*self._include_selected_suites_locator).click()
- self.selenium.find_element(*self._submit_locator).click()
+ self.fill_fields(
+ name=run['name'],
+ product_version=product_version,
+ desc=run['desc'],
+ start_date=start_date,
+ end_date=end_date,
+ suite_list=suite_list)
return run
View
@@ -6,30 +6,24 @@
from selenium.webdriver.common.by import By
+from pages.page import Page
from pages.base_page import MozTrapBasePage
+from pages.create_run_page import MozTrapEditRunPage
class MozTrapManageRunsPage(MozTrapBasePage):
_page_title = 'MozTrap'
- _delete_run_locator = (By.CSS_SELECTOR, '#manageruns .itemlist .listitem[data-title="%(run_name)s"] .action-delete')
- _run_activate_locator = (By.CSS_SELECTOR, '#manageruns .itemlist .listitem[data-title="%(run_name)s"] .status-action.active')
- _run_status_locator = (By.CSS_SELECTOR, '#manageruns .itemlist .listitem[data-title="%(run_name)s"] .status-title')
_filter_input_locator = (By.ID, 'text-filter')
_filter_suggestion_locator = (By.CSS_SELECTOR, '#filter .textual .suggest .suggestion[data-type="name"][data-name="%(filter_name)s"]')
_filter_locator = (By.CSS_SELECTOR, '#filterform .filter-group input[data-name="name"][value="%(filter_name)s"]:checked')
+ _run_item_locator = (By.CSS_SELECTOR, '#manageruns .itemlist .listitem')
def go_to_manage_runs_page(self):
self.selenium.get(self.base_url + '/manage/runs/')
self.is_the_current_page
- def delete_run(self, name='Test Run'):
- _delete_locator = (self._delete_run_locator[0], self._delete_run_locator[1] % {'run_name': name})
-
- self.selenium.find_element(*_delete_locator).click()
- self.wait_for_ajax()
-
def filter_runs_by_name(self, name):
_filter_suggestion_locator = (self._filter_suggestion_locator[0], self._filter_suggestion_locator[1] % {'filter_name': name})
@@ -43,11 +37,30 @@ def remove_name_filter(self, name):
self.selenium.find_element(*self._filter_locator).click()
self.wait_for_ajax()
- def activate_run(self, name='Test Run'):
- _run_activate_locator = (self._run_activate_locator[0], self._run_activate_locator[1] % {'run_name': name})
- _run_status_locator = (self._run_status_locator[0], self._run_status_locator[1] % {'run_name': name})
-
- self.selenium.find_element(*_run_status_locator).click()
- self.selenium.find_element(*_run_activate_locator).click()
-
- self.wait_for_ajax()
+ @property
+ def get_runs(self):
+ runs = self.selenium.find_elements(*self._run_item_locator)
+ return [self.Run(self.testsetup, run) for run in runs]
+
+ class Run(Page):
+ _delete_run_locator = (By.CSS_SELECTOR, '.action-delete')
+ _run_activate_locator = (By.CSS_SELECTOR, '.status-action.active')
+ _run_status_locator = (By.CSS_SELECTOR, '.status-title')
+ _edit_run_locator = (By.CSS_SELECTOR, 'a.edit-link')
+
+ def __init__(self, testsetup, webelement):
+ Page.__init__(self, testsetup)
+ self.webelement = webelement
+
+ def delete(self):
+ self.webelement.find_element(*self._delete_run_locator).click()
+ self.wait_for_ajax()
+
+ def edit(self):
+ self.webelement.find_element(*self._edit_run_locator).click()
+ return MozTrapEditRunPage(self.testsetup)
+
+ def activate(self):
+ self.webelement.find_element(*self._run_status_locator).click()
+ self.webelement.find_element(*self._run_activate_locator).click()
+ self.wait_for_ajax()
View
@@ -62,8 +62,9 @@ def is_element_visible(self, by, value):
return False
def wait_for_ajax(self):
- WebDriverWait(self.selenium, self.timeout).until(lambda s: s.execute_script("return $.active == 0"),
- "Wait for AJAX timed out after %s seconds" % self.timeout)
+ WebDriverWait(self.selenium, self.timeout).until(
+ lambda s: s.execute_script("return jQuery.active == 0"),
+ "Wait for AJAX timed out after %s seconds" % self.timeout)
def type_in_element(self, locator, text):
"""
Oops, something went wrong.

0 comments on commit 7a01058

Please sign in to comment.