resourceloader: Clean up mw.Map tests

* Move to separate file.
* Remove most of the verbose assert messages in favour of just
  a few words that label the asserted value or the call that it
  checks the value of. The actual/expected values are already in
  the UI, and the class/method are already in the formatted test
  name (which includes the module name).

Change-Id: I43ec038abd0946a92f222a859807e252696c33d4
This commit is contained in:
Timo Tijhof 2021-09-10 21:49:08 +01:00 committed by Jforrester
parent 6b6e846de6
commit b33dbb2aee
3 changed files with 131 additions and 80 deletions

View file

@ -60,6 +60,7 @@ return [
'tests/qunit/suites/resources/jquery/jquery.tablesorter.test.js',
'tests/qunit/suites/resources/jquery/jquery.tablesorter.parsers.test.js',
'tests/qunit/suites/resources/jquery/jquery.textSelection.test.js',
'tests/qunit/suites/resources/startup/mw.Map.test.js',
'tests/qunit/suites/resources/mediawiki/mediawiki.requestIdleCallback.test.js',
'tests/qunit/suites/resources/mediawiki/mediawiki.errorLogger.test.js',
'tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js',

View file

@ -73,86 +73,6 @@
);
} );
QUnit.test( 'mw.Map', function ( assert ) {
var arry, conf, funky, nummy, someValues;
conf = new mw.Map();
// Dummy variables
funky = function () {};
arry = [];
nummy = 7;
// Single get and set
assert.strictEqual( conf.set( 'foo', 'Bar' ), true, 'Map.set returns boolean true if a value was set for a valid key string' );
assert.strictEqual( conf.get( 'foo' ), 'Bar', 'Map.get returns a single value value correctly' );
assert.strictEqual( conf.get( 'example' ), null, 'Map.get returns null if selection was a string and the key was not found' );
assert.strictEqual( conf.get( 'example', arry ), arry, 'Map.get returns fallback by reference if the key was not found' );
assert.strictEqual( conf.get( 'example', undefined ), undefined, 'Map.get supports `undefined` as fallback instead of `null`' );
assert.strictEqual( conf.get( 'constructor' ), null, 'Map.get does not look at Object.prototype of internal storage (constructor)' );
assert.strictEqual( conf.get( 'hasOwnProperty' ), null, 'Map.get does not look at Object.prototype of internal storage (hasOwnProperty)' );
conf.set( 'hasOwnProperty', function () {
return true;
} );
assert.strictEqual( conf.get( 'example', 'missing' ), 'missing', 'Map.get uses neutral hasOwnProperty method (positive)' );
conf.set( 'example', 'Foo' );
conf.set( 'hasOwnProperty', function () {
return false;
} );
assert.strictEqual( conf.get( 'example' ), 'Foo', 'Map.get uses neutral hasOwnProperty method (negative)' );
assert.strictEqual( conf.set( 'constructor', 42 ), true, 'Map.set for key "constructor"' );
assert.strictEqual( conf.get( 'constructor' ), 42, 'Map.get for key "constructor"' );
assert.strictEqual( conf.set( 'undef' ), false, 'Map.set requires explicit value (no undefined default)' );
assert.strictEqual( conf.set( 'undef', undefined ), true, 'Map.set allows setting value to `undefined`' );
assert.strictEqual( conf.get( 'undef', 'fallback' ), undefined, 'Map.get supports retrieving value of `undefined`' );
assert.strictEqual( conf.set( funky, 'Funky' ), false, 'Map.set returns boolean false if key was invalid (Function)' );
assert.strictEqual( conf.set( arry, 'Arry' ), false, 'Map.set returns boolean false if key was invalid (Array)' );
assert.strictEqual( conf.set( nummy, 'Nummy' ), false, 'Map.set returns boolean false if key was invalid (Number)' );
assert.strictEqual( conf.set( null, 'Null' ), false, 'Map.set returns false if key is invalid (null)' );
assert.strictEqual( conf.set( {}, 'Object' ), false, 'Map.set returns false if key is invalid (plain object)' );
conf.set( String( nummy ), 'I used to be a number' );
assert.strictEqual( conf.get( funky ), null, 'Map.get returns null if selection was invalid (Function)' );
assert.strictEqual( conf.get( nummy ), null, 'Map.get returns null if selection was invalid (Number)' );
assert.propEqual( conf.get( [ nummy ] ), {}, 'Map.get returns null if selection was invalid (multiple)' );
assert.strictEqual( conf.get( nummy, false ), false, 'Map.get returns custom fallback for invalid selection' );
assert.strictEqual( conf.exists( 'doesNotExist' ), false, 'Map.exists where property does not exist' );
assert.strictEqual( conf.exists( 'undef' ), true, 'Map.exists where value is `undefined`' );
assert.strictEqual( conf.exists( nummy ), false, 'Map.exists with invalid key that looks like an existing key' );
// Multiple values at once
conf = new mw.Map();
someValues = {
foo: 'bar',
lorem: 'ipsum',
MediaWiki: true
};
assert.strictEqual( conf.set( someValues ), true, 'Map.set returns boolean true if multiple values were set by passing an object' );
assert.deepEqual( conf.get( [ 'foo', 'lorem' ] ), {
foo: 'bar',
lorem: 'ipsum'
}, 'Map.get returns multiple values correctly as an object' );
assert.deepEqual( conf.get( [ 'foo', 'notExist' ] ), {
foo: 'bar',
notExist: null
}, 'Map.get return includes keys that were not found as null values' );
assert.propEqual( conf.values, someValues, 'Map.values is an internal object with all values (exposed for convenience)' );
assert.propEqual( conf.get(), someValues, 'Map.get() returns an object with all values' );
} );
QUnit.test( 'mw.message & mw.messages', function ( assert ) {
var goodbye, hello;

View file

@ -0,0 +1,130 @@
( function () {
// Dummy variables
var funky = function () {};
var arry = [];
QUnit.module( 'mw.Map' );
QUnit.test( 'Store simple string key', function ( assert ) {
var conf = new mw.Map();
assert.true( conf.set( 'foo', 'Bar' ), 'set' );
assert.strictEqual( conf.get( 'foo' ), 'Bar', 'get' );
} );
QUnit.test( 'Store number-like key', function ( assert ) {
var conf = new mw.Map();
assert.true( conf.set( '42', 'X' ), 'set' );
assert.strictEqual( conf.get( '42' ), 'X', 'get' );
} );
QUnit.test( 'get()', function ( assert ) {
var conf = new mw.Map();
assert.strictEqual( conf.get( 'example' ), null, 'default fallback' );
assert.strictEqual( conf.get( 'example', arry ), arry, 'array fallback' );
assert.strictEqual( conf.get( 'example', funky ), funky, 'function fallback' );
assert.strictEqual( conf.get( 'example', undefined ), undefined, 'undefined fallback' );
// Numbers are not valid keys. Ignore any stored keys that could match after casting.
assert.true( conf.set( '7', 'I used to be a number' ) );
assert.strictEqual( conf.get( 7 ), null, 'ignore number key (single)' );
assert.deepEqual( conf.get( [ 7 ] ), {}, 'ignore number key (multiple)' );
assert.strictEqual( conf.get( 7, 42 ), 42, 'ignore number key (fallback)' );
// Functions are not valid keys.
assert.true( conf.set( String( funky ), 'I used to be a function' ) );
assert.strictEqual( conf.get( funky ), null, 'ignore function key' );
conf = new mw.Map();
conf.set( 'foo', 'bar' );
conf.set( 'x', [ 'y', 'z' ] );
conf.set( 'num', 7 );
conf.set( 'num2', 42 );
assert.deepEqual(
conf.get( [ 'foo', 'x', 'num' ] ),
{ foo: 'bar', x: [ 'y', 'z' ], num: 7 },
'get multiple'
);
assert.deepEqual(
conf.get( [ 'foo', 'bar', 'x', 'y' ] ),
{ foo: 'bar', bar: null, x: [ 'y', 'z' ], y: null },
'get multiple with some unknown'
);
assert.propEqual(
conf.get(),
{ foo: 'bar', x: [ 'y', 'z' ], num: 7, num2: 42 },
'get all values'
);
} );
// Expose 'values' getter with all values, for developer convenience on the console
QUnit.test( 'values', function ( assert ) {
var conf = new mw.Map();
conf.set( { num: 7, num2: 42 } );
conf.set( 'foo', 'bar' );
assert.propEqual( conf.values, { num: 7, num2: 42, foo: 'bar' } );
} );
QUnit.test( 'set()', function ( assert ) {
var conf = new mw.Map();
// There should not be an implied default value
assert.false( conf.set( 'no-value' ), 'reject without value argument' );
assert.false( conf.set( funky, 'Funky' ), 'reject Function key' );
assert.false( conf.set( arry, 'Arry' ), 'reject Array key' );
assert.false( conf.set( 7, 'Nummy' ), 'reject number key' );
assert.false( conf.set( null, 'Null' ), 'reject null key' );
assert.false( conf.set( {}, 'Object' ), 'reject plain object as key' );
// Support storing `undefined`, get() will not return the default.
assert.true( conf.set( 'example', undefined ), 'Store the undefined value' );
assert.strictEqual( conf.get( 'example' ), undefined, 'Get the undefined value' );
assert.strictEqual( conf.get( 'example', 42 ), undefined, 'Get the undefined value (ignore default)' );
assert.true( conf.set( { key1: { x: 'x' }, key2: [ 'y' ] } ), 'set multiple' );
assert.deepEqual( conf.get( 'key1' ), { x: 'x' } );
assert.deepEqual( conf.get( 'key2' ), [ 'y' ] );
} );
QUnit.test( 'exists()', function ( assert ) {
var conf = new mw.Map();
assert.false( conf.exists( 'doesNotExist' ), 'unknown' );
assert.true( conf.set( 'undef', undefined ) );
assert.true( conf.exists( 'undef' ), 'known with undefined value' );
assert.true( conf.set( '7', 42 ) );
assert.false( conf.exists( 7 ), 'unknown, with known number-like key' );
} );
// Confirm protection against Object.prototype inheritance
QUnit.test( 'Avoid prototype pollution', function ( assert ) {
var conf = new mw.Map();
assert.strictEqual( conf.get( 'constructor' ), null, 'Get unknown "constructor"' );
assert.strictEqual( conf.get( 'hasOwnProperty' ), null, 'Get unkonwn "hasOwnProperty"' );
conf.set(
'hasOwnProperty',
function () { return true; }
);
assert.strictEqual( conf.get( 'example', 'missing' ), 'missing', 'Use original hasOwnProperty method (positive)' );
conf.set( 'example', 'Foo' );
conf.set(
'hasOwnProperty',
function () { return false; }
);
assert.strictEqual( conf.get( 'example' ), 'Foo', 'Use original hasOwnProperty method (negative)' );
assert.strictEqual( conf.set( 'constructor', 42 ), true, 'Set "constructor"' );
assert.strictEqual( conf.get( 'constructor' ), 42, 'Get "constructor"' );
} );
}() );