2 QUnit
.module( 'mediawiki.api', QUnit
.newMwEnvironment( {
4 this.server
= this.sandbox
.useFakeServer();
8 QUnit
.test( 'Basic functionality', function ( assert
) {
11 var api
= new mw
.Api();
14 .done( function ( data
) {
15 assert
.deepEqual( data
, [], 'If request succeeds without errors, resolve deferred' );
19 .done( function ( data
) {
20 assert
.deepEqual( data
, [], 'Simple POST request' );
23 this.server
.respond( function ( request
) {
24 request
.respond( 200, { 'Content-Type': 'application/json' }, '[]' );
28 QUnit
.test( 'API error', function ( assert
) {
31 var api
= new mw
.Api();
33 api
.get( { action
: 'doesntexist' } )
34 .fail( function ( errorCode
) {
35 assert
.equal( errorCode
, 'unknown_action', 'API error should reject the deferred' );
38 this.server
.respond( function ( request
) {
39 request
.respond( 200, { 'Content-Type': 'application/json' },
40 '{ "error": { "code": "unknown_action" } }'
45 QUnit
.test( 'FormData support', function ( assert
) {
48 var api
= new mw
.Api();
50 api
.post( { action
: 'test' }, { contentType
: 'multipart/form-data' } );
52 this.server
.respond( function ( request
) {
53 if ( window
.FormData
) {
54 assert
.ok( !request
.url
.match( /action=/ ), 'Request has no query string' );
55 assert
.ok( request
.requestBody
instanceof FormData
, 'Request uses FormData body' );
57 assert
.ok( !request
.url
.match( /action=test/ ), 'Request has no query string' );
58 assert
.equal( request
.requestBody
, 'action=test&format=json', 'Request uses query string body' );
60 request
.respond( 200, { 'Content-Type': 'application/json' }, '[]' );
64 QUnit
.test( 'Converting arrays to pipe-separated', function ( assert
) {
67 var api
= new mw
.Api();
68 api
.get( { test
: [ 'foo', 'bar', 'baz' ] } );
70 this.server
.respond( function ( request
) {
71 assert
.ok( request
.url
.match( /test=foo%7Cbar%7Cbaz/ ), 'Pipe-separated value was submitted' );
72 request
.respond( 200, { 'Content-Type': 'application/json' }, '[]' );
76 QUnit
.test( 'getToken( pre-populated )', function ( assert
) {
79 var api
= new mw
.Api();
81 // Get editToken for local wiki, this should not make
82 // a request as it should be retrieved from user.tokens.
83 // This means that this test must run before the #badToken test below.
84 api
.getToken( 'edit' )
85 .done( function ( token
) {
86 assert
.ok( token
.length
, 'Got a token' );
88 .fail( function ( err
) {
89 assert
.equal( '', err
, 'API error' );
92 assert
.equal( this.server
.requests
.length
, 0, 'Requests made' );
95 QUnit
.test( 'badToken()', function ( assert
) {
98 var api
= new mw
.Api();
100 // Clear the default cached token
101 api
.badToken( 'edit' );
103 api
.getToken( 'edit' )
104 .done( function ( token
) {
105 assert
.equal( token
, '0123abc', 'Got a non-cached token' );
107 .fail( function ( err
) {
108 assert
.equal( '', err
, 'API error' );
111 this.server
.requests
[0].respond( 200, { 'Content-Type': 'application/json' },
112 '{ "tokens": { "edittoken": "0123abc" } }'
115 assert
.equal( this.server
.requests
.length
, 1, 'Requests made' );
118 QUnit
.test( 'getToken()', function ( assert
) {
124 // Get a token of a type that isn't prepopulated by user.tokens.
125 // Could use "block" or "delete" here, but those could in theory
126 // be added to user.tokens, use a fake one instead.
127 api
.getToken( 'testaction' )
128 .done( function ( token
) {
129 assert
.ok( token
.length
, 'Got testaction token' );
131 .fail( function ( err
) {
132 assert
.equal( err
, '', 'API error' );
134 api
.getToken( 'testaction' )
135 .done( function ( token
) {
136 assert
.ok( token
.length
, 'Got testaction token (cached)' );
138 .fail( function ( err
) {
139 assert
.equal( err
, '', 'API error' );
142 // Don't cache error (bug 65268)
143 api
.getToken( 'testaction2' )
144 .fail( function ( err
) {
145 assert
.equal( err
, 'bite-me', 'Expected error' );
147 .always( function () {
148 // Make this request after the first one has finished.
149 // If we make it simultaneously we still want it to share
150 // the cache, but as soon as it is fulfilled as error we
151 // reject it so that the next one tries fresh.
152 api
.getToken( 'testaction2' )
153 .done( function ( token
) {
154 assert
.ok( token
.length
, 'Got testaction2 token (error was not be cached)' );
156 .fail( function ( err
) {
157 assert
.equal( err
, '', 'API error' );
160 assert
.equal( test
.server
.requests
.length
, 3, 'Requests made' );
162 test
.server
.requests
[2].respond( 200, { 'Content-Type': 'application/json' },
163 '{ "tokens": { "testaction2token": "0123abc" } }'
167 this.server
.requests
[0].respond( 200, { 'Content-Type': 'application/json' },
168 '{ "tokens": { "testactiontoken": "0123abc" } }'
171 this.server
.requests
[1].respond( 200, { 'Content-Type': 'application/json' },
172 '{ "error": { "code": "bite-me", "info": "Smite me, O Mighty Smiter" } }'
176 QUnit
.test( 'postWithToken( tokenType, params )', function ( assert
) {
179 var api
= new mw
.Api( { ajax
: { url
: '/postWithToken/api.php' } } );
182 // - Performs action=example
183 api
.postWithToken( 'testsimpletoken', { action
: 'example', key
: 'foo' } )
184 .done( function ( data
) {
185 assert
.deepEqual( data
, { example
: { foo
: 'quux' } } );
188 this.server
.requests
[0].respond( 200, { 'Content-Type': 'application/json' },
189 '{ "tokens": { "testsimpletokentoken": "a-bad-token" } }'
192 this.server
.requests
[1].respond( 200, { 'Content-Type': 'application/json' },
193 '{ "example": { "foo": "quux" } }'
197 QUnit
.test( 'postWithToken( tokenType, params with assert )', function ( assert
) {
200 var api
= new mw
.Api( { ajax
: { url
: '/postWithToken/api.php' } } );
202 api
.postWithToken( 'testasserttoken', { action
: 'example', key
: 'foo', assert
: 'user' } )
203 .fail( function ( errorCode
) {
204 assert
.equal( errorCode
, 'assertuserfailed', 'getToken fails assert' );
207 assert
.equal( this.server
.requests
.length
, 1, 'Request for token made' );
208 this.server
.respondWith( /assert=user/, function ( request
) {
211 { 'Content-Type': 'application/json' },
212 '{ "error": { "code": "assertuserfailed", "info": "Assertion failed" } }'
216 this.server
.respond();
219 QUnit
.test( 'postWithToken( tokenType, params, ajaxOptions )', function ( assert
) {
222 var api
= new mw
.Api();
242 assert
.ok( false, 'This parameter cannot be a callback' );
245 .always( function ( data
) {
246 assert
.equal( data
.example
, 'quux' );
249 assert
.equal( this.server
.requests
.length
, 2, 'Request made' );
250 assert
.equal( this.server
.requests
[0].requestHeaders
['X-Foo'], 'Bar', 'Header sent' );
252 this.server
.respond( function ( request
) {
253 request
.respond( 200, { 'Content-Type': 'application/json' }, '{ "example": "quux" }' );
257 QUnit
.test( 'postWithToken() - badtoken', function ( assert
) {
260 var api
= new mw
.Api();
263 // - Request: action=example -> badtoken error
264 // - Request: new token
265 // - Request: action=example
266 api
.postWithToken( 'testbadtoken', { action
: 'example', key
: 'foo' } )
267 .done( function ( data
) {
268 assert
.deepEqual( data
, { example
: { foo
: 'quux' } } );
271 this.server
.requests
[0].respond( 200, { 'Content-Type': 'application/json' },
272 '{ "tokens": { "testbadtokentoken": "a-bad-token" } }'
275 this.server
.requests
[1].respond( 200, { 'Content-Type': 'application/json' },
276 '{ "error": { "code": "badtoken" } }'
279 this.server
.requests
[2].respond( 200, { 'Content-Type': 'application/json' },
280 '{ "tokens": { "testbadtokentoken": "a-good-token" } }'
283 this.server
.requests
[3].respond( 200, { 'Content-Type': 'application/json' },
284 '{ "example": { "foo": "quux" } }'
289 QUnit
.test( 'postWithToken() - badtoken-cached', function ( assert
) {
292 var api
= new mw
.Api();
295 // - Request: action=example
296 api
.postWithToken( 'testbadtokencache', { action
: 'example', key
: 'foo' } )
297 .done( function ( data
) {
298 assert
.deepEqual( data
, { example
: { foo
: 'quux' } } );
301 // - Cache: Try previously cached token
302 // - Request: action=example -> badtoken error
303 // - Request: new token
304 // - Request: action=example
305 api
.postWithToken( 'testbadtokencache', { action
: 'example', key
: 'bar' } )
306 .done( function ( data
) {
307 assert
.deepEqual( data
, { example
: { bar
: 'quux' } } );
310 this.server
.requests
[0].respond( 200, { 'Content-Type': 'application/json' },
311 '{ "tokens": { "testbadtokencachetoken": "a-good-token-once" } }'
314 this.server
.requests
[1].respond( 200, { 'Content-Type': 'application/json' },
315 '{ "example": { "foo": "quux" } }'
318 this.server
.requests
[2].respond( 200, { 'Content-Type': 'application/json' },
319 '{ "error": { "code": "badtoken" } }'
322 this.server
.requests
[3].respond( 200, { 'Content-Type': 'application/json' },
323 '{ "tokens": { "testbadtokencachetoken": "a-good-new-token" } }'
326 this.server
.requests
[4].respond( 200, { 'Content-Type': 'application/json' },
327 '{ "example": { "bar": "quux" } }'