mockjax 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +56 -0
- data/Rakefile +2 -0
- data/app/assets/javascripts/jquery.mockjax.js +521 -0
- data/lib/mockjax.rb +46 -0
- data/lib/mockjax/rack.rb +23 -0
- data/lib/mockjax/rails.rb +6 -0
- data/lib/mockjax/version.rb +3 -0
- data/mockjax.gemspec +19 -0
- metadata +68 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Eric J. Holmes
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Mockjax
|
2
|
+
|
3
|
+
Mockjax gem for rails and rack applications. Define javascript mocks in your
|
4
|
+
request specs
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'mockjax'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install mockjax
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
Assuming you're using capybara...
|
22
|
+
|
23
|
+
### Rack
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# spec/spec_helper.rb
|
27
|
+
Mockjax.path_to_js = '/path/to/jquery.mockjax.js'
|
28
|
+
|
29
|
+
Capybara.app = Rack::Build.new {
|
30
|
+
use Rack::Mockjax
|
31
|
+
run MyApp
|
32
|
+
}
|
33
|
+
```
|
34
|
+
|
35
|
+
#### Rails 3
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
# config/initializers/test.rb
|
39
|
+
config.middleware.use Rack::Mockjax
|
40
|
+
```
|
41
|
+
|
42
|
+
Then define your stubs like you would with any other stubbing library:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
before do
|
46
|
+
mockjax url: '/test', responseText: { message: 'hello world' }
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
## Contributing
|
51
|
+
|
52
|
+
1. Fork it
|
53
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
54
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
55
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
56
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,521 @@
|
|
1
|
+
/*!
|
2
|
+
* MockJax - jQuery Plugin to Mock Ajax requests
|
3
|
+
*
|
4
|
+
* Version: 1.5.0pre
|
5
|
+
* Released:
|
6
|
+
* Home: http://github.com/appendto/jquery-mockjax
|
7
|
+
* Author: Jonathan Sharp (http://jdsharp.com)
|
8
|
+
* License: MIT,GPL
|
9
|
+
*
|
10
|
+
* Copyright (c) 2011 appendTo LLC.
|
11
|
+
* Dual licensed under the MIT or GPL licenses.
|
12
|
+
* http://appendto.com/open-source-licenses
|
13
|
+
*/
|
14
|
+
(function($) {
|
15
|
+
var _ajax = $.ajax,
|
16
|
+
mockHandlers = [],
|
17
|
+
CALLBACK_REGEX = /=\?(&|$)/,
|
18
|
+
jsc = (new Date()).getTime();
|
19
|
+
|
20
|
+
|
21
|
+
// Parse the given XML string.
|
22
|
+
function parseXML(xml) {
|
23
|
+
if ( window['DOMParser'] == undefined && window.ActiveXObject ) {
|
24
|
+
DOMParser = function() { };
|
25
|
+
DOMParser.prototype.parseFromString = function( xmlString ) {
|
26
|
+
var doc = new ActiveXObject('Microsoft.XMLDOM');
|
27
|
+
doc.async = 'false';
|
28
|
+
doc.loadXML( xmlString );
|
29
|
+
return doc;
|
30
|
+
};
|
31
|
+
}
|
32
|
+
|
33
|
+
try {
|
34
|
+
var xmlDoc = ( new DOMParser() ).parseFromString( xml, 'text/xml' );
|
35
|
+
if ( $.isXMLDoc( xmlDoc ) ) {
|
36
|
+
var err = $('parsererror', xmlDoc);
|
37
|
+
if ( err.length == 1 ) {
|
38
|
+
throw('Error: ' + $(xmlDoc).text() );
|
39
|
+
}
|
40
|
+
} else {
|
41
|
+
throw('Unable to parse XML');
|
42
|
+
}
|
43
|
+
} catch( e ) {
|
44
|
+
var msg = ( e.name == undefined ? e : e.name + ': ' + e.message );
|
45
|
+
$(document).trigger('xmlParseError', [ msg ]);
|
46
|
+
return undefined;
|
47
|
+
}
|
48
|
+
return xmlDoc;
|
49
|
+
}
|
50
|
+
|
51
|
+
// Trigger a jQuery event
|
52
|
+
function trigger(s, type, args) {
|
53
|
+
(s.context ? jQuery(s.context) : jQuery.event).trigger(type, args);
|
54
|
+
}
|
55
|
+
|
56
|
+
// Check if the data field on the mock handler and the request match. This
|
57
|
+
// can be used to restrict a mock handler to being used only when a certain
|
58
|
+
// set of data is passed to it.
|
59
|
+
function isMockDataEqual( mock, live ) {
|
60
|
+
var identical = false;
|
61
|
+
// Test for situations where the data is a querystring (not an object)
|
62
|
+
if (typeof live === 'string') {
|
63
|
+
// Querystring may be a regex
|
64
|
+
return $.isFunction( mock.test ) ? mock.test(live) : mock == live;
|
65
|
+
}
|
66
|
+
$.each(mock, function(k, v) {
|
67
|
+
if ( live[k] === undefined ) {
|
68
|
+
identical = false;
|
69
|
+
return identical;
|
70
|
+
} else {
|
71
|
+
identical = true;
|
72
|
+
if ( typeof live[k] == 'object' ) {
|
73
|
+
return isMockDataEqual(mock[k], live[k]);
|
74
|
+
} else {
|
75
|
+
if ( $.isFunction( mock[k].test ) ) {
|
76
|
+
identical = mock[k].test(live[k]);
|
77
|
+
} else {
|
78
|
+
identical = ( mock[k] == live[k] );
|
79
|
+
}
|
80
|
+
return identical;
|
81
|
+
}
|
82
|
+
}
|
83
|
+
});
|
84
|
+
|
85
|
+
return identical;
|
86
|
+
}
|
87
|
+
|
88
|
+
// Check the given handler should mock the given request
|
89
|
+
function getMockForRequest( handler, requestSettings ) {
|
90
|
+
// If the mock was registered with a function, let the function decide if we
|
91
|
+
// want to mock this request
|
92
|
+
if ( $.isFunction(handler) ) {
|
93
|
+
return handler( requestSettings );
|
94
|
+
}
|
95
|
+
|
96
|
+
// Inspect the URL of the request and check if the mock handler's url
|
97
|
+
// matches the url for this ajax request
|
98
|
+
if ( $.isFunction(handler.url.test) ) {
|
99
|
+
// The user provided a regex for the url, test it
|
100
|
+
if ( !handler.url.test( requestSettings.url ) ) {
|
101
|
+
return null;
|
102
|
+
}
|
103
|
+
} else {
|
104
|
+
// Look for a simple wildcard '*' or a direct URL match
|
105
|
+
var star = handler.url.indexOf('*');
|
106
|
+
if (handler.url !== requestSettings.url && star === -1 ||
|
107
|
+
!new RegExp(handler.url.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\\$&").replace('*', '.+')).test(requestSettings.url)) {
|
108
|
+
return null;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
// Inspect the data submitted in the request (either POST body or GET query string)
|
113
|
+
if ( handler.data && requestSettings.data ) {
|
114
|
+
if ( !isMockDataEqual(handler.data, requestSettings.data) ) {
|
115
|
+
// They're not identical, do not mock this request
|
116
|
+
return null;
|
117
|
+
}
|
118
|
+
}
|
119
|
+
// Inspect the request type
|
120
|
+
if ( handler && handler.type &&
|
121
|
+
handler.type.toLowerCase() != requestSettings.type.toLowerCase() ) {
|
122
|
+
// The request type doesn't match (GET vs. POST)
|
123
|
+
return null;
|
124
|
+
}
|
125
|
+
|
126
|
+
return handler;
|
127
|
+
}
|
128
|
+
|
129
|
+
// If logging is enabled, log the mock to the console
|
130
|
+
function logMock( mockHandler, requestSettings ) {
|
131
|
+
var c = $.extend({}, $.mockjaxSettings, mockHandler);
|
132
|
+
if ( c.log && $.isFunction(c.log) ) {
|
133
|
+
c.log('MOCK ' + requestSettings.type.toUpperCase() + ': ' + requestSettings.url, $.extend({}, requestSettings));
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
// Process the xhr objects send operation
|
138
|
+
function _xhrSend(mockHandler, requestSettings, origSettings) {
|
139
|
+
|
140
|
+
// This is a substitute for < 1.4 which lacks $.proxy
|
141
|
+
var process = (function(that) {
|
142
|
+
return function() {
|
143
|
+
return (function() {
|
144
|
+
// The request has returned
|
145
|
+
this.status = mockHandler.status;
|
146
|
+
this.statusText = mockHandler.statusText;
|
147
|
+
this.readyState = 4;
|
148
|
+
|
149
|
+
// We have an executable function, call it to give
|
150
|
+
// the mock handler a chance to update it's data
|
151
|
+
if ( $.isFunction(mockHandler.response) ) {
|
152
|
+
mockHandler.response(origSettings);
|
153
|
+
}
|
154
|
+
// Copy over our mock to our xhr object before passing control back to
|
155
|
+
// jQuery's onreadystatechange callback
|
156
|
+
if ( requestSettings.dataType == 'json' && ( typeof mockHandler.responseText == 'object' ) ) {
|
157
|
+
this.responseText = JSON.stringify(mockHandler.responseText);
|
158
|
+
} else if ( requestSettings.dataType == 'xml' ) {
|
159
|
+
if ( typeof mockHandler.responseXML == 'string' ) {
|
160
|
+
this.responseXML = parseXML(mockHandler.responseXML);
|
161
|
+
} else {
|
162
|
+
this.responseXML = mockHandler.responseXML;
|
163
|
+
}
|
164
|
+
} else {
|
165
|
+
this.responseText = mockHandler.responseText;
|
166
|
+
}
|
167
|
+
if( typeof mockHandler.status == 'number' || typeof mockHandler.status == 'string' ) {
|
168
|
+
this.status = mockHandler.status;
|
169
|
+
}
|
170
|
+
if( typeof mockHandler.statusText === "string") {
|
171
|
+
this.statusText = mockHandler.statusText;
|
172
|
+
}
|
173
|
+
// jQuery < 1.4 doesn't have onreadystate change for xhr
|
174
|
+
if ( $.isFunction(this.onreadystatechange) ) {
|
175
|
+
if( mockHandler.isTimeout) {
|
176
|
+
this.status = -1;
|
177
|
+
}
|
178
|
+
this.onreadystatechange( mockHandler.isTimeout ? 'timeout' : undefined );
|
179
|
+
} else if ( mockHandler.isTimeout ) {
|
180
|
+
// Fix for 1.3.2 timeout to keep success from firing.
|
181
|
+
this.status = -1;
|
182
|
+
}
|
183
|
+
}).apply(that);
|
184
|
+
};
|
185
|
+
})(this);
|
186
|
+
|
187
|
+
if ( mockHandler.proxy ) {
|
188
|
+
// We're proxying this request and loading in an external file instead
|
189
|
+
_ajax({
|
190
|
+
global: false,
|
191
|
+
url: mockHandler.proxy,
|
192
|
+
type: mockHandler.proxyType,
|
193
|
+
data: mockHandler.data,
|
194
|
+
dataType: requestSettings.dataType === "script" ? "text/plain" : requestSettings.dataType,
|
195
|
+
complete: function(xhr, txt) {
|
196
|
+
mockHandler.responseXML = xhr.responseXML;
|
197
|
+
mockHandler.responseText = xhr.responseText;
|
198
|
+
mockHandler.status = xhr.status;
|
199
|
+
mockHandler.statusText = xhr.statusText;
|
200
|
+
this.responseTimer = setTimeout(process, mockHandler.responseTime || 0);
|
201
|
+
}
|
202
|
+
});
|
203
|
+
} else {
|
204
|
+
// type == 'POST' || 'GET' || 'DELETE'
|
205
|
+
if ( requestSettings.async === false ) {
|
206
|
+
// TODO: Blocking delay
|
207
|
+
process();
|
208
|
+
} else {
|
209
|
+
this.responseTimer = setTimeout(process, mockHandler.responseTime || 50);
|
210
|
+
}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
// Construct a mocked XHR Object
|
215
|
+
function xhr(mockHandler, requestSettings, origSettings, origHandler) {
|
216
|
+
// Extend with our default mockjax settings
|
217
|
+
mockHandler = $.extend({}, $.mockjaxSettings, mockHandler);
|
218
|
+
|
219
|
+
if (typeof mockHandler.headers === 'undefined') {
|
220
|
+
mockHandler.headers = {};
|
221
|
+
}
|
222
|
+
if ( mockHandler.contentType ) {
|
223
|
+
mockHandler.headers['content-type'] = mockHandler.contentType;
|
224
|
+
}
|
225
|
+
|
226
|
+
return {
|
227
|
+
status: mockHandler.status,
|
228
|
+
statusText: mockHandler.statusText,
|
229
|
+
readyState: 1,
|
230
|
+
open: function() { },
|
231
|
+
send: function() {
|
232
|
+
origHandler.fired = true;
|
233
|
+
_xhrSend.call(this, mockHandler, requestSettings, origSettings);
|
234
|
+
},
|
235
|
+
abort: function() {
|
236
|
+
clearTimeout(this.responseTimer);
|
237
|
+
},
|
238
|
+
setRequestHeader: function(header, value) {
|
239
|
+
mockHandler.headers[header] = value;
|
240
|
+
},
|
241
|
+
getResponseHeader: function(header) {
|
242
|
+
// 'Last-modified', 'Etag', 'content-type' are all checked by jQuery
|
243
|
+
if ( mockHandler.headers && mockHandler.headers[header] ) {
|
244
|
+
// Return arbitrary headers
|
245
|
+
return mockHandler.headers[header];
|
246
|
+
} else if ( header.toLowerCase() == 'last-modified' ) {
|
247
|
+
return mockHandler.lastModified || (new Date()).toString();
|
248
|
+
} else if ( header.toLowerCase() == 'etag' ) {
|
249
|
+
return mockHandler.etag || '';
|
250
|
+
} else if ( header.toLowerCase() == 'content-type' ) {
|
251
|
+
return mockHandler.contentType || 'text/plain';
|
252
|
+
}
|
253
|
+
},
|
254
|
+
getAllResponseHeaders: function() {
|
255
|
+
var headers = '';
|
256
|
+
$.each(mockHandler.headers, function(k, v) {
|
257
|
+
headers += k + ': ' + v + "\n";
|
258
|
+
});
|
259
|
+
return headers;
|
260
|
+
}
|
261
|
+
};
|
262
|
+
}
|
263
|
+
|
264
|
+
// Process a JSONP mock request.
|
265
|
+
function processJsonpMock( requestSettings, mockHandler, origSettings ) {
|
266
|
+
// Handle JSONP Parameter Callbacks, we need to replicate some of the jQuery core here
|
267
|
+
// because there isn't an easy hook for the cross domain script tag of jsonp
|
268
|
+
|
269
|
+
processJsonpUrl( requestSettings );
|
270
|
+
|
271
|
+
requestSettings.dataType = "json";
|
272
|
+
if(requestSettings.data && CALLBACK_REGEX.test(requestSettings.data) || CALLBACK_REGEX.test(requestSettings.url)) {
|
273
|
+
createJsonpCallback(requestSettings, mockHandler);
|
274
|
+
|
275
|
+
// We need to make sure
|
276
|
+
// that a JSONP style response is executed properly
|
277
|
+
|
278
|
+
var rurl = /^(\w+:)?\/\/([^\/?#]+)/,
|
279
|
+
parts = rurl.exec( requestSettings.url ),
|
280
|
+
remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
|
281
|
+
|
282
|
+
requestSettings.dataType = "script";
|
283
|
+
if(requestSettings.type.toUpperCase() === "GET" && remote ) {
|
284
|
+
var newMockReturn = processJsonpRequest( requestSettings, mockHandler, origSettings );
|
285
|
+
|
286
|
+
// Check if we are supposed to return a Deferred back to the mock call, or just
|
287
|
+
// signal success
|
288
|
+
if(newMockReturn) {
|
289
|
+
return newMockReturn;
|
290
|
+
} else {
|
291
|
+
return true;
|
292
|
+
}
|
293
|
+
}
|
294
|
+
}
|
295
|
+
return null;
|
296
|
+
}
|
297
|
+
|
298
|
+
// Append the required callback parameter to the end of the request URL, for a JSONP request
|
299
|
+
function processJsonpUrl( requestSettings ) {
|
300
|
+
if ( requestSettings.type.toUpperCase() === "GET" ) {
|
301
|
+
if ( !CALLBACK_REGEX.test( requestSettings.url ) ) {
|
302
|
+
requestSettings.url += (/\?/.test( requestSettings.url ) ? "&" : "?") +
|
303
|
+
(requestSettings.jsonp || "callback") + "=?";
|
304
|
+
}
|
305
|
+
} else if ( !requestSettings.data || !CALLBACK_REGEX.test(requestSettings.data) ) {
|
306
|
+
requestSettings.data = (requestSettings.data ? requestSettings.data + "&" : "") + (requestSettings.jsonp || "callback") + "=?";
|
307
|
+
}
|
308
|
+
}
|
309
|
+
|
310
|
+
// Process a JSONP request by evaluating the mocked response text
|
311
|
+
function processJsonpRequest( requestSettings, mockHandler, origSettings ) {
|
312
|
+
// Synthesize the mock request for adding a script tag
|
313
|
+
var callbackContext = origSettings && origSettings.context || requestSettings,
|
314
|
+
newMock = null;
|
315
|
+
|
316
|
+
|
317
|
+
// If the response handler on the moock is a function, call it
|
318
|
+
if ( mockHandler.response && $.isFunction(mockHandler.response) ) {
|
319
|
+
mockHandler.response(origSettings);
|
320
|
+
} else {
|
321
|
+
|
322
|
+
// Evaluate the responseText javascript in a global context
|
323
|
+
if( typeof mockHandler.responseText === 'object' ) {
|
324
|
+
$.globalEval( '(' + JSON.stringify( mockHandler.responseText ) + ')');
|
325
|
+
} else {
|
326
|
+
$.globalEval( '(' + mockHandler.responseText + ')');
|
327
|
+
}
|
328
|
+
}
|
329
|
+
|
330
|
+
// Successful response
|
331
|
+
jsonpSuccess( requestSettings, mockHandler );
|
332
|
+
jsonpComplete( requestSettings, mockHandler );
|
333
|
+
|
334
|
+
// If we are running under jQuery 1.5+, return a deferred object
|
335
|
+
if(jQuery.Deferred){
|
336
|
+
newMock = new jQuery.Deferred();
|
337
|
+
if(typeof mockHandler.responseText == "object"){
|
338
|
+
newMock.resolve( mockHandler.responseText );
|
339
|
+
}
|
340
|
+
else{
|
341
|
+
newMock.resolve( jQuery.parseJSON( mockHandler.responseText ) );
|
342
|
+
}
|
343
|
+
}
|
344
|
+
return newMock;
|
345
|
+
}
|
346
|
+
|
347
|
+
|
348
|
+
// Create the required JSONP callback function for the request
|
349
|
+
function createJsonpCallback( requestSettings, mockHandler ) {
|
350
|
+
jsonp = requestSettings.jsonpCallback || ("jsonp" + jsc++);
|
351
|
+
|
352
|
+
// Replace the =? sequence both in the query string and the data
|
353
|
+
if ( requestSettings.data ) {
|
354
|
+
requestSettings.data = (requestSettings.data + "").replace(CALLBACK_REGEX, "=" + jsonp + "$1");
|
355
|
+
}
|
356
|
+
|
357
|
+
requestSettings.url = requestSettings.url.replace(CALLBACK_REGEX, "=" + jsonp + "$1");
|
358
|
+
|
359
|
+
|
360
|
+
// Handle JSONP-style loading
|
361
|
+
window[ jsonp ] = window[ jsonp ] || function( tmp ) {
|
362
|
+
data = tmp;
|
363
|
+
jsonpSuccess( requestSettings, mockHandler );
|
364
|
+
jsonpComplete( requestSettings, mockHandler );
|
365
|
+
// Garbage collect
|
366
|
+
window[ jsonp ] = undefined;
|
367
|
+
|
368
|
+
try {
|
369
|
+
delete window[ jsonp ];
|
370
|
+
} catch(e) {}
|
371
|
+
|
372
|
+
if ( head ) {
|
373
|
+
head.removeChild( script );
|
374
|
+
}
|
375
|
+
};
|
376
|
+
}
|
377
|
+
|
378
|
+
// The JSONP request was successful
|
379
|
+
function jsonpSuccess(requestSettings, mockHandler) {
|
380
|
+
// If a local callback was specified, fire it and pass it the data
|
381
|
+
if ( requestSettings.success ) {
|
382
|
+
requestSettings.success.call( callbackContext, ( mockHandler.response ? mockHandler.response.toString() : mockHandler.responseText || ''), status, {} );
|
383
|
+
}
|
384
|
+
|
385
|
+
// Fire the global callback
|
386
|
+
if ( requestSettings.global ) {
|
387
|
+
trigger(requestSettings, "ajaxSuccess", [{}, requestSettings] );
|
388
|
+
}
|
389
|
+
}
|
390
|
+
|
391
|
+
// The JSONP request was completed
|
392
|
+
function jsonpComplete(requestSettings, mockHandler) {
|
393
|
+
// Process result
|
394
|
+
if ( requestSettings.complete ) {
|
395
|
+
requestSettings.complete.call( callbackContext, {} , status );
|
396
|
+
}
|
397
|
+
|
398
|
+
// The request was completed
|
399
|
+
if ( requestSettings.global ) {
|
400
|
+
trigger( "ajaxComplete", [{}, requestSettings] );
|
401
|
+
}
|
402
|
+
|
403
|
+
// Handle the global AJAX counter
|
404
|
+
if ( requestSettings.global && ! --jQuery.active ) {
|
405
|
+
jQuery.event.trigger( "ajaxStop" );
|
406
|
+
}
|
407
|
+
}
|
408
|
+
|
409
|
+
|
410
|
+
// The core $.ajax replacement.
|
411
|
+
function handleAjax( url, origSettings ) {
|
412
|
+
var mockRequest, requestSettings, mockHandler;
|
413
|
+
|
414
|
+
// If url is an object, simulate pre-1.5 signature
|
415
|
+
if ( typeof url === "object" ) {
|
416
|
+
origSettings = url;
|
417
|
+
url = undefined;
|
418
|
+
} else {
|
419
|
+
// work around to support 1.5 signature
|
420
|
+
origSettings.url = url;
|
421
|
+
}
|
422
|
+
|
423
|
+
// Extend the original settings for the request
|
424
|
+
requestSettings = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings);
|
425
|
+
|
426
|
+
// Iterate over our mock handlers (in registration order) until we find
|
427
|
+
// one that is willing to intercept the request
|
428
|
+
for(var k = 0; k < mockHandlers.length; k++) {
|
429
|
+
if ( !mockHandlers[k] ) {
|
430
|
+
continue;
|
431
|
+
}
|
432
|
+
|
433
|
+
mockHandler = getMockForRequest( mockHandlers[k], requestSettings );
|
434
|
+
if(!mockHandler) {
|
435
|
+
// No valid mock found for this request
|
436
|
+
continue;
|
437
|
+
}
|
438
|
+
|
439
|
+
// Handle console logging
|
440
|
+
logMock( mockHandler, requestSettings );
|
441
|
+
|
442
|
+
|
443
|
+
if ( requestSettings.dataType === "jsonp" ) {
|
444
|
+
if ((mockRequest = processJsonpMock( requestSettings, mockHandler, origSettings ))) {
|
445
|
+
// This mock will handle the JSONP request
|
446
|
+
return mockRequest;
|
447
|
+
}
|
448
|
+
}
|
449
|
+
|
450
|
+
|
451
|
+
// Removed to fix #54 - keep the mocking data object intact
|
452
|
+
//mockHandler.data = requestSettings.data;
|
453
|
+
|
454
|
+
mockHandler.cache = requestSettings.cache;
|
455
|
+
mockHandler.timeout = requestSettings.timeout;
|
456
|
+
mockHandler.global = requestSettings.global;
|
457
|
+
|
458
|
+
(function(mockHandler, requestSettings, origSettings, origHandler) {
|
459
|
+
mockRequest = _ajax.call($, $.extend(true, {}, origSettings, {
|
460
|
+
// Mock the XHR object
|
461
|
+
xhr: function() { return xhr( mockHandler, requestSettings, origSettings, origHandler ) }
|
462
|
+
}));
|
463
|
+
})(mockHandler, requestSettings, origSettings, mockHandlers[k]);
|
464
|
+
|
465
|
+
return mockRequest;
|
466
|
+
}
|
467
|
+
|
468
|
+
// We don't have a mock request, trigger a normal request
|
469
|
+
return _ajax.apply($, [origSettings]);
|
470
|
+
}
|
471
|
+
|
472
|
+
|
473
|
+
// Public
|
474
|
+
|
475
|
+
$.extend({
|
476
|
+
ajax: handleAjax
|
477
|
+
});
|
478
|
+
|
479
|
+
$.mockjaxSettings = {
|
480
|
+
//url: null,
|
481
|
+
//type: 'GET',
|
482
|
+
log: function(msg) {
|
483
|
+
window['console'] && window.console.log && window.console.log(msg);
|
484
|
+
},
|
485
|
+
status: 200,
|
486
|
+
statusText: "OK",
|
487
|
+
responseTime: 500,
|
488
|
+
isTimeout: false,
|
489
|
+
contentType: 'text/plain',
|
490
|
+
response: '',
|
491
|
+
responseText: '',
|
492
|
+
responseXML: '',
|
493
|
+
proxy: '',
|
494
|
+
proxyType: 'GET',
|
495
|
+
|
496
|
+
lastModified: null,
|
497
|
+
etag: '',
|
498
|
+
headers: {
|
499
|
+
etag: 'IJF@H#@923uf8023hFO@I#H#',
|
500
|
+
'content-type' : 'text/plain'
|
501
|
+
}
|
502
|
+
};
|
503
|
+
|
504
|
+
$.mockjax = function(settings) {
|
505
|
+
var i = mockHandlers.length;
|
506
|
+
mockHandlers[i] = settings;
|
507
|
+
return i;
|
508
|
+
};
|
509
|
+
$.mockjaxClear = function(i) {
|
510
|
+
if ( arguments.length == 1 ) {
|
511
|
+
mockHandlers[i] = null;
|
512
|
+
} else {
|
513
|
+
mockHandlers = [];
|
514
|
+
}
|
515
|
+
};
|
516
|
+
$.mockjax.handler = function(i) {
|
517
|
+
if ( arguments.length == 1 ) {
|
518
|
+
return mockHandlers[i];
|
519
|
+
}
|
520
|
+
};
|
521
|
+
})(jQuery);
|
data/lib/mockjax.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'rspec'
|
3
|
+
|
4
|
+
require 'mockjax/version'
|
5
|
+
require 'mockjax/rails'
|
6
|
+
require 'mockjax/rack'
|
7
|
+
|
8
|
+
module Mockjax
|
9
|
+
class << self
|
10
|
+
def mock(options)
|
11
|
+
@mocks ||= []
|
12
|
+
@mocks << options
|
13
|
+
end
|
14
|
+
|
15
|
+
def mocks
|
16
|
+
@mocks || []
|
17
|
+
end
|
18
|
+
|
19
|
+
def cleanup
|
20
|
+
@mocks = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def path_to_js=(path)
|
24
|
+
@path_to_js = path
|
25
|
+
end
|
26
|
+
|
27
|
+
def path_to_js
|
28
|
+
@path_to_js || '/assets/jquery.mockjax.js'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# RSpec helper
|
33
|
+
module Helpers
|
34
|
+
def mockjax(*args)
|
35
|
+
Mockjax.mock(*args)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
RSpec.configure do |config|
|
41
|
+
config.include Mockjax::Helpers
|
42
|
+
|
43
|
+
config.after(:each) do
|
44
|
+
Mockjax.cleanup
|
45
|
+
end
|
46
|
+
end
|
data/lib/mockjax/rack.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
class Rack::Mockjax
|
4
|
+
def initialize(app, options={})
|
5
|
+
@app = app
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
@status, @headers, @body = @app.call(env)
|
11
|
+
@body = @body.to_a.join
|
12
|
+
insert!
|
13
|
+
[@status, @headers, [@body]]
|
14
|
+
end
|
15
|
+
|
16
|
+
def insert!
|
17
|
+
mocks = ''.tap do |m|
|
18
|
+
Mockjax.mocks.each { |mock| m << "$.mockjax(#{mock.to_json});\n" }
|
19
|
+
end
|
20
|
+
@body.gsub!(/(<\/head>)/, "<script src='#{Mockjax.path_to_js}' type='text/javascript'></script>\n<script>#{mocks}</script>\\1")
|
21
|
+
@headers['Content-Length'] = Rack::Utils.bytesize(@body).to_s
|
22
|
+
end
|
23
|
+
end
|
data/mockjax.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/mockjax/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Eric J. Holmes"]
|
6
|
+
gem.email = ["eric@ejholmes.net"]
|
7
|
+
gem.description = %q{Ruby gem for using jquery mockjax within rspec examples}
|
8
|
+
gem.summary = %q{Ruby gem for using jquery mockjax within rspec examples}
|
9
|
+
gem.homepage = "https://github.com/ejholmes/mockjax"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "mockjax"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Mockjax::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'rack'
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mockjax
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Eric J. Holmes
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-24 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rack
|
16
|
+
requirement: &70176437967960 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70176437967960
|
25
|
+
description: Ruby gem for using jquery mockjax within rspec examples
|
26
|
+
email:
|
27
|
+
- eric@ejholmes.net
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- LICENSE
|
35
|
+
- README.md
|
36
|
+
- Rakefile
|
37
|
+
- app/assets/javascripts/jquery.mockjax.js
|
38
|
+
- lib/mockjax.rb
|
39
|
+
- lib/mockjax/rack.rb
|
40
|
+
- lib/mockjax/rails.rb
|
41
|
+
- lib/mockjax/version.rb
|
42
|
+
- mockjax.gemspec
|
43
|
+
homepage: https://github.com/ejholmes/mockjax
|
44
|
+
licenses: []
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 1.8.11
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: Ruby gem for using jquery mockjax within rspec examples
|
67
|
+
test_files: []
|
68
|
+
has_rdoc:
|