Selenium/PHP/Selenium Framework

Purpose
SeleniumFramework provides a standardised way of writing Selenium tests for MediaWiki and its extensions. It is based on PHPUnit tests.

Set up the environment
In order to work properly, the framework builds on some external dependencies:
 * You need to set up a Selenium server, either Selenium RC or Selenium Grid
 * The PEAR PHPUnit 3.4 library must be accessible within your PHP path
 * Also, PEAR Testing_Selenium must be accessible within your PHP path

Enable Selenium on your test Wiki
Set the following in your test wiki's LocalSettings.php:

The tests runner is a maintenance script maintenance/tests/RunSeleniumTests.php The next sections cover how you can tell the test runner about your selenium environment.

Configure Selenium using a configuration file
php RunSeleniumTests.php --seleniumConfig=../../selenium_settings.ini Using Selenium Configuration file: ../../selenium_settings.ini .... php RunSeleniumTests.php No command line configuration file or configuration hook found. ....
 * The easiest way is to point the test runner to your selenium configuration file through the command line option.
 * If the --seleniumConfig option is not found and in the absense of a hook, it looks for a global variable $wgSeleniumConfigFile that you can set in your LocalSettings.php

A sample configuration is checked into maintenance/tests/selenium/selenium_settings.ini.sample [SeleniumSettings]

browsers[firefox] 	= "*firefox" browsers[iexplorer] = "*iexploreproxy" browsers[chrome] 	= "*chrome"
 * Set up the available browsers that Selenium can control.


 * The simple configurations above usually work on Linux, but Windows and
 * Mac OS X hosts may need to specify a full path:
 * browsers[firefox] = "*firefox /Applications/Firefox.app/Contents/MacOS/firefox-bin"
 * browsers[firefox] = "*firefox C:\Program Files\Mozilla Firefox\firefox.exe"

host 				= "localhost" port 				= "4444" wikiUrl 			= "http://localhost/deployment" username 			= "wikiuser" userPassword 		= "wikipass" testBrowser 		= "firefox" startserver			= stopserver			= jUnitLogFile		=

seleniumserverexecpath = "/opt/local/selenium-remote-control-1.0.3/selenium-server-1.0.3/selenium-server.jar"
 * To let the test runner start and stop the selenium server, it needs the full
 * path to selenium-server.jar from the selenium-remote-control package.

[SeleniumTests]

testSuite[SimpleSeleniumTestSuite] = "maintenance/tests/selenium/SimpleSeleniumTestSuite.php" testSuite[PagedTiffHandlerSeleniumTestSuite] = "extensions/PagedTiffHandler/selenium/PagedTiffHandlerTestSuite.php"

Configure Selenium using command line parameters (This may go away soon)
You can override parameters from the configuration file or the hook function using command line paranteres: Usage: php RunSeleniumTests.php [--conf|--help|--host|--list-browsers|--port|--quiet|--seleniumConfig|--testBrowser|--userPassword|--username|--verbose|--wikiUrl] conf : Location of LocalSettings.php, if not default help : Display this help message host : Host selenium server. Default: $wgServer. $wgScriptPath list-browsers : List the available browsers. port : Port used by selenium server. Default: 4444 quiet : Whether to supress non-error output seleniumConfig : Location of the selenium config file. Default: empty testBrowser : The browser he used during testing. Default: firefox userPassword : The login password for running tests. Default: empty username : The login username for sunning tests. Default: empty verbose : Be noisier. wikiUrl : The Mediawiki installation to point to. Default: http://localhost

For example: php RunSeleniumTests.php --wikiUrl='http://localhost/deployment' --username='WikiSysop' --userPassword='xxxxxx'

Configure Selenium using a Hook function
Another way to configure your selenium test instance is through a Hook - SeleniumSettings. You will need to add MyCustomSeleniumTestConfigStatic to the AutoLoader or your LocalSettings.php.

The 3 required parameters passed by reference are:
 * $seleniumSettings: An array containing the selenium configuration parameters as key value pairs> Possible keys are:
 * $seleniumBrowsers: Browsers available to the selenium server. For example:
 * $seleniumTestSuites: Path to the test suites that the test runner will run. For example:

Writing tests

 * In order to add a Selenium test, you have to create a test suite that extends SeleniumTestSuite. For example look at maintenance/tests/selenium/SimpleSeleniumTestSuite.php
 * You have to implement the function addTests to add your test cases to the suite. You can override setUp and tearDown as required.
 * Then create as many test cases as you need and make them extend SeleniumTestCase. You can override setUp and tearDown as required.

Examples
[SeleniumTests] testSuite[SimpleSeleniumTestSuite] = "maintenance/tests/selenium/SimpleSeleniumTestSuite.php"
 * For a very basic sample test suite and test case look in maintenance/tests/selenium/SimpleSeleniumTestSuite.php and maintenance/tests/selenium/SimpleSeleniumTestCase.php
 * You will need the following in the selenium_settings.ini file to run these tests
 * A working example can also be found at the PagedTiffHandler extension.

Test Wiki configuration
Multiple test suites that need different wiki configurations are run against a single test wiki.

Requirements

 * The test wiki should have a default configuration. This is the state that test suites should assume for a test wiki before setUp is called.
 * Each test suite needs to tell the test wiki what configuration it needs. This may be
 * files to be included for an extension
 * global configuration variables
 * Could also be used to switch out the db and images directory.
 * (Do we need more fine grained control, like per test instead of per test suite?)


 * At the end of a test suite, the wiki needs to go back to its original default configuration.

Missing

 * Concurrent test suites point to the same wiki
 * Whether this will work to change the db and images directory for the test wiki.
 * If any extensions do custom configuration that is not an include or a global config variable.

Implementation details
Test suite: Test wiki: The following happens in WebStart.php only if a global variable $wgEnableSelenium is set.
 * The test suite's setUp makes a request to the test wiki with a request parameter whose value is the test suite name.
 * After this the test can assume that the the test wiki is configured correctly for this test suite.
 * The test suite's tearDown sends another request parameter which will tell the test wiki to do back to using the default configuration.


 * If request param setupTestSuite is set
 * set a cookie containing the test suite name
 * cookie is set to expire in 10 mins (Should this be configurable)


 * If request param clearTestSuite is set
 * clear the cookie containing the test suite name
 * If we find our testSuiteName cookie
 * Look for a global variable $wgSeleniumTestConfigs[testSuiteName]. If found, this is the test suite's function that is responsible for providing the following.
 * the test specific include files
 * the test specific globals (key value pairs)


 * $wgSeleniumTestConfigs[testSuiteName] needs to be set in LocalSettings.php. The reason this is not a done via a hook is because this configuration needs to happen before Setup.php.

Test wiki configuration example: As an example see extensions/WikiEditor/tests/selenium
 * In the case that it finds neither of the request params mentioned above nor the cookie, the Setup will proceed as usual with only the default configuration.
 * LocalSettings.php should contain
 * WikiEditorSeleniumConfig::getSettings returns an array of include files and configuration variables needed by the extension.
 * If a cookie has been set, indicating this is part of the WikiEditorTestSuite test run, we use the configuration we get from WikiEditorSeleniumConfig::getSettings

Architecture
These files are part of the framework:
 * RunSeleniumTests.php includes test suites specified in extension directories.
 * selenium/Selenium.php provides access to selenium and implements common tasks.
 * selenium/SeleniumLoader.php loads all the neccessary classes for the framework.
 * selenium/SeleniumTestSuite.php starts and stops selenium tests.
 * selenium/SeleniumTestCase.php provides some additional assertions.
 * selenium/SeleniumTestListerner.php is the interface to result logging.
 * selenium/SeleniumConsoleLogger.php and selenium/SeleniumHTMLLogger.php produce the actual output.
 * selenium/SimpleSeleniumTestSuite.php and selenium/SimpleSeleniumTestSuite.php provide an example test case.
 * Individual tests are located with the extensions in the directory selenium.

The tests should be located here:
 * Tests for core should be placed in the maintenance/tests/selenium folder
 * Extensions that do mirror the mw directory structure (like SMW) should place the tests similar to mw: extensions/EXTENSION/maintenance/tests/selenium
 * Extensions that don't should place the tests in extensions/EXTENSION/tests/selenium

Testing with a clean database and file state
testrunner                    wiki under test --                    --- 1.1 start selenium which in turn starts a browser to talk to the wiki under test 1.2 send request for new test with unique test id and tests that will be fired 2.1 create cookie with test id                              2.2 create temporal resources according to tests list 2.3 create test tracker with timestamp 2.4 return success code 3.1 start testsuites via selenium 3.2 send a lot of individual requests according to the tests 4.1 testrunner is identified by test id                              4.2 reconfigure database and resources according to test id                              4.3 ? Do something with memcached ? 4.4 execute request 4.5 update timestamp in test tracker 5.1 send a teardown request 6.1 execute teardown, i.e. delete all resources associated with test id                              6.2 delete test tracker 6.3 return success code 7.1 stop selenium

Test styleguides

 * A test should leave at best no traces in the wiki.
 * If this is not possible, the test should leave the wiki in a state which allows the test to be re-run.

Add common test tasks
Please add to this list...
 * Trigger user preferences
 * Edit a page (initial support already implemented)
 * Upload images (already in PagedTiffHandler tests)
 * Show edit and history mode
 * Revert pages

Add common assertions
Please add to this list
 * Text within an article
 * Text in Headlines
 * Text in Table of Contents
 * Error messages

Improvements

 * Make test result logging more talkative
 * Check prerequisites of MediaWiki configuration (initial support in PagedTiffHandler tests)
 * Find a way to execute selenes recorded via Selenium IDE
 * Refactor naming conventions
 * Ways to configure the wiki for specific test suites or extensions.
 * A way to bring the database to a clean initial state before each test
 * Use the mediawiki extension to write collaborative Selenium tests

Further ideas
A test (or a single test suite) should be able to reconfigure the wiki according to its needs. Here, some serious security issues arise. This might be a possible way: If the hook is not triggered in LocalSettings, no reconfiguration can take place.
 * Add a hook 'LocalSettingsEnd' at the end of LocalSettings.php
 * Add some URL parameter which indicates which test is being run
 * Within the extension, the hook code now changes the configuration

Error about Testing_Selenium (0.4.3 is installed from pear along with PHPUnit) not being found

 * Replace /PEAR/ by the actual path to the repository

General Tips

 * Ignore port A proxy time you out port 4444.
 * Uncomment any tests in RunSeleniumTests.php to run different test suites?

Experiences: Recent changes in handling of framework

 * PEAR PHPUnit 3.4 and PEAR Testing_Selenium: Check whether properly installed, esp. PHPUnit/Framework.php
 * Installation of selenium-rc is pretty easy:
 * Download selenium rc
 * start "java -jar selenium-server.jar"