Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web application UI tests #109

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
12 changes: 11 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
# Disable sudo to speed up the build
sudo: false
sudo: required
addons:
chrome: stable

language: python
python:
- "3.8.1"
cache: pip

install:
- pip install -r requirements.txt
- pip install codecov
- wget https://chromedriver.storage.googleapis.com/85.0.4183.87/chromedriver_linux64.zip
- unzip chromedriver_linux64.zip -d /home/travis/virtualenv/python3.8.1/bin/
- export CHROME_BIN=chromium-browser

script:
script:
- whereis google-chrome-stable
- whereis chromedriver
- python -m py_compile ./*/*.py ./*.py ./*/*/*.py
- flake8 ./*/*.py ./*.py ./*/*/*.py
- pylint ./*.py */*.py */*/*.py --reports=y --ignore=page_kinematics.py,ik_solver.py --disable=broad-except,too-few-public-methods,attribute-defined-outside-init,too-many-locals,too-many-instance-attributes,too-many-arguments,bad-continuation,missing-class-docstring,missing-module-docstring,missing-function-docstring,invalid-name,duplicate-code
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,5 @@ typed-ast==1.4.1
wcwidth==0.1.9
Werkzeug==1.0.1
wrapt==1.11.2

selenium~=3.141.0
104 changes: 104 additions & 0 deletions tests/test_ui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
from selenium import webdriver
import unittest
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from widgets import leg_patterns_ui, dimensions_ui, ik_ui
import secrets


# This class tests the UI for the web application.
# Index.py needs to be run first to start the server before the tests can be conducted.
class WidgetTests(unittest.TestCase):

def setUp(self):
options = webdriver.ChromeOptions()
options.add_argument("disable-gpu")
options.add_argument("headless")
options.add_argument("no-default-browser-check")
options.add_argument("no-first-run")
options.add_argument("no-sandbox")

self.browser = webdriver.Chrome(options=options)
self.browser.implicitly_wait(3)
self.server = 'http://127.0.0.1:8050/'
self.timeout = 10

# Helper function - wait until the webpage is loaded completely before starting tests
def load_webpage_completely(self):
self.browser.get(self.server)
try:
title_loaded = EC.title_contains("Hexapod")
body_loaded = EC.presence_of_element_located((By.TAG_NAME, "h6"))
WebDriverWait(self.browser, self.timeout).until(title_loaded)
WebDriverWait(self.browser, self.timeout).until(body_loaded)
except TimeoutException:
print("Timed out waiting for the webpage to load")

# Test all hyperlinks for all pages are available and working
def test_all_links_working(self):
self.load_webpage_completely()
links = ['/leg-patterns',
'/kinematics',
'/inverse-kinematics',
'/',
'https://github.com/mithi/hexapod-robot-simulator',
'https://github.com/mithi/hexapod-robot-simulator',
'https://ko-fi.com/minimithi']
for link in links:
element = self.browser.find_element_by_xpath("//a[@href='"+link+"']")
self.assertEqual(element.size!=0,True,"Web app has no link to "+ link)

# Tests the UI for changing robot dimensions
def test_dimensions_ui(self):
self.load_webpage_completely()
self.browser.find_element_by_xpath("//a[@href='/leg-patterns']").click()
leg_dimension_names = dimensions_ui.WIDGET_NAMES

for name in leg_dimension_names:
for i in range(3):
self.browser.find_element_by_id('widget-dimension-'+name).send_keys(Keys.BACK_SPACE)
self.browser.find_element_by_id('widget-dimension-'+name).send_keys(secrets.randbelow(30)+90)

# Tests the UI for changing leg patterns
def test_leg_patterns_ui(self):
self.load_webpage_completely()
self.browser.find_element_by_xpath("//a[@href='/leg-patterns']").click()
widget_names = leg_patterns_ui.WIDGET_NAMES

for name in widget_names:
slider = WebDriverWait(self.browser,self.timeout).until(
EC.element_to_be_clickable((By.ID,"widget-"+name)))
random_slide = secrets.randbelow(20)-10
action = webdriver.ActionChains(self.browser)
action.move_to_element(slider)
action.click_and_hold(slider)
action.move_by_offset(random_slide, 0)
action.release()
action.perform()

# Tests the UI for changing inverse kinematics settings
def test_inverse_kinematics_ui(self):
self.load_webpage_completely()
self.browser.find_element_by_xpath("//a[@href='/inverse-kinematics']").click()
widget_ids = ik_ui.IK_WIDGETS_IDS
for widget_id in widget_ids:
slider = WebDriverWait(self.browser,self.timeout).until(
EC.element_to_be_clickable((By.ID,widget_id)))
random_slide = secrets.randbelow(20)-10
action = webdriver.ActionChains(self.browser)
action.move_to_element(slider)
action.click_and_hold(slider)
action.move_by_offset(0,random_slide)
action.release()
action.perform()

# Close the web application test
def tearDown(self):
self.browser.quit()


if __name__ =='__main__':
unittest.main(warnings='ignore')