diff --git a/.gitignore b/.gitignore index 34e28e4..33f789d 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,8 @@ app/db/wordfreqapp.db app/static/donate-the-author.jpg app/static/donate-the-author-hidden.jpg app/model/__pycache__/ +app/test/__pycache__/ +app/test/.pytest_cache/ +app/test/pytest_report.html +app/test/assets app/log.txt diff --git a/README.md b/README.md index 77f25fa..15fc966 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,28 @@ We welcome feedback on EnglishPal. Feedback examples: EnglishPal's bugs and improvement suggestions are recorded in [Bugzilla](http://118.25.96.118/bugzilla/buglist.cgi?bug_status=__all__&list_id=1302&order=Importance&product=EnglishPal&query_format=specific). Send (lanhui at zjnu.edu.cn) an email message for opening a Bugzilla account or reporting a bug. +## End-to-end testing + +We use the Selenium test framework to test our app. + +In order to run the test, first we need to download a webdriver executable. + +Microsoft Edge's webdriver can be downloaded from [microsoft-edge-tools-webdriver](https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/). Make sure the version we download matches the version of the web browser installed on our laptop. + +After extracting the downloaded zip file (e.g., edgedriver_win64.zip), rename msedgedriver.exe to MicrosoftWebDriver.exe. + +Add MicrosoftWebDriver.exe's path to system's PATH variable. + +Install the following dependencies too: + +- pip install -U selenium==3.141.0 +- pip install -U urllib3==1.26.2 + +Run English Pal first, then run the test using pytest as follows: pytest --html=pytest_report.html test_add_word.py + +The above command will generate a HTML report file pytest_report.html after finishing executing test_add_word.py. Note: you need to install pytest-html package first: pip install pytest-html. + +You may also want to use [webdriver-manager](https://pypi.org/project/webdriver-manager/) from PyPI, so that you can avoid tediously installing a web driver executable manually. However, my experience shows that webdriver-manager is too slow. For example, it took me 16 minutes to run 9 tests, while with the pre-installed web driver executable, it took less than 2 minutes. ## TODO diff --git a/app/test/conftest.py b/app/test/conftest.py index 29f6431..ed4186c 100644 --- a/app/test/conftest.py +++ b/app/test/conftest.py @@ -1,6 +1,9 @@ import pytest +import sqlite3 +import time from selenium import webdriver -from selenium.webdriver.common.desired_capabilities import DesiredCapabilities + +from pathlib import Path @pytest.fixture def URL(): @@ -9,5 +12,24 @@ def URL(): @pytest.fixture def driver(): - my_driver = webdriver.Edge() # uncomment this line if you wish to run the test on your laptop - return my_driver + return webdriver.Edge() # follow the "End-to-end testing" section in README.md to install the web driver executable + + +@pytest.fixture +def restore_sqlite_database(): + ''' + Automatically restore SQLite database file app/db/wordfreqapp.db + using SQL statements from app/static/wordfreqapp.sql + ''' + con = sqlite3.connect('../db/wordfreqapp.db') + with con: + con.executescript('DROP TABLE IF EXISTS user;') + con.executescript('DROP TABLE IF EXISTS article;') + con.executescript(open('../static/wordfreqapp.sql', encoding='utf8').read()) + con.close() + + +@pytest.fixture(autouse=True) +def restart_englishpal(restore_sqlite_database): + (Path(__file__).parent / '../main.py').touch() + time.sleep(1) diff --git a/app/test/helper.py b/app/test/helper.py new file mode 100644 index 0000000..2b0deec --- /dev/null +++ b/app/test/helper.py @@ -0,0 +1,33 @@ +import uuid +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.common.exceptions import UnexpectedAlertPresentException, NoAlertPresentException + +def signup(URL, driver): + username = 'TestUser' + str(uuid.uuid1()).split('-')[0].title() + password = '[Abc+123]' + + driver.get(URL) + + elem = driver.find_element_by_link_text('注册') + elem.click() + + elem = driver.find_element_by_id('username') + elem.send_keys(username) + + elem = driver.find_element_by_id('password') + elem.send_keys(password) + + elem = driver.find_element_by_id('password2') + elem.send_keys(password) + + elem = driver.find_element_by_class_name('btn') # 找到"注册"按钮 + elem.click() + + try: + WebDriverWait(driver, 1).until(EC.alert_is_present()) + driver.switch_to.alert.accept() + except (UnexpectedAlertPresentException, NoAlertPresentException): + pass + + return username, password diff --git a/app/test/test_add_word.py b/app/test/test_add_word.py index a08c376..6526bf0 100644 --- a/app/test/test_add_word.py +++ b/app/test/test_add_word.py @@ -1,76 +1,31 @@ -# -*- coding: utf-8 -*- -# Run the docker image using the following command: -# docker run -d -p 4444:4444 selenium/standalone-chrome -from selenium import webdriver -from selenium.webdriver.common.desired_capabilities import DesiredCapabilities - -import random, time -import string - -driver = webdriver.Remote('http://localhost:4444/wd/hub', DesiredCapabilities.FIREFOX) -driver.implicitly_wait(10) - -HOME_PAGE = 'http://121.4.94.30:91/' +import time +from helper import signup -def has_punctuation(s): - return [c for c in s if c in string.punctuation] != [] - -def test_add_word(): +def test_add_word(URL, driver): try: - driver.get(HOME_PAGE) - assert 'English Pal -' in driver.page_source - - # login - elem = driver.find_element_by_link_text('登录') - elem.click() - - uname = 'lanhui' - password = 'l0ve1t' - elem = driver.find_element_by_name('username') - elem.send_keys(uname) - - elem = driver.find_element_by_name('password') - elem.send_keys(password) - - elem = driver.find_element_by_xpath('//form[1]/p[3]/input[1]') # 找到登录按钮 - elem.click() - - assert 'EnglishPal Study Room for ' + uname in driver.title - - # get essay content - elem = driver.find_element_by_id('text-content') - essay_content = elem.text - - elem = driver.find_element_by_id('selected-words') - word = random.choice(essay_content.split()) - while 'font>' in word or 'br>' in word or 'p>' in word or len(word) < 6 or has_punctuation(word): - word = random.choice(essay_content.split()) + username, password = signup(URL, driver) # sign up a new account and automatically log in + time.sleep(1) + # enter the word in the text area + elem = driver.find_element_by_id('selected-words') + word = 'devour' elem.send_keys(word) - elem = driver.find_element_by_xpath('//form[1]//input[1]') # 找到get所有词频按钮 - elem.click() - - elems = driver.find_elements_by_xpath("//input[@type='checkbox']") - for elem in elems: - if elem.get_attribute('name') == 'marked': - elem.click() - - elem = driver.find_element_by_name('add-btn') # 找到加入我的生词簿按钮 + elem = driver.find_element_by_xpath('//form[1]//button[1]') # 找到"把生词加入我的生词库"按钮 + elem.click() + + elem = driver.find_element_by_name('add-btn') # 找到"加入我的生词簿"按钮 elem.click() - driver.refresh() - driver.refresh() - driver.refresh() elems = driver.find_elements_by_xpath("//p[@class='new-word']/a") - + found = 0 for elem in elems: if word in elem.text: found = 1 break - + assert found == 1 - finally: + finally: driver.quit()