| 2 |
lars |
1 |
/*! jQuery Mockjax
|
|
|
2 |
* A Plugin providing simple and flexible mocking of ajax requests and responses
|
|
|
3 |
*
|
|
|
4 |
* Version: 2.2.1
|
|
|
5 |
* Home: https://github.com/jakerella/jquery-mockjax
|
|
|
6 |
* Copyright (c) 2016 Jordan Kasper, formerly appendTo;
|
|
|
7 |
* NOTE: This repository was taken over by Jordan Kasper (@jakerella) October, 2014
|
|
|
8 |
*
|
|
|
9 |
* Dual licensed under the MIT or GPL licenses.
|
|
|
10 |
* http://opensource.org/licenses/MIT OR http://www.gnu.org/licenses/gpl-2.0.html
|
|
|
11 |
*/
|
|
|
12 |
(function(root, factory) {
|
|
|
13 |
'use strict';
|
|
|
14 |
|
|
|
15 |
// AMDJS module definition
|
|
|
16 |
if ( typeof define === 'function' && define.amd && define.amd.jQuery ) {
|
|
|
17 |
define(['jquery'], function($) {
|
|
|
18 |
return factory($, root);
|
|
|
19 |
});
|
|
|
20 |
|
|
|
21 |
// CommonJS module definition
|
|
|
22 |
} else if ( typeof exports === 'object') {
|
|
|
23 |
|
|
|
24 |
// NOTE: To use Mockjax as a Node module you MUST provide the factory with
|
|
|
25 |
// a valid version of jQuery and a window object (the global scope):
|
|
|
26 |
// var mockjax = require('jquery.mockjax')(jQuery, window);
|
|
|
27 |
|
|
|
28 |
module.exports = factory;
|
|
|
29 |
|
|
|
30 |
// Global jQuery in web browsers
|
|
|
31 |
} else {
|
|
|
32 |
return factory(root.jQuery || root.$, root);
|
|
|
33 |
}
|
|
|
34 |
}(this, function($, window) {
|
|
|
35 |
'use strict';
|
|
|
36 |
|
|
|
37 |
var _ajax = $.ajax,
|
|
|
38 |
mockHandlers = [],
|
|
|
39 |
mockedAjaxCalls = [],
|
|
|
40 |
unmockedAjaxCalls = [],
|
|
|
41 |
CALLBACK_REGEX = /=\?(&|$)/,
|
|
|
42 |
jsc = (new Date()).getTime(),
|
|
|
43 |
DEFAULT_RESPONSE_TIME = 500;
|
|
|
44 |
|
|
|
45 |
// Parse the given XML string.
|
|
|
46 |
function parseXML(xml) {
|
|
|
47 |
if ( window.DOMParser === undefined && window.ActiveXObject ) {
|
|
|
48 |
window.DOMParser = function() { };
|
|
|
49 |
DOMParser.prototype.parseFromString = function( xmlString ) {
|
|
|
50 |
var doc = new ActiveXObject('Microsoft.XMLDOM');
|
|
|
51 |
doc.async = 'false';
|
|
|
52 |
doc.loadXML( xmlString );
|
|
|
53 |
return doc;
|
|
|
54 |
};
|
|
|
55 |
}
|
|
|
56 |
|
|
|
57 |
try {
|
|
|
58 |
var xmlDoc = ( new DOMParser() ).parseFromString( xml, 'text/xml' );
|
|
|
59 |
if ( $.isXMLDoc( xmlDoc ) ) {
|
|
|
60 |
var err = $('parsererror', xmlDoc);
|
|
|
61 |
if ( err.length === 1 ) {
|
|
|
62 |
throw new Error('Error: ' + $(xmlDoc).text() );
|
|
|
63 |
}
|
|
|
64 |
} else {
|
|
|
65 |
throw new Error('Unable to parse XML');
|
|
|
66 |
}
|
|
|
67 |
return xmlDoc;
|
|
|
68 |
} catch( e ) {
|
|
|
69 |
var msg = ( e.name === undefined ? e : e.name + ': ' + e.message );
|
|
|
70 |
$(document).trigger('xmlParseError', [ msg ]);
|
|
|
71 |
return undefined;
|
|
|
72 |
}
|
|
|
73 |
}
|
|
|
74 |
|
|
|
75 |
// Check if the data field on the mock handler and the request match. This
|
|
|
76 |
// can be used to restrict a mock handler to being used only when a certain
|
|
|
77 |
// set of data is passed to it.
|
|
|
78 |
function isMockDataEqual( mock, live ) {
|
|
|
79 |
logger.debug( mock, ['Checking mock data against request data', mock, live] );
|
|
|
80 |
var identical = true;
|
|
|
81 |
|
|
|
82 |
if ( $.isFunction(mock) ) {
|
|
|
83 |
return !!mock(live);
|
|
|
84 |
}
|
|
|
85 |
|
|
|
86 |
// Test for situations where the data is a querystring (not an object)
|
|
|
87 |
if (typeof live === 'string') {
|
|
|
88 |
// Querystring may be a regex
|
|
|
89 |
if ($.isFunction( mock.test )) {
|
|
|
90 |
return mock.test(live);
|
|
|
91 |
} else if (typeof mock === 'object') {
|
|
|
92 |
live = getQueryParams(live);
|
|
|
93 |
} else {
|
|
|
94 |
return mock === live;
|
|
|
95 |
}
|
|
|
96 |
}
|
|
|
97 |
|
|
|
98 |
$.each(mock, function(k) {
|
|
|
99 |
if ( live[k] === undefined ) {
|
|
|
100 |
identical = false;
|
|
|
101 |
return identical;
|
|
|
102 |
} else {
|
|
|
103 |
if ( typeof live[k] === 'object' && live[k] !== null ) {
|
|
|
104 |
if ( identical && $.isArray( live[k] ) ) {
|
|
|
105 |
identical = $.isArray( mock[k] ) && live[k].length === mock[k].length;
|
|
|
106 |
}
|
|
|
107 |
identical = identical && isMockDataEqual(mock[k], live[k]);
|
|
|
108 |
} else {
|
|
|
109 |
if ( mock[k] && $.isFunction( mock[k].test ) ) {
|
|
|
110 |
identical = identical && mock[k].test(live[k]);
|
|
|
111 |
} else {
|
|
|
112 |
identical = identical && ( mock[k] === live[k] );
|
|
|
113 |
}
|
|
|
114 |
}
|
|
|
115 |
}
|
|
|
116 |
});
|
|
|
117 |
|
|
|
118 |
return identical;
|
|
|
119 |
}
|
|
|
120 |
|
|
|
121 |
function getQueryParams(queryString) {
|
|
|
122 |
var i, l, param, tmp,
|
|
|
123 |
paramsObj = {},
|
|
|
124 |
params = String(queryString).split(/&/);
|
|
|
125 |
|
|
|
126 |
for (i=0, l=params.length; i<l; ++i) {
|
|
|
127 |
param = params[i];
|
|
|
128 |
try {
|
|
|
129 |
param = decodeURIComponent(param.replace(/\+/g, ' '));
|
|
|
130 |
param = param.split(/=/);
|
|
|
131 |
} catch(e) {
|
|
|
132 |
// Can't parse this one, so let it go?
|
|
|
133 |
continue;
|
|
|
134 |
}
|
|
|
135 |
|
|
|
136 |
if (paramsObj[param[0]]) {
|
|
|
137 |
// this is an array query param (more than one entry in query)
|
|
|
138 |
if (!paramsObj[param[0]].splice) {
|
|
|
139 |
// if not already an array, make it one
|
|
|
140 |
tmp = paramsObj[param[0]];
|
|
|
141 |
paramsObj[param[0]] = [];
|
|
|
142 |
paramsObj[param[0]].push(tmp);
|
|
|
143 |
}
|
|
|
144 |
paramsObj[param[0]].push(param[1]);
|
|
|
145 |
} else {
|
|
|
146 |
paramsObj[param[0]] = param[1];
|
|
|
147 |
}
|
|
|
148 |
}
|
|
|
149 |
|
|
|
150 |
logger.debug( null, ['Getting query params from string', queryString, paramsObj] );
|
|
|
151 |
|
|
|
152 |
return paramsObj;
|
|
|
153 |
}
|
|
|
154 |
|
|
|
155 |
// See if a mock handler property matches the default settings
|
|
|
156 |
function isDefaultSetting(handler, property) {
|
|
|
157 |
return handler[property] === $.mockjaxSettings[property];
|
|
|
158 |
}
|
|
|
159 |
|
|
|
160 |
// Check the given handler should mock the given request
|
|
|
161 |
function getMockForRequest( handler, requestSettings ) {
|
|
|
162 |
// If the mock was registered with a function, let the function decide if we
|
|
|
163 |
// want to mock this request
|
|
|
164 |
if ( $.isFunction(handler) ) {
|
|
|
165 |
return handler( requestSettings );
|
|
|
166 |
}
|
|
|
167 |
|
|
|
168 |
// Inspect the URL of the request and check if the mock handler's url
|
|
|
169 |
// matches the url for this ajax request
|
|
|
170 |
if ( $.isFunction(handler.url.test) ) {
|
|
|
171 |
// The user provided a regex for the url, test it
|
|
|
172 |
if ( !handler.url.test( requestSettings.url ) ) {
|
|
|
173 |
return null;
|
|
|
174 |
}
|
|
|
175 |
} else {
|
|
|
176 |
|
|
|
177 |
// Apply namespace prefix to the mock handler's url.
|
|
|
178 |
var namespace = handler.namespace || $.mockjaxSettings.namespace;
|
|
|
179 |
if (!!namespace) {
|
|
|
180 |
var namespacedUrl = [namespace, handler.url].join('/');
|
|
|
181 |
namespacedUrl = namespacedUrl.replace(/(\/+)/g, '/');
|
|
|
182 |
handler.url = namespacedUrl;
|
|
|
183 |
}
|
|
|
184 |
|
|
|
185 |
// Look for a simple wildcard '*' or a direct URL match
|
|
|
186 |
var star = handler.url.indexOf('*');
|
|
|
187 |
if (handler.url !== requestSettings.url && star === -1 ||
|
|
|
188 |
!new RegExp(handler.url.replace(/[-[\]{}()+?.,\\^$|#\s]/g, '\\$&').replace(/\*/g, '.+')).test(requestSettings.url)) {
|
|
|
189 |
return null;
|
|
|
190 |
}
|
|
|
191 |
}
|
|
|
192 |
|
|
|
193 |
// Inspect the request headers submitted
|
|
|
194 |
if ( handler.requestHeaders ) {
|
|
|
195 |
//No expectation for headers, do not mock this request
|
|
|
196 |
if (requestSettings.headers === undefined) {
|
|
|
197 |
return null;
|
|
|
198 |
} else {
|
|
|
199 |
var headersMismatch = false;
|
|
|
200 |
$.each(handler.requestHeaders, function(key, value) {
|
|
|
201 |
var v = requestSettings.headers[key];
|
|
|
202 |
if(v !== value) {
|
|
|
203 |
headersMismatch = true;
|
|
|
204 |
return false;
|
|
|
205 |
}
|
|
|
206 |
});
|
|
|
207 |
//Headers do not match, do not mock this request
|
|
|
208 |
if (headersMismatch) {
|
|
|
209 |
return null;
|
|
|
210 |
}
|
|
|
211 |
}
|
|
|
212 |
}
|
|
|
213 |
|
|
|
214 |
// Inspect the data submitted in the request (either POST body or GET query string)
|
|
|
215 |
if ( handler.data ) {
|
|
|
216 |
if ( !requestSettings.data || !isMockDataEqual(handler.data, requestSettings.data) ) {
|
|
|
217 |
// They're not identical, do not mock this request
|
|
|
218 |
return null;
|
|
|
219 |
}
|
|
|
220 |
}
|
|
|
221 |
// Inspect the request type
|
|
|
222 |
if ( handler && handler.type &&
|
|
|
223 |
handler.type.toLowerCase() !== requestSettings.type.toLowerCase() ) {
|
|
|
224 |
// The request type doesn't match (GET vs. POST)
|
|
|
225 |
return null;
|
|
|
226 |
}
|
|
|
227 |
|
|
|
228 |
return handler;
|
|
|
229 |
}
|
|
|
230 |
|
|
|
231 |
function isPosNum(value) {
|
|
|
232 |
return typeof value === 'number' && value >= 0;
|
|
|
233 |
}
|
|
|
234 |
|
|
|
235 |
function parseResponseTimeOpt(responseTime) {
|
|
|
236 |
if ($.isArray(responseTime) && responseTime.length === 2) {
|
|
|
237 |
var min = responseTime[0];
|
|
|
238 |
var max = responseTime[1];
|
|
|
239 |
if(isPosNum(min) && isPosNum(max)) {
|
|
|
240 |
return Math.floor(Math.random() * (max - min)) + min;
|
|
|
241 |
}
|
|
|
242 |
} else if(isPosNum(responseTime)) {
|
|
|
243 |
return responseTime;
|
|
|
244 |
}
|
|
|
245 |
return DEFAULT_RESPONSE_TIME;
|
|
|
246 |
}
|
|
|
247 |
|
|
|
248 |
// Process the xhr objects send operation
|
|
|
249 |
function _xhrSend(mockHandler, requestSettings, origSettings) {
|
|
|
250 |
logger.debug( mockHandler, ['Sending fake XHR request', mockHandler, requestSettings, origSettings] );
|
|
|
251 |
|
|
|
252 |
// This is a substitute for < 1.4 which lacks $.proxy
|
|
|
253 |
var process = (function(that) {
|
|
|
254 |
return function() {
|
|
|
255 |
return (function() {
|
|
|
256 |
// The request has returned
|
|
|
257 |
this.status = mockHandler.status;
|
|
|
258 |
this.statusText = mockHandler.statusText;
|
|
|
259 |
this.readyState = 1;
|
|
|
260 |
|
|
|
261 |
var finishRequest = function () {
|
|
|
262 |
this.readyState = 4;
|
|
|
263 |
|
|
|
264 |
var onReady;
|
|
|
265 |
// Copy over our mock to our xhr object before passing control back to
|
|
|
266 |
// jQuery's onreadystatechange callback
|
|
|
267 |
if ( requestSettings.dataType === 'json' && ( typeof mockHandler.responseText === 'object' ) ) {
|
|
|
268 |
this.responseText = JSON.stringify(mockHandler.responseText);
|
|
|
269 |
} else if ( requestSettings.dataType === 'xml' ) {
|
|
|
270 |
if ( typeof mockHandler.responseXML === 'string' ) {
|
|
|
271 |
this.responseXML = parseXML(mockHandler.responseXML);
|
|
|
272 |
//in jQuery 1.9.1+, responseXML is processed differently and relies on responseText
|
|
|
273 |
this.responseText = mockHandler.responseXML;
|
|
|
274 |
} else {
|
|
|
275 |
this.responseXML = mockHandler.responseXML;
|
|
|
276 |
}
|
|
|
277 |
} else if (typeof mockHandler.responseText === 'object' && mockHandler.responseText !== null) {
|
|
|
278 |
// since jQuery 1.9 responseText type has to match contentType
|
|
|
279 |
mockHandler.contentType = 'application/json';
|
|
|
280 |
this.responseText = JSON.stringify(mockHandler.responseText);
|
|
|
281 |
} else {
|
|
|
282 |
this.responseText = mockHandler.responseText;
|
|
|
283 |
}
|
|
|
284 |
if( typeof mockHandler.status === 'number' || typeof mockHandler.status === 'string' ) {
|
|
|
285 |
this.status = mockHandler.status;
|
|
|
286 |
}
|
|
|
287 |
if( typeof mockHandler.statusText === 'string') {
|
|
|
288 |
this.statusText = mockHandler.statusText;
|
|
|
289 |
}
|
|
|
290 |
// jQuery 2.0 renamed onreadystatechange to onload
|
|
|
291 |
onReady = this.onload || this.onreadystatechange;
|
|
|
292 |
|
|
|
293 |
// jQuery < 1.4 doesn't have onreadystate change for xhr
|
|
|
294 |
if ( $.isFunction( onReady ) ) {
|
|
|
295 |
if( mockHandler.isTimeout) {
|
|
|
296 |
this.status = -1;
|
|
|
297 |
}
|
|
|
298 |
onReady.call( this, mockHandler.isTimeout ? 'timeout' : undefined );
|
|
|
299 |
} else if ( mockHandler.isTimeout ) {
|
|
|
300 |
// Fix for 1.3.2 timeout to keep success from firing.
|
|
|
301 |
this.status = -1;
|
|
|
302 |
}
|
|
|
303 |
};
|
|
|
304 |
|
|
|
305 |
// We have an executable function, call it to give
|
|
|
306 |
// the mock handler a chance to update it's data
|
|
|
307 |
if ( $.isFunction(mockHandler.response) ) {
|
|
|
308 |
// Wait for it to finish
|
|
|
309 |
if ( mockHandler.response.length === 2 ) {
|
|
|
310 |
mockHandler.response(origSettings, function () {
|
|
|
311 |
finishRequest.call(that);
|
|
|
312 |
});
|
|
|
313 |
return;
|
|
|
314 |
} else {
|
|
|
315 |
mockHandler.response(origSettings);
|
|
|
316 |
}
|
|
|
317 |
}
|
|
|
318 |
|
|
|
319 |
finishRequest.call(that);
|
|
|
320 |
}).apply(that);
|
|
|
321 |
};
|
|
|
322 |
})(this);
|
|
|
323 |
|
|
|
324 |
if ( mockHandler.proxy ) {
|
|
|
325 |
logger.info( mockHandler, ['Retrieving proxy file: ' + mockHandler.proxy, mockHandler] );
|
|
|
326 |
// We're proxying this request and loading in an external file instead
|
|
|
327 |
_ajax({
|
|
|
328 |
global: false,
|
|
|
329 |
url: mockHandler.proxy,
|
|
|
330 |
type: mockHandler.proxyType,
|
|
|
331 |
data: mockHandler.data,
|
|
|
332 |
async: requestSettings.async,
|
|
|
333 |
dataType: requestSettings.dataType === 'script' ? 'text/plain' : requestSettings.dataType,
|
|
|
334 |
complete: function(xhr) {
|
|
|
335 |
// Fix for bug #105
|
|
|
336 |
// jQuery will convert the text to XML for us, and if we use the actual responseXML here
|
|
|
337 |
// then some other things don't happen, resulting in no data given to the 'success' cb
|
|
|
338 |
mockHandler.responseXML = mockHandler.responseText = xhr.responseText;
|
|
|
339 |
|
|
|
340 |
// Don't override the handler status/statusText if it's specified by the config
|
|
|
341 |
if (isDefaultSetting(mockHandler, 'status')) {
|
|
|
342 |
mockHandler.status = xhr.status;
|
|
|
343 |
}
|
|
|
344 |
if (isDefaultSetting(mockHandler, 'statusText')) {
|
|
|
345 |
mockHandler.statusText = xhr.statusText;
|
|
|
346 |
}
|
|
|
347 |
|
|
|
348 |
if ( requestSettings.async === false ) {
|
|
|
349 |
// TODO: Blocking delay
|
|
|
350 |
process();
|
|
|
351 |
} else {
|
|
|
352 |
this.responseTimer = setTimeout(process, parseResponseTimeOpt(mockHandler.responseTime));
|
|
|
353 |
}
|
|
|
354 |
}
|
|
|
355 |
});
|
|
|
356 |
} else {
|
|
|
357 |
// type === 'POST' || 'GET' || 'DELETE'
|
|
|
358 |
if ( requestSettings.async === false ) {
|
|
|
359 |
// TODO: Blocking delay
|
|
|
360 |
process();
|
|
|
361 |
} else {
|
|
|
362 |
this.responseTimer = setTimeout(process, parseResponseTimeOpt(mockHandler.responseTime));
|
|
|
363 |
}
|
|
|
364 |
}
|
|
|
365 |
|
|
|
366 |
}
|
|
|
367 |
|
|
|
368 |
// Construct a mocked XHR Object
|
|
|
369 |
function xhr(mockHandler, requestSettings, origSettings, origHandler) {
|
|
|
370 |
logger.debug( mockHandler, ['Creating new mock XHR object', mockHandler, requestSettings, origSettings, origHandler] );
|
|
|
371 |
|
|
|
372 |
// Extend with our default mockjax settings
|
|
|
373 |
mockHandler = $.extend(true, {}, $.mockjaxSettings, mockHandler);
|
|
|
374 |
|
|
|
375 |
if (typeof mockHandler.headers === 'undefined') {
|
|
|
376 |
mockHandler.headers = {};
|
|
|
377 |
}
|
|
|
378 |
if (typeof requestSettings.headers === 'undefined') {
|
|
|
379 |
requestSettings.headers = {};
|
|
|
380 |
}
|
|
|
381 |
if ( mockHandler.contentType ) {
|
|
|
382 |
mockHandler.headers['content-type'] = mockHandler.contentType;
|
|
|
383 |
}
|
|
|
384 |
|
|
|
385 |
return {
|
|
|
386 |
status: mockHandler.status,
|
|
|
387 |
statusText: mockHandler.statusText,
|
|
|
388 |
readyState: 1,
|
|
|
389 |
open: function() { },
|
|
|
390 |
send: function() {
|
|
|
391 |
origHandler.fired = true;
|
|
|
392 |
_xhrSend.call(this, mockHandler, requestSettings, origSettings);
|
|
|
393 |
},
|
|
|
394 |
abort: function() {
|
|
|
395 |
clearTimeout(this.responseTimer);
|
|
|
396 |
},
|
|
|
397 |
setRequestHeader: function(header, value) {
|
|
|
398 |
requestSettings.headers[header] = value;
|
|
|
399 |
},
|
|
|
400 |
getResponseHeader: function(header) {
|
|
|
401 |
// 'Last-modified', 'Etag', 'content-type' are all checked by jQuery
|
|
|
402 |
if ( mockHandler.headers && mockHandler.headers[header] ) {
|
|
|
403 |
// Return arbitrary headers
|
|
|
404 |
return mockHandler.headers[header];
|
|
|
405 |
} else if ( header.toLowerCase() === 'last-modified' ) {
|
|
|
406 |
return mockHandler.lastModified || (new Date()).toString();
|
|
|
407 |
} else if ( header.toLowerCase() === 'etag' ) {
|
|
|
408 |
return mockHandler.etag || '';
|
|
|
409 |
} else if ( header.toLowerCase() === 'content-type' ) {
|
|
|
410 |
return mockHandler.contentType || 'text/plain';
|
|
|
411 |
}
|
|
|
412 |
},
|
|
|
413 |
getAllResponseHeaders: function() {
|
|
|
414 |
var headers = '';
|
|
|
415 |
// since jQuery 1.9 responseText type has to match contentType
|
|
|
416 |
if (mockHandler.contentType) {
|
|
|
417 |
mockHandler.headers['Content-Type'] = mockHandler.contentType;
|
|
|
418 |
}
|
|
|
419 |
$.each(mockHandler.headers, function(k, v) {
|
|
|
420 |
headers += k + ': ' + v + '\n';
|
|
|
421 |
});
|
|
|
422 |
return headers;
|
|
|
423 |
}
|
|
|
424 |
};
|
|
|
425 |
}
|
|
|
426 |
|
|
|
427 |
// Process a JSONP mock request.
|
|
|
428 |
function processJsonpMock( requestSettings, mockHandler, origSettings ) {
|
|
|
429 |
// Handle JSONP Parameter Callbacks, we need to replicate some of the jQuery core here
|
|
|
430 |
// because there isn't an easy hook for the cross domain script tag of jsonp
|
|
|
431 |
|
|
|
432 |
processJsonpUrl( requestSettings );
|
|
|
433 |
|
|
|
434 |
requestSettings.dataType = 'json';
|
|
|
435 |
if(requestSettings.data && CALLBACK_REGEX.test(requestSettings.data) || CALLBACK_REGEX.test(requestSettings.url)) {
|
|
|
436 |
createJsonpCallback(requestSettings, mockHandler, origSettings);
|
|
|
437 |
|
|
|
438 |
// We need to make sure
|
|
|
439 |
// that a JSONP style response is executed properly
|
|
|
440 |
|
|
|
441 |
var rurl = /^(\w+:)?\/\/([^\/?#]+)/,
|
|
|
442 |
parts = rurl.exec( requestSettings.url ),
|
|
|
443 |
remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
|
|
|
444 |
|
|
|
445 |
requestSettings.dataType = 'script';
|
|
|
446 |
if(requestSettings.type.toUpperCase() === 'GET' && remote ) {
|
|
|
447 |
var newMockReturn = processJsonpRequest( requestSettings, mockHandler, origSettings );
|
|
|
448 |
|
|
|
449 |
// Check if we are supposed to return a Deferred back to the mock call, or just
|
|
|
450 |
// signal success
|
|
|
451 |
if(newMockReturn) {
|
|
|
452 |
return newMockReturn;
|
|
|
453 |
} else {
|
|
|
454 |
return true;
|
|
|
455 |
}
|
|
|
456 |
}
|
|
|
457 |
}
|
|
|
458 |
return null;
|
|
|
459 |
}
|
|
|
460 |
|
|
|
461 |
// Append the required callback parameter to the end of the request URL, for a JSONP request
|
|
|
462 |
function processJsonpUrl( requestSettings ) {
|
|
|
463 |
if ( requestSettings.type.toUpperCase() === 'GET' ) {
|
|
|
464 |
if ( !CALLBACK_REGEX.test( requestSettings.url ) ) {
|
|
|
465 |
requestSettings.url += (/\?/.test( requestSettings.url ) ? '&' : '?') +
|
|
|
466 |
(requestSettings.jsonp || 'callback') + '=?';
|
|
|
467 |
}
|
|
|
468 |
} else if ( !requestSettings.data || !CALLBACK_REGEX.test(requestSettings.data) ) {
|
|
|
469 |
requestSettings.data = (requestSettings.data ? requestSettings.data + '&' : '') + (requestSettings.jsonp || 'callback') + '=?';
|
|
|
470 |
}
|
|
|
471 |
}
|
|
|
472 |
|
|
|
473 |
// Process a JSONP request by evaluating the mocked response text
|
|
|
474 |
function processJsonpRequest( requestSettings, mockHandler, origSettings ) {
|
|
|
475 |
logger.debug( mockHandler, ['Performing JSONP request', mockHandler, requestSettings, origSettings] );
|
|
|
476 |
|
|
|
477 |
// Synthesize the mock request for adding a script tag
|
|
|
478 |
var callbackContext = origSettings && origSettings.context || requestSettings,
|
|
|
479 |
// If we are running under jQuery 1.5+, return a deferred object
|
|
|
480 |
newMock = ($.Deferred) ? (new $.Deferred()) : null;
|
|
|
481 |
|
|
|
482 |
// If the response handler on the moock is a function, call it
|
|
|
483 |
if ( mockHandler.response && $.isFunction(mockHandler.response) ) {
|
|
|
484 |
|
|
|
485 |
mockHandler.response(origSettings);
|
|
|
486 |
|
|
|
487 |
|
|
|
488 |
} else if ( typeof mockHandler.responseText === 'object' ) {
|
|
|
489 |
// Evaluate the responseText javascript in a global context
|
|
|
490 |
$.globalEval( '(' + JSON.stringify( mockHandler.responseText ) + ')');
|
|
|
491 |
|
|
|
492 |
} else if (mockHandler.proxy) {
|
|
|
493 |
logger.info( mockHandler, ['Performing JSONP proxy request: ' + mockHandler.proxy, mockHandler] );
|
|
|
494 |
|
|
|
495 |
// This handles the unique case where we have a remote URL, but want to proxy the JSONP
|
|
|
496 |
// response to another file (not the same URL as the mock matching)
|
|
|
497 |
_ajax({
|
|
|
498 |
global: false,
|
|
|
499 |
url: mockHandler.proxy,
|
|
|
500 |
type: mockHandler.proxyType,
|
|
|
501 |
data: mockHandler.data,
|
|
|
502 |
dataType: requestSettings.dataType === 'script' ? 'text/plain' : requestSettings.dataType,
|
|
|
503 |
complete: function(xhr) {
|
|
|
504 |
$.globalEval( '(' + xhr.responseText + ')');
|
|
|
505 |
completeJsonpCall( requestSettings, mockHandler, callbackContext, newMock );
|
|
|
506 |
}
|
|
|
507 |
});
|
|
|
508 |
|
|
|
509 |
return newMock;
|
|
|
510 |
|
|
|
511 |
} else {
|
|
|
512 |
$.globalEval( '(' +
|
|
|
513 |
((typeof mockHandler.responseText === 'string') ?
|
|
|
514 |
('"' + mockHandler.responseText + '"') : mockHandler.responseText) +
|
|
|
515 |
')');
|
|
|
516 |
}
|
|
|
517 |
|
|
|
518 |
completeJsonpCall( requestSettings, mockHandler, callbackContext, newMock );
|
|
|
519 |
|
|
|
520 |
return newMock;
|
|
|
521 |
}
|
|
|
522 |
|
|
|
523 |
function completeJsonpCall( requestSettings, mockHandler, callbackContext, newMock ) {
|
|
|
524 |
var json;
|
|
|
525 |
|
|
|
526 |
// Successful response
|
|
|
527 |
setTimeout(function() {
|
|
|
528 |
jsonpSuccess( requestSettings, callbackContext, mockHandler );
|
|
|
529 |
jsonpComplete( requestSettings, callbackContext );
|
|
|
530 |
|
|
|
531 |
if ( newMock ) {
|
|
|
532 |
try {
|
|
|
533 |
json = $.parseJSON( mockHandler.responseText );
|
|
|
534 |
} catch (err) { /* just checking... */ }
|
|
|
535 |
|
|
|
536 |
newMock.resolveWith( callbackContext, [json || mockHandler.responseText] );
|
|
|
537 |
logger.log( mockHandler, ['JSONP mock call complete', mockHandler, newMock] );
|
|
|
538 |
}
|
|
|
539 |
}, parseResponseTimeOpt( mockHandler.responseTime ));
|
|
|
540 |
}
|
|
|
541 |
|
|
|
542 |
|
|
|
543 |
// Create the required JSONP callback function for the request
|
|
|
544 |
function createJsonpCallback( requestSettings, mockHandler, origSettings ) {
|
|
|
545 |
var callbackContext = origSettings && origSettings.context || requestSettings;
|
|
|
546 |
var jsonp = (typeof requestSettings.jsonpCallback === 'string' && requestSettings.jsonpCallback) || ('jsonp' + jsc++);
|
|
|
547 |
|
|
|
548 |
// Replace the =? sequence both in the query string and the data
|
|
|
549 |
if ( requestSettings.data ) {
|
|
|
550 |
requestSettings.data = (requestSettings.data + '').replace(CALLBACK_REGEX, '=' + jsonp + '$1');
|
|
|
551 |
}
|
|
|
552 |
|
|
|
553 |
requestSettings.url = requestSettings.url.replace(CALLBACK_REGEX, '=' + jsonp + '$1');
|
|
|
554 |
|
|
|
555 |
|
|
|
556 |
// Handle JSONP-style loading
|
|
|
557 |
window[ jsonp ] = window[ jsonp ] || function() {
|
|
|
558 |
jsonpSuccess( requestSettings, callbackContext, mockHandler );
|
|
|
559 |
jsonpComplete( requestSettings, callbackContext );
|
|
|
560 |
// Garbage collect
|
|
|
561 |
window[ jsonp ] = undefined;
|
|
|
562 |
|
|
|
563 |
try {
|
|
|
564 |
delete window[ jsonp ];
|
|
|
565 |
} catch(e) {}
|
|
|
566 |
};
|
|
|
567 |
requestSettings.jsonpCallback = jsonp;
|
|
|
568 |
}
|
|
|
569 |
|
|
|
570 |
// The JSONP request was successful
|
|
|
571 |
function jsonpSuccess(requestSettings, callbackContext, mockHandler) {
|
|
|
572 |
// If a local callback was specified, fire it and pass it the data
|
|
|
573 |
if ( requestSettings.success ) {
|
|
|
574 |
requestSettings.success.call( callbackContext, mockHandler.responseText || '', 'success', {} );
|
|
|
575 |
}
|
|
|
576 |
|
|
|
577 |
// Fire the global callback
|
|
|
578 |
if ( requestSettings.global ) {
|
|
|
579 |
(requestSettings.context ? $(requestSettings.context) : $.event).trigger('ajaxSuccess', [{}, requestSettings]);
|
|
|
580 |
}
|
|
|
581 |
}
|
|
|
582 |
|
|
|
583 |
// The JSONP request was completed
|
|
|
584 |
function jsonpComplete(requestSettings, callbackContext) {
|
|
|
585 |
if ( requestSettings.complete ) {
|
|
|
586 |
requestSettings.complete.call( callbackContext, {
|
|
|
587 |
statusText: 'success',
|
|
|
588 |
status: 200
|
|
|
589 |
} , 'success' );
|
|
|
590 |
}
|
|
|
591 |
|
|
|
592 |
// The request was completed
|
|
|
593 |
if ( requestSettings.global ) {
|
|
|
594 |
(requestSettings.context ? $(requestSettings.context) : $.event).trigger('ajaxComplete', [{}, requestSettings]);
|
|
|
595 |
}
|
|
|
596 |
|
|
|
597 |
// Handle the global AJAX counter
|
|
|
598 |
if ( requestSettings.global && ! --$.active ) {
|
|
|
599 |
$.event.trigger( 'ajaxStop' );
|
|
|
600 |
}
|
|
|
601 |
}
|
|
|
602 |
|
|
|
603 |
|
|
|
604 |
// The core $.ajax replacement.
|
|
|
605 |
function handleAjax( url, origSettings ) {
|
|
|
606 |
var mockRequest, requestSettings, mockHandler, overrideCallback;
|
|
|
607 |
|
|
|
608 |
logger.debug( null, ['Ajax call intercepted', url, origSettings] );
|
|
|
609 |
|
|
|
610 |
// If url is an object, simulate pre-1.5 signature
|
|
|
611 |
if ( typeof url === 'object' ) {
|
|
|
612 |
origSettings = url;
|
|
|
613 |
url = undefined;
|
|
|
614 |
} else {
|
|
|
615 |
// work around to support 1.5 signature
|
|
|
616 |
origSettings = origSettings || {};
|
|
|
617 |
origSettings.url = url || origSettings.url;
|
|
|
618 |
}
|
|
|
619 |
|
|
|
620 |
// Extend the original settings for the request
|
|
|
621 |
requestSettings = $.ajaxSetup({}, origSettings);
|
|
|
622 |
requestSettings.type = requestSettings.method = requestSettings.method || requestSettings.type;
|
|
|
623 |
|
|
|
624 |
// Generic function to override callback methods for use with
|
|
|
625 |
// callback options (onAfterSuccess, onAfterError, onAfterComplete)
|
|
|
626 |
overrideCallback = function(action, mockHandler) {
|
|
|
627 |
var origHandler = origSettings[action.toLowerCase()];
|
|
|
628 |
return function() {
|
|
|
629 |
if ( $.isFunction(origHandler) ) {
|
|
|
630 |
origHandler.apply(this, [].slice.call(arguments));
|
|
|
631 |
}
|
|
|
632 |
mockHandler['onAfter' + action]();
|
|
|
633 |
};
|
|
|
634 |
};
|
|
|
635 |
|
|
|
636 |
// Iterate over our mock handlers (in registration order) until we find
|
|
|
637 |
// one that is willing to intercept the request
|
|
|
638 |
for(var k = 0; k < mockHandlers.length; k++) {
|
|
|
639 |
if ( !mockHandlers[k] ) {
|
|
|
640 |
continue;
|
|
|
641 |
}
|
|
|
642 |
|
|
|
643 |
mockHandler = getMockForRequest( mockHandlers[k], requestSettings );
|
|
|
644 |
if(!mockHandler) {
|
|
|
645 |
logger.debug( mockHandlers[k], ['Mock does not match request', url, requestSettings] );
|
|
|
646 |
// No valid mock found for this request
|
|
|
647 |
continue;
|
|
|
648 |
}
|
|
|
649 |
|
|
|
650 |
if ($.mockjaxSettings.retainAjaxCalls) {
|
|
|
651 |
mockedAjaxCalls.push(requestSettings);
|
|
|
652 |
}
|
|
|
653 |
|
|
|
654 |
// If logging is enabled, log the mock to the console
|
|
|
655 |
logger.info( mockHandler, [
|
|
|
656 |
'MOCK ' + requestSettings.type.toUpperCase() + ': ' + requestSettings.url,
|
|
|
657 |
$.ajaxSetup({}, requestSettings)
|
|
|
658 |
] );
|
|
|
659 |
|
|
|
660 |
|
|
|
661 |
if ( requestSettings.dataType && requestSettings.dataType.toUpperCase() === 'JSONP' ) {
|
|
|
662 |
if ((mockRequest = processJsonpMock( requestSettings, mockHandler, origSettings ))) {
|
|
|
663 |
// This mock will handle the JSONP request
|
|
|
664 |
return mockRequest;
|
|
|
665 |
}
|
|
|
666 |
}
|
|
|
667 |
|
|
|
668 |
// We are mocking, so there will be no cross domain request, however, jQuery
|
|
|
669 |
// aggressively pursues this if the domains don't match, so we need to
|
|
|
670 |
// explicitly disallow it. (See #136)
|
|
|
671 |
origSettings.crossDomain = false;
|
|
|
672 |
|
|
|
673 |
// Removed to fix #54 - keep the mocking data object intact
|
|
|
674 |
//mockHandler.data = requestSettings.data;
|
|
|
675 |
|
|
|
676 |
mockHandler.cache = requestSettings.cache;
|
|
|
677 |
mockHandler.timeout = requestSettings.timeout;
|
|
|
678 |
mockHandler.global = requestSettings.global;
|
|
|
679 |
|
|
|
680 |
// In the case of a timeout, we just need to ensure
|
|
|
681 |
// an actual jQuery timeout (That is, our reponse won't)
|
|
|
682 |
// return faster than the timeout setting.
|
|
|
683 |
if ( mockHandler.isTimeout ) {
|
|
|
684 |
if ( mockHandler.responseTime > 1 ) {
|
|
|
685 |
origSettings.timeout = mockHandler.responseTime - 1;
|
|
|
686 |
} else {
|
|
|
687 |
mockHandler.responseTime = 2;
|
|
|
688 |
origSettings.timeout = 1;
|
|
|
689 |
}
|
|
|
690 |
}
|
|
|
691 |
|
|
|
692 |
// Set up onAfter[X] callback functions
|
|
|
693 |
if ( $.isFunction( mockHandler.onAfterSuccess ) ) {
|
|
|
694 |
origSettings.success = overrideCallback('Success', mockHandler);
|
|
|
695 |
}
|
|
|
696 |
if ( $.isFunction( mockHandler.onAfterError ) ) {
|
|
|
697 |
origSettings.error = overrideCallback('Error', mockHandler);
|
|
|
698 |
}
|
|
|
699 |
if ( $.isFunction( mockHandler.onAfterComplete ) ) {
|
|
|
700 |
origSettings.complete = overrideCallback('Complete', mockHandler);
|
|
|
701 |
}
|
|
|
702 |
|
|
|
703 |
copyUrlParameters(mockHandler, origSettings);
|
|
|
704 |
|
|
|
705 |
/* jshint loopfunc:true */
|
|
|
706 |
(function(mockHandler, requestSettings, origSettings, origHandler) {
|
|
|
707 |
|
|
|
708 |
mockRequest = _ajax.call($, $.extend(true, {}, origSettings, {
|
|
|
709 |
// Mock the XHR object
|
|
|
710 |
xhr: function() { return xhr( mockHandler, requestSettings, origSettings, origHandler ); }
|
|
|
711 |
}));
|
|
|
712 |
})(mockHandler, requestSettings, origSettings, mockHandlers[k]);
|
|
|
713 |
/* jshint loopfunc:false */
|
|
|
714 |
|
|
|
715 |
return mockRequest;
|
|
|
716 |
}
|
|
|
717 |
|
|
|
718 |
// We don't have a mock request
|
|
|
719 |
logger.log( null, ['No mock matched to request', url, origSettings] );
|
|
|
720 |
if ($.mockjaxSettings.retainAjaxCalls) {
|
|
|
721 |
unmockedAjaxCalls.push(origSettings);
|
|
|
722 |
}
|
|
|
723 |
if($.mockjaxSettings.throwUnmocked === true) {
|
|
|
724 |
throw new Error('AJAX not mocked: ' + origSettings.url);
|
|
|
725 |
}
|
|
|
726 |
else { // trigger a normal request
|
|
|
727 |
return _ajax.apply($, [origSettings]);
|
|
|
728 |
}
|
|
|
729 |
}
|
|
|
730 |
|
|
|
731 |
/**
|
|
|
732 |
* Copies URL parameter values if they were captured by a regular expression
|
|
|
733 |
* @param {Object} mockHandler
|
|
|
734 |
* @param {Object} origSettings
|
|
|
735 |
*/
|
|
|
736 |
function copyUrlParameters(mockHandler, origSettings) {
|
|
|
737 |
//parameters aren't captured if the URL isn't a RegExp
|
|
|
738 |
if (!(mockHandler.url instanceof RegExp)) {
|
|
|
739 |
return;
|
|
|
740 |
}
|
|
|
741 |
//if no URL params were defined on the handler, don't attempt a capture
|
|
|
742 |
if (!mockHandler.hasOwnProperty('urlParams')) {
|
|
|
743 |
return;
|
|
|
744 |
}
|
|
|
745 |
var captures = mockHandler.url.exec(origSettings.url);
|
|
|
746 |
//the whole RegExp match is always the first value in the capture results
|
|
|
747 |
if (captures.length === 1) {
|
|
|
748 |
return;
|
|
|
749 |
}
|
|
|
750 |
captures.shift();
|
|
|
751 |
//use handler params as keys and capture resuts as values
|
|
|
752 |
var i = 0,
|
|
|
753 |
capturesLength = captures.length,
|
|
|
754 |
paramsLength = mockHandler.urlParams.length,
|
|
|
755 |
//in case the number of params specified is less than actual captures
|
|
|
756 |
maxIterations = Math.min(capturesLength, paramsLength),
|
|
|
757 |
paramValues = {};
|
|
|
758 |
for (i; i < maxIterations; i++) {
|
|
|
759 |
var key = mockHandler.urlParams[i];
|
|
|
760 |
paramValues[key] = captures[i];
|
|
|
761 |
}
|
|
|
762 |
origSettings.urlParams = paramValues;
|
|
|
763 |
}
|
|
|
764 |
|
|
|
765 |
/**
|
|
|
766 |
* Clears handlers that mock given url
|
|
|
767 |
* @param url
|
|
|
768 |
* @returns {Array}
|
|
|
769 |
*/
|
|
|
770 |
function clearByUrl(url) {
|
|
|
771 |
var i, len,
|
|
|
772 |
handler,
|
|
|
773 |
results = [],
|
|
|
774 |
match=url instanceof RegExp ?
|
|
|
775 |
function(testUrl) { return url.test(testUrl); } :
|
|
|
776 |
function(testUrl) { return url === testUrl; };
|
|
|
777 |
for (i=0, len=mockHandlers.length; i<len; i++) {
|
|
|
778 |
handler = mockHandlers[i];
|
|
|
779 |
if (!match(handler.url)) {
|
|
|
780 |
results.push(handler);
|
|
|
781 |
} else {
|
|
|
782 |
logger.log( handler, [
|
|
|
783 |
'Clearing mock: ' + (handler && handler.url),
|
|
|
784 |
handler
|
|
|
785 |
] );
|
|
|
786 |
}
|
|
|
787 |
}
|
|
|
788 |
return results;
|
|
|
789 |
}
|
|
|
790 |
|
|
|
791 |
|
|
|
792 |
// Public
|
|
|
793 |
|
|
|
794 |
$.extend({
|
|
|
795 |
ajax: handleAjax
|
|
|
796 |
});
|
|
|
797 |
|
|
|
798 |
var logger = {
|
|
|
799 |
_log: function logger( mockHandler, args, level ) {
|
|
|
800 |
var loggerLevel = $.mockjaxSettings.logging;
|
|
|
801 |
if (mockHandler && typeof mockHandler.logging !== 'undefined') {
|
|
|
802 |
loggerLevel = mockHandler.logging;
|
|
|
803 |
}
|
|
|
804 |
level = ( level === 0 ) ? level : ( level || logLevels.LOG );
|
|
|
805 |
args = (args.splice) ? args : [ args ];
|
|
|
806 |
|
|
|
807 |
// Is logging turned off for this mock or mockjax as a whole?
|
|
|
808 |
// Or is this log message above the desired log level?
|
|
|
809 |
if ( loggerLevel === false || loggerLevel < level ) {
|
|
|
810 |
return;
|
|
|
811 |
}
|
|
|
812 |
|
|
|
813 |
if ( $.mockjaxSettings.log ) {
|
|
|
814 |
return $.mockjaxSettings.log( mockHandler, args[1] || args[0] );
|
|
|
815 |
} else if ( $.mockjaxSettings.logger && $.mockjaxSettings.logger[$.mockjaxSettings.logLevelMethods[level]] ) {
|
|
|
816 |
return $.mockjaxSettings.logger[$.mockjaxSettings.logLevelMethods[level]].apply( $.mockjaxSettings.logger, args );
|
|
|
817 |
}
|
|
|
818 |
},
|
|
|
819 |
/**
|
|
|
820 |
* Convenience method for logging a DEBUG level message
|
|
|
821 |
* @param {Object} m The mock handler in question
|
|
|
822 |
* @param {Array|String|Object} a The items to log
|
|
|
823 |
* @return {?} Will return whatever the $.mockjaxSettings.logger method for this level would return (generally 'undefined')
|
|
|
824 |
*/
|
|
|
825 |
debug: function(m,a) { return logger._log(m,a,logLevels.DEBUG); },
|
|
|
826 |
/**
|
|
|
827 |
* @see logger.debug
|
|
|
828 |
*/
|
|
|
829 |
log: function(m,a) { return logger._log(m,a,logLevels.LOG); },
|
|
|
830 |
/**
|
|
|
831 |
* @see logger.debug
|
|
|
832 |
*/
|
|
|
833 |
info: function(m,a) { return logger._log(m,a,logLevels.INFO); },
|
|
|
834 |
/**
|
|
|
835 |
* @see logger.debug
|
|
|
836 |
*/
|
|
|
837 |
warn: function(m,a) { return logger._log(m,a,logLevels.WARN); },
|
|
|
838 |
/**
|
|
|
839 |
* @see logger.debug
|
|
|
840 |
*/
|
|
|
841 |
error: function(m,a) { return logger._log(m,a,logLevels.ERROR); }
|
|
|
842 |
};
|
|
|
843 |
|
|
|
844 |
var logLevels = {
|
|
|
845 |
DEBUG: 4,
|
|
|
846 |
LOG: 3,
|
|
|
847 |
INFO: 2,
|
|
|
848 |
WARN: 1,
|
|
|
849 |
ERROR: 0
|
|
|
850 |
};
|
|
|
851 |
|
|
|
852 |
/**
|
|
|
853 |
* Default settings for mockjax. Some of these are used for defaults of
|
|
|
854 |
* individual mock handlers, and some are for the library as a whole.
|
|
|
855 |
* For individual mock handler settings, please see the README on the repo:
|
|
|
856 |
* https://github.com/jakerella/jquery-mockjax#api-methods
|
|
|
857 |
*
|
|
|
858 |
* @type {Object}
|
|
|
859 |
*/
|
|
|
860 |
$.mockjaxSettings = {
|
|
|
861 |
log: null, // this is only here for historical purposes... use $.mockjaxSettings.logger
|
|
|
862 |
logger: window.console,
|
|
|
863 |
logging: 2,
|
|
|
864 |
logLevelMethods: ['error', 'warn', 'info', 'log', 'debug'],
|
|
|
865 |
namespace: null,
|
|
|
866 |
status: 200,
|
|
|
867 |
statusText: 'OK',
|
|
|
868 |
responseTime: DEFAULT_RESPONSE_TIME,
|
|
|
869 |
isTimeout: false,
|
|
|
870 |
throwUnmocked: false,
|
|
|
871 |
retainAjaxCalls: true,
|
|
|
872 |
contentType: 'text/plain',
|
|
|
873 |
response: '',
|
|
|
874 |
responseText: '',
|
|
|
875 |
responseXML: '',
|
|
|
876 |
proxy: '',
|
|
|
877 |
proxyType: 'GET',
|
|
|
878 |
|
|
|
879 |
lastModified: null,
|
|
|
880 |
etag: '',
|
|
|
881 |
headers: {
|
|
|
882 |
etag: 'IJF@H#@923uf8023hFO@I#H#',
|
|
|
883 |
'content-type' : 'text/plain'
|
|
|
884 |
}
|
|
|
885 |
};
|
|
|
886 |
|
|
|
887 |
/**
|
|
|
888 |
* Create a new mock Ajax handler. When a mock handler is matched during a
|
|
|
889 |
* $.ajax() call this library will intercept that request and fake a response
|
|
|
890 |
* using the data and methods in the mock. You can see all settings in the
|
|
|
891 |
* README of the main repository:
|
|
|
892 |
* https://github.com/jakerella/jquery-mockjax#api-methods
|
|
|
893 |
*
|
|
|
894 |
* @param {Object} settings The mock handelr settings: https://github.com/jakerella/jquery-mockjax#api-methods
|
|
|
895 |
* @return {Number} The id (index) of the mock handler suitable for clearing (see $.mockjax.clear())
|
|
|
896 |
*/
|
|
|
897 |
$.mockjax = function(settings) {
|
|
|
898 |
// Multiple mocks.
|
|
|
899 |
if ( $.isArray(settings) ) {
|
|
|
900 |
return $.map(settings, function(s) {
|
|
|
901 |
return $.mockjax(s);
|
|
|
902 |
});
|
|
|
903 |
}
|
|
|
904 |
|
|
|
905 |
var i = mockHandlers.length;
|
|
|
906 |
mockHandlers[i] = settings;
|
|
|
907 |
logger.log( settings, ['Created new mock handler', settings] );
|
|
|
908 |
return i;
|
|
|
909 |
};
|
|
|
910 |
|
|
|
911 |
$.mockjax._logger = logger;
|
|
|
912 |
|
|
|
913 |
/**
|
|
|
914 |
* Remove an Ajax mock from those held in memory. This will prevent any
|
|
|
915 |
* future Ajax request mocking for matched requests.
|
|
|
916 |
* NOTE: Clearing a mock will not prevent the resolution of in progress requests
|
|
|
917 |
*
|
|
|
918 |
* @param {Number|String|RegExp} i OPTIONAL The mock to clear. If not provided, all mocks are cleared,
|
|
|
919 |
* if a number it is the index in the in-memory cache. If a string or
|
|
|
920 |
* RegExp, find a mock that matches that URL and clear it.
|
|
|
921 |
* @return {void}
|
|
|
922 |
*/
|
|
|
923 |
$.mockjax.clear = function(i) {
|
|
|
924 |
if ( typeof i === 'string' || i instanceof RegExp) {
|
|
|
925 |
mockHandlers = clearByUrl(i);
|
|
|
926 |
} else if ( i || i === 0 ) {
|
|
|
927 |
logger.log( mockHandlers[i], [
|
|
|
928 |
'Clearing mock: ' + (mockHandlers[i] && mockHandlers[i].url),
|
|
|
929 |
mockHandlers[i]
|
|
|
930 |
] );
|
|
|
931 |
mockHandlers[i] = null;
|
|
|
932 |
} else {
|
|
|
933 |
logger.log( null, 'Clearing all mocks' );
|
|
|
934 |
mockHandlers = [];
|
|
|
935 |
}
|
|
|
936 |
mockedAjaxCalls = [];
|
|
|
937 |
unmockedAjaxCalls = [];
|
|
|
938 |
};
|
|
|
939 |
|
|
|
940 |
/**
|
|
|
941 |
* By default all Ajax requests performed after loading Mockjax are recorded
|
|
|
942 |
* so that we can see which requests were mocked and which were not. This
|
|
|
943 |
* method allows the developer to clear those retained requests.
|
|
|
944 |
*
|
|
|
945 |
* @return {void}
|
|
|
946 |
*/
|
|
|
947 |
$.mockjax.clearRetainedAjaxCalls = function() {
|
|
|
948 |
mockedAjaxCalls = [];
|
|
|
949 |
unmockedAjaxCalls = [];
|
|
|
950 |
logger.debug( null, 'Cleared retained ajax calls' );
|
|
|
951 |
};
|
|
|
952 |
|
|
|
953 |
/**
|
|
|
954 |
* Retrive the mock handler with the given id (index).
|
|
|
955 |
*
|
|
|
956 |
* @param {Number} i The id (index) to retrieve
|
|
|
957 |
* @return {Object} The mock handler settings
|
|
|
958 |
*/
|
|
|
959 |
$.mockjax.handler = function(i) {
|
|
|
960 |
if ( arguments.length === 1 ) {
|
|
|
961 |
return mockHandlers[i];
|
|
|
962 |
}
|
|
|
963 |
};
|
|
|
964 |
|
|
|
965 |
/**
|
|
|
966 |
* Retrieve all Ajax calls that have been mocked by this library during the
|
|
|
967 |
* current session (in other words, only since you last loaded this file).
|
|
|
968 |
*
|
|
|
969 |
* @return {Array} The mocked Ajax calls (request settings)
|
|
|
970 |
*/
|
|
|
971 |
$.mockjax.mockedAjaxCalls = function() {
|
|
|
972 |
return mockedAjaxCalls;
|
|
|
973 |
};
|
|
|
974 |
|
|
|
975 |
/**
|
|
|
976 |
* Return all mock handlers that have NOT been matched against Ajax requests
|
|
|
977 |
*
|
|
|
978 |
* @return {Array} The mock handlers
|
|
|
979 |
*/
|
|
|
980 |
$.mockjax.unfiredHandlers = function() {
|
|
|
981 |
var results = [];
|
|
|
982 |
for (var i=0, len=mockHandlers.length; i<len; i++) {
|
|
|
983 |
var handler = mockHandlers[i];
|
|
|
984 |
if (handler !== null && !handler.fired) {
|
|
|
985 |
results.push(handler);
|
|
|
986 |
}
|
|
|
987 |
}
|
|
|
988 |
return results;
|
|
|
989 |
};
|
|
|
990 |
|
|
|
991 |
/**
|
|
|
992 |
* Retrieve all Ajax calls that have NOT been mocked by this library during
|
|
|
993 |
* the current session (in other words, only since you last loaded this file).
|
|
|
994 |
*
|
|
|
995 |
* @return {Array} The mocked Ajax calls (request settings)
|
|
|
996 |
*/
|
|
|
997 |
$.mockjax.unmockedAjaxCalls = function() {
|
|
|
998 |
return unmockedAjaxCalls;
|
|
|
999 |
};
|
|
|
1000 |
|
|
|
1001 |
return $.mockjax;
|
|
|
1002 |
|
|
|
1003 |
}));
|