/** tests for includes/Html.php */
class HtmlTest extends MediaWikiTestCase {
- private static $oldLang;
- private static $oldContLang;
- private static $oldLanguageCode;
- private static $oldNamespaces;
- private static $oldHTML5;
- public function setUp() {
- global $wgLang, $wgContLang, $wgLanguageCode, $wgHtml5;
+ protected function setUp() {
+ parent::setUp();
- // Save globals
- self::$oldLang = $wgLang;
- self::$oldContLang = $wgContLang;
- self::$oldNamespaces = $wgContLang->getNamespaces();
- self::$oldLanguageCode = $wgLanguageCode;
- self::$oldHTML5 = $wgHtml5;
-
- $wgLanguageCode = 'en';
- $wgContLang = $wgLang = Language::factory( $wgLanguageCode );
+ $langCode = 'en';
+ $langObj = Language::factory( $langCode );
// Hardcode namespaces during test runs,
// so that html output based on existing namespaces
// can be properly evaluated.
- $wgContLang->setNamespaces( array(
+ $langObj->setNamespaces( array(
-2 => 'Media',
-1 => 'Special',
0 => '',
100 => 'Custom',
101 => 'Custom_talk',
) );
+
+ $this->setMwGlobals( array(
+ 'wgLanguageCode' => $langCode,
+ 'wgContLang' => $langObj,
+ 'wgLang' => $langObj,
+ 'wgHtml5' => true,
+ 'wgWellFormedXml' => false,
+ ) );
}
- public function tearDown() {
- global $wgLang, $wgContLang, $wgLanguageCode, $wgHtml5;
+ public function testElementBasics() {
+ global $wgWellFormedXml;
- // Restore globals
- $wgContLang->setNamespaces( self::$oldNamespaces );
- $wgLang = self::$oldLang;
- $wgContLang = self::$oldContLang;
- $wgLanguageCode = self::$oldLanguageCode;
- $wgHtml5 = self::$oldHTML5;
- }
+ $this->assertEquals(
+ '<img>',
+ Html::element( 'img', null, '' ),
+ 'No close tag for short-tag elements'
+ );
- /**
- * Wrapper to easily set $wgHtml5 = true.
- * Original value will be restored after test completion.
- * @todo Move to MediaWikiTestCase
- */
- public function enableHTML5() {
- global $wgHtml5;
- $wgHtml5 = true;
- }
- /**
- * Wrapper to easily set $wgHtml5 = false
- * Original value will be restored after test completion.
- * @todo Move to MediaWikiTestCase
- */
- public function disableHTML5() {
- global $wgHtml5;
- $wgHtml5 = false;
+ $this->assertEquals(
+ '<element></element>',
+ Html::element( 'element', null, null ),
+ 'Close tag for empty element (null, null)'
+ );
+
+ $this->assertEquals(
+ '<element></element>',
+ Html::element( 'element', array(), '' ),
+ 'Close tag for empty element (array, string)'
+ );
+
+ $wgWellFormedXml = true;
+
+ $this->assertEquals(
+ '<img />',
+ Html::element( 'img', null, '' ),
+ 'Self-closing tag for short-tag elements (wgWellFormedXml = true)'
+ );
}
public function testExpandAttributesSkipsNullAndFalse() {
### EMPTY ########
- $this->AssertEmpty(
+ $this->assertEmpty(
Html::expandAttributes( array( 'foo' => null ) ),
'skip keys with null value'
);
- $this->AssertEmpty(
+ $this->assertEmpty(
Html::expandAttributes( array( 'foo' => false ) ),
'skip keys with false value'
);
- $this->AssertNotEmpty(
+ $this->assertNotEmpty(
Html::expandAttributes( array( 'foo' => '' ) ),
'keep keys with an empty string'
);
}
public function testExpandAttributesForBooleans() {
- global $wgHtml5;
- $this->AssertEquals(
+ global $wgHtml5, $wgWellFormedXml;
+
+ $this->assertEquals(
'',
Html::expandAttributes( array( 'selected' => false ) ),
'Boolean attributes do not generates output when value is false'
);
- $this->AssertEquals(
+ $this->assertEquals(
'',
Html::expandAttributes( array( 'selected' => null ) ),
'Boolean attributes do not generates output when value is null'
);
- $this->AssertEquals(
- $wgHtml5 ? ' selected=""' : ' selected="selected"',
+ $this->assertEquals(
+ ' selected',
Html::expandAttributes( array( 'selected' => true ) ),
- 'Boolean attributes skip value output'
+ 'Boolean attributes have no value when value is true'
);
- $this->AssertEquals(
- $wgHtml5 ? ' selected=""' : ' selected="selected"',
+ $this->assertEquals(
+ ' selected',
Html::expandAttributes( array( 'selected' ) ),
- 'Boolean attributes (ex: selected) do not need a value'
+ 'Boolean attributes have no value when value is true (passed as numerical array)'
+ );
+
+ $wgWellFormedXml = true;
+
+ $this->assertEquals(
+ ' selected=""',
+ Html::expandAttributes( array( 'selected' => true ) ),
+ 'Boolean attributes have empty string value when value is true (wgWellFormedXml)'
+ );
+
+ $wgHtml5 = false;
+
+ $this->assertEquals(
+ ' selected="selected"',
+ Html::expandAttributes( array( 'selected' => true ) ),
+ 'Boolean attributes have their key as value when value is true (wgWellFormedXml, wgHTML5 = false)'
);
}
* Please note it output a string prefixed with a space!
*/
public function testExpandAttributesVariousExpansions() {
+ global $wgWellFormedXml;
+
### NOT EMPTY ####
- $this->AssertEquals(
+ $this->assertEquals(
+ ' empty_string=""',
+ Html::expandAttributes( array( 'empty_string' => '' ) ),
+ 'Empty string is always quoted'
+ );
+ $this->assertEquals(
+ ' key=value',
+ Html::expandAttributes( array( 'key' => 'value' ) ),
+ 'Simple string value needs no quotes'
+ );
+ $this->assertEquals(
+ ' one=1',
+ Html::expandAttributes( array( 'one' => 1 ) ),
+ 'Number 1 value needs no quotes'
+ );
+ $this->assertEquals(
+ ' zero=0',
+ Html::expandAttributes( array( 'zero' => 0 ) ),
+ 'Number 0 value needs no quotes'
+ );
+
+ $wgWellFormedXml = true;
+
+ $this->assertEquals(
' empty_string=""',
Html::expandAttributes( array( 'empty_string' => '' ) ),
- 'Value with an empty string'
+ 'Attribtue values are always quoted (wgWellFormedXml): Empty string'
);
- $this->AssertEquals(
+ $this->assertEquals(
' key="value"',
Html::expandAttributes( array( 'key' => 'value' ) ),
- 'Value is a string'
+ 'Attribtue values are always quoted (wgWellFormedXml): Simple string'
);
- $this->AssertEquals(
+ $this->assertEquals(
' one="1"',
Html::expandAttributes( array( 'one' => 1 ) ),
- 'Value is a numeric one'
+ 'Attribtue values are always quoted (wgWellFormedXml): Number 1'
);
- $this->AssertEquals(
+ $this->assertEquals(
' zero="0"',
Html::expandAttributes( array( 'zero' => 0 ) ),
- 'Value is a numeric zero'
+ 'Attribtue values are always quoted (wgWellFormedXml): Number 0'
);
}
*/
public function testExpandAttributesListValueAttributes() {
### STRING VALUES
- $this->AssertEquals(
+ $this->assertEquals(
' class="redundant spaces here"',
Html::expandAttributes( array( 'class' => ' redundant spaces here ' ) ),
'Normalization should strip redundant spaces'
);
- $this->AssertEquals(
+ $this->assertEquals(
' class="foo bar"',
Html::expandAttributes( array( 'class' => 'foo bar foo bar bar' ) ),
'Normalization should remove duplicates in string-lists'
);
### "EMPTY" ARRAY VALUES
- $this->AssertEquals(
+ $this->assertEquals(
' class=""',
Html::expandAttributes( array( 'class' => array() ) ),
'Value with an empty array'
);
- $this->AssertEquals(
+ $this->assertEquals(
' class=""',
Html::expandAttributes( array( 'class' => array( null, '', ' ', ' ' ) ) ),
'Array with null, empty string and spaces'
);
### NON-EMPTY ARRAY VALUES
- $this->AssertEquals(
+ $this->assertEquals(
' class="foo bar"',
Html::expandAttributes( array( 'class' => array(
'foo',
) ) ),
'Normalization should remove duplicates in the array'
);
- $this->AssertEquals(
+ $this->assertEquals(
' class="foo bar"',
Html::expandAttributes( array( 'class' => array(
'foo bar',
function testNamespaceSelector() {
$this->assertEquals(
- '<select id="namespace" name="namespace">' . "\n" .
-'<option value="0">(Main)</option>' . "\n" .
-'<option value="1">Talk</option>' . "\n" .
-'<option value="2">User</option>' . "\n" .
-'<option value="3">User talk</option>' . "\n" .
-'<option value="4">MyWiki</option>' . "\n" .
-'<option value="5">MyWiki Talk</option>' . "\n" .
-'<option value="6">File</option>' . "\n" .
-'<option value="7">File talk</option>' . "\n" .
-'<option value="8">MediaWiki</option>' . "\n" .
-'<option value="9">MediaWiki talk</option>' . "\n" .
-'<option value="10">Template</option>' . "\n" .
-'<option value="11">Template talk</option>' . "\n" .
-'<option value="14">Category</option>' . "\n" .
-'<option value="15">Category talk</option>' . "\n" .
-'<option value="100">Custom</option>' . "\n" .
-'<option value="101">Custom talk</option>' . "\n" .
+ '<select id=namespace name=namespace>' . "\n" .
+'<option value=0>(Main)</option>' . "\n" .
+'<option value=1>Talk</option>' . "\n" .
+'<option value=2>User</option>' . "\n" .
+'<option value=3>User talk</option>' . "\n" .
+'<option value=4>MyWiki</option>' . "\n" .
+'<option value=5>MyWiki Talk</option>' . "\n" .
+'<option value=6>File</option>' . "\n" .
+'<option value=7>File talk</option>' . "\n" .
+'<option value=8>MediaWiki</option>' . "\n" .
+'<option value=9>MediaWiki talk</option>' . "\n" .
+'<option value=10>Template</option>' . "\n" .
+'<option value=11>Template talk</option>' . "\n" .
+'<option value=14>Category</option>' . "\n" .
+'<option value=15>Category talk</option>' . "\n" .
+'<option value=100>Custom</option>' . "\n" .
+'<option value=101>Custom talk</option>' . "\n" .
'</select>',
Html::namespaceSelector(),
'Basic namespace selector without custom options'
);
$this->assertEquals(
- '<label for="mw-test-namespace">Select a namespace:</label> ' .
-'<select id="mw-test-namespace" name="wpNamespace">' . "\n" .
-'<option value="all">all</option>' . "\n" .
-'<option value="0">(Main)</option>' . "\n" .
-'<option value="1">Talk</option>' . "\n" .
-'<option value="2" selected="">User</option>' . "\n" .
-'<option value="3">User talk</option>' . "\n" .
-'<option value="4">MyWiki</option>' . "\n" .
-'<option value="5">MyWiki Talk</option>' . "\n" .
-'<option value="6">File</option>' . "\n" .
-'<option value="7">File talk</option>' . "\n" .
-'<option value="8">MediaWiki</option>' . "\n" .
-'<option value="9">MediaWiki talk</option>' . "\n" .
-'<option value="10">Template</option>' . "\n" .
-'<option value="11">Template talk</option>' . "\n" .
-'<option value="14">Category</option>' . "\n" .
-'<option value="15">Category talk</option>' . "\n" .
-'<option value="100">Custom</option>' . "\n" .
-'<option value="101">Custom talk</option>' . "\n" .
+ '<label for=mw-test-namespace>Select a namespace:</label> ' .
+'<select id=mw-test-namespace name=wpNamespace>' . "\n" .
+'<option value=all>all</option>' . "\n" .
+'<option value=0>(Main)</option>' . "\n" .
+'<option value=1>Talk</option>' . "\n" .
+'<option value=2 selected>User</option>' . "\n" .
+'<option value=3>User talk</option>' . "\n" .
+'<option value=4>MyWiki</option>' . "\n" .
+'<option value=5>MyWiki Talk</option>' . "\n" .
+'<option value=6>File</option>' . "\n" .
+'<option value=7>File talk</option>' . "\n" .
+'<option value=8>MediaWiki</option>' . "\n" .
+'<option value=9>MediaWiki talk</option>' . "\n" .
+'<option value=10>Template</option>' . "\n" .
+'<option value=11>Template talk</option>' . "\n" .
+'<option value=14>Category</option>' . "\n" .
+'<option value=15>Category talk</option>' . "\n" .
+'<option value=100>Custom</option>' . "\n" .
+'<option value=101>Custom talk</option>' . "\n" .
'</select>',
Html::namespaceSelector(
array( 'selected' => '2', 'all' => 'all', 'label' => 'Select a namespace:' ),
);
$this->assertEquals(
- '<label for="namespace">Select a namespace:</label> ' .
-'<select id="namespace" name="namespace">' . "\n" .
-'<option value="0">(Main)</option>' . "\n" .
-'<option value="1">Talk</option>' . "\n" .
-'<option value="2">User</option>' . "\n" .
-'<option value="3">User talk</option>' . "\n" .
-'<option value="4">MyWiki</option>' . "\n" .
-'<option value="5">MyWiki Talk</option>' . "\n" .
-'<option value="6">File</option>' . "\n" .
-'<option value="7">File talk</option>' . "\n" .
-'<option value="8">MediaWiki</option>' . "\n" .
-'<option value="9">MediaWiki talk</option>' . "\n" .
-'<option value="10">Template</option>' . "\n" .
-'<option value="11">Template talk</option>' . "\n" .
-'<option value="14">Category</option>' . "\n" .
-'<option value="15">Category talk</option>' . "\n" .
-'<option value="100">Custom</option>' . "\n" .
-'<option value="101">Custom talk</option>' . "\n" .
+ '<label for=namespace>Select a namespace:</label> ' .
+'<select id=namespace name=namespace>' . "\n" .
+'<option value=0>(Main)</option>' . "\n" .
+'<option value=1>Talk</option>' . "\n" .
+'<option value=2>User</option>' . "\n" .
+'<option value=3>User talk</option>' . "\n" .
+'<option value=4>MyWiki</option>' . "\n" .
+'<option value=5>MyWiki Talk</option>' . "\n" .
+'<option value=6>File</option>' . "\n" .
+'<option value=7>File talk</option>' . "\n" .
+'<option value=8>MediaWiki</option>' . "\n" .
+'<option value=9>MediaWiki talk</option>' . "\n" .
+'<option value=10>Template</option>' . "\n" .
+'<option value=11>Template talk</option>' . "\n" .
+'<option value=14>Category</option>' . "\n" .
+'<option value=15>Category talk</option>' . "\n" .
+'<option value=100>Custom</option>' . "\n" .
+'<option value=101>Custom talk</option>' . "\n" .
'</select>',
Html::namespaceSelector(
array( 'label' => 'Select a namespace:' )
function testCanFilterOutNamespaces() {
$this->assertEquals(
-'<select id="namespace" name="namespace">' . "\n" .
-'<option value="2">User</option>' . "\n" .
-'<option value="4">MyWiki</option>' . "\n" .
-'<option value="5">MyWiki Talk</option>' . "\n" .
-'<option value="6">File</option>' . "\n" .
-'<option value="7">File talk</option>' . "\n" .
-'<option value="8">MediaWiki</option>' . "\n" .
-'<option value="9">MediaWiki talk</option>' . "\n" .
-'<option value="10">Template</option>' . "\n" .
-'<option value="11">Template talk</option>' . "\n" .
-'<option value="14">Category</option>' . "\n" .
-'<option value="15">Category talk</option>' . "\n" .
+'<select id=namespace name=namespace>' . "\n" .
+'<option value=2>User</option>' . "\n" .
+'<option value=4>MyWiki</option>' . "\n" .
+'<option value=5>MyWiki Talk</option>' . "\n" .
+'<option value=6>File</option>' . "\n" .
+'<option value=7>File talk</option>' . "\n" .
+'<option value=8>MediaWiki</option>' . "\n" .
+'<option value=9>MediaWiki talk</option>' . "\n" .
+'<option value=10>Template</option>' . "\n" .
+'<option value=11>Template talk</option>' . "\n" .
+'<option value=14>Category</option>' . "\n" .
+'<option value=15>Category talk</option>' . "\n" .
'</select>',
Html::namespaceSelector(
array( 'exclude' => array( 0, 1, 3, 100, 101 ) )
function testCanDisableANamespaces() {
$this->assertEquals(
-'<select id="namespace" name="namespace">' . "\n" .
-'<option disabled="" value="0">(Main)</option>' . "\n" .
-'<option disabled="" value="1">Talk</option>' . "\n" .
-'<option disabled="" value="2">User</option>' . "\n" .
-'<option disabled="" value="3">User talk</option>' . "\n" .
-'<option disabled="" value="4">MyWiki</option>' . "\n" .
-'<option value="5">MyWiki Talk</option>' . "\n" .
-'<option value="6">File</option>' . "\n" .
-'<option value="7">File talk</option>' . "\n" .
-'<option value="8">MediaWiki</option>' . "\n" .
-'<option value="9">MediaWiki talk</option>' . "\n" .
-'<option value="10">Template</option>' . "\n" .
-'<option value="11">Template talk</option>' . "\n" .
-'<option value="14">Category</option>' . "\n" .
-'<option value="15">Category talk</option>' . "\n" .
-'<option value="100">Custom</option>' . "\n" .
-'<option value="101">Custom talk</option>' . "\n" .
+'<select id=namespace name=namespace>' . "\n" .
+'<option disabled value=0>(Main)</option>' . "\n" .
+'<option disabled value=1>Talk</option>' . "\n" .
+'<option disabled value=2>User</option>' . "\n" .
+'<option disabled value=3>User talk</option>' . "\n" .
+'<option disabled value=4>MyWiki</option>' . "\n" .
+'<option value=5>MyWiki Talk</option>' . "\n" .
+'<option value=6>File</option>' . "\n" .
+'<option value=7>File talk</option>' . "\n" .
+'<option value=8>MediaWiki</option>' . "\n" .
+'<option value=9>MediaWiki talk</option>' . "\n" .
+'<option value=10>Template</option>' . "\n" .
+'<option value=11>Template talk</option>' . "\n" .
+'<option value=14>Category</option>' . "\n" .
+'<option value=15>Category talk</option>' . "\n" .
+'<option value=100>Custom</option>' . "\n" .
+'<option value=101>Custom talk</option>' . "\n" .
'</select>',
Html::namespaceSelector( array(
'disable' => array( 0, 1, 2, 3, 4 )
}
/**
- * @dataProvider providesHtml5InputTypes
+ * @dataProvider provideHtml5InputTypes
*/
function testHtmlElementAcceptsNewHtml5TypesInHtml5Mode( $HTML5InputType ) {
- $this->enableHTML5();
$this->assertEquals(
- '<input type="' . $HTML5InputType . '" />',
+ '<input type=' . $HTML5InputType . '>',
Html::element( 'input', array( 'type' => $HTML5InputType ) ),
'In HTML5, HTML::element() should accept type="' . $HTML5InputType . '"'
);
* List of input element types values introduced by HTML5
* Full list at http://www.w3.org/TR/html-markup/input.html
*/
- function providesHtml5InputTypes() {
+ function provideHtml5InputTypes() {
$types = array(
'datetime',
'datetime-local',
* @cover Html::dropDefaults
* @dataProvider provideElementsWithAttributesHavingDefaultValues
*/
- function testDropDefaults( $expected, $element, $message = '' ) {
- $this->enableHTML5();
- $this->assertEquals( $expected, $element, $message );
+ function testDropDefaults( $expected, $element, $attribs, $message = '' ) {
+ $this->assertEquals( $expected, Html::element( $element, $attribs ), $message );
}
- function provideElementsWithAttributesHavingDefaultValues() {
+ public static function provideElementsWithAttributesHavingDefaultValues() {
# Use cases in a concise format:
# <expected>, <element name>, <array of attributes> [, <message>]
# Will be mapped to Html::element()
$cases = array();
### Generic cases, match $attribDefault static array
- $cases[] = array( '<area />',
+ $cases[] = array( '<area>',
'area', array( 'shape' => 'rect' )
);
'canvas', array( 'width' => 300 )
);
- $cases[] = array( '<command />',
+ $cases[] = array( '<command>',
'command', array( 'type' => 'command' )
);
'form', array( 'enctype' => 'application/x-www-form-urlencoded' )
);
- $cases[] = array( '<input />',
+ $cases[] = array( '<input>',
'input', array( 'formaction' => 'GET' )
);
- $cases[] = array( '<input />',
+ $cases[] = array( '<input>',
'input', array( 'type' => 'text' )
);
- $cases[] = array( '<keygen />',
+ $cases[] = array( '<keygen>',
'keygen', array( 'keytype' => 'rsa' )
);
- $cases[] = array( '<link />',
+ $cases[] = array( '<link>',
'link', array( 'media' => 'all' )
);
### SPECIFIC CASES
- # <link type="text/css" />
- $cases[] = array( '<link />',
+ # <link type="text/css">
+ $cases[] = array( '<link>',
'link', array( 'type' => 'text/css' )
);
- # <input /> specific handling
- $cases[] = array( '<input type="checkbox" />',
+ # <input> specific handling
+ $cases[] = array( '<input type=checkbox>',
'input', array( 'type' => 'checkbox', 'value' => 'on' ),
'Default value "on" is stripped of checkboxes',
);
- $cases[] = array( '<input type="radio" />',
+ $cases[] = array( '<input type=radio>',
'input', array( 'type' => 'radio', 'value' => 'on' ),
'Default value "on" is stripped of radio buttons',
);
- $cases[] = array( '<input type="submit" value="Submit" />',
+ $cases[] = array( '<input type=submit value=Submit>',
'input', array( 'type' => 'submit', 'value' => 'Submit' ),
'Default value "Submit" is kept on submit buttons (for possible l10n issues)',
);
- $cases[] = array( '<input type="color" />',
+ $cases[] = array( '<input type=color>',
'input', array( 'type' => 'color', 'value' => '' ),
);
- $cases[] = array( '<input type="range" />',
+ $cases[] = array( '<input type=range>',
'input', array( 'type' => 'range', 'value' => '' ),
);
- # <select /> specifc handling
- $cases[] = array( '<select multiple=""></select>',
+ # <select> specifc handling
+ $cases[] = array( '<select multiple></select>',
'select', array( 'size' => '4', 'multiple' => true ),
);
# .. with numeric value
- $cases[] = array( '<select multiple=""></select>',
+ $cases[] = array( '<select multiple></select>',
'select', array( 'size' => 4, 'multiple' => true ),
);
$cases[] = array( '<select></select>',
"dropDefaults accepts values given as an array"
);
-
# Craft the Html elements
$ret = array();
foreach( $cases as $case ) {
$ret[] = array(
$case[0],
- Html::element( $case[1], $case[2] )
+ $case[1], $case[2],
+ isset( $case[3] ) ? $case[3] : ''
);
}
return $ret;