-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
33 changed files
with
1,079 additions
and
418 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from django.test import LiveServerTestCase | ||
from selenium import webdriver | ||
from RIGS import models as rigsmodels | ||
from . import pages | ||
import os | ||
|
||
|
||
def create_browser(): | ||
options = webdriver.ChromeOptions() | ||
options.add_argument("--window-size=1920,1080") | ||
if os.environ.get('CI', False): | ||
options.add_argument("--headless") | ||
options.add_argument("--no-sandbox") | ||
driver = webdriver.Chrome(chrome_options=options) | ||
return driver | ||
|
||
|
||
class BaseTest(LiveServerTestCase): | ||
def setUp(self): | ||
super().setUpClass() | ||
self.driver = create_browser() | ||
|
||
def tearDown(self): | ||
super().tearDown() | ||
self.driver.quit() | ||
|
||
|
||
class AutoLoginTest(BaseTest): | ||
def setUp(self): | ||
super().setUp() | ||
self.profile = rigsmodels.Profile( | ||
username="EventTest", first_name="Event", last_name="Test", initials="ETU", is_superuser=True) | ||
self.profile.set_password("EventTestPassword") | ||
self.profile.save() | ||
loginPage = pages.LoginPage(self.driver, self.live_server_url).open() | ||
loginPage.login("EventTest", "EventTestPassword") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
from pypom import Page, Region | ||
from selenium.webdriver.common.by import By | ||
from selenium.webdriver import Chrome | ||
from selenium.common.exceptions import NoSuchElementException | ||
|
||
|
||
class BasePage(Page): | ||
form_items = {} | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
|
||
def __getattr__(self, name): | ||
if name in self.form_items: | ||
element = self.form_items[name] | ||
form_element = element[0](self, self.find_element(*element[1])) | ||
return form_element.value | ||
else: | ||
return super().__getattribute__(name) | ||
|
||
def __setattr__(self, name, value): | ||
if name in self.form_items: | ||
element = self.form_items[name] | ||
form_element = element[0](self, self.find_element(*element[1])) | ||
form_element.set_value(value) | ||
else: | ||
self.__dict__[name] = value | ||
|
||
|
||
class FormPage(BasePage): | ||
_errors_selector = (By.CLASS_NAME, "alert-danger") | ||
|
||
def remove_all_required(self): | ||
self.driver.execute_script("Array.from(document.getElementsByTagName(\"input\")).forEach(function (el, ind, arr) { el.removeAttribute(\"required\")});") | ||
self.driver.execute_script("Array.from(document.getElementsByTagName(\"select\")).forEach(function (el, ind, arr) { el.removeAttribute(\"required\")});") | ||
|
||
@property | ||
def errors(self): | ||
try: | ||
error_page = self.ErrorPage(self, self.find_element(*self._errors_selector)) | ||
return error_page.errors | ||
except NoSuchElementException: | ||
return None | ||
|
||
class ErrorPage(Region): | ||
_error_item_selector = (By.CSS_SELECTOR, "dl>span") | ||
|
||
class ErrorItem(Region): | ||
_field_selector = (By.CSS_SELECTOR, "dt") | ||
_error_selector = (By.CSS_SELECTOR, "dd>ul>li") | ||
|
||
@property | ||
def field_name(self): | ||
return self.find_element(*self._field_selector).text | ||
|
||
@property | ||
def errors(self): | ||
return [x.text for x in self.find_elements(*self._error_selector)] | ||
|
||
@property | ||
def errors(self): | ||
error_items = [self.ErrorItem(self, x) for x in self.find_elements(*self._error_item_selector)] | ||
errors = {} | ||
for error in error_items: | ||
errors[error.field_name] = error.errors | ||
return errors | ||
|
||
|
||
class LoginPage(BasePage): | ||
URL_TEMPLATE = '/user/login' | ||
|
||
_username_locator = (By.ID, 'id_username') | ||
_password_locator = (By.ID, 'id_password') | ||
_submit_locator = (By.ID, 'id_submit') | ||
_error_locator = (By.CSS_SELECTOR, '.errorlist>li') | ||
|
||
def login(self, username, password): | ||
username_element = self.find_element(*self._username_locator) | ||
username_element.clear() | ||
username_element.send_keys(username) | ||
|
||
password_element = self.find_element(*self._password_locator) | ||
password_element.clear() | ||
password_element.send_keys(password) | ||
|
||
self.find_element(*self._submit_locator).click() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
from pypom import Region | ||
from selenium.webdriver.common.by import By | ||
from selenium.webdriver.support import expected_conditions | ||
from selenium.webdriver.remote.webelement import WebElement | ||
from selenium.webdriver.support.ui import WebDriverWait | ||
from selenium.webdriver.support.select import Select | ||
import datetime | ||
|
||
|
||
def parse_bool_from_string(string): | ||
# Used to convert from attribute strings to boolean values, written after I found this: | ||
# >>> bool("false") | ||
# True | ||
if string == "true": | ||
return True | ||
else: | ||
return False | ||
|
||
|
||
class BootstrapSelectElement(Region): | ||
_main_button_locator = (By.CSS_SELECTOR, 'button.dropdown-toggle') | ||
_option_box_locator = (By.CSS_SELECTOR, 'ul.dropdown-menu') | ||
_option_locator = (By.CSS_SELECTOR, 'ul.dropdown-menu.inner>li>a[role=option]') | ||
_select_all_locator = (By.CLASS_NAME, 'bs-select-all') | ||
_deselect_all_locator = (By.CLASS_NAME, 'bs-deselect-all') | ||
_search_locator = (By.CSS_SELECTOR, '.bs-searchbox>input') | ||
_status_locator = (By.CLASS_NAME, 'status') | ||
|
||
@property | ||
def is_open(self): | ||
return parse_bool_from_string(self.find_element(*self._main_button_locator).get_attribute("aria-expanded")) | ||
|
||
def toggle(self): | ||
original_state = self.is_open | ||
return self.find_element(*self._main_button_locator).click() | ||
option_box = self.find_element(*self._option_box_locator) | ||
if original_state: | ||
self.wait.until(expected_conditions.invisibility_of_element_located(option_box)) | ||
else: | ||
self.wait.until(expected_conditions.visibility_of_element_located(option_box)) | ||
|
||
def open(self): | ||
if not self.is_open: | ||
self.toggle() | ||
|
||
def close(self): | ||
if self.is_open: | ||
self.toggle() | ||
|
||
def select_all(self): | ||
self.find_element(*self._select_all_locator).click() | ||
|
||
def deselect_all(self): | ||
self.find_element(*self._deselect_all_locator).click() | ||
|
||
def search(self, query): | ||
search_box = self.find_element(*self._search_locator) | ||
search_box.clear() | ||
search_box.send_keys(query) | ||
status_text = self.find_element(*self._status_locator) | ||
self.wait.until(expected_conditions.invisibility_of_element_located(self._status_locator)) | ||
|
||
@property | ||
def options(self): | ||
options = list(self.find_elements(*self._option_locator)) | ||
return [self.BootstrapSelectOption(self, i) for i in options] | ||
|
||
def set_option(self, name, selected): | ||
options = list((x for x in self.options if x.name == name)) | ||
assert len(options) == 1 | ||
options[0].set_selected(selected) | ||
|
||
class BootstrapSelectOption(Region): | ||
_text_locator = (By.CLASS_NAME, 'text') | ||
|
||
@property | ||
def selected(self): | ||
return parse_bool_from_string(self.root.get_attribute("aria-selected")) | ||
|
||
def toggle(self): | ||
self.root.click() | ||
|
||
def set_selected(self, selected): | ||
if self.selected != selected: | ||
self.toggle() | ||
|
||
@property | ||
def name(self): | ||
return self.find_element(*self._text_locator).text | ||
|
||
|
||
class TextBox(Region): | ||
@property | ||
def value(self): | ||
return self.root.get_attribute("value") | ||
|
||
def set_value(self, value): | ||
self.root.clear() | ||
self.root.send_keys(value) | ||
|
||
|
||
class CheckBox(Region): | ||
def toggle(self): | ||
self.root.click() | ||
|
||
@property | ||
def value(self): | ||
return parse_bool_from_string(self.root.get_attribute("checked")) | ||
|
||
def set_value(self, value): | ||
if value != self.value: | ||
self.toggle() | ||
|
||
|
||
class DatePicker(Region): | ||
@property | ||
def value(self): | ||
return datetime.datetime.strptime(self.root.get_attribute("value"), "%Y-%m-%d") | ||
|
||
def set_value(self, value): | ||
self.root.clear() | ||
self.root.send_keys(value.strftime("%d%m%Y")) | ||
|
||
|
||
class SingleSelectPicker(Region): | ||
@property | ||
def value(self): | ||
picker = Select(self.root) | ||
return picker.first_selected_option.text | ||
|
||
def set_value(self, value): | ||
picker = Select(self.root) | ||
picker.select_by_visible_text(value) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.