Skip to content

Commit d2643b7

Browse files
committed
chore(release): release v0.2.0. See CHANGELOG.md
1 parent 38d7b4c commit d2643b7

File tree

5 files changed

+151
-68
lines changed

5 files changed

+151
-68
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
<a name="0.2.0"></a>
2+
# 0.2.0 (2015-08-09)
3+
4+
5+
### Bug Fixes
6+
7+
* **demo:** simple demo was outdated ([96b0196](https://github.com/seriema/angular-apimock/commit/96b0196))
8+
* **grunt:** grunt-conventional-changelog 2.0 changed name ([b21b909](https://github.com/seriema/angular-apimock/commit/b21b909))
9+
* **tests:** switch back to Jasmine for IE8 support ([6338b69](https://github.com/seriema/angular-apimock/commit/6338b69))
10+
11+
### Features
12+
13+
* **apimock:** add network latency simulation ([2783f10](https://github.com/seriema/angular-apimock/commit/2783f10)), closes [#20](https://github.com/seriema/angular-apimock/issues/20)
14+
* **delay:** add network latency simulation ([8b996d3](https://github.com/seriema/angular-apimock/commit/8b996d3)), closes [#20](https://github.com/seriema/angular-apimock/issues/20)
15+
* **queryParams:** add query param functionality ([1e779c3](https://github.com/seriema/angular-apimock/commit/1e779c3)), closes [#23](https://github.com/seriema/angular-apimock/issues/23)
16+
* **queryParams:** ignore nested objects and arrays on $http config.param ([0e3138a](https://github.com/seriema/angular-apimock/commit/0e3138a))
17+
* **queryParams:** lowercase query params ([2aeb262](https://github.com/seriema/angular-apimock/commit/2aeb262))
18+
* **queryParams:** support nested objects and arrays in $http config ([4147b33](https://github.com/seriema/angular-apimock/commit/4147b33))
19+
* **readme:** add coverage status badge ([61dc226](https://github.com/seriema/angular-apimock/commit/61dc226))
20+
* **travis:** add Sauce Labs testing to CI ([3375513](https://github.com/seriema/angular-apimock/commit/3375513))
21+
22+
23+
124
<a name="0.1.8"></a>
225
### 0.1.8 (2015-03-22)
326

bower.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angular-apimock",
3-
"version": "0.1.8",
3+
"version": "0.2.0",
44
"main": "dist/angular-apimock.min.js",
55
"appPath": "app",
66
"ignore": [

dist/angular-apimock.js

Lines changed: 124 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*! Angular API Mock v0.1.8
1+
/*! Angular API Mock v0.2.0
22
* Licensed with MIT
33
* Made with ♥ from Seriema + Redhorn */
44
/* Create the main module, `apiMock`. It's the one that needs to be included in
@@ -49,57 +49,102 @@ angular.module('apiMock', [])
4949
mockDataPath: '/mock_data',
5050
apiPath: '/api',
5151
disable: false,
52-
stripQueries: true
52+
stripQueries: true,
53+
delay: 0,
5354
};
5455
var fallbacks = [];
5556

5657
// Helper methods
5758
//
5859

59-
function serialize(obj) {
60-
var str = [];
60+
// TODO: IE8: remove when we drop IE8/Angular 1.2 support.
61+
// Object.keys isn't supported in IE8. Which we need to support as long as we support Angular 1.2.
62+
// This isn't a complete polyfill! It's just enough for what we need (and we don't need to bloat).
63+
function objectKeys(object) {
64+
var keys = [];
6165

62-
obj = sortObjPropertiesAlpha(obj);
63-
angular.forEach(obj, function(value, p) {
64-
var encodedValue = encodeURIComponent(value);
65-
str.push(encodeURIComponent(p) + '=' + encodedValue);
66+
angular.forEach(object, function (value, key) {
67+
keys.push(key);
6668
});
67-
return str.join('&');
68-
}
6969

70-
function queryStringToJSON(url) {
71-
var paramString = url.split('?')[1];
72-
var paramArray = [];
70+
return keys;
71+
}
7372

74-
if (paramString) {
75-
paramArray = paramString.split('&');
73+
// Taken from Angular 1.4.x: https://github.com/angular/angular.js/blob/f13852c179ffd9ec18b7a94df27dec39eb5f19fc/src/Angular.js#L296
74+
function forEachSorted(obj, iterator, context) {
75+
var keys = objectKeys(obj).sort();
76+
for (var i = 0; i < keys.length; i++) {
77+
iterator.call(context, obj[keys[i]], keys[i]);
7678
}
79+
return keys;
80+
}
7781

78-
var result = {};
79-
paramArray.forEach(function(param) {
80-
param = param.split('=');
81-
result[param[0]] = decodeURIComponent(param[1] || '');
82-
});
82+
// Taken from Angular 1.4.x: https://github.com/angular/angular.js/blob/929ec6ba5a60e926654583033a90aebe716123c0/src/ng/http.js#L18
83+
function serializeValue(v) {
84+
if (angular.isObject(v)) {
85+
return angular.isDate(v) ? v.toISOString() : angular.toJson(v);
86+
}
87+
return v;
88+
}
8389

84-
return JSON.parse(JSON.stringify(result));
90+
// Taken from Angular 1.4.x: https://github.com/angular/angular.js/blob/720012eab6fef5e075a1d6876dd2e508c8e95b73/src/ngResource/resource.js#L405
91+
function encodeUriQuery(val, pctEncodeSpaces) {
92+
return encodeURIComponent(val).
93+
replace(/%40/gi, '@').
94+
replace(/%3A/gi, ':').
95+
replace(/%24/g, '$').
96+
replace(/%2C/gi, ',').
97+
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
8598
}
8699

87-
function sortObjPropertiesAlpha(obj) {
88-
var sorted = {},
89-
key, a = [];
100+
// TODO: replace with a $httpParamSerializerJQLikeProvider() call when we require Angular 1.4 (i.e. when we drop 1.2 and 1.3).
101+
// Taken from Angular 1.4.x: https://github.com/angular/angular.js/blob/929ec6ba5a60e926654583033a90aebe716123c0/src/ng/http.js#L108
102+
function jQueryLikeParamSerializer(params) {
103+
if (!params) {
104+
return '';
105+
}
106+
107+
var parts = [];
108+
109+
function serialize(toSerialize, prefix, topLevel) {
110+
if (toSerialize === null || angular.isUndefined(toSerialize)) {
111+
return;
112+
}
90113

91-
for (key in obj) {
92-
if (obj.hasOwnProperty(key)) {
93-
a.push(key);
114+
if (angular.isArray(toSerialize)) {
115+
angular.forEach(toSerialize, function(value, index) {
116+
serialize(value, prefix + '[' + (angular.isObject(value) ? index : '') + ']');
117+
});
118+
} else if (angular.isObject(toSerialize) && !angular.isDate(toSerialize)) {
119+
forEachSorted(toSerialize, function(value, key) {
120+
serialize(value, prefix +
121+
(topLevel ? '' : '[') +
122+
key +
123+
(topLevel ? '' : ']'));
124+
});
125+
} else {
126+
parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
94127
}
95128
}
96129

97-
a.sort();
130+
serialize(params, '', true);
131+
return parts.join('&');
132+
}
98133

99-
for (key = 0; key < a.length; key++) {
100-
sorted[a[key]] = obj[a[key]];
134+
function queryStringToObject(paramString) {
135+
if (!paramString) {
136+
return {};
101137
}
102-
return sorted;
138+
139+
var paramArray = paramString.split('&');
140+
141+
var result = {};
142+
angular.forEach(paramArray, function(param) {
143+
param = param.split('=');
144+
result[param[0]] = param[1] || '';
145+
});
146+
147+
return result;
103148
}
104149

105150
function detectParameter(keys) {
@@ -195,43 +240,33 @@ angular.module('apiMock', [])
195240
}
196241

197242
function reroute(req) {
198-
var regex;
199243
if (!isApiPath(req.url)) {
200244
return req;
201245
}
202246

203247
// replace apiPath with mockDataPath.
204248
var oldPath = req.url;
205-
var newPath = req.url.substring(config.apiPath.length);
206-
newPath = config.mockDataPath + newPath;
207-
208-
if (config.stripQueries) {
209-
// strip query strings (like ?search=banana).
210-
regex = /[a-zA-z0-9/.\-]*/;
211-
newPath = regex.exec(newPath)[0];
212-
} else {
213-
var queryParamsFromUrl = queryStringToJSON(newPath);
214-
//if req.params is an object leave it as is but if it isn't then
215-
//normalize it to an empty object so we can cleanly merge it with queryParamsFromUrl
216-
req.params = typeof req.params === 'object' ? req.params : {};
217-
218-
// strip query strings (like ?search=banana).
219-
regex = /[a-zA-z0-9/.\-]*/;
220-
newPath = regex.exec(newPath)[0];
249+
var redirectedPath = req.url.replace(config.apiPath, config.mockDataPath);
250+
251+
var split = redirectedPath.split('?');
252+
var newPath = split[0];
253+
var queries = split[1] || '';
221254

255+
// query strings are stripped by default (like ?search=banana).
256+
if (!config.stripQueries) {
222257
//test if we have query params
223258
//if we do merge them on to the params object
224-
if (typeof queryParamsFromUrl === 'object') {
225-
req.params = angular.extend(req.params, queryParamsFromUrl);
226-
}
259+
var queryParamsFromUrl = queryStringToObject(queries);
260+
var params = angular.extend(req.params || {}, queryParamsFromUrl);
261+
227262
//test if there is already a trailing /
228-
if (newPath.substring(newPath.length-1) !== '/') {
229-
newPath = newPath + '/';
263+
if (newPath[newPath.length-1] !== '/') {
264+
newPath += '/';
230265
}
266+
231267
//serialize the param object to convert to string
232268
//and concatenate to the newPath
233-
newPath = newPath + serialize(req.params);
234-
269+
newPath += angular.lowercase(jQueryLikeParamSerializer(params));
235270
}
236271

237272
//Kill the params property so they aren't added back on to the end of the url
@@ -265,6 +300,10 @@ angular.module('apiMock', [])
265300
return fallbacks.length;
266301
};
267302

303+
p.getDelay = function () {
304+
return config.delay;
305+
};
306+
268307
p.onRequest = function (req) {
269308
if (config.disable) {
270309
return req;
@@ -327,7 +366,7 @@ angular.module('apiMock', [])
327366
}];
328367
})
329368

330-
.service('httpInterceptor', ["$injector", "$q", "apiMock", function($injector, $q, apiMock) {
369+
.service('httpInterceptor', ["$injector", "$q", "$timeout", "apiMock", function($injector, $q, $timeout, apiMock) {
331370
/* The main service. Is jacked in as a interceptor on `$http` so it gets called
332371
* on every http call. This allows us to do our magic. It uses the provider
333372
* `apiMock` to determine if a mock should be done, then do the actual mocking.
@@ -340,18 +379,39 @@ angular.module('apiMock', [])
340379
};
341380

342381
this.response = function (res) {
343-
res = apiMock.onResponse(res);
382+
var deferred = $q.defer();
344383

345-
return res || $q.when(res);
384+
$timeout(
385+
function() {
386+
deferred.resolve( apiMock.onResponse(res) ); // TODO: Apparently, no tests break regardless what this resolves to. Fix the tests!
387+
},
388+
apiMock.getDelay(),
389+
true // Trigger a $digest.
390+
);
391+
392+
return deferred.promise;
346393
};
347394

348395
this.responseError = function (rej) {
349-
var recover = apiMock.recover(rej);
350-
if (recover) {
351-
var $http = $injector.get('$http');
352-
return $http(recover);
353-
}
396+
var deferred = $q.defer();
397+
398+
$timeout(
399+
function () {
400+
var recover = apiMock.recover(rej);
401+
402+
if (recover) {
403+
var $http = $injector.get('$http');
404+
$http(recover).then(function (data) {
405+
deferred.resolve(data);
406+
});
407+
} else {
408+
deferred.reject( rej );
409+
}
410+
},
411+
apiMock.getDelay(),
412+
true // Trigger a $digest.
413+
);
354414

355-
return $q.reject(rej);
415+
return deferred.promise;
356416
};
357417
}]);

dist/angular-apimock.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angular-apiMock",
3-
"version": "0.1.8",
3+
"version": "0.2.0",
44
"author": "John-Philip Johansson <seriema@gmail.com> (http://johansson.jp/)",
55
"homepage": "http://johansson.jp/angular-apimock/",
66
"bugs": "https://github.com/seriema/angular-apimock/issues",

0 commit comments

Comments
 (0)