Difference between revisions of "Extension:Selenium.php"
(rv, htmlspecialchars also escapes the table tags rendering source) |
(Documentation changes) |
||
Line 7: | Line 7: | ||
* - Author: http://www.organicdesign.co.nz/User:Sven (M Davy) | * - Author: http://www.organicdesign.co.nz/User:Sven (M Davy) | ||
*/ | */ | ||
− | + | ||
if (!defined('MEDIAWIKI')) die('Not an entry point.'); | if (!defined('MEDIAWIKI')) die('Not an entry point.'); | ||
define('SELENIUM_VERSION','0.7.6, 2007-1-09, selenium-core 0.8.3'); | define('SELENIUM_VERSION','0.7.6, 2007-1-09, selenium-core 0.8.3'); | ||
− | + | ||
$egSeleniumTag = "selenium"; | $egSeleniumTag = "selenium"; | ||
$egSeleniumPath = "/wiki/extensions/Selenium/selenium-core-0/core/TestRunner.html"; | $egSeleniumPath = "/wiki/extensions/Selenium/selenium-core-0/core/TestRunner.html"; | ||
Line 17: | Line 17: | ||
$egSeleniumCategory = "Selenium"; | $egSeleniumCategory = "Selenium"; | ||
$egSeleniumNamespace = ""; | $egSeleniumNamespace = ""; | ||
− | + | ||
/** | /** | ||
* http://www.mediawiki.org/wiki/Manual:Special_pages | * http://www.mediawiki.org/wiki/Manual:Special_pages | ||
* $wgSpecialPages['Selenium'] = 'Selenium'; | * $wgSpecialPages['Selenium'] = 'Selenium'; | ||
*/ | */ | ||
− | + | ||
$wgExtensionFunctions[] = 'efSetupSelenium'; | $wgExtensionFunctions[] = 'efSetupSelenium'; | ||
$wgHooks['LanguageGetMagic'][] = 'efSeleniumLanguageGetMagic'; | $wgHooks['LanguageGetMagic'][] = 'efSeleniumLanguageGetMagic'; | ||
− | + | ||
$wgExtensionCredits['specialpage'][] = array( | $wgExtensionCredits['specialpage'][] = array( | ||
'name' => 'Special:Selenium', | 'name' => 'Special:Selenium', | ||
− | 'author' => '[http://www.organicdesign.co.nz/User:Sven | + | 'author' => '[http://www.organicdesign.co.nz/User:Sven Sven (M Davy)]', |
'description' => 'Incorporating Selenium tests into the MediaWiki environment', | 'description' => 'Incorporating Selenium tests into the MediaWiki environment', | ||
'url' => 'http://www.organicdesign.co.nz/Extension:Selenium.php', | 'url' => 'http://www.organicdesign.co.nz/Extension:Selenium.php', | ||
'version' => SELENIUM_VERSION | 'version' => SELENIUM_VERSION | ||
); | ); | ||
− | + | ||
require_once "$IP/includes/SpecialPage.php"; | require_once "$IP/includes/SpecialPage.php"; | ||
+ | |||
+ | # Define the seleium tag class | ||
+ | class Selenium { | ||
+ | # Properties | ||
− | + | ||
− | |||
− | |||
# Constructor | # Constructor | ||
function __construct() { | function __construct() { | ||
global $wgHooks,$wgParser,$egSeleniumTag; | global $wgHooks,$wgParser,$egSeleniumTag; | ||
− | + | ||
# Add the tagHook | # Add the tagHook | ||
$wgParser->setHook($egSeleniumTag,array($this,'tagSelenium')); | $wgParser->setHook($egSeleniumTag,array($this,'tagSelenium')); | ||
} | } | ||
− | + | ||
# Deploy tags to allow additional html table tags | # Deploy tags to allow additional html table tags | ||
public function tagSelenium($text,$argv,&$parser) { | public function tagSelenium($text,$argv,&$parser) { | ||
Line 55: | Line 57: | ||
* $text = $parser->preprocess($text,$wgTitle,$parser->mOptions); | * $text = $parser->preprocess($text,$wgTitle,$parser->mOptions); | ||
*/ | */ | ||
− | + | ||
− | + | /** | |
+ | * Want the Selenium tag to strip out <html>...</html> enclosing tags | ||
+ | * It currently removes everything around the first <table...</table> tags found | ||
+ | */ | ||
+ | |||
$text = eregi_replace('<html>.+<table', '<div class="selenium"><table', $text); | $text = eregi_replace('<html>.+<table', '<div class="selenium"><table', $text); | ||
$text = eregi_replace('</table>.+', '</table></div>', $text); | $text = eregi_replace('</table>.+', '</table></div>', $text); | ||
− | + | # Automatically create category as specified in $egSeleniumCategory | |
− | # | ||
if($egSeleniumCategory) { | if($egSeleniumCategory) { | ||
$this->magicCategory($parser, $egSeleniumCategory, $sortkey = ''); | $this->magicCategory($parser, $egSeleniumCategory, $sortkey = ''); | ||
} | } | ||
+ | |||
+ | # We have not run htmlspecialchars to minimize cross-site scripting vulnerabilities | ||
return($text); | return($text); | ||
} | } | ||
− | + | ||
# Expand the category-magic to nothing and parse separately as normal category links | # Expand the category-magic to nothing and parse separately as normal category links | ||
private function magicCategory(&$parser,$cat,$sortkey = '') { | private function magicCategory(&$parser,$cat,$sortkey = '') { | ||
Line 74: | Line 81: | ||
return ''; | return ''; | ||
} | } | ||
− | + | ||
− | + | ||
# Needed in some versions to prevent Special:Version from breaking | # Needed in some versions to prevent Special:Version from breaking | ||
private function __toString() { return 'Selenium'; } | private function __toString() { return 'Selenium'; } | ||
} | } | ||
− | + | ||
− | + | ||
# Define a new class based on the SpecialPage class | # Define a new class based on the SpecialPage class | ||
class SpecialSelenium extends SpecialPage { | class SpecialSelenium extends SpecialPage { | ||
− | + | ||
/** | /** | ||
* Need a global for the location of Selenium | * Need a global for the location of Selenium | ||
*/ | */ | ||
− | + | ||
# Properties | # Properties | ||
var $suite = array( | var $suite = array( | ||
Line 93: | Line 100: | ||
'footer' => "\n</tbody></table></body></html>" | 'footer' => "\n</tbody></table></body></html>" | ||
); | ); | ||
− | + | ||
# Constructor | # Constructor | ||
function __construct() { | function __construct() { | ||
− | + | ||
SpecialPage::SpecialPage( | SpecialPage::SpecialPage( | ||
'Selenium', # name as seen in links etc | 'Selenium', # name as seen in links etc | ||
Line 106: | Line 113: | ||
); | ); | ||
} | } | ||
− | + | ||
/** | /** | ||
* -------------------- Create form for Special:Selenium -------------------- | * -------------------- Create form for Special:Selenium -------------------- | ||
Line 113: | Line 120: | ||
public function execute() { | public function execute() { | ||
global $wgOut, $wgParser, $wgRequest, $egResultsUrlPath; | global $wgOut, $wgParser, $wgRequest, $egResultsUrlPath; | ||
− | + | ||
# Process suite or test if ?suite=article_name in query string | # Process suite or test if ?suite=article_name in query string | ||
if($wgRequest->getText('suite')) { | if($wgRequest->getText('suite')) { | ||
# Grab article $param and process contents | # Grab article $param and process contents | ||
$suiteTitle = Title::newFromText($wgRequest->getText('suite')); | $suiteTitle = Title::newFromText($wgRequest->getText('suite')); | ||
− | + | ||
# print $suiteTitle; | # print $suiteTitle; | ||
# print $suiteTitle->getText(); | # print $suiteTitle->getText(); | ||
# print $wgRequest->getText('suite'); | # print $wgRequest->getText('suite'); | ||
− | + | ||
$wikitext = $this->fetchContents($suiteTitle); | $wikitext = $this->fetchContents($suiteTitle); | ||
# Expanding braces of any transcluded tests | # Expanding braces of any transcluded tests | ||
$wikitext = $wgParser->preprocess($wikitext,$suiteTitle,new ParserOptions()); | $wikitext = $wgParser->preprocess($wikitext,$suiteTitle,new ParserOptions()); | ||
− | + | ||
# Preparse encapsulations around Selenium tags e.g. <nowiki><selenium></nowiki> | # Preparse encapsulations around Selenium tags e.g. <nowiki><selenium></nowiki> | ||
− | $wikitext = preg_replace("|<nowiki></?selenium></nowiki>|", "<nowiki> | + | $wikitext = preg_replace("|<nowiki></?selenium></nowiki>|", "<nowiki><selenium></nowiki>", $wikitext); |
− | + | ||
$matches = array(); | $matches = array(); | ||
if(! $this->articleRegex($wikitext, $matches)) { | if(! $this->articleRegex($wikitext, $matches)) { | ||
Line 153: | Line 160: | ||
} | } | ||
} else { | } else { | ||
− | + | ||
# Obtain suite section headers | # Obtain suite section headers | ||
$suite_urls = array(); | $suite_urls = array(); | ||
Line 166: | Line 173: | ||
# Retrieve articles in category labelled $egSeleniumCategory | # Retrieve articles in category labelled $egSeleniumCategory | ||
$list = $this->categoryArticles($egSeleniumCategory); | $list = $this->categoryArticles($egSeleniumCategory); | ||
− | + | ||
# Grab article $param and process contents | # Grab article $param and process contents | ||
$suites = array(); | $suites = array(); | ||
Line 172: | Line 179: | ||
$suiteTitle = Title::newFromText($articleName); | $suiteTitle = Title::newFromText($articleName); | ||
$wikitext = $this->fetchContents($suiteTitle); | $wikitext = $this->fetchContents($suiteTitle); | ||
− | + | ||
if( $this->articleRegex($wikitext, $matches) ) { | if( $this->articleRegex($wikitext, $matches) ) { | ||
$suites[] = $articleName; | $suites[] = $articleName; | ||
Line 182: | Line 189: | ||
} | } | ||
$selectTag .= '</select>'; | $selectTag .= '</select>'; | ||
− | + | ||
$this->setHeaders(); | $this->setHeaders(); | ||
$title = Title::makeTitle(NS_SPECIAL,'Selenium'); | $title = Title::makeTitle(NS_SPECIAL,'Selenium'); | ||
− | + | ||
global $egSeleniumPath, $egSpecialPath; | global $egSeleniumPath, $egSpecialPath; | ||
$path = "$egSeleniumPath?test=" . urlencode($egSpecialPath); | $path = "$egSeleniumPath?test=" . urlencode($egSpecialPath); | ||
− | + | ||
$form = wfElement('form',array('action' => $title->getLocalURL('action=submit'),'method' => 'post'),null); | $form = wfElement('form',array('action' => $title->getLocalURL('action=submit'),'method' => 'post'),null); | ||
$form .= '<fieldset><legend>Select a suite to run</legend>'; | $form .= '<fieldset><legend>Select a suite to run</legend>'; | ||
Line 195: | Line 202: | ||
$form .= "<br /><br />" . wfCheckLabel("Run automatically","wfRunAuto" , "wfRunAuto",$checked = false); | $form .= "<br /><br />" . wfCheckLabel("Run automatically","wfRunAuto" , "wfRunAuto",$checked = false); | ||
$form .= '</fieldset></form>'; | $form .= '</fieldset></form>'; | ||
− | + | ||
$wgOut->addHTML($form); | $wgOut->addHTML($form); | ||
− | + | ||
if($wgRequest->getText('action')) { | if($wgRequest->getText('action')) { | ||
# foreach($_REQUEST as $key=>$value) { | # foreach($_REQUEST as $key=>$value) { | ||
Line 203: | Line 210: | ||
# } | # } | ||
$path .= urlencode($wgRequest->getText('selenium')); | $path .= urlencode($wgRequest->getText('selenium')); | ||
− | + | ||
if($wgRequest->getBool('wfRunAuto')) { | if($wgRequest->getBool('wfRunAuto')) { | ||
$path .= "&auto=true&resultsUrl=$egResultsUrlPath"; | $path .= "&auto=true&resultsUrl=$egResultsUrlPath"; | ||
} | } | ||
− | + | ||
$form_link = '<fieldset><legend>Click link to run selenium-core</legend>'; | $form_link = '<fieldset><legend>Click link to run selenium-core</legend>'; | ||
$form_link .= "<a href=\"$path\">" . $wgRequest->getText('selenium') . '</a></fieldset>'; | $form_link .= "<a href=\"$path\">" . $wgRequest->getText('selenium') . '</a></fieldset>'; | ||
Line 214: | Line 221: | ||
} | } | ||
} | } | ||
− | + | ||
private function categoryArticles($category) { | private function categoryArticles($category) { | ||
$list = array(); | $list = array(); | ||
Line 225: | Line 232: | ||
return($list); | return($list); | ||
} | } | ||
− | + | ||
private function fetchContents($title) { | private function fetchContents($title) { | ||
$article = new Article($title); | $article = new Article($title); | ||
Line 231: | Line 238: | ||
return($contents); | return($contents); | ||
} | } | ||
− | + | ||
private function articleRegex(&$wikitext,&$matches) { | private function articleRegex(&$wikitext,&$matches) { | ||
$count = preg_match_all('|^={2,}\s*([^\#\<\>\[\]\|\{\}\n]+?)\s*={2,}(.+?</selenium>)|ms',$wikitext,$matches); | $count = preg_match_all('|^={2,}\s*([^\#\<\>\[\]\|\{\}\n]+?)\s*={2,}(.+?</selenium>)|ms',$wikitext,$matches); | ||
return($count); | return($count); | ||
} | } | ||
− | + | ||
# Method to bypass $wgOut -must be called early to avoid conflict with other extensions | # Method to bypass $wgOut -must be called early to avoid conflict with other extensions | ||
static function disableHTML(&$wgOut) { | static function disableHTML(&$wgOut) { | ||
Line 243: | Line 250: | ||
return; | return; | ||
} | } | ||
− | + | ||
# Method to generate 404 error | # Method to generate 404 error | ||
private function build404($message) { | private function build404($message) { | ||
Line 252: | Line 259: | ||
return; | return; | ||
} | } | ||
− | + | ||
# Method to build a suite from an array of tests | # Method to build a suite from an array of tests | ||
private function buildSuite($tests, $article) { | private function buildSuite($tests, $article) { | ||
− | + | ||
$html = $this->suite['header']; | $html = $this->suite['header']; | ||
$html .= "<tr><td><b>$article</b></td></tr>"; | $html .= "<tr><td><b>$article</b></td></tr>"; | ||
Line 265: | Line 272: | ||
} | } | ||
} | } | ||
− | + | ||
# Called from $wgExtensionFunctions array when initialising extensions | # Called from $wgExtensionFunctions array when initialising extensions | ||
function efSetupSelenium() { | function efSetupSelenium() { | ||
Line 274: | Line 281: | ||
SpecialSelenium::disableHTML($wgOut); | SpecialSelenium::disableHTML($wgOut); | ||
} | } | ||
− | + | ||
global $egSelenium, $wgLanguageCode, $wgMessageCache; | global $egSelenium, $wgLanguageCode, $wgMessageCache; | ||
$egSelenium = new Selenium(); | $egSelenium = new Selenium(); | ||
− | + | ||
# Add the messages used by the specialpage | # Add the messages used by the specialpage | ||
if ($wgLanguageCode == 'en') { | if ($wgLanguageCode == 'en') { | ||
Line 284: | Line 291: | ||
)); | )); | ||
} | } | ||
− | + | ||
# Add the specialpage to the environment | # Add the specialpage to the environment | ||
SpecialPage::addPage(new SpecialSelenium()); | SpecialPage::addPage(new SpecialSelenium()); | ||
} | } | ||
− | + | ||
# Needed in MediaWiki >1.8.0 for magic word hooks to work properly | # Needed in MediaWiki >1.8.0 for magic word hooks to work properly | ||
function efSeleniumLanguageGetMagic(&$magicWords,$langCode = 0) { | function efSeleniumLanguageGetMagic(&$magicWords,$langCode = 0) { |
Revision as of 03:12, 15 April 2008
<?php
/** * Extension:Selenium Template:Php
Category:Extensions in progress
* Category:SeleniumCategory:Extensions created with Template:SpecialPage * - Licenced under LGPL http://www.gnu.org/copyleft/lesser.html * - Author: http://www.organicdesign.co.nz/User:Sven (M Davy) */
if (!defined('MEDIAWIKI')) die('Not an entry point.'); define('SELENIUM_VERSION','0.7.6, 2007-1-09, selenium-core 0.8.3');
$egSeleniumTag = "selenium"; $egSeleniumPath = "/wiki/extensions/Selenium/selenium-core-0/core/TestRunner.html"; $egResultsUrlPath = "../../tmp/results.php"; $egSpecialPath = "/wiki/index.php?title=Special:Selenium&suite="; $egSeleniumCategory = "Selenium"; $egSeleniumNamespace = "";
/**
* http://www.mediawiki.org/wiki/Manual:Special_pages * $wgSpecialPages['Selenium'] = 'Selenium'; */
$wgExtensionFunctions[] = 'efSetupSelenium'; $wgHooks['LanguageGetMagic'][] = 'efSeleniumLanguageGetMagic';
$wgExtensionCredits['specialpage'][] = array( 'name' => 'Special:Selenium', 'author' => 'Sven (M Davy)', 'description' => 'Incorporating Selenium tests into the MediaWiki environment', 'url' => 'http://www.organicdesign.co.nz/Extension:Selenium.php', 'version' => SELENIUM_VERSION );
require_once "$IP/includes/SpecialPage.php";
- Define the seleium tag class
class Selenium {
- Properties
- Constructor
function __construct() { global $wgHooks,$wgParser,$egSeleniumTag;
- Add the tagHook
$wgParser->setHook($egSeleniumTag,array($this,'tagSelenium')); }
- Deploy tags to allow additional html table tags
public function tagSelenium($text,$argv,&$parser) { global $wgTitle, $egSeleniumCategory; /** * Should be a preprocess using first stage of parser * $text = $parser->preprocess($text,$wgTitle,$parser->mOptions); */
/** * Want the Selenium tag to strip out ... enclosing tags
* It currently removes everything around the first <table... tags found
*/
$text = eregi_replace('.+
);
- Constructor
function __construct() { SpecialPage::SpecialPage(
'Selenium', # name as seen in links etc , # user rights required true, # listed in special:specialpages false, # function called by execute() - defaults to wfSpecial{$name} false, # file included by execute() - defaults to Special{$name}.php, only used if no function false # includable );
} /** * -------------------- Create form for Special:Selenium -------------------- * Override SpecialPage::execute() */ public function execute() { global $wgOut, $wgParser, $wgRequest, $egResultsUrlPath;
- Process suite or test if ?suite=article_name in query string
if($wgRequest->getText('suite')) {
- Grab article $param and process contents
$suiteTitle = Title::newFromText($wgRequest->getText('suite'));
- print $suiteTitle;
- print $suiteTitle->getText();
- print $wgRequest->getText('suite');
$wikitext = $this->fetchContents($suiteTitle);
- Expanding braces of any transcluded tests
$wikitext = $wgParser->preprocess($wikitext,$suiteTitle,new ParserOptions());
- Preparse encapsulations around Selenium tags e.g. <selenium>
$wikitext = preg_replace("|</?selenium>|", "<selenium>", $wikitext); $matches = array(); if(! $this->articleRegex($wikitext, $matches)) {
$this -> build404('Specified suite contains no selenium test tags');
} else {
- Determine whether suite or test from ?suite=article_name&test=section_num in query string
if($wgRequest->getText('test')) {
- Grab name of test
$testTitle = Title::newFromText($wgRequest->getText('test')); if(in_array($testTitle->getText(), $matches[1])) { $counter = 0; foreach($matches[1] as $value) { if($value == $testTitle->getText()) {
- Generating test html
$matches[2][$counter] = preg_replace('|.+?<selenium>\n?(.+?)</selenium>|ms', "\\1", $matches[2][$counter]); print $matches[2][$counter]; break; #exit foreach loop when test is found } $counter++; } } else { $this -> build404("Specified test does not exist in " . $wgRequest->getText('suite')); } } else {
- Obtain suite section headers
$suite_urls = array(); foreach($matches[1] as $value) { array_push($suite_urls, $value); } print $this->buildSuite($suite_urls, $wgRequest->getText('suite')); }
} } else { global $egSeleniumCategory;
- Retrieve articles in category labelled $egSeleniumCategory
$list = $this->categoryArticles($egSeleniumCategory);
- Grab article $param and process contents
$suites = array(); foreach($list as $articleName) {
$suiteTitle = Title::newFromText($articleName); $wikitext = $this->fetchContents($suiteTitle);
if( $this->articleRegex($wikitext, $matches) ) { $suites[] = $articleName; }
} $selectTag = '<select name="selenium">'; foreach($suites as $suite) {
$selectTag .= "<option>$suite</option>";
} $selectTag .= '</select>'; $this->setHeaders(); $title = Title::makeTitle(NS_SPECIAL,'Selenium'); global $egSeleniumPath, $egSpecialPath; $path = "$egSeleniumPath?test=" . urlencode($egSpecialPath); $form = wfElement('form',array('action' => $title->getLocalURL('action=submit'),'method' => 'post'),null); $form .= '<fieldset><legend>Select a suite to run</legend>'; $form .= $selectTag; $form .= wfElement('input',array('type' => 'submit')); $form .= "
" . wfCheckLabel("Run automatically","wfRunAuto" , "wfRunAuto",$checked = false); $form .= '</fieldset></form>'; $wgOut->addHTML($form); if($wgRequest->getText('action')) {
- foreach($_REQUEST as $key=>$value) {
- print "$key>$value" . "
"; - }
$path .= urlencode($wgRequest->getText('selenium'));
if($wgRequest->getBool('wfRunAuto')) { $path .= "&auto=true&resultsUrl=$egResultsUrlPath"; }
$form_link = '<fieldset><legend>Click link to run selenium-core</legend>'; $form_link .= "<a href=\"$path\">" . $wgRequest->getText('selenium') . '</a></fieldset>'; $wgOut->addHTML($form_link);
} } } private function categoryArticles($category) { $list = array(); $dbr = &wfGetDB(DB_SLAVE); $cl = $dbr->tableName('categorylinks'); $res = $dbr->select($cl,'cl_from',"cl_to = '$category'",__METHOD__,array('ORDER BY' => 'cl_sortkey')); while ($row = $dbr->fetchRow($res)){ $list[] = Title::newFromID($row[0])->getPrefixedText(); } return($list);
}
private function fetchContents($title) { $article = new Article($title); $contents = $article->getContent(); return($contents); } private function articleRegex(&$wikitext,&$matches) { $count = preg_match_all('|^={2,}\s*([^\#\<\>\[\]\|\{\}\n]+?)\s*={2,}(.+?</selenium>)|ms',$wikitext,$matches); return($count); }
- Method to bypass $wgOut -must be called early to avoid conflict with other extensions
static function disableHTML(&$wgOut) { $wgOut->disable(); wfResetOutputBuffers(); return; }
- Method to generate 404 error
private function build404($message) { header('HTTP/1.0 404 not Found'); $err = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">404 Error $message
The requested URL was not found on this server.
"; print $err; return; }
- Method to build a suite from an array of tests
private function buildSuite($tests, $article) { $html = $this->suite['header'];
$html .= "$article";
foreach ($tests as $element) {
$html .= "\n<a href=\"/wiki/index.php?title=Special:Selenium&suite=$article&test=$element\">$element</a>";
} $html .= $this->suite['footer']; return $html; }
}
- Called from $wgExtensionFunctions array when initialising extensions
function efSetupSelenium() {
global $wgRequest, $wgOut;
- Process suite or test if ?suite=article_name in query string
if($wgRequest->getText('suite')) {
- Render only Selenium html
SpecialSelenium::disableHTML($wgOut); } global $egSelenium, $wgLanguageCode, $wgMessageCache; $egSelenium = new Selenium();
- Add the messages used by the specialpage
if ($wgLanguageCode == 'en') { $wgMessageCache->addMessages(array(
'selenium' => 'Selenium testing environment', # The friendly page title ));
}
- Add the specialpage to the environment
SpecialPage::addPage(new SpecialSelenium());
}
- Needed in MediaWiki >1.8.0 for magic word hooks to work properly
function efSeleniumLanguageGetMagic(&$magicWords,$langCode = 0) {
global $egSeleniumMagic; $magicWords[$egSeleniumMagic] = array(0,$egSeleniumMagic); return true;
}