@@ -39,30 +39,30 @@ describe("binding", () => {
3939
4040 afterEach ( ( ) => dealoc ( document . getElementById ( "app" ) ) ) ;
4141
42- it ( "BindUpdate " , ( ) => {
42+ it ( "should initialize a scope property with ng-init on a self-closing element " , ( ) => {
4343 $compile ( '<div ng-init="a=123"/>' ) ( $rootScope ) ;
4444 expect ( $rootScope . a ) . toBe ( 123 ) ;
4545 } ) ;
4646
47- it ( "ExecuteInitialization " , ( ) => {
47+ it ( "should execute ng-init on a standard opening element " , ( ) => {
4848 $compile ( '<div ng-init="a=123">' ) ( $rootScope ) ;
4949 expect ( $rootScope . a ) . toBe ( 123 ) ;
5050 } ) ;
5151
52- it ( "ExecuteInitializationStatements " , ( ) => {
52+ it ( "should execute multiple statements declared in ng-init " , ( ) => {
5353 $compile ( '<div ng-init="a=123;b=345">' ) ( $rootScope ) ;
5454 expect ( $rootScope . a ) . toBe ( 123 ) ;
5555 expect ( $rootScope . b ) . toBe ( 345 ) ;
5656 } ) ;
5757
58- it ( "ApplyTextBindings " , async ( ) => {
58+ it ( "should apply ng-bind text updates when the model changes " , async ( ) => {
5959 element = $compile ( '<div ng-bind="model.a">x</div>' ) ( $rootScope ) ;
6060 $rootScope . model = { a : 123 } ;
6161 await wait ( ) ;
6262 expect ( element . textContent ) . toBe ( "123" ) ;
6363 } ) ;
6464
65- it ( "InputTypeButtonActionExecutesInScope " , ( ) => {
65+ it ( "should execute an ng-click handler on an input button within the current scope " , ( ) => {
6666 let savedCalled = false ;
6767 element = $compile (
6868 '<input type="button" ng-click="person.save()" value="Apply">' ,
@@ -81,7 +81,7 @@ describe("binding", () => {
8181 expect ( savedCalled ) . toBe ( true ) ;
8282 } ) ;
8383
84- it ( "InputTypeButtonActionExecutesInScope2 " , ( ) => {
84+ it ( "should execute an ng-click handler on an input image element " , ( ) => {
8585 let log = "" ;
8686 element = $compile ( '<input type="image" ng-click="action()">' ) ( $rootScope ) ;
8787 $rootScope . action = function ( ) {
@@ -98,7 +98,7 @@ describe("binding", () => {
9898 expect ( log ) . toEqual ( "click;" ) ;
9999 } ) ;
100100
101- it ( "ButtonElementActionExecutesInScope " , ( ) => {
101+ it ( "should execute an ng-click handler on a button element within the current scope " , ( ) => {
102102 let savedCalled = false ;
103103 element = $compile ( '<button ng-click="person.save()">Apply</button>' ) (
104104 $rootScope ,
@@ -117,7 +117,7 @@ describe("binding", () => {
117117 expect ( savedCalled ) . toBe ( true ) ;
118118 } ) ;
119119
120- it ( "RepeaterUpdateBindings " , async ( ) => {
120+ it ( "should update ng-repeat bindings when items are added and removed " , async ( ) => {
121121 let elem = createElementFromHTML (
122122 "<ul>" + '<li ng-repeat="item in items" ng-bind="item.a"></li>' + "</ul>" ,
123123 ) ;
@@ -156,7 +156,79 @@ describe("binding", () => {
156156 elem . remove ( ) ;
157157 } ) ;
158158
159- it ( "RepeaterContentDoesNotBind" , async ( ) => {
159+ it ( "should update ng-repeat when proxied collection items are swapped directly" , async ( ) => {
160+ let elem = createElementFromHTML (
161+ "<ul>" + '<li ng-repeat="item in items" ng-bind="item.a"></li>' + "</ul>" ,
162+ ) ;
163+ document . getElementById ( "app" ) . insertAdjacentElement ( "afterend" , elem ) ;
164+ $injector = window . angular . bootstrap ( elem , [ "myModule" ] ) ;
165+ $rootScope = $injector . get ( "$rootScope" ) ;
166+
167+ $rootScope . items = [ { a : "A" } , { a : "B" } ] ;
168+ await wait ( ) ;
169+
170+ let lis = elem . querySelectorAll ( "li" ) ;
171+ const firstRow = lis [ 0 ] ;
172+ const secondRow = lis [ 1 ] ;
173+
174+ firstRow . setAttribute ( "mark" , "first" ) ;
175+ secondRow . setAttribute ( "mark" , "second" ) ;
176+
177+ const tmp = $rootScope . items [ 0 ] ;
178+
179+ $rootScope . items [ 0 ] = $rootScope . items [ 1 ] ;
180+ $rootScope . items [ 1 ] = tmp ;
181+ await wait ( ) ;
182+
183+ lis = elem . querySelectorAll ( "li" ) ;
184+ expect ( elem . outerHTML ) . toBe (
185+ "<ul><!---->" +
186+ '<li ng-repeat="item in items" ng-bind="item.a" mark="second">B</li>' +
187+ '<li ng-repeat="item in items" ng-bind="item.a" mark="first">A</li>' +
188+ "</ul>" ,
189+ ) ;
190+ expect ( lis [ 0 ] ) . toBe ( secondRow ) ;
191+ expect ( lis [ 1 ] ) . toBe ( firstRow ) ;
192+ elem . remove ( ) ;
193+ } ) ;
194+
195+ it ( "should keep nested child scopes alive when proxied collection items are swapped directly" , async ( ) => {
196+ let elem = createElementFromHTML (
197+ "<ul>" + '<li ng-repeat="item in items" ng-bind="item.a"></li>' + "</ul>" ,
198+ ) ;
199+ document . getElementById ( "app" ) . insertAdjacentElement ( "afterend" , elem ) ;
200+ $injector = window . angular . bootstrap ( elem , [ "myModule" ] ) ;
201+ $rootScope = $injector . get ( "$rootScope" ) ;
202+
203+ const nestedA = $rootScope . $new ( ) ;
204+ const nestedB = $rootScope . $new ( ) ;
205+ const destroyA = jasmine . createSpy ( "nestedA destroy" ) ;
206+ const destroyB = jasmine . createSpy ( "nestedB destroy" ) ;
207+
208+ nestedA . $on ( "$destroy" , destroyA ) ;
209+ nestedB . $on ( "$destroy" , destroyB ) ;
210+
211+ $rootScope . items = [
212+ { a : "A" , nested : nestedA } ,
213+ { a : "B" , nested : nestedB } ,
214+ ] ;
215+ await wait ( ) ;
216+
217+ const tmp = $rootScope . items [ 0 ] ;
218+
219+ $rootScope . items [ 0 ] = $rootScope . items [ 1 ] ;
220+ $rootScope . items [ 1 ] = tmp ;
221+ await wait ( ) ;
222+
223+ expect ( elem . textContent ) . toBe ( "BA" ) ;
224+ expect ( destroyA ) . not . toHaveBeenCalled ( ) ;
225+ expect ( destroyB ) . not . toHaveBeenCalled ( ) ;
226+ expect ( nestedA . $handler . _destroyed ) . toBeFalse ( ) ;
227+ expect ( nestedB . $handler . _destroyed ) . toBeFalse ( ) ;
228+ elem . remove ( ) ;
229+ } ) ;
230+
231+ it ( "should bind repeated content when the repeated collection becomes available" , async ( ) => {
160232 element = $compile (
161233 "<ul>" +
162234 '<LI ng-repeat="item in model.items"><span ng-bind="item.a"></span></li>' +
@@ -172,14 +244,14 @@ describe("binding", () => {
172244 ) ;
173245 } ) ;
174246
175- it ( "DoNotOverwriteCustomAction " , async function ( ) {
247+ it ( "should preserve a custom action attribute on a submit input " , async function ( ) {
176248 const html = await this . compileToHtml (
177249 '<input type="submit" value="Save" action="foo();">' ,
178250 ) ;
179251 expect ( html . indexOf ( 'action="foo();"' ) ) . toBeGreaterThan ( 0 ) ;
180252 } ) ;
181253
182- it ( "ItShouldRemoveExtraChildrenWhenIteratingOverHash " , async ( ) => {
254+ it ( "should remove extra repeated children when iterating over an object that shrinks " , async ( ) => {
183255 element = $compile ( '<div><div ng-repeat="i in items">{{i}}</div></div>' ) (
184256 $rootScope ,
185257 ) ;
@@ -197,7 +269,7 @@ describe("binding", () => {
197269 expect ( element . textContent ) . toEqual ( "" ) ;
198270 } ) ;
199271
200- it ( "IfAttrBindingThrowsErrorDecorateTheAttribute " , async ( ) => {
272+ it ( "should report interpolation errors from attribute bindings and recover afterward " , async ( ) => {
201273 $compile (
202274 '<div attr="before {{error.throw()}} after"></div>' ,
203275 null ,
@@ -222,7 +294,7 @@ describe("binding", () => {
222294 expect ( errors . length ) . toMatch ( "0" ) ;
223295 } ) ;
224296
225- it ( "NestedRepeater " , async ( ) => {
297+ it ( "should render nested ng-repeat blocks for nested collections " , async ( ) => {
226298 element = $compile (
227299 "<div>" +
228300 '<div ng-repeat="m in model" name="{{m.name}}">' +
@@ -252,7 +324,7 @@ describe("binding", () => {
252324 ) ;
253325 } ) ;
254326
255- it ( "HideBindingExpression " , async ( ) => {
327+ it ( "should toggle ng-hide from an expression result " , async ( ) => {
256328 element = $compile ( '<div ng-hide="hidden === 3"/>' ) ( $rootScope ) ;
257329
258330 $rootScope . hidden = 3 ;
@@ -265,7 +337,7 @@ describe("binding", () => {
265337 expect ( element . classList . contains ( "ng-hide" ) ) . toBe ( false ) ;
266338 } ) ;
267339
268- it ( "HideBinding " , async ( ) => {
340+ it ( "should apply ng-hide according to truthy and falsy values " , async ( ) => {
269341 element = $compile ( '<div ng-hide="hidden"/>' ) ( $rootScope ) ;
270342
271343 $rootScope . hidden = "true" ;
@@ -289,7 +361,7 @@ describe("binding", () => {
289361 expect ( element . classList . contains ( "ng-hide" ) ) . toBeFalse ( ) ;
290362 } ) ;
291363
292- it ( "ShowBinding " , async ( ) => {
364+ it ( "should apply ng-show according to truthy and falsy values " , async ( ) => {
293365 element = $compile ( '<div ng-show="show"/>' ) ( $rootScope ) ;
294366
295367 $rootScope . show = "true" ;
@@ -309,7 +381,7 @@ describe("binding", () => {
309381 expect ( element . classList . contains ( "ng-hide" ) ) . toBeTrue ( ) ;
310382 } ) ;
311383
312- it ( "BindClass " , async ( ) => {
384+ it ( "should apply ng-class values from strings and arrays " , async ( ) => {
313385 element = $compile ( '<div ng-class="clazz"/>' ) ( $rootScope ) ;
314386
315387 $rootScope . clazz = "testClass" ;
@@ -323,7 +395,7 @@ describe("binding", () => {
323395 expect ( element . classList . contains ( "b" ) ) . toBeTrue ( ) ;
324396 } ) ;
325397
326- it ( "BindClassEvenOdd " , async ( ) => {
398+ it ( "should apply ng-class-even and ng-class-odd inside ng-repeat " , async ( ) => {
327399 element = $compile (
328400 "<div>" +
329401 '<div ng-repeat="i in [0,1]" ng-class-even="\'e\'" ng-class-odd="\'o\'"></div>' +
@@ -338,7 +410,7 @@ describe("binding", () => {
338410 expect ( d2 . classList . contains ( "e" ) ) . toBeTruthy ( ) ;
339411 } ) ;
340412
341- it ( "BindStyle " , async ( ) => {
413+ it ( "should apply ng-style values from the evaluated style object " , async ( ) => {
342414 element = $compile ( '<div ng-style="style"/>' ) ( $rootScope ) ;
343415
344416 $rootScope . $eval ( 'style={height: "10px"}' ) ;
@@ -350,7 +422,7 @@ describe("binding", () => {
350422 await wait ( ) ;
351423 } ) ;
352424
353- it ( "ActionOnAHrefThrowsError " , async ( ) => {
425+ it ( "should report errors thrown from an ng-click handler on a link " , async ( ) => {
354426 const input = $compile ( '<a ng-click="action()">Add Phone</a>' ) ( $rootScope ) ;
355427 $rootScope . action = function ( ) {
356428 throw new Error ( "MyError" ) ;
@@ -367,7 +439,7 @@ describe("binding", () => {
367439 expect ( errors [ 0 ] ) . toMatch ( / M y E r r o r / ) ;
368440 } ) ;
369441
370- it ( "ShouldIgnoreVbNonBindable " , async ( ) => {
442+ it ( "should ignore bindings inside ng-non-bindable sections " , async ( ) => {
371443 element = $compile (
372444 "<div>{{a}}" +
373445 "<div ng-non-bindable>{{a}}</div>" +
@@ -380,15 +452,15 @@ describe("binding", () => {
380452 expect ( element . textContent ) . toBe ( "123{{a}}{{b}}{{c}}" ) ;
381453 } ) ;
382454
383- it ( "ShouldTemplateBindPreElements " , async ( ) => {
455+ it ( "should preserve and bind interpolation inside preformatted elements " , async ( ) => {
384456 element = $compile ( "<pre>Hello {{name}}!</pre>" ) ( $rootScope ) ;
385457 $rootScope . name = "World" ;
386458 await wait ( ) ;
387459
388460 expect ( element . outerHTML ) . toBe ( `<pre>Hello World!</pre>` ) ;
389461 } ) ;
390462
391- it ( "FillInOptionValueWhenMissing " , async ( ) => {
463+ it ( "should fill in option values when an option value attribute is missing " , async ( ) => {
392464 element = $compile (
393465 '<select ng-model="foo">' +
394466 '<option selected="true">{{a}}</option>' +
@@ -414,7 +486,7 @@ describe("binding", () => {
414486 expect ( optionC . textContent ) . toEqual ( "C" ) ;
415487 } ) ;
416488
417- it ( "ItShouldSelectTheCorrectRadioBox " , async ( ) => {
489+ it ( "should keep radio inputs synchronized with the bound model " , async ( ) => {
418490 const ELEMENT = document . getElementById ( "app" ) ;
419491 ELEMENT . innerHTML =
420492 "<div>" +
@@ -439,7 +511,7 @@ describe("binding", () => {
439511 expect ( $rootScope . sex ) . toBe ( "male" ) ;
440512 } ) ;
441513
442- it ( "ItShouldRepeatOnHashes " , async ( ) => {
514+ it ( "should repeat over object literals with ng-repeat " , async ( ) => {
443515 element = $compile (
444516 "<ul>" +
445517 '<li ng-repeat="(k,v) in {a:0,b:1}" ng-bind="k + v"></li>' +
@@ -454,7 +526,7 @@ describe("binding", () => {
454526 ) ;
455527 } ) ;
456528
457- it ( "ItShouldFireChangeListenersBeforeUpdate " , async ( ) => {
529+ it ( "should fire change listeners before the bound DOM is updated " , async ( ) => {
458530 element = $compile ( '<div ng-bind="name"></div>' ) ( $rootScope ) ;
459531 $rootScope . name = "" ;
460532 $rootScope . $watch ( "watched" , ( ) => {
@@ -466,7 +538,7 @@ describe("binding", () => {
466538 expect ( element . outerHTML ) . toBe ( '<div ng-bind="name">123</div>' ) ;
467539 } ) ;
468540
469- it ( "ItShouldHandleMultilineBindings " , async ( ) => {
541+ it ( "should evaluate multiline interpolation expressions " , async ( ) => {
470542 element = $compile ( "<div>{{\n 1 \n + \n 2 \n}}</div>" ) ( $rootScope ) ;
471543 await wait ( ) ;
472544 expect ( element . textContent ) . toBe ( "3" ) ;
0 commit comments