mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-24 08:46:24 -07:00
Add selenium tests
This commit is contained in:
parent
ae179a3762
commit
05da962dfe
5 changed files with 405 additions and 1 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -16,4 +16,5 @@ __debug_bin
|
|||
node_modules
|
||||
/frontend/coverage
|
||||
/frontend/tests/coverage
|
||||
.parcel-cache
|
||||
.parcel-cache
|
||||
__pycache__
|
176
devtools/selenium-testing/main.py
Executable file
176
devtools/selenium-testing/main.py
Executable file
|
@ -0,0 +1,176 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Don't forget to set NewThreadDelay and ReplyDelay to 0 in
|
||||
# the config (with gochan running) before running, otherwise some posts may be rejected
|
||||
# by the server
|
||||
|
||||
import argparse
|
||||
from lib2to3.pgen2 import driver
|
||||
from os import path
|
||||
import os
|
||||
from pickletools import optimize
|
||||
import re
|
||||
import sys
|
||||
import unittest
|
||||
from urllib.parse import urljoin
|
||||
from selenium import webdriver
|
||||
|
||||
from selenium.webdriver.chrome.webdriver import WebDriver
|
||||
from selenium.webdriver.edge.webdriver import WebDriver
|
||||
from selenium.webdriver.firefox.webdriver import WebDriver
|
||||
from selenium.webdriver.chrome.options import Options as ChromeOptions
|
||||
from selenium.webdriver.edge.options import Options as EdgeOptions
|
||||
from selenium.webdriver.firefox.options import Options as FirefoxOptions
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.remote.webelement import WebElement
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
|
||||
from util.localstorage import LocalStorage
|
||||
from util.qr import openQR,closeQR,qrIsVisible
|
||||
|
||||
testingSite = "http://192.168.56.3"
|
||||
testingName = "Selenium"
|
||||
testingEmail = "selenium@gochan.org#noko"
|
||||
testingMessage = "Hello, from Selenium!\n(driver is %s)"
|
||||
testingSubject = "Selenium post creation"
|
||||
testingUploadPath = "../../html/banned.png"
|
||||
testingPassword = "12345"
|
||||
testingBoard = "test"
|
||||
|
||||
threadRE = re.compile('.*/(\S+)/(\d+)(\+50)?.html')
|
||||
parser = argparse.ArgumentParser(description="Browser testing via Selenium")
|
||||
browser = ""
|
||||
headless = False
|
||||
keepOpen = False
|
||||
|
||||
def gotoPage(driver: WebDriver, page: str):
|
||||
driver.get(urljoin(testingSite, page))
|
||||
|
||||
def loginToStaff(driver: WebDriver, username = "admin", pw = "password"):
|
||||
gotoPage(driver, "manage")
|
||||
driver.find_element(by=By.NAME, value="username").send_keys(username)
|
||||
driver.find_element(by=By.NAME, value="password").send_keys(pw)
|
||||
driver.find_element(by=By.CSS_SELECTOR, value="input[value=Login]").click()
|
||||
|
||||
def sendPost(postForm:WebElement, name="", email="", subject="", message="", file=""):
|
||||
postForm.find_element(by=By.NAME, value="postname").send_keys(name)
|
||||
postForm.find_element(by=By.NAME, value="postemail").send_keys(email)
|
||||
postForm.find_element(by=By.NAME, value="postsubject").send_keys(subject)
|
||||
postForm.find_element(by=By.NAME, value="postmsg").send_keys(message)
|
||||
if file != "":
|
||||
postForm.find_element(by=By.NAME, value="imagefile").send_keys(file)
|
||||
postForm.find_element(by=By.CSS_SELECTOR, value="input[type=submit]").click()
|
||||
|
||||
class TestRunner(unittest.TestCase):
|
||||
def setUp(self):
|
||||
if browser == "firefox":
|
||||
options = FirefoxOptions()
|
||||
if headless:
|
||||
options.headless = True
|
||||
self.driver = webdriver.Firefox(options=options)
|
||||
elif browser == "chrome" or browser == "chromium":
|
||||
options = ChromeOptions()
|
||||
if headless:
|
||||
options.headless = True
|
||||
if keepOpen:
|
||||
options.add_experimental_option("detach", True)
|
||||
self.driver = webdriver.Chrome(options=options)
|
||||
else:
|
||||
self.fail("Unrecognized --browser option '%s'" % browser)
|
||||
return super().setUp()
|
||||
|
||||
def test_qr(self):
|
||||
gotoPage(self.driver, testingBoard)
|
||||
self.assertIn("/test/ - Testing board", self.driver.title)
|
||||
elem = self.driver.find_element(by=By.ID, value="board-subtitle")
|
||||
self.assertIn("Board for testing stuff", elem.text)
|
||||
openQR(self.driver)
|
||||
self.assertTrue(qrIsVisible(self.driver), "Confirm that the QR box was properly opened")
|
||||
closeQR(self.driver)
|
||||
self.assertFalse(qrIsVisible(self.driver), "Confirm that the QR box was properly closed")
|
||||
|
||||
def test_localStorage(self):
|
||||
gotoPage(self.driver, testingBoard)
|
||||
localStorage = LocalStorage(self.driver)
|
||||
localStorage["foo"] = "bar"
|
||||
self.assertEqual(localStorage.get("foo"), "bar", "making sure that LocalStorage.get works")
|
||||
self.assertGreater(localStorage.__len__(), 0)
|
||||
|
||||
def test_staffLogin(self):
|
||||
loginToStaff(self.driver)
|
||||
self.assertEqual(
|
||||
self.driver.find_element(by=By.CSS_SELECTOR, value="header h1").text,
|
||||
"Dashboard",
|
||||
"Testing staff login"
|
||||
)
|
||||
|
||||
def test_makeThread(self):
|
||||
gotoPage(self.driver, testingBoard)
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
EC.element_to_be_clickable((By.CSS_SELECTOR, "form#postform input[type=submit]")))
|
||||
|
||||
valProp = self.driver.find_element(by=By.CSS_SELECTOR, value="form#postform input[type=submit]").get_property("value")
|
||||
self.assertEqual(valProp, "Post")
|
||||
form = self.driver.find_element(by=By.CSS_SELECTOR, value="form#postform")
|
||||
|
||||
sendPost(form,
|
||||
testingName,
|
||||
testingEmail,
|
||||
testingSubject,
|
||||
testingMessage % self.driver.name,
|
||||
path.abspath(testingUploadPath))
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
EC.url_matches(threadRE))
|
||||
threadID = threadRE.findall(self.driver.current_url)[0][1]
|
||||
self.driver.find_element(by=By.CSS_SELECTOR, value=("input#check%s"%threadID)).click()
|
||||
delPasswordInput = self.driver.find_element(by=By.CSS_SELECTOR, value="input#delete-password")
|
||||
val = delPasswordInput.get_attribute("value")
|
||||
if val == "" or val is None:
|
||||
val = testingPassword
|
||||
delPasswordInput.send_keys(testingPassword)
|
||||
cur_url = self.driver.current_url
|
||||
self.driver.find_element(by=By.CSS_SELECTOR, value="input[name=delete_btn]").click()
|
||||
self.driver.switch_to.alert.accept()
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
EC.url_changes(cur_url))
|
||||
self.assertNotIn("Error :c", self.driver.title, "No errors when we try to delete the post we just made")
|
||||
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
if not keepOpen:
|
||||
self.driver.close()
|
||||
return super().tearDown()
|
||||
|
||||
def startBrowserTests(testBrowser:str, testHeadless=False, testKeepOpen=False, site=testingSite, board=testingBoard):
|
||||
global browser
|
||||
global testingSite
|
||||
global testingBoard
|
||||
global headless
|
||||
global keepOpen
|
||||
browser = testBrowser
|
||||
headless = testHeadless
|
||||
keepOpen = testKeepOpen
|
||||
if headless:
|
||||
keepOpen = False
|
||||
testingSite = site
|
||||
testingBoard = board
|
||||
|
||||
print("Using browser %s (headless: %s) on site %s" % (browser, headless, testingSite))
|
||||
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestRunner)
|
||||
unittest.TextTestRunner(verbosity=3, descriptions=True).run(suite)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
testable_browsers = ("firefox","chrome","chromium")
|
||||
parser.add_argument("--browser", choices=testable_browsers, required=True)
|
||||
parser.add_argument("--site", default=testingSite, help=("Sets the site to be used for testing, defaults to %s" % testingSite))
|
||||
parser.add_argument("--board", default=testingBoard, help="Sets the board to be used for testing")
|
||||
parser.add_argument("--headless", action="store_true", help="If set, the driver will run without opening windows (overrides --keepopen if it is set)")
|
||||
parser.add_argument("--keepopen", action="store_true", help="If set, the browser windows will stay open after the tests are complete")
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
startBrowserTests(args.browser, args.headless, args.keepopen, args.site, args.board)
|
||||
except KeyboardInterrupt:
|
||||
print("Tests interrupted, exiting")
|
129
devtools/selenium-testing/tests.py
Normal file
129
devtools/selenium-testing/tests.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
from os import path
|
||||
|
||||
import re
|
||||
import unittest
|
||||
|
||||
from urllib.parse import urljoin
|
||||
from selenium import webdriver
|
||||
|
||||
from selenium.webdriver.chrome.webdriver import WebDriver
|
||||
from selenium.webdriver.edge.webdriver import WebDriver
|
||||
from selenium.webdriver.firefox.webdriver import WebDriver
|
||||
from selenium.webdriver.chrome.options import Options as ChromeOptions
|
||||
from selenium.webdriver.edge.options import Options as EdgeOptions
|
||||
from selenium.webdriver.firefox.options import Options as FirefoxOptions
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.remote.webelement import WebElement
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
|
||||
from util.localstorage import LocalStorage
|
||||
from util.qr import openQR,closeQR,qrIsVisible
|
||||
|
||||
testingSite = "http://192.168.56.3"
|
||||
testingName = "Selenium"
|
||||
testingEmail = "selenium@gochan.org#noko"
|
||||
testingMessage = "Hello, from Selenium!\n(driver is %s)"
|
||||
testingSubject = "Selenium post creation"
|
||||
testingUploadPath = "../../html/banned.png"
|
||||
testingPassword = "12345"
|
||||
testingBoard = "test"
|
||||
|
||||
browser = ""
|
||||
threadRE = re.compile('.*/(\S+)/(\d+)(\+50)?.html')
|
||||
|
||||
|
||||
def gotoPage(driver: WebDriver, page: str):
|
||||
driver.get(urljoin(testingSite, page))
|
||||
|
||||
def loginToStaff(driver: WebDriver, username = "admin", pw = "password"):
|
||||
gotoPage(driver, "manage")
|
||||
driver.find_element(by=By.NAME, value="username").send_keys(username)
|
||||
driver.find_element(by=By.NAME, value="password").send_keys(pw)
|
||||
driver.find_element(by=By.CSS_SELECTOR, value="input[value=Login]").click()
|
||||
|
||||
def sendPost(postForm:WebElement, name="", email="", subject="", message="", file=""):
|
||||
postForm.find_element(by=By.NAME, value="postname").send_keys(name)
|
||||
postForm.find_element(by=By.NAME, value="postemail").send_keys(email)
|
||||
postForm.find_element(by=By.NAME, value="postsubject").send_keys(subject)
|
||||
postForm.find_element(by=By.NAME, value="postmsg").send_keys(message)
|
||||
if file != "":
|
||||
postForm.find_element(by=By.NAME, value="imagefile").send_keys(file)
|
||||
postForm.find_element(by=By.CSS_SELECTOR, value="input[type=submit]").click()
|
||||
|
||||
class TestRunner(unittest.TestCase):
|
||||
def setUp(self):
|
||||
if browser == "firefox":
|
||||
options = FirefoxOptions()
|
||||
options.headless = True
|
||||
self.driver = webdriver.Firefox(options=options)
|
||||
elif browser == "chrome" or browser == "chromium":
|
||||
options = ChromeOptions()
|
||||
options.headless = True
|
||||
self.driver = webdriver.Chrome(options=options)
|
||||
else:
|
||||
self.fail("Unrecognized --browser option '%s'" % browser)
|
||||
print("Using browser %s on site %s" % (browser, testingSite))
|
||||
return super().setUp()
|
||||
|
||||
def test_qr(self):
|
||||
gotoPage(self.driver, testingBoard)
|
||||
self.assertIn("/test/ - Testing board", self.driver.title)
|
||||
elem = self.driver.find_element(by=By.ID, value="board-subtitle")
|
||||
self.assertIn("Board for testing stuff", elem.text)
|
||||
openQR(self.driver)
|
||||
self.assertTrue(qrIsVisible(self.driver), "Confirm that the QR box was properly opened")
|
||||
closeQR(self.driver)
|
||||
self.assertFalse(qrIsVisible(self.driver), "Confirm that the QR box was properly closed")
|
||||
|
||||
def test_localStorage(self):
|
||||
gotoPage(self.driver, testingBoard)
|
||||
localStorage = LocalStorage(self.driver)
|
||||
localStorage["foo"] = "bar"
|
||||
self.assertEqual(localStorage.get("foo"), "bar", "making sure that LocalStorage.get works")
|
||||
self.assertGreater(localStorage.__len__(), 0)
|
||||
|
||||
def test_staffLogin(self):
|
||||
loginToStaff(self.driver)
|
||||
self.assertEqual(
|
||||
self.driver.find_element(by=By.CSS_SELECTOR, value="header h1").text,
|
||||
"Dashboard",
|
||||
"Testing staff login"
|
||||
)
|
||||
|
||||
def test_makeThread(self):
|
||||
gotoPage(self.driver, testingBoard)
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
EC.element_to_be_clickable((By.CSS_SELECTOR, "form#postform input[type=submit]")))
|
||||
|
||||
valProp = self.driver.find_element(by=By.CSS_SELECTOR, value="form#postform input[type=submit]").get_property("value")
|
||||
self.assertEqual(valProp, "Post")
|
||||
form = self.driver.find_element(by=By.CSS_SELECTOR, value="form#postform")
|
||||
|
||||
sendPost(form,
|
||||
testingName,
|
||||
testingEmail,
|
||||
testingSubject,
|
||||
testingMessage % self.driver.name,
|
||||
path.abspath(testingUploadPath))
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
EC.url_matches(threadRE))
|
||||
threadID = threadRE.findall(self.driver.current_url)[0][1]
|
||||
self.driver.find_element(by=By.CSS_SELECTOR, value=("input#check%s"%threadID)).click()
|
||||
delPasswordInput = self.driver.find_element(by=By.CSS_SELECTOR, value="input#delete-password")
|
||||
val = delPasswordInput.get_attribute("value")
|
||||
if val == "" or val is None:
|
||||
val = testingPassword
|
||||
delPasswordInput.send_keys(testingPassword)
|
||||
cur_url = self.driver.current_url
|
||||
self.driver.find_element(by=By.CSS_SELECTOR, value="input[name=delete_btn]").click()
|
||||
self.driver.switch_to.alert.accept()
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
EC.url_changes(cur_url))
|
||||
self.assertNotIn("Error :c", self.driver.title, "No errors when we try to delete the post we just made")
|
||||
|
||||
def tearDown(self):
|
||||
self.driver.close()
|
||||
|
||||
return super().tearDown()
|
||||
|
54
devtools/selenium-testing/util/localstorage.py
Normal file
54
devtools/selenium-testing/util/localstorage.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
from selenium.webdriver.chrome.webdriver import WebDriver
|
||||
from selenium.webdriver.edge.webdriver import WebDriver
|
||||
from selenium.webdriver.firefox.webdriver import WebDriver
|
||||
|
||||
class LocalStorage():
|
||||
# from https://stackoverflow.com/a/46361900
|
||||
def __init__(self, driver: WebDriver):
|
||||
self.driver = driver
|
||||
|
||||
def __len__(self):
|
||||
return self.driver.execute_script("return window.localStorage.length;")
|
||||
|
||||
def items(self):
|
||||
return self.driver.execute_script( \
|
||||
"var ls = window.localStorage, items = {}; " \
|
||||
"for (var i = 0, k; i < ls.length; ++i) " \
|
||||
" items[k = ls.key(i)] = ls.getItem(k); " \
|
||||
"return items;")
|
||||
|
||||
def keys(self):
|
||||
return self.driver.execute_script("return Object.keys(window.localStorage);")
|
||||
|
||||
def get(self, key):
|
||||
return self.driver.execute_script("return window.localStorage.getItem(arguments[0]);", key)
|
||||
|
||||
def set(self, key, value):
|
||||
self.driver.execute_script("window.localStorage.setItem(arguments[0], arguments[1]);", key, value)
|
||||
|
||||
def has(self, key):
|
||||
return key in self.keys()
|
||||
|
||||
def remove(self, key):
|
||||
self.driver.execute_script("window.localStorage.removeItem(arguments[0]);", key)
|
||||
|
||||
def clear(self):
|
||||
self.driver.execute_script("window.localStorage.clear();")
|
||||
|
||||
def __getitem__(self, key) :
|
||||
value = self.get(key)
|
||||
if value is None :
|
||||
raise KeyError(key)
|
||||
return value
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.set(key, value)
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self.keys()
|
||||
|
||||
def __iter__(self):
|
||||
return self.items().__iter__()
|
||||
|
||||
def __repr__(self):
|
||||
return self.items().__str__()
|
44
devtools/selenium-testing/util/qr.py
Normal file
44
devtools/selenium-testing/util/qr.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
from selenium.webdriver.chrome.webdriver import WebDriver
|
||||
from selenium.webdriver.edge.webdriver import WebDriver
|
||||
from selenium.webdriver.firefox.webdriver import WebDriver
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
|
||||
def qrIsVisible(driver: WebDriver):
|
||||
try:
|
||||
return driver.find_element(by=By.CSS_SELECTOR, value="div#qr-box").is_displayed()
|
||||
except:
|
||||
return False
|
||||
|
||||
def enableQR(driver: WebDriver):
|
||||
topbar = driver.find_element(by=By.ID, value="topbar")
|
||||
topbar.click()
|
||||
topbar.find_element(by=By.CSS_SELECTOR, value="a#settings").click()
|
||||
useqr = driver.find_element(by=By.CSS_SELECTOR, value="input#useqr")
|
||||
if not useqr.is_selected():
|
||||
useqr.click()
|
||||
driver.find_element(by=By.CSS_SELECTOR, value="a.lightbox-x").click()
|
||||
|
||||
def disableQR(driver: WebDriver):
|
||||
topbar = driver.find_element(by=By.ID, value="topbar")
|
||||
topbar.click()
|
||||
topbar.find_element(by=By.CSS_SELECTOR, value="a#settings").click()
|
||||
useqr = driver.find_element(by=By.CSS_SELECTOR, value="input#useqr")
|
||||
if useqr.is_selected():
|
||||
useqr.click()
|
||||
driver.find_element(by=By.CSS_SELECTOR, value="a#lightbox-x").click()
|
||||
|
||||
def openQR(driver: WebDriver):
|
||||
enableQR(driver)
|
||||
if qrIsVisible(driver):
|
||||
return
|
||||
body = driver.find_element(by=By.CSS_SELECTOR, value="body")
|
||||
body.click()
|
||||
body.send_keys("q")
|
||||
|
||||
|
||||
def closeQR(driver: WebDriver):
|
||||
if not qrIsVisible(driver):
|
||||
return
|
||||
closeLink = driver.find_element(by=By.LINK_TEXT, value="X")
|
||||
driver.execute_script("arguments[0].click();", closeLink)
|
Loading…
Add table
Add a link
Reference in a new issue