1 module( 'mediawiki.Uri', QUnit
.newMwEnvironment() );
3 test( '-- Initial check', function () {
6 // Ensure we have a generic URI parser if not running in a browser
8 mw
.Uri
= mw
.UriRelative( 'http://example.com/' );
11 ok( mw
.UriRelative
, 'mw.UriRelative defined' );
12 ok( mw
.Uri
, 'mw.Uri defined' );
15 $.each( [true, false], function ( i
, strictMode
) {
16 test( 'Basic mw.Uri object test in ' + ( strictMode
? '' : 'non-' ) + 'strict mode for a simple HTTP URI', function () {
20 uriString
= 'http://www.ietf.org/rfc/rfc2396.txt';
21 uri
= new mw
.Uri( uriString
, {
22 strictMode
: strictMode
27 protocol
: uri
.protocol
,
32 fragment
: uri
.fragment
37 path
: '/rfc/rfc2396.txt',
41 'basic object properties'
46 userInfo
: uri
.getUserInfo(),
47 authority
: uri
.getAuthority(),
48 hostPort
: uri
.getHostPort(),
49 queryString
: uri
.getQueryString(),
50 relativePath
: uri
.getRelativePath(),
51 toString
: uri
.toString()
55 authority
: 'www.ietf.org',
56 hostPort
: 'www.ietf.org',
58 relativePath
: '/rfc/rfc2396.txt',
61 'construct composite components of URI on request'
67 test( 'Parse an ftp URI correctly with user and password', function () {
71 uri
= new mw
.Uri( 'ftp://usr:pwd@192.0.2.16/' );
75 protocol
: uri
.protocol
,
77 password
: uri
.password
,
82 fragment
: uri
.fragment
94 'basic object properties'
98 test( 'Parse a uri with simple querystring', function () {
102 uri
= new mw
.Uri( 'http://www.google.com/?q=uri' );
106 protocol
: uri
.protocol
,
111 fragment
: uri
.fragment
,
112 queryString
: uri
.getQueryString()
116 host
: 'www.google.com',
123 'basic object properties'
127 test( 'Handle multiple query parameter (overrideKeys on)', function () {
131 uri
= new mw
.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
135 equal( uri
.query
.n
, '1', 'multiple parameters are parsed' );
136 equal( uri
.query
.m
, 'bar', 'last key overrides earlier keys' );
138 uri
.query
.n
= [ 'x', 'y', 'z' ];
140 // Verify parts and total length instead of entire string because order
141 // of iteration can vary.
142 ok( uri
.toString().indexOf( 'm=bar' ), 'toString preserves other values' );
143 ok( uri
.toString().indexOf( 'n=x&n=y&n=z' ), 'toString parameter includes all values of an array query parameter' );
144 equal( uri
.toString().length
, 'http://www.example.com/dir/?m=bar&n=x&n=y&n=z'.length
, 'toString matches expected string' );
147 test( 'Handle multiple query parameter (overrideKeys off)', function () {
151 uri
= new mw
.Uri( 'http://www.example.com/dir/?m=foo&m=bar&n=1', {
155 // Strict comparison so that types are also verified (n should be string '1')
156 strictEqual( uri
.query
.m
.length
, 2, 'multi-value query should be an array with 2 items' );
157 strictEqual( uri
.query
.m
[0], 'foo', 'order and value is correct' );
158 strictEqual( uri
.query
.m
[1], 'bar', 'order and value is correct' );
159 strictEqual( uri
.query
.n
, '1', 'n=1 is parsed with the correct value of the expected type' );
161 // Change query values
162 uri
.query
.n
= [ 'x', 'y', 'z' ];
164 // Verify parts and total length instead of entire string because order
165 // of iteration can vary.
166 ok( uri
.toString().indexOf( 'm=foo&m=bar' ) >= 0, 'toString preserves other values' );
167 ok( uri
.toString().indexOf( 'n=x&n=y&n=z' ) >= 0, 'toString parameter includes all values of an array query parameter' );
168 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 // Remove query values
171 uri
.query
.m
.splice( 0, 1 );
174 equal( uri
.toString(), 'http://www.example.com/dir/?m=bar', 'deletion properties' );
176 // Remove more query values, leaving an empty array
177 uri
.query
.m
.splice( 0, 1 );
178 equal( uri
.toString(), 'http://www.example.com/dir/', 'empty array value is ommitted' );
181 test( 'All-dressed URI with everything', function () {
182 var uri
, queryString
, relativePath
;
185 uri
= new mw
.Uri( 'http://auth@www.example.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value+%28escaped%29#top' );
189 protocol
: uri
.protocol
,
191 password
: uri
.password
,
196 fragment
: uri
.fragment
202 host
: 'www.example.com',
204 path
: '/dir/dir.2/index.htm',
205 query
: { q1
: '0', test1
: null, test2
: 'value (escaped)' },
208 'basic object properties'
211 equal( uri
.getUserInfo(), 'auth', 'user info' );
213 equal( uri
.getAuthority(), 'auth@www.example.com:81', 'authority equal to auth@hostport' );
215 equal( uri
.getHostPort(), 'www.example.com:81', 'hostport equal to host:port' );
217 queryString
= uri
.getQueryString();
218 ok( queryString
.indexOf( 'q1=0' ) >= 0, 'query param with numbers' );
219 ok( queryString
.indexOf( 'test1' ) >= 0, 'query param with null value is included' );
220 ok( queryString
.indexOf( 'test1=' ) === -1, 'query param with null value does not generate equals sign' );
221 ok( queryString
.indexOf( 'test2=value+%28escaped%29' ) >= 0, 'query param is url escaped' );
223 relativePath
= uri
.getRelativePath();
224 ok( relativePath
.indexOf( uri
.path
) >= 0, 'path in relative path' );
225 ok( relativePath
.indexOf( uri
.getQueryString() ) >= 0, 'query string in relative path' );
226 ok( relativePath
.indexOf( uri
.fragment
) >= 0, 'fragement in relative path' );
229 test( 'Cloning', function () {
233 original
= new mw
.Uri( 'http://en.wiki.local/w/api.php?action=query&foo=bar' );
234 clone
= original
.clone();
236 deepEqual( clone
, original
, 'clone has equivalent properties' );
237 equal( original
.toString(), clone
.toString(), 'toString matches original' );
239 notStrictEqual( clone
, original
, 'clone is not the same when compared by reference' );
241 clone
.host
= 'fr.wiki.local';
242 notEqual( original
.host
, clone
.host
, 'manipulating clone did not effect original' );
243 notEqual( original
.toString(), clone
.toString(), 'toString no longer matches original' );
246 test( 'Constructing mw.Uri from plain object', function () {
252 host
: 'www.foo.local',
255 equal( uri
.toString(), 'http://www.foo.local/this', 'Basic properties' );
259 host
: 'www.foo.local',
261 query
: { hi
: 'there' },
264 equal( uri
.toString(), 'http://www.foo.local/this?hi=there#blah', 'More complex properties' );
268 var uri
= new mw
.Uri({
270 host
: 'www.foo.local'
274 return e
.message
=== 'Bad constructor arguments';
276 'Construction failed when missing required properties'
280 test( 'Manipulate properties', function () {
284 uriBase
= new mw
.Uri( 'http://en.wiki.local/w/api.php' );
286 uri
= uriBase
.clone();
287 uri
.fragment
= 'frag';
288 equal( uri
.toString(), 'http://en.wiki.local/w/api.php#frag', 'add a fragment' );
290 uri
= uriBase
.clone();
291 uri
.host
= 'fr.wiki.local';
293 equal( uri
.toString(), 'http://fr.wiki.local:8080/w/api.php', 'change host and port' );
295 uri
= uriBase
.clone();
296 uri
.query
.foo
= 'bar';
297 equal( uri
.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'add query arguments' );
299 delete uri
.query
.foo
;
300 equal( uri
.toString(), 'http://en.wiki.local/w/api.php', 'delete query arguments' );
302 uri
= uriBase
.clone();
303 uri
.query
.foo
= 'bar';
304 equal( uri
.toString(), 'http://en.wiki.local/w/api.php?foo=bar', 'extend query arguments' );
309 ok( uri
.toString().indexOf( 'foo=quux' ) >= 0, 'extend query arguments' );
310 ok( uri
.toString().indexOf( 'foo=bar' ) === -1, 'extend query arguments' );
311 ok( uri
.toString().indexOf( 'pif=paf' ) >= 0 , 'extend query arguments' );
314 test( 'Handle protocol-relative URLs', function () {
318 UriRel
= mw
.UriRelative( 'glork://en.wiki.local/foo.php' );
320 uri
= new UriRel( '//en.wiki.local/w/api.php' );
321 equal( uri
.protocol
, 'glork', 'create protocol-relative URLs with same protocol as document' );
323 uri
= new UriRel( '/foo.com' );
324 equal( uri
.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in loose mode' );
326 uri
= new UriRel( 'http:/foo.com' );
327 equal( uri
.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in loose mode' );
329 uri
= new UriRel( '/foo.com', true );
330 equal( uri
.toString(), 'glork://en.wiki.local/foo.com', 'handle absolute paths by supplying protocol and host from document in strict mode' );
332 uri
= new UriRel( 'http:/foo.com', true );
333 equal( uri
.toString(), 'http://en.wiki.local/foo.com', 'handle absolute paths by supplying host from document in strict mode' );
336 test( 'Bad calls', function () {
345 return e
.message
=== 'Bad constructor arguments';
347 'throw error on no arguments to constructor'
355 return e
.message
=== 'Bad constructor arguments';
357 'throw error on empty string as argument to constructor'
362 new mw
.Uri( 'glaswegian penguins' );
365 return e
.message
=== 'Bad constructor arguments';
367 'throw error on non-URI as argument to constructor'
372 new mw
.Uri( 'foo.com/bar/baz', {
377 return e
.message
=== 'Bad constructor arguments';
379 'throw error on URI without protocol or // or leading / in strict mode'
382 uri
= new mw
.Uri( 'foo.com/bar/baz', {
385 equal( uri
.toString(), 'http://foo.com/bar/baz', 'normalize URI without protocol or // in loose mode' );
388 test( 'bug 35658', function () {
391 var testProtocol
, testServer
, testPort
, testPath
, UriClass
, uri
, href
;
393 testProtocol
= 'https://';
394 testServer
= 'foo.example.org';
398 UriClass
= mw
.UriRelative( testProtocol
+ testServer
+ '/some/path/index.html' );
399 uri
= new UriClass( testPath
);
400 href
= uri
.toString();
401 equal( href
, testProtocol
+ testServer
+ testPath
, 'Root-relative URL gets host & protocol supplied' );
403 UriClass
= mw
.UriRelative( testProtocol
+ testServer
+ ':' + testPort
+ '/some/path.php' );
404 uri
= new UriClass( testPath
);
405 href
= uri
.toString();
406 equal( href
, testProtocol
+ testServer
+ ':' + testPort
+ testPath
, 'Root-relative URL gets host, protocol, and port supplied' );