3 QUnit
.module( 'mediawiki.Uri', QUnit
.newMwEnvironment( {
5 this.mwUriOrg
= mw
.Uri
;
6 mw
.Uri
= mw
.UriRelative( 'http://example.org/w/index.php' );
8 teardown: function () {
9 mw
.Uri
= this.mwUriOrg
;
14 $.each( [ true, false ], function ( i
, strictMode
) {
15 QUnit
.test( 'Basic construction and properties (' + ( strictMode
? '' : 'non-' ) + 'strict mode)', 2, function ( assert
) {
17 uriString
= 'http://www.ietf.org/rfc/rfc2396.txt';
18 uri
= new mw
.Uri( uriString
, {
19 strictMode
: strictMode
24 protocol
: uri
.protocol
,
29 fragment
: uri
.fragment
34 path
: '/rfc/rfc2396.txt',
38 'basic object properties'
43 userInfo
: uri
.getUserInfo(),
44 authority
: uri
.getAuthority(),
45 hostPort
: uri
.getHostPort(),
46 queryString
: uri
.getQueryString(),
47 relativePath
: uri
.getRelativePath(),
48 toString
: uri
.toString()
52 authority
: 'www.ietf.org',
53 hostPort
: 'www.ietf.org',
55 relativePath
: '/rfc/rfc2396.txt',
58 'construct composite components of URI on request'
63 QUnit
.test( 'Constructor( String[, Object ] )', 11, function ( assert
) {
66 uri
= new mw
.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
70 // Strict comparison to assert that numerical values stay strings
71 assert
.strictEqual( uri
.query
.n
, '1', 'Simple parameter with overrideKeys:true' );
72 assert
.strictEqual( uri
.query
.m
, 'bar', 'Last key overrides earlier keys with overrideKeys:true' );
74 uri
= new mw
.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
78 assert
.strictEqual( uri
.query
.n
, '1', 'Simple parameter with overrideKeys:false' );
79 assert
.strictEqual( uri
.query
.m
[ 0 ], 'foo', 'Order of multi-value parameters with overrideKeys:true' );
80 assert
.strictEqual( uri
.query
.m
[ 1 ], 'bar', 'Order of multi-value parameters with overrideKeys:true' );
81 assert
.strictEqual( uri
.query
.m
.length
, 2, 'Number of mult-value field is correct' );
83 uri
= new mw
.Uri( 'ftp://usr:pwd@192.0.2.16/' );
87 protocol
: uri
.protocol
,
89 password
: uri
.password
,
94 fragment
: uri
.fragment
106 'Parse an ftp URI correctly with user and password'
111 return new mw
.Uri( 'glaswegian penguins' );
114 return e
.message
=== 'Bad constructor arguments';
116 'throw error on non-URI as argument to constructor'
121 return new mw
.Uri( 'example.com/bar/baz', {
126 return e
.message
=== 'Bad constructor arguments';
128 'throw error on URI without protocol or // or leading / in strict mode'
131 uri
= new mw
.Uri( 'example.com/bar/baz', {
134 assert
.equal( uri
.toString(), 'http://example.com/bar/baz', 'normalize URI without protocol or // in loose mode' );
137 uri
= new mw
.Uri( 'http://example.com/index.php?key=key&hasOwnProperty=hasOwnProperty&constructor=constructor&watch=watch' );
142 constructor: 'constructor',
143 hasOwnProperty
: 'hasOwnProperty',
146 'Keys in query strings support names of Object prototypes (bug T114344)'
151 QUnit
.test( 'Constructor( Object )', 3, function ( assert
) {
152 var uri
= new mw
.Uri( {
154 host
: 'www.foo.local',
157 assert
.equal( uri
.toString(), 'http://www.foo.local/this', 'Basic properties' );
161 host
: 'www.foo.local',
163 query
: { hi
: 'there' },
166 assert
.equal( uri
.toString(), 'http://www.foo.local/this?hi=there#blah', 'More complex properties' );
172 host
: 'www.foo.local'
176 return e
.message
=== 'Bad constructor arguments';
178 'Construction failed when missing required properties'
182 QUnit
.test( 'Constructor( empty )', 4, function ( assert
) {
183 var testuri
, MyUri
, uri
;
185 testuri
= 'http://example.org/w/index.php';
186 MyUri
= mw
.UriRelative( testuri
);
189 assert
.equal( uri
.toString(), testuri
, 'no arguments' );
191 uri
= new MyUri( undefined );
192 assert
.equal( uri
.toString(), testuri
, 'undefined' );
194 uri
= new MyUri( null );
195 assert
.equal( uri
.toString(), testuri
, 'null' );
197 uri
= new MyUri( '' );
198 assert
.equal( uri
.toString(), testuri
, 'empty string' );
201 QUnit
.test( 'Properties', 8, function ( assert
) {
204 uriBase
= new mw
.Uri( 'http://en.wiki.local/w/api.php' );
206 uri
= uriBase
.clone();
207 uri
.fragment
= 'frag';
208 assert
.equal( uri
.toString(), 'http://en.wiki.local/w/api.php#frag', 'add a fragment' );
210 uri
= uriBase
.clone();
211 uri
.host
= 'fr.wiki.local';
213 assert
.equal( uri
.toString(), 'http://fr.wiki.local:8080/w/api.php', 'change host and port' );
215 uri
= uriBase
.clone();
216 uri
.query
.foo
= 'bar';
217 assert
.equal( uri
.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'add query arguments' );
219 delete uri
.query
.foo
;
220 assert
.equal( uri
.toString(), 'http://en.wiki.local/w/api.php', 'delete query arguments' );
222 uri
= uriBase
.clone();
223 uri
.query
.foo
= 'bar';
224 assert
.equal( uri
.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'extend query arguments' );
229 assert
.ok( uri
.toString().indexOf( 'foo=quux' ) >= 0, 'extend query arguments' );
230 assert
.ok( uri
.toString().indexOf( 'foo=bar' ) === -1, 'extend query arguments' );
231 assert
.ok( uri
.toString().indexOf( 'pif=paf' ) >= 0, 'extend query arguments' );
234 QUnit
.test( '.getQueryString()', 2, function ( assert
) {
235 var uri
= new mw
.Uri( 'http://search.example.com/?q=uri' );
239 protocol
: uri
.protocol
,
244 fragment
: uri
.fragment
,
245 queryString
: uri
.getQueryString()
249 host
: 'search.example.com',
256 'basic object properties'
259 uri
= new mw
.Uri( 'https://example.com/mw/index.php?title=Sandbox/7&other=Sandbox/7&foo' );
261 uri
.getQueryString(),
262 'title=Sandbox/7&other=Sandbox%2F7&foo',
263 'title parameter is escaped the wiki-way'
268 QUnit
.test( '.clone()', 6, function ( assert
) {
271 original
= new mw
.Uri( 'http://foo.example.org/index.php?one=1&two=2' );
272 clone
= original
.clone();
274 assert
.deepEqual( clone
, original
, 'clone has equivalent properties' );
275 assert
.equal( original
.toString(), clone
.toString(), 'toString matches original' );
277 assert
.notStrictEqual( clone
, original
, 'clone is a different object when compared by reference' );
279 clone
.host
= 'bar.example.org';
280 assert
.notEqual( original
.host
, clone
.host
, 'manipulating clone did not effect original' );
281 assert
.notEqual( original
.toString(), clone
.toString(), 'Stringified url no longer matches original' );
283 clone
.query
.three
= 3;
287 { one
: '1', two
: '2' },
288 'Properties is deep cloned (bug 37708)'
292 QUnit
.test( '.toString() after query manipulation', 8, function ( assert
) {
295 uri
= new mw
.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
299 uri
.query
.n
= [ 'x', 'y', 'z' ];
301 // Verify parts and total length instead of entire string because order
302 // of iteration can vary.
303 assert
.ok( uri
.toString().indexOf( 'm=bar' ), 'toString preserves other values' );
304 assert
.ok( uri
.toString().indexOf( 'n=x&n=y&n=z' ), 'toString parameter includes all values of an array query parameter' );
305 assert
.equal( uri
.toString().length
, 'http://www.example.com/dir/?m=bar&n=x&n=y&n=z'.length
, 'toString matches expected string' );
307 uri
= new mw
.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
311 // Change query values
312 uri
.query
.n
= [ 'x', 'y', 'z' ];
314 // Verify parts and total length instead of entire string because order
315 // of iteration can vary.
316 assert
.ok( uri
.toString().indexOf( 'm=foo&m=bar' ) >= 0, 'toString preserves other values' );
317 assert
.ok( uri
.toString().indexOf( 'n=x&n=y&n=z' ) >= 0, 'toString parameter includes all values of an array query parameter' );
318 assert
.equal( uri
.toString().length
, 'http://www.example.com/dir/?m=foo&m=bar&n=x&n=y&n=z'.length
, 'toString matches expected string' );
320 // Remove query values
321 uri
.query
.m
.splice( 0, 1 );
324 assert
.equal( uri
.toString(), 'http://www.example.com/dir/?m=bar', 'deletion properties' );
326 // Remove more query values, leaving an empty array
327 uri
.query
.m
.splice( 0, 1 );
328 assert
.equal( uri
.toString(), 'http://www.example.com/dir/', 'empty array value is ommitted' );
331 QUnit
.test( 'Variable defaultUri', 2, function ( assert
) {
333 href
= 'http://example.org/w/index.php#here',
334 UriClass
= mw
.UriRelative( function () {
338 uri
= new UriClass();
341 protocol
: uri
.protocol
,
343 password
: uri
.password
,
348 fragment
: uri
.fragment
356 path
: '/w/index.php',
360 'basic object properties'
363 // Default URI may change, e.g. via history.replaceState, pushState or location.hash (T74334)
364 href
= 'https://example.com/wiki/Foo?v=2';
365 uri
= new UriClass();
368 protocol
: uri
.protocol
,
370 password
: uri
.password
,
375 fragment
: uri
.fragment
387 'basic object properties'
391 QUnit
.test( 'Advanced URL', 11, function ( assert
) {
392 var uri
, queryString
, relativePath
;
394 uri
= new mw
.Uri( 'http://auth@www.example.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value+%28escaped%29#top' );
398 protocol
: uri
.protocol
,
400 password
: uri
.password
,
405 fragment
: uri
.fragment
411 host
: 'www.example.com',
413 path
: '/dir/dir.2/index.htm',
414 query
: { q1
: '0', test1
: null, test2
: 'value (escaped)' },
417 'basic object properties'
420 assert
.equal( uri
.getUserInfo(), 'auth', 'user info' );
422 assert
.equal( uri
.getAuthority(), 'auth@www.example.com:81', 'authority equal to auth@hostport' );
424 assert
.equal( uri
.getHostPort(), 'www.example.com:81', 'hostport equal to host:port' );
426 queryString
= uri
.getQueryString();
427 assert
.ok( queryString
.indexOf( 'q1=0' ) >= 0, 'query param with numbers' );
428 assert
.ok( queryString
.indexOf( 'test1' ) >= 0, 'query param with null value is included' );
429 assert
.ok( queryString
.indexOf( 'test1=' ) === -1, 'query param with null value does not generate equals sign' );
430 assert
.ok( queryString
.indexOf( 'test2=value+%28escaped%29' ) >= 0, 'query param is url escaped' );
432 relativePath
= uri
.getRelativePath();
433 assert
.ok( relativePath
.indexOf( uri
.path
) >= 0, 'path in relative path' );
434 assert
.ok( relativePath
.indexOf( uri
.getQueryString() ) >= 0, 'query string in relative path' );
435 assert
.ok( relativePath
.indexOf( uri
.fragment
) >= 0, 'fragment in relative path' );
438 QUnit
.test( 'Parse a uri with an @ symbol in the path and query', 1, function ( assert
) {
439 var uri
= new mw
.Uri( 'http://www.example.com/test@test?x=@uri&y@=uri&z@=@' );
443 protocol
: uri
.protocol
,
445 password
: uri
.password
,
450 fragment
: uri
.fragment
,
451 queryString
: uri
.getQueryString()
457 host
: 'www.example.com',
460 query
: { x
: '@uri', 'y@': 'uri', 'z@': '@' },
462 queryString
: 'x=%40uri&y%40=uri&z%40=%40'
464 'basic object properties'
468 QUnit
.test( 'Handle protocol-relative URLs', 5, function ( assert
) {
471 UriRel
= mw
.UriRelative( 'glork://en.wiki.local/foo.php' );
473 uri
= new UriRel( '//en.wiki.local/w/api.php' );
474 assert
.equal( uri
.protocol
, 'glork', 'create protocol-relative URLs with same protocol as document' );
476 uri
= new UriRel( '/foo.com' );
477 assert
.equal( uri
.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in loose mode' );
479 uri
= new UriRel( 'http:/foo.com' );
480 assert
.equal( uri
.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in loose mode' );
482 uri
= new UriRel( '/foo.com', true );
483 assert
.equal( uri
.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in strict mode' );
485 uri
= new UriRel( 'http:/foo.com', true );
486 assert
.equal( uri
.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in strict mode' );
489 QUnit
.test( 'bug 35658', 2, function ( assert
) {
490 var testProtocol
, testServer
, testPort
, testPath
, UriClass
, uri
, href
;
492 testProtocol
= 'https://';
493 testServer
= 'foo.example.org';
497 UriClass
= mw
.UriRelative( testProtocol
+ testServer
+ '/some/path/index.html' );
498 uri
= new UriClass( testPath
);
499 href
= uri
.toString();
500 assert
.equal( href
, testProtocol
+ testServer
+ testPath
, 'Root-relative URL gets host & protocol supplied' );
502 UriClass
= mw
.UriRelative( testProtocol
+ testServer
+ ':' + testPort
+ '/some/path.php' );
503 uri
= new UriClass( testPath
);
504 href
= uri
.toString();
505 assert
.equal( href
, testProtocol
+ testServer
+ ':' + testPort
+ testPath
, 'Root-relative URL gets host, protocol, and port supplied' );
507 }( mediaWiki
, jQuery
) );