Skip to content

Commit 14c1fb8

Browse files
fix(ngMock/$httpBackend): fail if a url is provided but is undefined
While the `url` parameter is optional for `$httpBackend.when`, `$httpBackend.expect` and related shortcut methods, it should not have the value of `undefined` if it has been provided. This change ensures that an error is thrown in those cases. Closes angular#8442 Closes angular#8462 Closes angular#10934 BREAKING CHANGE It is no longer valid to explicitly pass `undefined` as the `url` argument to any of the `$httpBackend.when...()` and `$httpBackend.expect...()` methods. While this argument is optional, it must have a defined value if it is provided. Previously passing an explicit `undefined` value was ignored but this lead to invalid tests passing unexpectedly.
1 parent 470eb37 commit 14c1fb8

File tree

2 files changed

+140
-27
lines changed

2 files changed

+140
-27
lines changed

src/ngMock/angular-mocks.js

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,7 +1233,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
12331233
* Creates a new backend definition.
12341234
*
12351235
* @param {string} method HTTP method.
1236-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1236+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
12371237
* and returns true if the url matches the current definition.
12381238
* @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
12391239
* data string and returns true if the data is as expected.
@@ -1252,6 +1252,9 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
12521252
* `requestHandler` object for possible overrides.
12531253
*/
12541254
$httpBackend.when = function(method, url, data, headers) {
1255+
1256+
assertArgDefined(arguments, 1, 'url');
1257+
12551258
var definition = new MockHttpExpectation(method, url, data, headers),
12561259
chain = {
12571260
respond: function(status, data, headers, statusText) {
@@ -1279,7 +1282,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
12791282
* @description
12801283
* Creates a new backend definition for GET requests. For more info see `when()`.
12811284
*
1282-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1285+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
12831286
* and returns true if the url matches the current definition.
12841287
* @param {(Object|function(Object))=} headers HTTP headers.
12851288
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
@@ -1293,7 +1296,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
12931296
* @description
12941297
* Creates a new backend definition for HEAD requests. For more info see `when()`.
12951298
*
1296-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1299+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
12971300
* and returns true if the url matches the current definition.
12981301
* @param {(Object|function(Object))=} headers HTTP headers.
12991302
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
@@ -1307,7 +1310,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
13071310
* @description
13081311
* Creates a new backend definition for DELETE requests. For more info see `when()`.
13091312
*
1310-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1313+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
13111314
* and returns true if the url matches the current definition.
13121315
* @param {(Object|function(Object))=} headers HTTP headers.
13131316
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
@@ -1321,7 +1324,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
13211324
* @description
13221325
* Creates a new backend definition for POST requests. For more info see `when()`.
13231326
*
1324-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1327+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
13251328
* and returns true if the url matches the current definition.
13261329
* @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
13271330
* data string and returns true if the data is as expected.
@@ -1337,7 +1340,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
13371340
* @description
13381341
* Creates a new backend definition for PUT requests. For more info see `when()`.
13391342
*
1340-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1343+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
13411344
* and returns true if the url matches the current definition.
13421345
* @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
13431346
* data string and returns true if the data is as expected.
@@ -1353,7 +1356,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
13531356
* @description
13541357
* Creates a new backend definition for JSONP requests. For more info see `when()`.
13551358
*
1356-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1359+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
13571360
* and returns true if the url matches the current definition.
13581361
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
13591362
* request is handled. You can save this object for later use and invoke `respond` again in
@@ -1369,7 +1372,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
13691372
* Creates a new request expectation.
13701373
*
13711374
* @param {string} method HTTP method.
1372-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1375+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
13731376
* and returns true if the url matches the current definition.
13741377
* @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
13751378
* receives data string and returns true if the data is as expected, or Object if request body
@@ -1389,6 +1392,9 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
13891392
* `requestHandler` object for possible overrides.
13901393
*/
13911394
$httpBackend.expect = function(method, url, data, headers) {
1395+
1396+
assertArgDefined(arguments, 1, 'url');
1397+
13921398
var expectation = new MockHttpExpectation(method, url, data, headers),
13931399
chain = {
13941400
respond: function(status, data, headers, statusText) {
@@ -1408,7 +1414,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
14081414
* @description
14091415
* Creates a new request expectation for GET requests. For more info see `expect()`.
14101416
*
1411-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1417+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
14121418
* and returns true if the url matches the current definition.
14131419
* @param {Object=} headers HTTP headers.
14141420
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
@@ -1422,7 +1428,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
14221428
* @description
14231429
* Creates a new request expectation for HEAD requests. For more info see `expect()`.
14241430
*
1425-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1431+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
14261432
* and returns true if the url matches the current definition.
14271433
* @param {Object=} headers HTTP headers.
14281434
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
@@ -1436,7 +1442,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
14361442
* @description
14371443
* Creates a new request expectation for DELETE requests. For more info see `expect()`.
14381444
*
1439-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1445+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
14401446
* and returns true if the url matches the current definition.
14411447
* @param {Object=} headers HTTP headers.
14421448
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
@@ -1450,7 +1456,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
14501456
* @description
14511457
* Creates a new request expectation for POST requests. For more info see `expect()`.
14521458
*
1453-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1459+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
14541460
* and returns true if the url matches the current definition.
14551461
* @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
14561462
* receives data string and returns true if the data is as expected, or Object if request body
@@ -1467,7 +1473,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
14671473
* @description
14681474
* Creates a new request expectation for PUT requests. For more info see `expect()`.
14691475
*
1470-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1476+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
14711477
* and returns true if the url matches the current definition.
14721478
* @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
14731479
* receives data string and returns true if the data is as expected, or Object if request body
@@ -1484,7 +1490,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
14841490
* @description
14851491
* Creates a new request expectation for PATCH requests. For more info see `expect()`.
14861492
*
1487-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1493+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
14881494
* and returns true if the url matches the current definition.
14891495
* @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
14901496
* receives data string and returns true if the data is as expected, or Object if request body
@@ -1501,7 +1507,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
15011507
* @description
15021508
* Creates a new request expectation for JSONP requests. For more info see `expect()`.
15031509
*
1504-
* @param {string|RegExp|function(string)} url HTTP url or function that receives an url
1510+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives an url
15051511
* and returns true if the url matches the current definition.
15061512
* @returns {requestHandler} Returns an object with `respond` method that controls how a matched
15071513
* request is handled. You can save this object for later use and invoke `respond` again in
@@ -1595,22 +1601,38 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) {
15951601

15961602
return $httpBackend;
15971603

1598-
15991604
function createShortMethods(prefix) {
16001605
angular.forEach(['GET', 'DELETE', 'JSONP', 'HEAD'], function(method) {
1601-
$httpBackend[prefix + method] = function(url, headers) {
1602-
return $httpBackend[prefix](method, url, undefined, headers);
1603-
};
1606+
$httpBackend[prefix + method] = function(url, headers) {
1607+
assertArgDefined(arguments, 0, 'url');
1608+
1609+
// Change url to `null` if `undefined` to stop it throwing an exception further down
1610+
if (angular.isUndefined(url)) url = null;
1611+
1612+
return $httpBackend[prefix](method, url, undefined, headers);
1613+
};
16041614
});
16051615

16061616
angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
16071617
$httpBackend[prefix + method] = function(url, data, headers) {
1618+
assertArgDefined(arguments, 0, 'url');
1619+
1620+
// Change url to `null` if `undefined` to stop it throwing an exception further down
1621+
if (angular.isUndefined(url)) url = null;
1622+
16081623
return $httpBackend[prefix](method, url, data, headers);
16091624
};
16101625
});
16111626
}
16121627
}
16131628

1629+
function assertArgDefined(args, index, name) {
1630+
if (args.length > index && angular.isUndefined(args[index])) {
1631+
throw new Error("Undefined argument `" + name + "`; the argument is provided but not defined");
1632+
}
1633+
}
1634+
1635+
16141636
function MockHttpExpectation(method, url, data, headers) {
16151637

16161638
this.data = data;
@@ -1969,7 +1991,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
19691991
* Creates a new backend definition.
19701992
*
19711993
* @param {string} method HTTP method.
1972-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
1994+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
19731995
* and returns true if the url matches the current definition.
19741996
* @param {(string|RegExp)=} data HTTP request body.
19751997
* @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
@@ -1997,7 +2019,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
19972019
* @description
19982020
* Creates a new backend definition for GET requests. For more info see `when()`.
19992021
*
2000-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2022+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
20012023
* and returns true if the url matches the current definition.
20022024
* @param {(Object|function(Object))=} headers HTTP headers.
20032025
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
@@ -2012,7 +2034,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
20122034
* @description
20132035
* Creates a new backend definition for HEAD requests. For more info see `when()`.
20142036
*
2015-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2037+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
20162038
* and returns true if the url matches the current definition.
20172039
* @param {(Object|function(Object))=} headers HTTP headers.
20182040
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
@@ -2027,7 +2049,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
20272049
* @description
20282050
* Creates a new backend definition for DELETE requests. For more info see `when()`.
20292051
*
2030-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2052+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
20312053
* and returns true if the url matches the current definition.
20322054
* @param {(Object|function(Object))=} headers HTTP headers.
20332055
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
@@ -2042,7 +2064,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
20422064
* @description
20432065
* Creates a new backend definition for POST requests. For more info see `when()`.
20442066
*
2045-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2067+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
20462068
* and returns true if the url matches the current definition.
20472069
* @param {(string|RegExp)=} data HTTP request body.
20482070
* @param {(Object|function(Object))=} headers HTTP headers.
@@ -2058,7 +2080,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
20582080
* @description
20592081
* Creates a new backend definition for PUT requests. For more info see `when()`.
20602082
*
2061-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2083+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
20622084
* and returns true if the url matches the current definition.
20632085
* @param {(string|RegExp)=} data HTTP request body.
20642086
* @param {(Object|function(Object))=} headers HTTP headers.
@@ -2074,7 +2096,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
20742096
* @description
20752097
* Creates a new backend definition for PATCH requests. For more info see `when()`.
20762098
*
2077-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2099+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
20782100
* and returns true if the url matches the current definition.
20792101
* @param {(string|RegExp)=} data HTTP request body.
20802102
* @param {(Object|function(Object))=} headers HTTP headers.
@@ -2090,7 +2112,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
20902112
* @description
20912113
* Creates a new backend definition for JSONP requests. For more info see `when()`.
20922114
*
2093-
* @param {string|RegExp|function(string)} url HTTP url or function that receives a url
2115+
* @param {string|RegExp|function(string)=} url HTTP url or function that receives a url
20942116
* and returns true if the url matches the current definition.
20952117
* @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
20962118
* control how a matched request is handled. You can save this object for later use and invoke

test/ngMock/angular-mocksSpec.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,97 @@ describe('ngMock', function() {
10821082
});
10831083

10841084

1085+
it('should not error if the url is not provided', function() {
1086+
expect(function() {
1087+
hb.when('GET');
1088+
1089+
hb.whenGET();
1090+
hb.whenPOST();
1091+
hb.whenPUT();
1092+
hb.whenPATCH();
1093+
hb.whenDELETE();
1094+
hb.whenHEAD();
1095+
1096+
hb.expect('GET');
1097+
1098+
hb.expectGET();
1099+
hb.expectPOST();
1100+
hb.expectPUT();
1101+
hb.expectPATCH();
1102+
hb.expectDELETE();
1103+
hb.expectHEAD();
1104+
}).not.toThrow();
1105+
});
1106+
1107+
1108+
it('should error if the url is undefined', function() {
1109+
expect(function() {
1110+
hb.when('GET', undefined);
1111+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1112+
1113+
expect(function() {
1114+
hb.whenGET(undefined);
1115+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1116+
1117+
expect(function() {
1118+
hb.whenDELETE(undefined);
1119+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1120+
1121+
expect(function() {
1122+
hb.whenJSONP(undefined);
1123+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1124+
1125+
expect(function() {
1126+
hb.whenHEAD(undefined);
1127+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1128+
1129+
expect(function() {
1130+
hb.whenPATCH(undefined);
1131+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1132+
1133+
expect(function() {
1134+
hb.whenPOST(undefined);
1135+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1136+
1137+
expect(function() {
1138+
hb.whenPUT(undefined);
1139+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1140+
1141+
1142+
expect(function() {
1143+
hb.expect('GET', undefined);
1144+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1145+
1146+
expect(function() {
1147+
hb.expectGET(undefined);
1148+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1149+
1150+
expect(function() {
1151+
hb.expectDELETE(undefined);
1152+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1153+
1154+
expect(function() {
1155+
hb.expectJSONP(undefined);
1156+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1157+
1158+
expect(function() {
1159+
hb.expectHEAD(undefined);
1160+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1161+
1162+
expect(function() {
1163+
hb.expectPATCH(undefined);
1164+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1165+
1166+
expect(function() {
1167+
hb.expectPOST(undefined);
1168+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1169+
1170+
expect(function() {
1171+
hb.expectPUT(undefined);
1172+
}).toThrow('Undefined argument `url`; the argument is provided but not defined');
1173+
});
1174+
1175+
10851176
it('should preserve the order of requests', function() {
10861177
hb.when('GET', '/url1').respond(200, 'first');
10871178
hb.when('GET', '/url2').respond(201, 'second');

0 commit comments

Comments
 (0)