diff --git a/app/main/views.py b/app/main/views.py index e892d67e4..9c3c1e5ad 100644 --- a/app/main/views.py +++ b/app/main/views.py @@ -9,6 +9,17 @@ from ..decorators import admin_required, permission_required +@main.route('/shutdown') +def server_shutdown(): + if not current_app.testing: + abort(404) + shutdown = request.environ.get('werkzeug.server.shutdown') + if not shutdown: + abort(500) + shutdown() + return 'Shutting down...' + + @main.route('/', methods=['GET', 'POST']) def index(): form = PostForm() diff --git a/requirements/dev.txt b/requirements/dev.txt index 18e80ec73..393f41655 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -5,3 +5,4 @@ colorama==0.2.7 coverage==3.7.1 httpie==0.7.2 requests==2.1.0 +selenium==2.39.0 diff --git a/tests/test_selenium.py b/tests/test_selenium.py new file mode 100644 index 000000000..0ee3fcabc --- /dev/null +++ b/tests/test_selenium.py @@ -0,0 +1,89 @@ +import re +import threading +import unittest +from selenium import webdriver +from app import create_app, db +from app.models import Role, User, Post + + +class SeleniumTestCase(unittest.TestCase): + client = None + + @classmethod + def setUpClass(cls): + # start Firefox + try: + cls.client = webdriver.Firefox() + except: + pass + + # skip these tests if the browser could not be started + if cls.client: + # create the application + cls.app = create_app('testing') + cls.app_context = cls.app.app_context() + cls.app_context.push() + + # suppress logging to keep unittest output clean + import logging + logger = logging.getLogger('werkzeug') + logger.setLevel("ERROR") + + # create the database and populate with some fake data + db.create_all() + Role.insert_roles() + User.generate_fake(10) + Post.generate_fake(10) + + # add an administrator user + admin_role = Role.query.filter_by(permissions=0xff).first() + admin = User(email='john@example.com', + username='john', password='cat', + role=admin_role, confirmed=True) + db.session.add(admin) + db.session.commit() + + # start the Flask server in a thread + threading.Thread(target=cls.app.run).start() + + @classmethod + def tearDownClass(cls): + if cls.client: + # stop the flask server and the browser + cls.client.get('http://localhost:5000/shutdown') + cls.client.close() + + # destroy database + db.drop_all() + db.session.remove() + + # remove application context + cls.app_context.pop() + + def setUp(self): + if not self.client: + self.skipTest('Web browser not available') + + def tearDown(self): + pass + + def test_admin_home_page(self): + # navigate to home page + self.client.get('http://localhost:5000/') + self.assertTrue(re.search('Hello,\s+Stranger!', + self.client.page_source)) + + # navigate to login page + self.client.find_element_by_link_text('Log In').click() + self.assertTrue('

Login

' in self.client.page_source) + + # login + self.client.find_element_by_name('email').\ + send_keys('john@example.com') + self.client.find_element_by_name('password').send_keys('cat') + self.client.find_element_by_name('submit').click() + self.assertTrue(re.search('Hello,\s+john!', self.client.page_source)) + + # navigate to the user's profile page + self.client.find_element_by_link_text('Profile').click() + self.assertTrue('

john

' in self.client.page_source)