Update docs/hooks.txt for ShowSearchHitTitle
[mediawiki.git] / tests / qunit / suites / resources / mediawiki / mediawiki.Uri.test.js
blob97185fca7310400740939121ca347d66da2259bd
1 ( function ( mw, $ ) {
2 QUnit.module( 'mediawiki.Uri', QUnit.newMwEnvironment( {
3 setup: function () {
4 this.mwUriOrg = mw.Uri;
5 mw.Uri = mw.UriRelative( 'http://example.org/w/index.php' );
6 },
7 teardown: function () {
8 mw.Uri = this.mwUriOrg;
9 delete this.mwUriOrg;
11 } ) );
13 $.each( [ true, false ], function ( i, strictMode ) {
14 QUnit.test( 'Basic construction and properties (' + ( strictMode ? '' : 'non-' ) + 'strict mode)', 2, function ( assert ) {
15 var uriString, uri;
16 uriString = 'http://www.ietf.org/rfc/rfc2396.txt';
17 uri = new mw.Uri( uriString, {
18 strictMode: strictMode
19 } );
21 assert.deepEqual(
23 protocol: uri.protocol,
24 host: uri.host,
25 port: uri.port,
26 path: uri.path,
27 query: uri.query,
28 fragment: uri.fragment
29 }, {
30 protocol: 'http',
31 host: 'www.ietf.org',
32 port: undefined,
33 path: '/rfc/rfc2396.txt',
34 query: {},
35 fragment: undefined
37 'basic object properties'
40 assert.deepEqual(
42 userInfo: uri.getUserInfo(),
43 authority: uri.getAuthority(),
44 hostPort: uri.getHostPort(),
45 queryString: uri.getQueryString(),
46 relativePath: uri.getRelativePath(),
47 toString: uri.toString()
50 userInfo: '',
51 authority: 'www.ietf.org',
52 hostPort: 'www.ietf.org',
53 queryString: '',
54 relativePath: '/rfc/rfc2396.txt',
55 toString: uriString
57 'construct composite components of URI on request'
59 } );
60 } );
62 QUnit.test( 'Constructor( String[, Object ] )', 11, function ( assert ) {
63 var uri;
65 uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
66 overrideKeys: true
67 } );
69 // Strict comparison to assert that numerical values stay strings
70 assert.strictEqual( uri.query.n, '1', 'Simple parameter with overrideKeys:true' );
71 assert.strictEqual( uri.query.m, 'bar', 'Last key overrides earlier keys with overrideKeys:true' );
73 uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
74 overrideKeys: false
75 } );
77 assert.strictEqual( uri.query.n, '1', 'Simple parameter with overrideKeys:false' );
78 assert.strictEqual( uri.query.m[ 0 ], 'foo', 'Order of multi-value parameters with overrideKeys:true' );
79 assert.strictEqual( uri.query.m[ 1 ], 'bar', 'Order of multi-value parameters with overrideKeys:true' );
80 assert.strictEqual( uri.query.m.length, 2, 'Number of mult-value field is correct' );
82 uri = new mw.Uri( 'ftp://usr:pwd@192.0.2.16/' );
84 assert.deepEqual(
86 protocol: uri.protocol,
87 user: uri.user,
88 password: uri.password,
89 host: uri.host,
90 port: uri.port,
91 path: uri.path,
92 query: uri.query,
93 fragment: uri.fragment
96 protocol: 'ftp',
97 user: 'usr',
98 password: 'pwd',
99 host: '192.0.2.16',
100 port: undefined,
101 path: '/',
102 query: {},
103 fragment: undefined
105 'Parse an ftp URI correctly with user and password'
108 assert.throws(
109 function () {
110 return new mw.Uri( 'glaswegian penguins' );
112 function ( e ) {
113 return e.message === 'Bad constructor arguments';
115 'throw error on non-URI as argument to constructor'
118 assert.throws(
119 function () {
120 return new mw.Uri( 'example.com/bar/baz', {
121 strictMode: true
122 } );
124 function ( e ) {
125 return e.message === 'Bad constructor arguments';
127 'throw error on URI without protocol or // or leading / in strict mode'
130 uri = new mw.Uri( 'example.com/bar/baz', {
131 strictMode: false
132 } );
133 assert.equal( uri.toString(), 'http://example.com/bar/baz', 'normalize URI without protocol or // in loose mode' );
135 /*jshint -W001 */
136 uri = new mw.Uri( 'http://example.com/index.php?key=key&hasOwnProperty=hasOwnProperty&constructor=constructor&watch=watch' );
137 assert.deepEqual(
138 uri.query,
140 key: 'key',
141 constructor: 'constructor',
142 hasOwnProperty: 'hasOwnProperty',
143 watch: 'watch'
145 'Keys in query strings support names of Object prototypes (bug T114344)'
147 /*jshint +W001 */
148 } );
150 QUnit.test( 'Constructor( Object )', 3, function ( assert ) {
151 var uri = new mw.Uri( {
152 protocol: 'http',
153 host: 'www.foo.local',
154 path: '/this'
155 } );
156 assert.equal( uri.toString(), 'http://www.foo.local/this', 'Basic properties' );
158 uri = new mw.Uri( {
159 protocol: 'http',
160 host: 'www.foo.local',
161 path: '/this',
162 query: { hi: 'there' },
163 fragment: 'blah'
164 } );
165 assert.equal( uri.toString(), 'http://www.foo.local/this?hi=there#blah', 'More complex properties' );
167 assert.throws(
168 function () {
169 return new mw.Uri( {
170 protocol: 'http',
171 host: 'www.foo.local'
172 } );
174 function ( e ) {
175 return e.message === 'Bad constructor arguments';
177 'Construction failed when missing required properties'
179 } );
181 QUnit.test( 'Constructor( empty )', 4, function ( assert ) {
182 var testuri, MyUri, uri;
184 testuri = 'http://example.org/w/index.php';
185 MyUri = mw.UriRelative( testuri );
187 uri = new MyUri();
188 assert.equal( uri.toString(), testuri, 'no arguments' );
190 uri = new MyUri( undefined );
191 assert.equal( uri.toString(), testuri, 'undefined' );
193 uri = new MyUri( null );
194 assert.equal( uri.toString(), testuri, 'null' );
196 uri = new MyUri( '' );
197 assert.equal( uri.toString(), testuri, 'empty string' );
198 } );
200 QUnit.test( 'Properties', 8, function ( assert ) {
201 var uriBase, uri;
203 uriBase = new mw.Uri( 'http://en.wiki.local/w/api.php' );
205 uri = uriBase.clone();
206 uri.fragment = 'frag';
207 assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php#frag', 'add a fragment' );
209 uri = uriBase.clone();
210 uri.host = 'fr.wiki.local';
211 uri.port = '8080';
212 assert.equal( uri.toString(), 'http://fr.wiki.local:8080/w/api.php', 'change host and port' );
214 uri = uriBase.clone();
215 uri.query.foo = 'bar';
216 assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'add query arguments' );
218 delete uri.query.foo;
219 assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php', 'delete query arguments' );
221 uri = uriBase.clone();
222 uri.query.foo = 'bar';
223 assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'extend query arguments' );
224 uri.extend( {
225 foo: 'quux',
226 pif: 'paf'
227 } );
228 assert.ok( uri.toString().indexOf( 'foo=quux' ) >= 0, 'extend query arguments' );
229 assert.ok( uri.toString().indexOf( 'foo=bar' ) === -1, 'extend query arguments' );
230 assert.ok( uri.toString().indexOf( 'pif=paf' ) >= 0, 'extend query arguments' );
231 } );
233 QUnit.test( '.getQueryString()', 2, function ( assert ) {
234 var uri = new mw.Uri( 'http://search.example.com/?q=uri' );
236 assert.deepEqual(
238 protocol: uri.protocol,
239 host: uri.host,
240 port: uri.port,
241 path: uri.path,
242 query: uri.query,
243 fragment: uri.fragment,
244 queryString: uri.getQueryString()
247 protocol: 'http',
248 host: 'search.example.com',
249 port: undefined,
250 path: '/',
251 query: { q: 'uri' },
252 fragment: undefined,
253 queryString: 'q=uri'
255 'basic object properties'
258 uri = new mw.Uri( 'https://example.com/mw/index.php?title=Sandbox/7&other=Sandbox/7&foo' );
259 assert.equal(
260 uri.getQueryString(),
261 'title=Sandbox/7&other=Sandbox%2F7&foo',
262 'title parameter is escaped the wiki-way'
265 } );
267 QUnit.test( '.clone()', 6, function ( assert ) {
268 var original, clone;
270 original = new mw.Uri( 'http://foo.example.org/index.php?one=1&two=2' );
271 clone = original.clone();
273 assert.deepEqual( clone, original, 'clone has equivalent properties' );
274 assert.equal( original.toString(), clone.toString(), 'toString matches original' );
276 assert.notStrictEqual( clone, original, 'clone is a different object when compared by reference' );
278 clone.host = 'bar.example.org';
279 assert.notEqual( original.host, clone.host, 'manipulating clone did not effect original' );
280 assert.notEqual( original.toString(), clone.toString(), 'Stringified url no longer matches original' );
282 clone.query.three = 3;
284 assert.deepEqual(
285 original.query,
286 { one: '1', two: '2' },
287 'Properties is deep cloned (bug 37708)'
289 } );
291 QUnit.test( '.toString() after query manipulation', 8, function ( assert ) {
292 var uri;
294 uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
295 overrideKeys: true
296 } );
298 uri.query.n = [ 'x', 'y', 'z' ];
300 // Verify parts and total length instead of entire string because order
301 // of iteration can vary.
302 assert.ok( uri.toString().indexOf( 'm=bar' ), 'toString preserves other values' );
303 assert.ok( uri.toString().indexOf( 'n=x&n=y&n=z' ), 'toString parameter includes all values of an array query parameter' );
304 assert.equal( uri.toString().length, 'http://www.example.com/dir/?m=bar&n=x&n=y&n=z'.length, 'toString matches expected string' );
306 uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
307 overrideKeys: false
308 } );
310 // Change query values
311 uri.query.n = [ 'x', 'y', 'z' ];
313 // Verify parts and total length instead of entire string because order
314 // of iteration can vary.
315 assert.ok( uri.toString().indexOf( 'm=foo&m=bar' ) >= 0, 'toString preserves other values' );
316 assert.ok( uri.toString().indexOf( 'n=x&n=y&n=z' ) >= 0, 'toString parameter includes all values of an array query parameter' );
317 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' );
319 // Remove query values
320 uri.query.m.splice( 0, 1 );
321 delete uri.query.n;
323 assert.equal( uri.toString(), 'http://www.example.com/dir/?m=bar', 'deletion properties' );
325 // Remove more query values, leaving an empty array
326 uri.query.m.splice( 0, 1 );
327 assert.equal( uri.toString(), 'http://www.example.com/dir/', 'empty array value is ommitted' );
328 } );
330 QUnit.test( 'Variable defaultUri', 2, function ( assert ) {
331 var uri,
332 href = 'http://example.org/w/index.php#here',
333 UriClass = mw.UriRelative( function () {
334 return href;
335 } );
337 uri = new UriClass();
338 assert.deepEqual(
340 protocol: uri.protocol,
341 user: uri.user,
342 password: uri.password,
343 host: uri.host,
344 port: uri.port,
345 path: uri.path,
346 query: uri.query,
347 fragment: uri.fragment
350 protocol: 'http',
351 user: undefined,
352 password: undefined,
353 host: 'example.org',
354 port: undefined,
355 path: '/w/index.php',
356 query: {},
357 fragment: 'here'
359 'basic object properties'
362 // Default URI may change, e.g. via history.replaceState, pushState or location.hash (T74334)
363 href = 'https://example.com/wiki/Foo?v=2';
364 uri = new UriClass();
365 assert.deepEqual(
367 protocol: uri.protocol,
368 user: uri.user,
369 password: uri.password,
370 host: uri.host,
371 port: uri.port,
372 path: uri.path,
373 query: uri.query,
374 fragment: uri.fragment
377 protocol: 'https',
378 user: undefined,
379 password: undefined,
380 host: 'example.com',
381 port: undefined,
382 path: '/wiki/Foo',
383 query: { v: '2' },
384 fragment: undefined
386 'basic object properties'
388 } );
390 QUnit.test( 'Advanced URL', 11, function ( assert ) {
391 var uri, queryString, relativePath;
393 uri = new mw.Uri( 'http://auth@www.example.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value+%28escaped%29#top' );
395 assert.deepEqual(
397 protocol: uri.protocol,
398 user: uri.user,
399 password: uri.password,
400 host: uri.host,
401 port: uri.port,
402 path: uri.path,
403 query: uri.query,
404 fragment: uri.fragment
407 protocol: 'http',
408 user: 'auth',
409 password: undefined,
410 host: 'www.example.com',
411 port: '81',
412 path: '/dir/dir.2/index.htm',
413 query: { q1: '0', test1: null, test2: 'value (escaped)' },
414 fragment: 'top'
416 'basic object properties'
419 assert.equal( uri.getUserInfo(), 'auth', 'user info' );
421 assert.equal( uri.getAuthority(), 'auth@www.example.com:81', 'authority equal to auth@hostport' );
423 assert.equal( uri.getHostPort(), 'www.example.com:81', 'hostport equal to host:port' );
425 queryString = uri.getQueryString();
426 assert.ok( queryString.indexOf( 'q1=0' ) >= 0, 'query param with numbers' );
427 assert.ok( queryString.indexOf( 'test1' ) >= 0, 'query param with null value is included' );
428 assert.ok( queryString.indexOf( 'test1=' ) === -1, 'query param with null value does not generate equals sign' );
429 assert.ok( queryString.indexOf( 'test2=value+%28escaped%29' ) >= 0, 'query param is url escaped' );
431 relativePath = uri.getRelativePath();
432 assert.ok( relativePath.indexOf( uri.path ) >= 0, 'path in relative path' );
433 assert.ok( relativePath.indexOf( uri.getQueryString() ) >= 0, 'query string in relative path' );
434 assert.ok( relativePath.indexOf( uri.fragment ) >= 0, 'fragment in relative path' );
435 } );
437 QUnit.test( 'Parse a uri with an @ symbol in the path and query', 1, function ( assert ) {
438 var uri = new mw.Uri( 'http://www.example.com/test@test?x=@uri&y@=uri&z@=@' );
440 assert.deepEqual(
442 protocol: uri.protocol,
443 user: uri.user,
444 password: uri.password,
445 host: uri.host,
446 port: uri.port,
447 path: uri.path,
448 query: uri.query,
449 fragment: uri.fragment,
450 queryString: uri.getQueryString()
453 protocol: 'http',
454 user: undefined,
455 password: undefined,
456 host: 'www.example.com',
457 port: undefined,
458 path: '/test@test',
459 query: { x: '@uri', 'y@': 'uri', 'z@': '@' },
460 fragment: undefined,
461 queryString: 'x=%40uri&y%40=uri&z%40=%40'
463 'basic object properties'
465 } );
467 QUnit.test( 'Handle protocol-relative URLs', 5, function ( assert ) {
468 var UriRel, uri;
470 UriRel = mw.UriRelative( 'glork://en.wiki.local/foo.php' );
472 uri = new UriRel( '//en.wiki.local/w/api.php' );
473 assert.equal( uri.protocol, 'glork', 'create protocol-relative URLs with same protocol as document' );
475 uri = new UriRel( '/foo.com' );
476 assert.equal( uri.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in loose mode' );
478 uri = new UriRel( 'http:/foo.com' );
479 assert.equal( uri.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in loose mode' );
481 uri = new UriRel( '/foo.com', true );
482 assert.equal( uri.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in strict mode' );
484 uri = new UriRel( 'http:/foo.com', true );
485 assert.equal( uri.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in strict mode' );
486 } );
488 QUnit.test( 'bug 35658', 2, function ( assert ) {
489 var testProtocol, testServer, testPort, testPath, UriClass, uri, href;
491 testProtocol = 'https://';
492 testServer = 'foo.example.org';
493 testPort = '3004';
494 testPath = '/!1qy';
496 UriClass = mw.UriRelative( testProtocol + testServer + '/some/path/index.html' );
497 uri = new UriClass( testPath );
498 href = uri.toString();
499 assert.equal( href, testProtocol + testServer + testPath, 'Root-relative URL gets host & protocol supplied' );
501 UriClass = mw.UriRelative( testProtocol + testServer + ':' + testPort + '/some/path.php' );
502 uri = new UriClass( testPath );
503 href = uri.toString();
504 assert.equal( href, testProtocol + testServer + ':' + testPort + testPath, 'Root-relative URL gets host, protocol, and port supplied' );
505 } );
506 }( mediaWiki, jQuery ) );