Implement extension registration from an extension.json file
[mediawiki.git] / tests / qunit / suites / resources / mediawiki / mediawiki.Uri.test.js
blobba3665538252f6e2d4ffa43ec9eeacbdc7af171e
1 /*jshint -W024 */
2 ( function ( mw, $ ) {
3         QUnit.module( 'mediawiki.Uri', QUnit.newMwEnvironment( {
4                 setup: function () {
5                         this.mwUriOrg = mw.Uri;
6                         mw.Uri = mw.UriRelative( 'http://example.org/w/index.php' );
7                 },
8                 teardown: function () {
9                         mw.Uri = this.mwUriOrg;
10                         delete this.mwUriOrg;
11                 }
12         } ) );
14         $.each( [true, false], function ( i, strictMode ) {
15                 QUnit.test( 'Basic construction and properties (' + ( strictMode ? '' : 'non-' ) + 'strict mode)', 2, function ( assert ) {
16                         var uriString, uri;
17                         uriString = 'http://www.ietf.org/rfc/rfc2396.txt';
18                         uri = new mw.Uri( uriString, {
19                                 strictMode: strictMode
20                         } );
22                         assert.deepEqual(
23                                 {
24                                         protocol: uri.protocol,
25                                         host: uri.host,
26                                         port: uri.port,
27                                         path: uri.path,
28                                         query: uri.query,
29                                         fragment: uri.fragment
30                                 }, {
31                                         protocol: 'http',
32                                         host: 'www.ietf.org',
33                                         port: undefined,
34                                         path: '/rfc/rfc2396.txt',
35                                         query: {},
36                                         fragment: undefined
37                                 },
38                                 'basic object properties'
39                         );
41                         assert.deepEqual(
42                                 {
43                                         userInfo: uri.getUserInfo(),
44                                         authority: uri.getAuthority(),
45                                         hostPort: uri.getHostPort(),
46                                         queryString: uri.getQueryString(),
47                                         relativePath: uri.getRelativePath(),
48                                         toString: uri.toString()
49                                 },
50                                 {
51                                         userInfo: '',
52                                         authority: 'www.ietf.org',
53                                         hostPort: 'www.ietf.org',
54                                         queryString: '',
55                                         relativePath: '/rfc/rfc2396.txt',
56                                         toString: uriString
57                                 },
58                                 'construct composite components of URI on request'
59                         );
60                 } );
61         } );
63         QUnit.test( 'Constructor( String[, Object ] )', 10, function ( assert ) {
64                 var uri;
66                 uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
67                         overrideKeys: true
68                 } );
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', {
75                         overrideKeys: false
76                 } );
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/' );
85                 assert.deepEqual(
86                         {
87                                 protocol: uri.protocol,
88                                 user: uri.user,
89                                 password: uri.password,
90                                 host: uri.host,
91                                 port: uri.port,
92                                 path: uri.path,
93                                 query: uri.query,
94                                 fragment: uri.fragment
95                         },
96                         {
97                                 protocol: 'ftp',
98                                 user: 'usr',
99                                 password: 'pwd',
100                                 host: '192.0.2.16',
101                                 port: undefined,
102                                 path: '/',
103                                 query: {},
104                                 fragment: undefined
105                         },
106                         'Parse an ftp URI correctly with user and password'
107                 );
109                 assert.throws(
110                         function () {
111                                 return new mw.Uri( 'glaswegian penguins' );
112                         },
113                         function ( e ) {
114                                 return e.message === 'Bad constructor arguments';
115                         },
116                         'throw error on non-URI as argument to constructor'
117                 );
119                 assert.throws(
120                         function () {
121                                 return new mw.Uri( 'example.com/bar/baz', {
122                                         strictMode: true
123                                 } );
124                         },
125                         function ( e ) {
126                                 return e.message === 'Bad constructor arguments';
127                         },
128                         'throw error on URI without protocol or // or leading / in strict mode'
129                 );
131                 uri = new mw.Uri( 'example.com/bar/baz', {
132                         strictMode: false
133                 } );
134                 assert.equal( uri.toString(), 'http://example.com/bar/baz', 'normalize URI without protocol or // in loose mode' );
135         } );
137         QUnit.test( 'Constructor( Object )', 3, function ( assert ) {
138                 var uri = new mw.Uri( {
139                         protocol: 'http',
140                         host: 'www.foo.local',
141                         path: '/this'
142                 } );
143                 assert.equal( uri.toString(), 'http://www.foo.local/this', 'Basic properties' );
145                 uri = new mw.Uri( {
146                         protocol: 'http',
147                         host: 'www.foo.local',
148                         path: '/this',
149                         query: { hi: 'there' },
150                         fragment: 'blah'
151                 } );
152                 assert.equal( uri.toString(), 'http://www.foo.local/this?hi=there#blah', 'More complex properties' );
154                 assert.throws(
155                         function () {
156                                 return new mw.Uri( {
157                                         protocol: 'http',
158                                         host: 'www.foo.local'
159                                 } );
160                         },
161                         function ( e ) {
162                                 return e.message === 'Bad constructor arguments';
163                         },
164                         'Construction failed when missing required properties'
165                 );
166         } );
168         QUnit.test( 'Constructor( empty )', 4, function ( assert ) {
169                 var testuri, MyUri, uri;
171                 testuri = 'http://example.org/w/index.php';
172                 MyUri = mw.UriRelative( testuri );
174                 uri = new MyUri();
175                 assert.equal( uri.toString(), testuri, 'no arguments' );
177                 uri = new MyUri( undefined );
178                 assert.equal( uri.toString(), testuri, 'undefined' );
180                 uri = new MyUri( null );
181                 assert.equal( uri.toString(), testuri, 'null' );
183                 uri = new MyUri( '' );
184                 assert.equal( uri.toString(), testuri, 'empty string' );
185         } );
187         QUnit.test( 'Properties', 8, function ( assert ) {
188                 var uriBase, uri;
190                 uriBase = new mw.Uri( 'http://en.wiki.local/w/api.php' );
192                 uri = uriBase.clone();
193                 uri.fragment = 'frag';
194                 assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php#frag', 'add a fragment' );
196                 uri = uriBase.clone();
197                 uri.host = 'fr.wiki.local';
198                 uri.port = '8080';
199                 assert.equal( uri.toString(), 'http://fr.wiki.local:8080/w/api.php', 'change host and port' );
201                 uri = uriBase.clone();
202                 uri.query.foo = 'bar';
203                 assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'add query arguments' );
205                 delete uri.query.foo;
206                 assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php', 'delete query arguments' );
208                 uri = uriBase.clone();
209                 uri.query.foo = 'bar';
210                 assert.equal( uri.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'extend query arguments' );
211                 uri.extend( {
212                         foo: 'quux',
213                         pif: 'paf'
214                 } );
215                 assert.ok( uri.toString().indexOf( 'foo=quux' ) >= 0, 'extend query arguments' );
216                 assert.ok( uri.toString().indexOf( 'foo=bar' ) === -1, 'extend query arguments' );
217                 assert.ok( uri.toString().indexOf( 'pif=paf' ) >= 0, 'extend query arguments' );
218         } );
220         QUnit.test( '.getQueryString()', 2, function ( assert ) {
221                 var uri = new mw.Uri( 'http://search.example.com/?q=uri' );
223                 assert.deepEqual(
224                         {
225                                 protocol: uri.protocol,
226                                 host: uri.host,
227                                 port: uri.port,
228                                 path: uri.path,
229                                 query: uri.query,
230                                 fragment: uri.fragment,
231                                 queryString: uri.getQueryString()
232                         },
233                         {
234                                 protocol: 'http',
235                                 host: 'search.example.com',
236                                 port: undefined,
237                                 path: '/',
238                                 query: { q: 'uri' },
239                                 fragment: undefined,
240                                 queryString: 'q=uri'
241                         },
242                         'basic object properties'
243                 );
245                 uri = new mw.Uri( 'https://example.com/mw/index.php?title=Sandbox/7&other=Sandbox/7&foo' );
246                 assert.equal(
247                         uri.getQueryString(),
248                         'title=Sandbox/7&other=Sandbox%2F7&foo',
249                         'title parameter is escaped the wiki-way'
250                 );
252         } );
254         QUnit.test( '.clone()', 6, function ( assert ) {
255                 var original, clone;
257                 original = new mw.Uri( 'http://foo.example.org/index.php?one=1&two=2' );
258                 clone = original.clone();
260                 assert.deepEqual( clone, original, 'clone has equivalent properties' );
261                 assert.equal( original.toString(), clone.toString(), 'toString matches original' );
263                 assert.notStrictEqual( clone, original, 'clone is a different object when compared by reference' );
265                 clone.host = 'bar.example.org';
266                 assert.notEqual( original.host, clone.host, 'manipulating clone did not effect original' );
267                 assert.notEqual( original.toString(), clone.toString(), 'Stringified url no longer matches original' );
269                 clone.query.three = 3;
271                 assert.deepEqual(
272                         original.query,
273                         { 'one': '1', 'two': '2' },
274                         'Properties is deep cloned (bug 37708)'
275                 );
276         } );
278         QUnit.test( '.toString() after query manipulation', 8, function ( assert ) {
279                 var uri;
281                 uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
282                         overrideKeys: true
283                 } );
285                 uri.query.n = [ 'x', 'y', 'z' ];
287                 // Verify parts and total length instead of entire string because order
288                 // of iteration can vary.
289                 assert.ok( uri.toString().indexOf( 'm=bar' ), 'toString preserves other values' );
290                 assert.ok( uri.toString().indexOf( 'n=x&n=y&n=z' ), 'toString parameter includes all values of an array query parameter' );
291                 assert.equal( uri.toString().length, 'http://www.example.com/dir/?m=bar&n=x&n=y&n=z'.length, 'toString matches expected string' );
293                 uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
294                         overrideKeys: false
295                 } );
297                 // Change query values
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=foo&m=bar' ) >= 0, 'toString preserves other values' );
303                 assert.ok( uri.toString().indexOf( 'n=x&n=y&n=z' ) >= 0, 'toString parameter includes all values of an array query parameter' );
304                 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' );
306                 // Remove query values
307                 uri.query.m.splice( 0, 1 );
308                 delete uri.query.n;
310                 assert.equal( uri.toString(), 'http://www.example.com/dir/?m=bar', 'deletion properties' );
312                 // Remove more query values, leaving an empty array
313                 uri.query.m.splice( 0, 1 );
314                 assert.equal( uri.toString(), 'http://www.example.com/dir/', 'empty array value is ommitted' );
315         } );
317         QUnit.test( 'Variable defaultUri', 2, function ( assert ) {
318                 var uri,
319                         href = 'http://example.org/w/index.php#here',
320                         UriClass = mw.UriRelative( function () {
321                                 return href;
322                         } );
324                 uri = new UriClass();
325                 assert.deepEqual(
326                         {
327                                 protocol: uri.protocol,
328                                 user: uri.user,
329                                 password: uri.password,
330                                 host: uri.host,
331                                 port: uri.port,
332                                 path: uri.path,
333                                 query: uri.query,
334                                 fragment: uri.fragment
335                         },
336                         {
337                                 protocol: 'http',
338                                 user: undefined,
339                                 password: undefined,
340                                 host: 'example.org',
341                                 port: undefined,
342                                 path: '/w/index.php',
343                                 query: {},
344                                 fragment: 'here'
345                         },
346                         'basic object properties'
347                 );
349                 // Default URI may change, e.g. via history.replaceState, pushState or location.hash (T74334)
350                 href = 'https://example.com/wiki/Foo?v=2';
351                 uri = new UriClass();
352                 assert.deepEqual(
353                         {
354                                 protocol: uri.protocol,
355                                 user: uri.user,
356                                 password: uri.password,
357                                 host: uri.host,
358                                 port: uri.port,
359                                 path: uri.path,
360                                 query: uri.query,
361                                 fragment: uri.fragment
362                         },
363                         {
364                                 protocol: 'https',
365                                 user: undefined,
366                                 password: undefined,
367                                 host: 'example.com',
368                                 port: undefined,
369                                 path: '/wiki/Foo',
370                                 query: { 'v': '2' },
371                                 fragment: undefined
372                         },
373                         'basic object properties'
374                 );
375         } );
377         QUnit.test( 'Advanced URL', 11, function ( assert ) {
378                 var uri, queryString, relativePath;
380                 uri = new mw.Uri( 'http://auth@www.example.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value+%28escaped%29#top' );
382                 assert.deepEqual(
383                         {
384                                 protocol: uri.protocol,
385                                 user: uri.user,
386                                 password: uri.password,
387                                 host: uri.host,
388                                 port: uri.port,
389                                 path: uri.path,
390                                 query: uri.query,
391                                 fragment: uri.fragment
392                         },
393                         {
394                                 protocol: 'http',
395                                 user: 'auth',
396                                 password: undefined,
397                                 host: 'www.example.com',
398                                 port: '81',
399                                 path: '/dir/dir.2/index.htm',
400                                 query: { q1: '0', test1: null, test2: 'value (escaped)' },
401                                 fragment: 'top'
402                         },
403                         'basic object properties'
404                 );
406                 assert.equal( uri.getUserInfo(), 'auth', 'user info' );
408                 assert.equal( uri.getAuthority(), 'auth@www.example.com:81', 'authority equal to auth@hostport' );
410                 assert.equal( uri.getHostPort(), 'www.example.com:81', 'hostport equal to host:port' );
412                 queryString = uri.getQueryString();
413                 assert.ok( queryString.indexOf( 'q1=0' ) >= 0, 'query param with numbers' );
414                 assert.ok( queryString.indexOf( 'test1' ) >= 0, 'query param with null value is included' );
415                 assert.ok( queryString.indexOf( 'test1=' ) === -1, 'query param with null value does not generate equals sign' );
416                 assert.ok( queryString.indexOf( 'test2=value+%28escaped%29' ) >= 0, 'query param is url escaped' );
418                 relativePath = uri.getRelativePath();
419                 assert.ok( relativePath.indexOf( uri.path ) >= 0, 'path in relative path' );
420                 assert.ok( relativePath.indexOf( uri.getQueryString() ) >= 0, 'query string in relative path' );
421                 assert.ok( relativePath.indexOf( uri.fragment ) >= 0, 'fragement in relative path' );
422         } );
424         QUnit.test( 'Parse a uri with an @ symbol in the path and query', 1, function ( assert ) {
425                 var uri = new mw.Uri( 'http://www.example.com/test@test?x=@uri&y@=uri&z@=@' );
427                 assert.deepEqual(
428                         {
429                                 protocol: uri.protocol,
430                                 user: uri.user,
431                                 password: uri.password,
432                                 host: uri.host,
433                                 port: uri.port,
434                                 path: uri.path,
435                                 query: uri.query,
436                                 fragment: uri.fragment,
437                                 queryString: uri.getQueryString()
438                         },
439                         {
440                                 protocol: 'http',
441                                 user: undefined,
442                                 password: undefined,
443                                 host: 'www.example.com',
444                                 port: undefined,
445                                 path: '/test@test',
446                                 query: { x: '@uri', 'y@': 'uri', 'z@': '@' },
447                                 fragment: undefined,
448                                 queryString: 'x=%40uri&y%40=uri&z%40=%40'
449                         },
450                         'basic object properties'
451                 );
452         } );
454         QUnit.test( 'Handle protocol-relative URLs', 5, function ( assert ) {
455                 var UriRel, uri;
457                 UriRel = mw.UriRelative( 'glork://en.wiki.local/foo.php' );
459                 uri = new UriRel( '//en.wiki.local/w/api.php' );
460                 assert.equal( uri.protocol, 'glork', 'create protocol-relative URLs with same protocol as document' );
462                 uri = new UriRel( '/foo.com' );
463                 assert.equal( uri.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in loose mode' );
465                 uri = new UriRel( 'http:/foo.com' );
466                 assert.equal( uri.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in loose mode' );
468                 uri = new UriRel( '/foo.com', true );
469                 assert.equal( uri.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in strict mode' );
471                 uri = new UriRel( 'http:/foo.com', true );
472                 assert.equal( uri.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in strict mode' );
473         } );
475         QUnit.test( 'bug 35658', 2, function ( assert ) {
476                 var testProtocol, testServer, testPort, testPath, UriClass, uri, href;
478                 testProtocol = 'https://';
479                 testServer = 'foo.example.org';
480                 testPort = '3004';
481                 testPath = '/!1qy';
483                 UriClass = mw.UriRelative( testProtocol + testServer + '/some/path/index.html' );
484                 uri = new UriClass( testPath );
485                 href = uri.toString();
486                 assert.equal( href, testProtocol + testServer + testPath, 'Root-relative URL gets host & protocol supplied' );
488                 UriClass = mw.UriRelative( testProtocol + testServer + ':' + testPort + '/some/path.php' );
489                 uri = new UriClass( testPath );
490                 href = uri.toString();
491                 assert.equal( href, testProtocol + testServer + ':' + testPort + testPath, 'Root-relative URL gets host, protocol, and port supplied' );
492         } );
493 }( mediaWiki, jQuery ) );