* Switch to using geckodriver * Switch to selenium 4 * Undo * Remove comment * Fixes * Restore non-standard line endings to minimize diff * Undo * Remove comment * test: Fix test_upcoming_view_time_zone_selection The inputs are hidden and managed by JS, so click the visible elements instead. * test: Clumsy fix to test_upcoming_materials_modal Waiting for the button to be clickable does not work because the modal is still fading in, so does not actually close. Would be better to check for it responding, but I haven't found the right way to do that yet. * test: Fix test_add_author_forms Sending '\n' does not seem to work as it did before, so click the option instead. Also reverted some fixme hacks that seem to be obe. * ci: Update base.Dockerfile * test: add resource limits to dev/tests/debug.sh env * ci: add upload of geckodriver.log on failure * ci: run tests as user 1001 * ci: run app-create-dirs as sudo * ci: set home folder to root to run tests --------- Co-authored-by: Jennifer Richards <jennifer@staff.ietf.org> Co-authored-by: Nicolas Giard <github@ngpixel.com> Co-authored-by: Robert Sparks <rjsparks@nostrum.com>
103 lines
3.5 KiB
Python
103 lines
3.5 KiB
Python
# Copyright The IETF Trust 2014-2021, All Rights Reserved
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import os
|
|
|
|
from django.urls import reverse as urlreverse
|
|
from unittest import skipIf
|
|
|
|
skip_selenium = False
|
|
skip_message = ""
|
|
try:
|
|
from selenium import webdriver
|
|
from selenium.webdriver.firefox.service import Service
|
|
from selenium.webdriver.firefox.options import Options
|
|
from selenium.webdriver.common.by import By
|
|
except ImportError as e:
|
|
skip_selenium = True
|
|
skip_message = "Skipping selenium tests: %s" % e
|
|
|
|
|
|
from ietf.utils.pipe import pipe
|
|
from ietf.utils.test_runner import IetfLiveServerTestCase
|
|
|
|
executable_name = 'geckodriver'
|
|
code, out, err = pipe('{} --version'.format(executable_name))
|
|
if code != 0:
|
|
skip_selenium = True
|
|
skip_message = "Skipping selenium tests: '{}' executable not found.".format(executable_name)
|
|
if skip_selenium:
|
|
print(" "+skip_message)
|
|
|
|
def start_web_driver():
|
|
service = Service(log_output=f"{executable_name}.log", service_args=['--log-no-truncate'])
|
|
options = Options()
|
|
options.add_argument("--headless")
|
|
os.environ["MOZ_REMOTE_SETTINGS_DEVTOOLS"] = "1"
|
|
return webdriver.Firefox(service=service, options=options)
|
|
|
|
|
|
def selenium_enabled():
|
|
"""Are Selenium tests enabled?"""
|
|
return not skip_selenium
|
|
|
|
|
|
def ifSeleniumEnabled(func):
|
|
"""Only run test if Selenium testing is enabled"""
|
|
return skipIf(skip_selenium, skip_message)(func)
|
|
|
|
|
|
class IetfSeleniumTestCase(IetfLiveServerTestCase):
|
|
login_view = 'ietf.ietfauth.views.login'
|
|
|
|
def setUp(self):
|
|
super(IetfSeleniumTestCase, self).setUp()
|
|
self.driver = start_web_driver()
|
|
self.driver.set_window_size(1024,768)
|
|
|
|
def tearDown(self):
|
|
super(IetfSeleniumTestCase, self).tearDown()
|
|
self.driver.close()
|
|
|
|
def absreverse(self,*args,**kwargs):
|
|
return '%s%s'%(self.live_server_url, urlreverse(*args, **kwargs))
|
|
|
|
def debug_snapshot(self,filename='debug_this.png'):
|
|
self.driver.execute_script("document.body.bgColor = 'white';")
|
|
self.driver.save_screenshot(filename)
|
|
|
|
def login(self, username='plain'):
|
|
url = self.absreverse(self.login_view)
|
|
password = '%s+password' % username
|
|
self.driver.get(url)
|
|
self.driver.find_element(By.NAME, 'username').send_keys(username)
|
|
self.driver.find_element(By.NAME, 'password').send_keys(password)
|
|
self.driver.find_element(By.XPATH, '//*[@id="content"]//button[@type="submit"]').click()
|
|
|
|
def scroll_to_element(self, element):
|
|
"""Scroll an element into view"""
|
|
# Compute the offset to put the element in the center of the window
|
|
win_height = self.driver.get_window_rect()['height']
|
|
offset = element.rect['y'] + (element.rect['height'] - win_height) // 2
|
|
self.driver.execute_script(
|
|
'window.scroll({top: arguments[0], behavior: "instant"})',
|
|
offset,
|
|
)
|
|
# The ActionChains approach below seems to be fragile, hence he JS above.
|
|
# actions = ActionChains(self.driver)
|
|
# actions.move_to_element(element).perform()
|
|
|
|
|
|
class presence_of_element_child_by_css_selector:
|
|
"""Wait for presence of a child of a WebElement matching a CSS selector
|
|
|
|
This is a condition class for use with WebDriverWait.
|
|
"""
|
|
def __init__(self, element, child_selector):
|
|
self.element = element
|
|
self.child_selector = child_selector
|
|
|
|
def __call__(self, driver):
|
|
child = self.element.find_element(By.CSS_SELECTOR, self.child_selector)
|
|
return child if child is not None else False
|