Skip to content

Commit 1827acd

Browse files
Chapter 15: Unit tests with Selenium (15d)
1 parent 441abfb commit 1827acd

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

app/main/views.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@
99
from ..decorators import admin_required, permission_required
1010

1111

12+
@main.route('/shutdown')
13+
def server_shutdown():
14+
if not current_app.testing:
15+
abort(404)
16+
shutdown = request.environ.get('werkzeug.server.shutdown')
17+
if not shutdown:
18+
abort(500)
19+
shutdown()
20+
return 'Shutting down...'
21+
22+
1223
@main.route('/', methods=['GET', 'POST'])
1324
def index():
1425
form = PostForm()

requirements/dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ httpie==0.9.9
77
idna==2.5
88
Pygments==2.2.0
99
requests==2.18.2
10+
selenium==3.4.3
1011
urllib3==1.22

tests/test_selenium.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import re
2+
import threading
3+
import time
4+
import unittest
5+
from selenium import webdriver
6+
from app import create_app, db, fake
7+
from app.models import Role, User, Post
8+
9+
10+
class SeleniumTestCase(unittest.TestCase):
11+
client = None
12+
13+
@classmethod
14+
def setUpClass(cls):
15+
# start Chrome
16+
options = webdriver.ChromeOptions()
17+
options.add_argument('headless')
18+
try:
19+
cls.client = webdriver.Chrome(chrome_options=options)
20+
except:
21+
pass
22+
23+
# skip these tests if the browser could not be started
24+
if cls.client:
25+
# create the application
26+
cls.app = create_app('testing')
27+
cls.app_context = cls.app.app_context()
28+
cls.app_context.push()
29+
30+
# suppress logging to keep unittest output clean
31+
import logging
32+
logger = logging.getLogger('werkzeug')
33+
logger.setLevel("ERROR")
34+
35+
# create the database and populate with some fake data
36+
db.create_all()
37+
Role.insert_roles()
38+
fake.users(10)
39+
fake.posts(10)
40+
41+
# add an administrator user
42+
admin_role = Role.query.filter_by(name='Administrator').first()
43+
admin = User(email='john@example.com',
44+
username='john', password='cat',
45+
role=admin_role, confirmed=True)
46+
db.session.add(admin)
47+
db.session.commit()
48+
49+
# start the Flask server in a thread
50+
cls.server_thread = threading.Thread(target=cls.app.run,
51+
kwargs={'debug': False})
52+
cls.server_thread.start()
53+
54+
# give the server a second to ensure it is up
55+
time.sleep(1)
56+
57+
@classmethod
58+
def tearDownClass(cls):
59+
if cls.client:
60+
# stop the flask server and the browser
61+
cls.client.get('http://localhost:5000/shutdown')
62+
cls.client.quit()
63+
cls.server_thread.join()
64+
65+
# destroy database
66+
db.drop_all()
67+
db.session.remove()
68+
69+
# remove application context
70+
cls.app_context.pop()
71+
72+
def setUp(self):
73+
if not self.client:
74+
self.skipTest('Web browser not available')
75+
76+
def tearDown(self):
77+
pass
78+
79+
def test_admin_home_page(self):
80+
# navigate to home page
81+
self.client.get('http://localhost:5000/')
82+
self.assertTrue(re.search('Hello,\s+Stranger!',
83+
self.client.page_source))
84+
85+
# navigate to login page
86+
self.client.find_element_by_link_text('Log In').click()
87+
self.assertIn('<h1>Login</h1>', self.client.page_source)
88+
89+
# login
90+
self.client.find_element_by_name('email').\
91+
send_keys('john@example.com')
92+
self.client.find_element_by_name('password').send_keys('cat')
93+
self.client.find_element_by_name('submit').click()
94+
self.assertTrue(re.search('Hello,\s+john!', self.client.page_source))
95+
96+
# navigate to the user's profile page
97+
self.client.find_element_by_link_text('Profile').click()
98+
self.assertIn('<h1>john</h1>', self.client.page_source)

0 commit comments

Comments
 (0)