changeset 1782:f87d2e646c60

created a first selenium test, specifically of adding subitems to an item
author Hugh Perkins <hughperkins@gmail.com>
date Tue, 18 Sep 2012 21:29:28 +0800
parents 90eb2ea82c32
children d7ed70f19dc3
files _ui_tests/README.txt _ui_tests/config.py _ui_tests/conftest.py _ui_tests/driver_register.py _ui_tests/test_subitems.py _ui_tests/utils.py
diffstat 6 files changed, 234 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_ui_tests/README.txt	Tue Sep 18 21:29:28 2012 +0800
@@ -0,0 +1,62 @@
+Functional tests
+================
+
+Summary
+=======
+
+This directory contains functional tests, which directly test the ui, without
+needing access to the underlying code.
+
+These tests use selenium.
+
+Licensing issues
+----------------
+
+The selenium license is apache 2.0.  MoinMoin license is "GPL v2 or later".  
+GPL v2 license is currently considered by some to be incompatible with apache 
+2 license. GPL v3 is currently considered by many to be ok for use in 
+conjunction with apache 2 license.
+
+By separating the functional tests from the unit tests, we avoid having to 
+import selenium and MoinMoin in the same python runtime, which
+means that there should not be any licensing issues.
+
+Everything in this 'tests/functional' folder should be licensed "GPL v3 or 
+later", and not link to anything GPL v2.  Specifically, these tests should 
+not link with MoinMoin itself.
+
+Pre-requisites
+--------------
+
+- have activated the MoinMoin environment:
+      source env/bin/activate
+- have installed selenium:
+      pip install selenium
+- have installed firefox
+
+Instructions
+------------
+
+1. Open a terminal
+2. Change into the directory of this README
+3. Execute 'py.test -v -s'
+
+If any tests fail, screenshots will be generated in the current directory 
+with names corresponding to the test class name and method name.
+
+To run in the background
+------------------------
+
+Pre-requisite:
+- have installed xfvb
+
+1. Open a terminal
+2. Change into the directory of this README
+3. Execute 'xfvb-run py.test -v -s'
+
+Configuration
+-------------
+
+configuration is in 'config.py'.  You can define where your MoinMoin 
+installation is running, ie which URL.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_ui_tests/config.py	Tue Sep 18 21:29:28 2012 +0800
@@ -0,0 +1,6 @@
+# Copyright: 2012 MoinMoin:HughPerkins
+# License: GNU GPL v3 (or any later version), see LICENSE.txt for details.
+
+"""Contains global configuration for functional tests"""
+
+BASE_URL = "http://localhost:8080/"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_ui_tests/conftest.py	Tue Sep 18 21:29:28 2012 +0800
@@ -0,0 +1,30 @@
+# Copyright: 2012 MoinMoin:HughPerkins
+# License: GNU GPL v3 (or any later version), see LICENSE.txt for details.
+
+"""
+Contains events called by py.test during the life-cycle of the test suite
+This module is automatically loaded by py.test, which looks for a file
+of this name
+"""
+
+import os
+import sys
+sys.path.append(os.path.dirname(__file__))
+import driver_register
+
+def pytest_runtest_makereport(item, call):
+    """
+    Entry point for event which occurs after each test has run
+    The parameters are:
+    - item: the method called
+    - call: an object of type CallInfo, which has two properties, of which
+      excinfo contains info about any exception that got thrown by the method
+    This method is called automatically by py.test.  The name of the method
+    is used by py.test to locate it, and decide when to call it
+    This specific method instance is used to take a screenshot whenever a test
+    fails, ie whenever the method throws an exception
+    """
+    if call.excinfo is not None:
+        if driver_register.get_driver() is not None and hasattr(item, 'obj'):
+            driver_register.get_driver().get_screenshot_as_file(
+                unicode(item.obj).split(u" ")[2] + u'.png')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_ui_tests/driver_register.py	Tue Sep 18 21:29:28 2012 +0800
@@ -0,0 +1,24 @@
+# Copyright: 2012 MoinMoin:HughPerkins
+# License: GNU GPL v3 (or any later version), see LICENSE.txt for details.
+
+"""
+This module is used to register the webdriver driver module as a global
+variable, so that it can be used by conftest methods, eg for doing a
+printscreen when a test fails
+"""
+
+driver = None
+
+def register_driver(driver_):
+    """
+    set the driver global variable to driver_
+    """
+    global driver
+    driver = driver_
+
+def get_driver():
+    """
+    get the value of the driver global variable
+    """
+    global driver
+    return driver
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_ui_tests/test_subitems.py	Tue Sep 18 21:29:28 2012 +0800
@@ -0,0 +1,69 @@
+# Copyright: 2012 MoinMoin:HughPerkins
+# License: GNU GPL v3 (or any later version), see LICENSE.txt for details.
+
+"""Functional test: create subitem"""
+
+from selenium import webdriver
+
+import config
+import utils
+
+
+class TestSubitems(object):
+    """Functional test: create subitem"""
+
+    def setup_class(self):
+        """opens browser and creates some random item names for these tests"""
+        self.driver = utils.create_browser()
+        self.base_url = config.BASE_URL
+        self.base_item_name = u"page_" + utils.generate_random_word(5)
+        self.subitem_name = u"subitem_" + utils.generate_random_word(5)
+
+    def create_wiki_item(self, item_name):
+        """Creates a new wiki item with name 'item_name'"""
+        driver = self.driver
+
+        driver.get(self.base_url + u"/" + item_name)
+        driver.find_element_by_link_text(u"Default").click()
+        driver.find_element_by_link_text(u"Wiki (MoinMoin)").click()
+        driver.find_element_by_link_text(
+            u"create the item from scratch").click()
+        driver.find_element_by_id("f_content_form_data_text").send_keys(
+            u"This is a test item\n")
+        driver.find_element_by_id("f_submit").click()
+
+    def test_createsubitem(self):
+        """Test create subitem"""
+        driver = self.driver
+
+        self.create_wiki_item(self.base_item_name)
+
+        driver.get(self.base_url + u"/" + self.base_item_name)
+        driver.find_element_by_link_text(u"Modify").click()
+        driver.find_element_by_id(u"f_content_form_data_text").send_keys(
+            u"\n[[/" + self.subitem_name + "]]\n")
+        driver.find_element_by_id(u"f_submit").click()
+        driver.find_element_by_link_text(u"/" + self.subitem_name).click()
+        driver.find_element_by_link_text(u"Default").click()
+        driver.find_element_by_link_text(u"Wiki (MoinMoin)").click()
+        driver.find_element_by_link_text(u"create the item from scratch").click()
+        driver.find_element_by_id(u"f_content_form_data_text").send_keys(
+            u"This is a test subitem")
+        driver.find_element_by_id(u"f_submit").click()
+        assert u"This is a test subitem" in driver.find_element_by_id(
+            u"moin-content-data").text
+        assert driver.title.split(u" - ")[0] == self.base_item_name + \
+            u"/" + self.subitem_name
+
+    def teardown_class(self):
+        """shuts down browser"""
+        self.driver.quit()
+
+if __name__ == u'__main__':
+    # This lets us run the test directly, without using py.test
+    # This is useful for example for being able to call help, eg
+    # 'help(driver)', or 'help(driver.find_element_by_id("f_submit"))'
+    testSubitems = TestSubitems()
+    testSubitems.setup_class()
+    testSubitems.test_createsubitem()
+    testSubitems.teardown_class()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_ui_tests/utils.py	Tue Sep 18 21:29:28 2012 +0800
@@ -0,0 +1,43 @@
+# Copyright: 2012 MoinMoin:LiHaiyan
+# Copyright: 2012 MoinMoin:HughPerkins
+# License: GNU GPL v3 (or any later version), see LICENSE.txt for details.
+
+"""Functions to facilitate functional testing"""
+
+import random
+from selenium import webdriver
+import driver_register
+
+
+def create_browser():
+    """
+    Instantiates a firefox browser object, and configures it for English language
+    and registers it for screenshots, and sets the timeout
+    """
+    profile = webdriver.FirefoxProfile()
+    profile.set_preference("intl.accept_languages", "en")
+    driver = webdriver.Firefox(firefox_profile=profile)
+    driver_register.register_driver(driver) # register with
+    # driver_register, which is needed so that printscreen on test
+    # failure works
+    driver.implicitly_wait(20)
+    return driver
+
+
+def generate_random_word(length):
+    """
+    generates a random string containing numbers, of length 'length'
+    """
+    word = unicode(random.randint(10**(length-1), 10**length))
+    return word
+
+
+def generate_random_name(prefix, totallength):
+    """
+    create a random name, starting with 'prefix'
+    of total length 'totallength'
+    """
+    length = totallength - len(prefix)
+    numberword = generate_random_word(length)
+    name = prefix + numberword
+    return name