Merge "Remove extra unneeded whitespace"
[lhc/web/wiklou.git] / tests / qunit / suites / resources / mediawiki / mediawiki.Uri.test.js
1 module( 'mediawiki.Uri', QUnit.newMwEnvironment() );
2
3 test( '-- Initial check', function () {
4 expect( 2 );
5
6 // Ensure we have a generic mw.Uri constructor. By default mediawiki.uri,
7 // will use the currrent window ocation as base. But for testing we need
8 // to have a generic one, so that it doens't return false negatives if
9 // we run the test suite from an https server.
10 mw.Uri = mw.UriRelative( 'http://example.org/w/index.php' );
11
12 ok( mw.UriRelative, 'mw.UriRelative defined' );
13 ok( mw.Uri, 'mw.Uri defined' );
14 } );
15
16 $.each( [true, false], function ( i, strictMode ) {
17 test( 'Basic mw.Uri object test in ' + ( strictMode ? '' : 'non-' ) + 'strict mode for a simple HTTP URI', function () {
18 var uriString, uri;
19 expect( 2 );
20
21 uriString = 'http://www.ietf.org/rfc/rfc2396.txt';
22 uri = new mw.Uri( uriString, {
23 strictMode: strictMode
24 });
25
26 deepEqual(
27 {
28 protocol: uri.protocol,
29 host: uri.host,
30 port: uri.port,
31 path: uri.path,
32 query: uri.query,
33 fragment: uri.fragment
34 }, {
35 protocol: 'http',
36 host: 'www.ietf.org',
37 port: undefined,
38 path: '/rfc/rfc2396.txt',
39 query: {},
40 fragment: undefined
41 },
42 'basic object properties'
43 );
44
45 deepEqual(
46 {
47 userInfo: uri.getUserInfo(),
48 authority: uri.getAuthority(),
49 hostPort: uri.getHostPort(),
50 queryString: uri.getQueryString(),
51 relativePath: uri.getRelativePath(),
52 toString: uri.toString()
53 },
54 {
55 userInfo: '',
56 authority: 'www.ietf.org',
57 hostPort: 'www.ietf.org',
58 queryString: '',
59 relativePath: '/rfc/rfc2396.txt',
60 toString: uriString
61 },
62 'construct composite components of URI on request'
63 );
64
65 });
66 });
67
68 test( 'Parse an ftp URI correctly with user and password', function () {
69 var uri;
70 expect( 1 );
71
72 uri = new mw.Uri( 'ftp://usr:pwd@192.0.2.16/' );
73
74 deepEqual(
75 {
76 protocol: uri.protocol,
77 user: uri.user,
78 password: uri.password,
79 host: uri.host,
80 port: uri.port,
81 path: uri.path,
82 query: uri.query,
83 fragment: uri.fragment
84 },
85 {
86 protocol: 'ftp',
87 user: 'usr',
88 password: 'pwd',
89 host: '192.0.2.16',
90 port: undefined,
91 path: '/',
92 query: {},
93 fragment: undefined
94 },
95 'basic object properties'
96 );
97 } );
98
99 test( 'Parse a uri with simple querystring', function () {
100 var uri;
101 expect( 1 );
102
103 uri = new mw.Uri( 'http://www.google.com/?q=uri' );
104
105 deepEqual(
106 {
107 protocol: uri.protocol,
108 host: uri.host,
109 port: uri.port,
110 path: uri.path,
111 query: uri.query,
112 fragment: uri.fragment,
113 queryString: uri.getQueryString()
114 },
115 {
116 protocol: 'http',
117 host: 'www.google.com',
118 port: undefined,
119 path: '/',
120 query: { q: 'uri' },
121 fragment: undefined,
122 queryString: 'q=uri'
123 },
124 'basic object properties'
125 );
126 } );
127
128 test( 'Handle multiple query parameter (overrideKeys on)', function () {
129 var uri;
130 expect( 5 );
131
132 uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
133 overrideKeys: true
134 });
135
136 equal( uri.query.n, '1', 'multiple parameters are parsed' );
137 equal( uri.query.m, 'bar', 'last key overrides earlier keys' );
138
139 uri.query.n = [ 'x', 'y', 'z' ];
140
141 // Verify parts and total length instead of entire string because order
142 // of iteration can vary.
143 ok( uri.toString().indexOf( 'm=bar' ), 'toString preserves other values' );
144 ok( uri.toString().indexOf( 'n=x&n=y&n=z' ), 'toString parameter includes all values of an array query parameter' );
145 equal( uri.toString().length, 'http://www.example.com/dir/?m=bar&n=x&n=y&n=z'.length, 'toString matches expected string' );
146 } );
147
148 test( 'Handle multiple query parameter (overrideKeys off)', function () {
149 var uri;
150 expect( 9 );
151
152 uri = new mw.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
153 overrideKeys: false
154 });
155
156 // Strict comparison so that types are also verified (n should be string '1')
157 strictEqual( uri.query.m.length, 2, 'multi-value query should be an array with 2 items' );
158 strictEqual( uri.query.m[0], 'foo', 'order and value is correct' );
159 strictEqual( uri.query.m[1], 'bar', 'order and value is correct' );
160 strictEqual( uri.query.n, '1', 'n=1 is parsed with the correct value of the expected type' );
161
162 // Change query values
163 uri.query.n = [ 'x', 'y', 'z' ];
164
165 // Verify parts and total length instead of entire string because order
166 // of iteration can vary.
167 ok( uri.toString().indexOf( 'm=foo&m=bar' ) >= 0, 'toString preserves other values' );
168 ok( uri.toString().indexOf( 'n=x&n=y&n=z' ) >= 0, 'toString parameter includes all values of an array query parameter' );
169 equal( uri.toString().length, 'http://www.example.com/dir/?m=foo&m=bar&n=x&n=y&n=z'.length, 'toString matches expected string' );
170
171 // Remove query values
172 uri.query.m.splice( 0, 1 );
173 delete uri.query.n;
174
175 equal( uri.toString(), 'http://www.example.com/dir/?m=bar', 'deletion properties' );
176
177 // Remove more query values, leaving an empty array
178 uri.query.m.splice( 0, 1 );
179 equal( uri.toString(), 'http://www.example.com/dir/', 'empty array value is ommitted' );
180 } );
181
182 test( 'All-dressed URI with everything', function () {
183 var uri, queryString, relativePath;
184 expect( 11 );
185
186 uri = new mw.Uri( 'http://auth@www.example.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value+%28escaped%29#top' );
187
188 deepEqual(
189 {
190 protocol: uri.protocol,
191 user: uri.user,
192 password: uri.password,
193 host: uri.host,
194 port: uri.port,
195 path: uri.path,
196 query: uri.query,
197 fragment: uri.fragment
198 },
199 {
200 protocol: 'http',
201 user: 'auth',
202 password: undefined,
203 host: 'www.example.com',
204 port: '81',
205 path: '/dir/dir.2/index.htm',
206 query: { q1: '0', test1: null, test2: 'value (escaped)' },
207 fragment: 'top'
208 },
209 'basic object properties'
210 );
211
212 equal( uri.getUserInfo(), 'auth', 'user info' );
213
214 equal( uri.getAuthority(), 'auth@www.example.com:81', 'authority equal to auth@hostport' );
215
216 equal( uri.getHostPort(), 'www.example.com:81', 'hostport equal to host:port' );
217
218 queryString = uri.getQueryString();
219 ok( queryString.indexOf( 'q1=0' ) >= 0, 'query param with numbers' );
220 ok( queryString.indexOf( 'test1' ) >= 0, 'query param with null value is included' );
221 ok( queryString.indexOf( 'test1=' ) === -1, 'query param with null value does not generate equals sign' );
222 ok( queryString.indexOf( 'test2=value+%28escaped%29' ) >= 0, 'query param is url escaped' );
223
224 relativePath = uri.getRelativePath();
225 ok( relativePath.indexOf( uri.path ) >= 0, 'path in relative path' );
226 ok( relativePath.indexOf( uri.getQueryString() ) >= 0, 'query string in relative path' );
227 ok( relativePath.indexOf( uri.fragment ) >= 0, 'fragement in relative path' );
228 } );
229
230 test( 'Cloning', function () {
231 var original, clone;
232 expect( 5 );
233
234 original = new mw.Uri( 'http://en.wiki.local/w/api.php?action=query&foo=bar' );
235 clone = original.clone();
236
237 deepEqual( clone, original, 'clone has equivalent properties' );
238 equal( original.toString(), clone.toString(), 'toString matches original' );
239
240 notStrictEqual( clone, original, 'clone is not the same when compared by reference' );
241
242 clone.host = 'fr.wiki.local';
243 notEqual( original.host, clone.host, 'manipulating clone did not effect original' );
244 notEqual( original.toString(), clone.toString(), 'toString no longer matches original' );
245 } );
246
247 test( 'Constructing mw.Uri from plain object', function () {
248 var uri;
249 expect( 3 );
250
251 uri = new mw.Uri({
252 protocol: 'http',
253 host: 'www.foo.local',
254 path: '/this'
255 });
256 equal( uri.toString(), 'http://www.foo.local/this', 'Basic properties' );
257
258 uri = new mw.Uri({
259 protocol: 'http',
260 host: 'www.foo.local',
261 path: '/this',
262 query: { hi: 'there' },
263 fragment: 'blah'
264 });
265 equal( uri.toString(), 'http://www.foo.local/this?hi=there#blah', 'More complex properties' );
266
267 raises(
268 function () {
269 var uri = new mw.Uri({
270 protocol: 'http',
271 host: 'www.foo.local'
272 });
273 },
274 function ( e ) {
275 return e.message === 'Bad constructor arguments';
276 },
277 'Construction failed when missing required properties'
278 );
279 } );
280
281 test( 'Manipulate properties', function () {
282 var uriBase, uri;
283 expect( 8 );
284
285 uriBase = new mw.Uri( 'http://en.wiki.local/w/api.php' );
286
287 uri = uriBase.clone();
288 uri.fragment = 'frag';
289 equal( uri.toString(), 'http://en.wiki.local/w/api.php#frag', 'add a fragment' );
290
291 uri = uriBase.clone();
292 uri.host = 'fr.wiki.local';
293 uri.port = '8080';
294 equal( uri.toString(), 'http://fr.wiki.local:8080/w/api.php', 'change host and port' );
295
296 uri = uriBase.clone();
297 uri.query.foo = 'bar';
298 equal( uri.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'add query arguments' );
299
300 delete uri.query.foo;
301 equal( uri.toString(), 'http://en.wiki.local/w/api.php', 'delete query arguments' );
302
303 uri = uriBase.clone();
304 uri.query.foo = 'bar';
305 equal( uri.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'extend query arguments' );
306 uri.extend({
307 foo: 'quux',
308 pif: 'paf'
309 });
310 ok( uri.toString().indexOf( 'foo=quux' ) >= 0, 'extend query arguments' );
311 ok( uri.toString().indexOf( 'foo=bar' ) === -1, 'extend query arguments' );
312 ok( uri.toString().indexOf( 'pif=paf' ) >= 0 , 'extend query arguments' );
313 } );
314
315 test( 'Handle protocol-relative URLs', function () {
316 var UriRel, uri;
317 expect( 5 );
318
319 UriRel = mw.UriRelative( 'glork://en.wiki.local/foo.php' );
320
321 uri = new UriRel( '//en.wiki.local/w/api.php' );
322 equal( uri.protocol, 'glork', 'create protocol-relative URLs with same protocol as document' );
323
324 uri = new UriRel( '/foo.com' );
325 equal( uri.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in loose mode' );
326
327 uri = new UriRel( 'http:/foo.com' );
328 equal( uri.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in loose mode' );
329
330 uri = new UriRel( '/foo.com', true );
331 equal( uri.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in strict mode' );
332
333 uri = new UriRel( 'http:/foo.com', true );
334 equal( uri.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in strict mode' );
335 } );
336
337 test( 'Bad calls', function () {
338 var uri;
339 expect( 5 );
340
341 raises(
342 function () {
343 new mw.Uri();
344 },
345 function ( e ) {
346 return e.message === 'Bad constructor arguments';
347 },
348 'throw error on no arguments to constructor'
349 );
350
351 raises(
352 function () {
353 new mw.Uri( '' );
354 },
355 function ( e ) {
356 return e.message === 'Bad constructor arguments';
357 },
358 'throw error on empty string as argument to constructor'
359 );
360
361 raises(
362 function () {
363 new mw.Uri( 'glaswegian penguins' );
364 },
365 function ( e ) {
366 return e.message === 'Bad constructor arguments';
367 },
368 'throw error on non-URI as argument to constructor'
369 );
370
371 raises(
372 function () {
373 new mw.Uri( 'foo.com/bar/baz', {
374 strictMode: true
375 });
376 },
377 function ( e ) {
378 return e.message === 'Bad constructor arguments';
379 },
380 'throw error on URI without protocol or // or leading / in strict mode'
381 );
382
383 uri = new mw.Uri( 'foo.com/bar/baz', {
384 strictMode: false
385 });
386 equal( uri.toString(), 'http://foo.com/bar/baz', 'normalize URI without protocol or // in loose mode' );
387 });
388
389 test( 'bug 35658', function () {
390 expect( 2 );
391
392 var testProtocol, testServer, testPort, testPath, UriClass, uri, href;
393
394 testProtocol = 'https://';
395 testServer = 'foo.example.org';
396 testPort = '3004';
397 testPath = '/!1qy';
398
399 UriClass = mw.UriRelative( testProtocol + testServer + '/some/path/index.html' );
400 uri = new UriClass( testPath );
401 href = uri.toString();
402 equal( href, testProtocol + testServer + testPath, 'Root-relative URL gets host & protocol supplied' );
403
404 UriClass = mw.UriRelative( testProtocol + testServer + ':' + testPort + '/some/path.php' );
405 uri = new UriClass( testPath );
406 href = uri.toString();
407 equal( href, testProtocol + testServer + ':' + testPort + testPath, 'Root-relative URL gets host, protocol, and port supplied' );
408
409 } );