Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 75c83ff

Browse files
gkalpakpetebacondarwin
authored andcommitted
fix(ngMock/$controller): respect $compileProvider.preAssignBindingsEnabled()
Fixes #15387 Closes #15395
1 parent e36dbab commit 75c83ff

File tree

2 files changed

+158
-54
lines changed

2 files changed

+158
-54
lines changed

src/ngMock/angular-mocks.js

+42-24
Original file line numberDiff line numberDiff line change
@@ -2159,6 +2159,10 @@ angular.mock.$RootElementProvider = function() {
21592159
* A decorator for {@link ng.$controller} with additional `bindings` parameter, useful when testing
21602160
* controllers of directives that use {@link $compile#-bindtocontroller- `bindToController`}.
21612161
*
2162+
* Depending on the value of
2163+
* {@link ng.$compileProvider#preAssignBindingsEnabled `preAssignBindingsEnabled()`}, the properties
2164+
* will be bound before or after invoking the constructor.
2165+
*
21622166
*
21632167
* ## Example
21642168
*
@@ -2177,18 +2181,24 @@ angular.mock.$RootElementProvider = function() {
21772181
* // Controller definition ...
21782182
*
21792183
* myMod.controller('MyDirectiveController', ['$log', function($log) {
2180-
* $log.info(this.name);
2184+
* this.log = function() {
2185+
* $log.info(this.name);
2186+
* };
21812187
* }]);
21822188
*
21832189
*
21842190
* // In a test ...
21852191
*
21862192
* describe('myDirectiveController', function() {
2187-
* it('should write the bound name to the log', inject(function($controller, $log) {
2188-
* var ctrl = $controller('MyDirectiveController', { /* no locals */ }, { name: 'Clark Kent' });
2189-
* expect(ctrl.name).toEqual('Clark Kent');
2190-
* expect($log.info.logs).toEqual(['Clark Kent']);
2191-
* }));
2193+
* describe('log()', function() {
2194+
* it('should write the bound name to the log', inject(function($controller, $log) {
2195+
* var ctrl = $controller('MyDirectiveController', { /* no locals */ }, { name: 'Clark Kent' });
2196+
* ctrl.log();
2197+
*
2198+
* expect(ctrl.name).toEqual('Clark Kent');
2199+
* expect($log.info.logs).toEqual(['Clark Kent']);
2200+
* }));
2201+
* });
21922202
* });
21932203
*
21942204
* ```
@@ -2207,26 +2217,34 @@ angular.mock.$RootElementProvider = function() {
22072217
* to work correctly.
22082218
*
22092219
* @param {Object} locals Injection locals for Controller.
2210-
* @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
2211-
* to simulate the `bindToController` feature and simplify certain kinds of tests.
2220+
* @param {Object=} bindings Properties to add to the controller instance. This is used to simulate
2221+
* the `bindToController` feature and simplify certain kinds of tests.
22122222
* @return {Object} Instance of given controller.
22132223
*/
2214-
angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
2215-
return function(expression, locals, later, ident) {
2216-
if (later && typeof later === 'object') {
2217-
var instantiate = $delegate(expression, locals, true, ident);
2218-
angular.extend(instantiate.instance, later);
2219-
2220-
var instance = instantiate();
2221-
if (instance !== instantiate.instance) {
2222-
angular.extend(instance, later);
2224+
function createControllerDecorator(compileProvider) {
2225+
angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
2226+
return function(expression, locals, later, ident) {
2227+
if (later && typeof later === 'object') {
2228+
var preAssignBindingsEnabled = compileProvider.preAssignBindingsEnabled();
2229+
2230+
var instantiate = $delegate(expression, locals, true, ident);
2231+
if (preAssignBindingsEnabled) {
2232+
angular.extend(instantiate.instance, later);
2233+
}
2234+
2235+
var instance = instantiate();
2236+
if (!preAssignBindingsEnabled || instance !== instantiate.instance) {
2237+
angular.extend(instance, later);
2238+
}
2239+
2240+
return instance;
22232241
}
2242+
return $delegate(expression, locals, later, ident);
2243+
};
2244+
}];
22242245

2225-
return instance;
2226-
}
2227-
return $delegate(expression, locals, later, ident);
2228-
};
2229-
}];
2246+
return angular.mock.$ControllerDecorator;
2247+
}
22302248

22312249
/**
22322250
* @ngdoc service
@@ -2335,11 +2353,11 @@ angular.module('ngMock', ['ng']).provider({
23352353
$httpBackend: angular.mock.$HttpBackendProvider,
23362354
$rootElement: angular.mock.$RootElementProvider,
23372355
$componentController: angular.mock.$ComponentControllerProvider
2338-
}).config(['$provide', function($provide) {
2356+
}).config(['$provide', '$compileProvider', function($provide, $compileProvider) {
23392357
$provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
23402358
$provide.decorator('$$rAF', angular.mock.$RAFDecorator);
23412359
$provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
2342-
$provide.decorator('$controller', angular.mock.$ControllerDecorator);
2360+
$provide.decorator('$controller', createControllerDecorator($compileProvider));
23432361
}]);
23442362

23452363
/**

test/ngMock/angular-mocksSpec.js

+116-30
Original file line numberDiff line numberDiff line change
@@ -1947,27 +1947,15 @@ describe('ngMock', function() {
19471947

19481948

19491949
describe('$controllerDecorator', function() {
1950-
it('should support creating controller with bindings', function() {
1951-
var called = false;
1952-
var data = [
1953-
{ name: 'derp1', id: 0 },
1954-
{ name: 'testname', id: 1 },
1955-
{ name: 'flurp', id: 2 }
1956-
];
1957-
module(function($controllerProvider) {
1958-
$controllerProvider.register('testCtrl', function() {
1959-
called = true;
1960-
expect(this.data).toBe(data);
1961-
});
1962-
});
1963-
inject(function($controller, $rootScope) {
1964-
$controller('testCtrl', { scope: $rootScope }, { data: data });
1965-
expect(called).toBe(true);
1966-
});
1967-
});
19681950

1969-
it('should support assigning bindings when a value is returned from the constructor',
1970-
function() {
1951+
describe('with `preAssignBindingsEnabled(true)`', function() {
1952+
1953+
beforeEach(module(function($compileProvider) {
1954+
$compileProvider.preAssignBindingsEnabled(true);
1955+
}));
1956+
1957+
1958+
it('should support creating controller with bindings', function() {
19711959
var called = false;
19721960
var data = [
19731961
{ name: 'derp1', id: 0 },
@@ -1976,40 +1964,138 @@ describe('ngMock', function() {
19761964
];
19771965
module(function($controllerProvider) {
19781966
$controllerProvider.register('testCtrl', function() {
1979-
called = true;
19801967
expect(this.data).toBe(data);
1981-
1982-
return {};
1968+
called = true;
19831969
});
19841970
});
19851971
inject(function($controller, $rootScope) {
19861972
var ctrl = $controller('testCtrl', { scope: $rootScope }, { data: data });
19871973
expect(ctrl.data).toBe(data);
19881974
expect(called).toBe(true);
19891975
});
1976+
});
1977+
1978+
1979+
it('should support assigning bindings when a value is returned from the constructor',
1980+
function() {
1981+
var called = false;
1982+
var data = [
1983+
{ name: 'derp1', id: 0 },
1984+
{ name: 'testname', id: 1 },
1985+
{ name: 'flurp', id: 2 }
1986+
];
1987+
module(function($controllerProvider) {
1988+
$controllerProvider.register('testCtrl', function() {
1989+
expect(this.data).toBe(data);
1990+
called = true;
1991+
return {};
1992+
});
1993+
});
1994+
inject(function($controller, $rootScope) {
1995+
var ctrl = $controller('testCtrl', { scope: $rootScope }, { data: data });
1996+
expect(ctrl.data).toBe(data);
1997+
expect(called).toBe(true);
1998+
});
1999+
}
2000+
);
2001+
2002+
2003+
if (/chrome/.test(window.navigator.userAgent)) {
2004+
it('should support assigning bindings to class-based controller', function() {
2005+
var called = false;
2006+
var data = [
2007+
{ name: 'derp1', id: 0 },
2008+
{ name: 'testname', id: 1 },
2009+
{ name: 'flurp', id: 2 }
2010+
];
2011+
module(function($controllerProvider) {
2012+
// eslint-disable-next-line no-eval
2013+
var TestCtrl = eval('(class { constructor() { called = true; } })');
2014+
$controllerProvider.register('testCtrl', TestCtrl);
2015+
});
2016+
inject(function($controller, $rootScope) {
2017+
var ctrl = $controller('testCtrl', { scope: $rootScope }, { data: data });
2018+
expect(ctrl.data).toBe(data);
2019+
expect(called).toBe(true);
2020+
});
2021+
});
19902022
}
1991-
);
2023+
});
2024+
19922025

1993-
if (/chrome/.test(window.navigator.userAgent)) {
1994-
it('should support assigning bindings to class-based controller', function() {
2026+
describe('with `preAssignBindingsEnabled(false)`', function() {
2027+
2028+
beforeEach(module(function($compileProvider) {
2029+
$compileProvider.preAssignBindingsEnabled(false);
2030+
}));
2031+
2032+
2033+
it('should support creating controller with bindings', function() {
19952034
var called = false;
19962035
var data = [
19972036
{ name: 'derp1', id: 0 },
19982037
{ name: 'testname', id: 1 },
19992038
{ name: 'flurp', id: 2 }
20002039
];
20012040
module(function($controllerProvider) {
2002-
// eslint-disable-next-line no-eval
2003-
var TestCtrl = eval('(class { constructor() { called = true; } })');
2004-
$controllerProvider.register('testCtrl', TestCtrl);
2041+
$controllerProvider.register('testCtrl', function() {
2042+
expect(this.data).toBeUndefined();
2043+
called = true;
2044+
});
20052045
});
20062046
inject(function($controller, $rootScope) {
20072047
var ctrl = $controller('testCtrl', { scope: $rootScope }, { data: data });
20082048
expect(ctrl.data).toBe(data);
20092049
expect(called).toBe(true);
20102050
});
20112051
});
2012-
}
2052+
2053+
2054+
it('should support assigning bindings when a value is returned from the constructor',
2055+
function() {
2056+
var called = false;
2057+
var data = [
2058+
{ name: 'derp1', id: 0 },
2059+
{ name: 'testname', id: 1 },
2060+
{ name: 'flurp', id: 2 }
2061+
];
2062+
module(function($controllerProvider) {
2063+
$controllerProvider.register('testCtrl', function() {
2064+
expect(this.data).toBeUndefined();
2065+
called = true;
2066+
return {};
2067+
});
2068+
});
2069+
inject(function($controller, $rootScope) {
2070+
var ctrl = $controller('testCtrl', { scope: $rootScope }, { data: data });
2071+
expect(ctrl.data).toBe(data);
2072+
expect(called).toBe(true);
2073+
});
2074+
}
2075+
);
2076+
2077+
2078+
if (/chrome/.test(window.navigator.userAgent)) {
2079+
it('should support assigning bindings to class-based controller', function() {
2080+
var called = false;
2081+
var data = [
2082+
{ name: 'derp1', id: 0 },
2083+
{ name: 'testname', id: 1 },
2084+
{ name: 'flurp', id: 2 }
2085+
];
2086+
module(function($controllerProvider) {
2087+
// eslint-disable-next-line no-eval
2088+
var TestCtrl = eval('(class { constructor() { called = true; } })');
2089+
$controllerProvider.register('testCtrl', TestCtrl);
2090+
});
2091+
inject(function($controller, $rootScope) {
2092+
var ctrl = $controller('testCtrl', { scope: $rootScope }, { data: data });
2093+
expect(ctrl.data).toBe(data);
2094+
expect(called).toBe(true);
2095+
});
2096+
});
2097+
}
2098+
});
20132099
});
20142100

20152101

0 commit comments

Comments
 (0)