@angular-wave/angular.ts 0.4.4 → 0.4.6
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.
- package/Makefile +1 -0
- package/dist/angular-ts.esm.js +2 -2
- package/dist/angular-ts.umd.js +2 -12
- package/index.html +3 -74
- package/package.json +1 -1
- package/src/angular.spec.js +5 -0
- package/src/animations/animate-css.js +13 -5
- package/src/animations/animate-queue.js +21 -22
- package/src/animations/animate-runner.js +8 -4
- package/src/animations/animate.md +1 -1
- package/src/animations/animate.spec.js +21 -0
- package/src/animations/animation.js +1 -1
- package/src/binding.spec.js +1 -0
- package/src/core/compile/compile.js +25 -27
- package/src/core/compile/compile.spec.js +266 -17
- package/src/core/controller/controller.js +0 -2
- package/src/core/di/injector.md +1 -1
- package/src/core/di/injector.spec.js +2 -0
- package/src/core/di/internal-injector.js +1 -2
- package/src/core/interpolate/interpolate.js +12 -28
- package/src/core/interpolate/interpolate.spec.js +16 -70
- package/src/core/interval/interval-factory.js +50 -0
- package/src/core/interval/interval.html +18 -0
- package/src/core/interval/interval.js +77 -0
- package/src/core/interval/interval.md +123 -0
- package/src/core/interval/interval.spec.js +280 -0
- package/src/core/interval/interval.test.js +1 -1
- package/src/core/location/location.js +53 -59
- package/src/core/location/location.spec.js +27 -27
- package/src/core/on.spec.js +7 -0
- package/src/core/parse/interpreter.js +7 -10
- package/src/core/parse/parse.js +5 -26
- package/src/core/parse/parse.spec.js +91 -95
- package/src/core/prop.spec.js +60 -4
- package/src/core/q/q.html +18 -0
- package/src/core/q/q.js +472 -0
- package/src/core/q/q.md +211 -0
- package/src/core/q/q.spec.js +2748 -0
- package/src/core/q/q.test.js +12 -0
- package/src/core/sce/sce.spec.js +8 -0
- package/src/core/{model/model.html → scope/scope.html} +1 -1
- package/src/core/scope/scope.js +16 -15
- package/src/core/scope/scope.spec.js +1959 -24
- package/src/core/scope/scope.test.js +12 -0
- package/src/core/timeout/timeout.html +18 -0
- package/src/core/timeout/timeout.js +109 -0
- package/src/core/timeout/timeout.spec.js +354 -0
- package/src/core/timeout/timout.test.js +12 -0
- package/src/core/url-utils/url-utils.spec.js +1 -1
- package/src/directive/aria/aria.js +6 -3
- package/src/directive/aria/aria.spec.js +87 -0
- package/src/directive/attrs/attrs.spec.js +5 -0
- package/src/directive/attrs/boolean.spec.js +15 -0
- package/src/directive/attrs/element-style.spec.js +8 -0
- package/src/directive/attrs/src.spec.js +7 -0
- package/src/directive/bind/bind.spec.js +33 -0
- package/src/directive/bind/bing-html.spec.js +3 -0
- package/src/directive/class/class.js +3 -3
- package/src/directive/class/class.spec.js +75 -9
- package/src/directive/controller/controller.spec.js +13 -0
- package/src/directive/events/click.spec.js +3 -0
- package/src/directive/events/event.spec.js +6 -0
- package/src/directive/events/events.html +1 -0
- package/src/directive/form/form.js +3 -2
- package/src/directive/form/form.spec.js +65 -0
- package/src/directive/if/if.spec.js +4 -0
- package/src/directive/include/include.spec.js +59 -8
- package/src/directive/init/init.js +2 -6
- package/src/directive/init/init.spec.js +2 -0
- package/src/directive/input/input.spec.js +136 -0
- package/src/directive/messages/messages.spec.js +35 -4
- package/src/directive/model/model.js +25 -18
- package/src/directive/model/model.spec.js +49 -2
- package/src/directive/model-options/model-options.spec.js +6 -0
- package/src/directive/non-bindable/non-bindable.spec.js +1 -0
- package/src/directive/observe/observe.js +5 -1
- package/src/directive/observe/observe.spec.js +22 -0
- package/src/directive/observe/test.html +3 -11
- package/src/directive/options/options.spec.js +34 -0
- package/src/directive/ref/href.spec.js +15 -0
- package/src/directive/repeat/repeat.spec.js +135 -8
- package/src/directive/script/script.spec.js +2 -0
- package/src/directive/select/select.js +3 -3
- package/src/directive/select/select.spec.js +96 -0
- package/src/directive/show-hide/show-hide.js +2 -2
- package/src/directive/show-hide/show-hide.spec.js +19 -8
- package/src/directive/style/style.spec.js +7 -0
- package/src/directive/switch/switch.spec.js +5 -5
- package/src/directive/validators/validators.spec.js +1 -0
- package/src/loader.js +1 -0
- package/src/public.js +10 -2
- package/src/router/common/coreservices.js +2 -0
- package/src/router/directives/state-directives.js +14 -6
- package/src/router/directives/state-directives.spec.js +83 -0
- package/src/router/directives/view-directive.js +13 -4
- package/src/router/directives/view-directive.spec.js +71 -25
- package/src/router/hooks/lazy-load.js +2 -2
- package/src/router/hooks/views.js +5 -3
- package/src/router/resolve/resolvable.js +6 -3
- package/src/router/resolve/resolve-context.js +2 -2
- package/src/router/state/state-service.js +4 -4
- package/src/router/state/state.spec.js +5 -2
- package/src/router/state/state.test.js +1 -1
- package/src/router/state/views.js +10 -7
- package/src/router/template-factory.js +6 -3
- package/src/router/template-factory.spec.js +4 -0
- package/src/router/transition/transition-hook.js +1 -1
- package/src/router/transition/transition.js +1 -1
- package/src/router/view-hook.spec.js +2 -2
- package/src/router/view-scroll.js +6 -4
- package/src/services/browser.js +5 -8
- package/src/services/http/http.js +9 -6
- package/src/services/http/http.spec.js +31 -30
- package/src/services/http/template-request.spec.js +10 -0
- package/src/services/http-backend/http-backend.spec.js +3 -3
- package/src/services/template-request.js +4 -2
- package/src/shared/common.js +2 -1
- package/types/core/location/location.d.ts +37 -34
- package/types/core/parse/parse.d.ts +0 -26
- package/types/core/scope/scope.d.ts +11 -11
- package/src/core/model/model.js +0 -944
- package/src/core/model/model.spec.js +0 -3012
- package/types/core/model/model.d.ts +0 -204
|
@@ -1,3012 +0,0 @@
|
|
|
1
|
-
import { wait } from "../../shared/test-utils";
|
|
2
|
-
import { $postUpdateQueue, createModel } from "./model";
|
|
3
|
-
import { Angular } from "../../loader";
|
|
4
|
-
import { createInjector } from "../di/injector";
|
|
5
|
-
import { isDefined, sliceArgs } from "../../shared/utils";
|
|
6
|
-
|
|
7
|
-
describe("Model", () => {
|
|
8
|
-
let model;
|
|
9
|
-
let $parse;
|
|
10
|
-
let logs;
|
|
11
|
-
let $rootModel;
|
|
12
|
-
let injector;
|
|
13
|
-
let count;
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
logs = [];
|
|
17
|
-
count = 0;
|
|
18
|
-
delete window.angular;
|
|
19
|
-
window.angular = new Angular();
|
|
20
|
-
window.angular
|
|
21
|
-
.module("myModule", ["ng"])
|
|
22
|
-
.decorator("$exceptionHandler", function () {
|
|
23
|
-
return (exception, cause) => {
|
|
24
|
-
logs.push(exception);
|
|
25
|
-
console.error(exception, cause);
|
|
26
|
-
};
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
injector = createInjector(["myModule"]);
|
|
30
|
-
$parse = injector.get("$parse");
|
|
31
|
-
$rootModel = injector.get("$rootScope");
|
|
32
|
-
model = $rootModel;
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("can be instantiated without parameters", () => {
|
|
36
|
-
model = createModel();
|
|
37
|
-
expect(model).toBeDefined();
|
|
38
|
-
|
|
39
|
-
model.a = 1;
|
|
40
|
-
expect(model.a).toEqual(1);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("can be instantiated with plain object", () => {
|
|
44
|
-
model = createModel({ a: 1, b: { c: 2 } });
|
|
45
|
-
expect(model).toBeDefined();
|
|
46
|
-
expect(model.a).toEqual(1);
|
|
47
|
-
expect(model.b.c).toEqual(2);
|
|
48
|
-
model.a = 2;
|
|
49
|
-
expect(model.a).toEqual(2);
|
|
50
|
-
model.d = 3;
|
|
51
|
-
expect(model.d).toEqual(3);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
describe("$id", () => {
|
|
55
|
-
it("should have a unique id", () => {
|
|
56
|
-
expect(model.id < model.$new().id).toBeTruthy();
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
describe("inheritance", () => {
|
|
61
|
-
it("can be constructed and used as an object", () => {
|
|
62
|
-
const model = createModel();
|
|
63
|
-
model.aProperty = 1;
|
|
64
|
-
|
|
65
|
-
expect(model.aProperty).toBe(1);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it("constructs a root model by default while all children non-root", () => {
|
|
69
|
-
const model = createModel();
|
|
70
|
-
expect(model.$isRoot()).toBe(true);
|
|
71
|
-
|
|
72
|
-
const child = model.$new();
|
|
73
|
-
expect(child.$isRoot()).toBe(false);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it("inherits the parents properties", () => {
|
|
77
|
-
model.aValue = [1, 2, 3];
|
|
78
|
-
|
|
79
|
-
const child = model.$new();
|
|
80
|
-
expect(child.aValue).toEqual([1, 2, 3]);
|
|
81
|
-
|
|
82
|
-
model.bValue = 2;
|
|
83
|
-
expect(child.bValue).toEqual(2);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it("does not cause a parent to inherit its properties", () => {
|
|
87
|
-
const child = model.$new();
|
|
88
|
-
child.aValue = [1, 2, 3];
|
|
89
|
-
|
|
90
|
-
expect(model.aValue).toBeUndefined();
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it("inherits the parents properties whenever they are defined", () => {
|
|
94
|
-
const child = model.$new();
|
|
95
|
-
|
|
96
|
-
model.aValue = [1, 2, 3];
|
|
97
|
-
|
|
98
|
-
expect(child.aValue).toEqual([1, 2, 3]);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it("can create a scope from an existing object", () => {
|
|
102
|
-
let instance = { bValue: "child" };
|
|
103
|
-
const child = model.$new(instance);
|
|
104
|
-
|
|
105
|
-
model.aValue = [1, 2, 3];
|
|
106
|
-
|
|
107
|
-
expect(child.aValue).toEqual([1, 2, 3]);
|
|
108
|
-
expect(child.bValue).toEqual("child");
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it("can be nested at any depth", () => {
|
|
112
|
-
const a = model;
|
|
113
|
-
const aa = a.$new();
|
|
114
|
-
const aaa = aa.$new();
|
|
115
|
-
const aab = aa.$new();
|
|
116
|
-
const ab = a.$new();
|
|
117
|
-
const abb = ab.$new();
|
|
118
|
-
|
|
119
|
-
a.value = 1;
|
|
120
|
-
|
|
121
|
-
expect(aa.value).toBe(1);
|
|
122
|
-
expect(aaa.value).toBe(1);
|
|
123
|
-
expect(aab.value).toBe(1);
|
|
124
|
-
expect(ab.value).toBe(1);
|
|
125
|
-
expect(abb.value).toBe(1);
|
|
126
|
-
|
|
127
|
-
ab.anotherValue = 2;
|
|
128
|
-
|
|
129
|
-
expect(abb.anotherValue).toBe(2);
|
|
130
|
-
expect(aa.anotherValue).toBeUndefined();
|
|
131
|
-
expect(aaa.anotherValue).toBeUndefined();
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it("can manipulate a parent models property", () => {
|
|
135
|
-
const child = model.$new();
|
|
136
|
-
|
|
137
|
-
model.aValue = [1, 2, 3];
|
|
138
|
-
child.aValue.push(4);
|
|
139
|
-
|
|
140
|
-
expect(child.aValue).toEqual([1, 2, 3, 4]);
|
|
141
|
-
expect(model.aValue).toEqual([1, 2, 3, 4]);
|
|
142
|
-
expect(child.aValue).toEqual(model.aValue);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it("can manipulate a parent models property with functions", () => {
|
|
146
|
-
class Demo {
|
|
147
|
-
test() {
|
|
148
|
-
return "Test";
|
|
149
|
-
}
|
|
150
|
-
increase() {
|
|
151
|
-
this.counter++;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
let instance = new Demo();
|
|
156
|
-
expect(instance.test()).toEqual("Test");
|
|
157
|
-
const child = model.$new(instance);
|
|
158
|
-
|
|
159
|
-
model.counter = 0;
|
|
160
|
-
|
|
161
|
-
expect(child.counter).toEqual(0);
|
|
162
|
-
expect(child.test()).toEqual("Test");
|
|
163
|
-
|
|
164
|
-
child.increase();
|
|
165
|
-
expect(child.counter).toEqual(1);
|
|
166
|
-
|
|
167
|
-
child.increase();
|
|
168
|
-
expect(child.counter).toEqual(2);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it("cannot override a parent models property", () => {
|
|
172
|
-
const child = model.$new();
|
|
173
|
-
model.aValue = [1, 2, 3];
|
|
174
|
-
child.aValue = [1, 2, 3, 4];
|
|
175
|
-
model.bValue = { a: 1 };
|
|
176
|
-
child.bValue = { b: 2 };
|
|
177
|
-
model.cValue = 1;
|
|
178
|
-
child.cValue = 2;
|
|
179
|
-
expect(model.aValue).toEqual([1, 2, 3]);
|
|
180
|
-
expect(child.aValue).toEqual([1, 2, 3, 4]);
|
|
181
|
-
expect(model.bValue).toEqual({ a: 1 });
|
|
182
|
-
expect(child.bValue).toEqual({ b: 2 });
|
|
183
|
-
expect(model.cValue).toEqual(1);
|
|
184
|
-
expect(child.cValue).toEqual(2);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it("inherits the parents listeners", () => {
|
|
188
|
-
const child = model.$new();
|
|
189
|
-
|
|
190
|
-
expect(child.$$listeners).toBe(model.$$listeners);
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
describe("$new()", () => {
|
|
195
|
-
it("should create a child model", () => {
|
|
196
|
-
const child = model.$new();
|
|
197
|
-
model.a = 123;
|
|
198
|
-
expect(child.a).toEqual(123);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
it("should create a non prototypically inherited child model", () => {
|
|
202
|
-
const child = model.$new(true);
|
|
203
|
-
model.a = 123;
|
|
204
|
-
expect(child.a).toBeUndefined();
|
|
205
|
-
expect(child.$parent).toBe(model.$root);
|
|
206
|
-
expect(child.$new).toBeDefined();
|
|
207
|
-
expect(child.$root).toEqual(model.$root);
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it("should attach the child model to a specified parent", () => {
|
|
211
|
-
const isolated = model.$new(true);
|
|
212
|
-
|
|
213
|
-
const trans = model.$new(false, isolated);
|
|
214
|
-
model.a = 123;
|
|
215
|
-
expect(isolated.a).toBeUndefined();
|
|
216
|
-
expect(trans.a).toEqual(123);
|
|
217
|
-
expect(trans.$root.$id).toEqual(model.$root.$id);
|
|
218
|
-
expect(trans.$parent.$id).toEqual(isolated.$id);
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
describe("$root", () => {
|
|
223
|
-
it("should point to itself", () => {
|
|
224
|
-
expect(model.$root.$id).toEqual(model.$id);
|
|
225
|
-
expect(model.$root).toEqual(model.$root.$root);
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
it("should expose the constructor", () => {
|
|
229
|
-
expect(Object.getPrototypeOf(model)).toBe(model.constructor.prototype);
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
it("should not have $root on children, but should inherit", () => {
|
|
233
|
-
const child = model.$new();
|
|
234
|
-
expect(child.$root).toEqual(model.$root);
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
describe("$parent", () => {
|
|
239
|
-
it("should point to parent", () => {
|
|
240
|
-
const child = model.$new();
|
|
241
|
-
|
|
242
|
-
expect(model.$parent).toEqual(null);
|
|
243
|
-
expect(child.$parent.$id).toEqual(model.$id);
|
|
244
|
-
expect(child.$parent).toEqual(model.$handler);
|
|
245
|
-
expect(child.$new().$parent).toEqual(child.$handler);
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
it("should keep track of its children", () => {
|
|
249
|
-
const child = model.$new();
|
|
250
|
-
expect(model.$children).toEqual([child]);
|
|
251
|
-
|
|
252
|
-
const child2 = model.$new();
|
|
253
|
-
expect(model.$children).toEqual([child, child2]);
|
|
254
|
-
|
|
255
|
-
const child3 = child2.$new();
|
|
256
|
-
expect(model.$children).toEqual([child, child2]);
|
|
257
|
-
expect(child2.$children).toEqual([child3]);
|
|
258
|
-
});
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
describe("this", () => {
|
|
262
|
-
it("should evaluate 'this' to be the model", () => {
|
|
263
|
-
const child = model.$new();
|
|
264
|
-
expect(model.$eval("this")).toEqual(model.$target);
|
|
265
|
-
expect(child.$eval("this")).toEqual(child.$target);
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it("'this' should not be recursive", () => {
|
|
269
|
-
expect(model.$eval("this.this")).toBeUndefined();
|
|
270
|
-
expect(model.$eval("$parent.this")).toBeUndefined();
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
it("should not be able to overwrite the 'this' keyword", () => {
|
|
274
|
-
model.this = 123;
|
|
275
|
-
expect(model.$eval("this")).toEqual(model);
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
it("should be able to access a constant variable named 'this'", () => {
|
|
279
|
-
model.this = 42;
|
|
280
|
-
expect(model.$eval("this['this']")).toBe(42);
|
|
281
|
-
});
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
describe("$watch", () => {
|
|
285
|
-
it("needs an expression to designate a watched property", async () => {
|
|
286
|
-
expect(() => model.$watch()).toThrowError();
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
it("does not need a listener function", async () => {
|
|
290
|
-
expect(() => model.$watch("1")).not.toThrowError();
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
it("can register listeners via watch", async () => {
|
|
294
|
-
var listenerFn = jasmine.createSpy();
|
|
295
|
-
model.$watch("a", listenerFn);
|
|
296
|
-
model.a = 1;
|
|
297
|
-
await wait();
|
|
298
|
-
expect(listenerFn).toHaveBeenCalled();
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it("should return a deregistration function watch", () => {
|
|
302
|
-
let fn = model.$watch("a", () => {});
|
|
303
|
-
expect(fn).toBeDefined();
|
|
304
|
-
expect(typeof fn).toEqual("function");
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
it("should not expose the `inner working of watch", async () => {
|
|
308
|
-
let get, listen;
|
|
309
|
-
function Listener() {
|
|
310
|
-
listen = this;
|
|
311
|
-
}
|
|
312
|
-
model.$watch("foo", Listener);
|
|
313
|
-
|
|
314
|
-
model.a = 1;
|
|
315
|
-
await wait();
|
|
316
|
-
|
|
317
|
-
expect(get).toBeUndefined();
|
|
318
|
-
expect(listen).toBeUndefined();
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it("can trigger watch from a class", async () => {
|
|
322
|
-
let called = false;
|
|
323
|
-
class Demo {
|
|
324
|
-
constructor() {
|
|
325
|
-
this.counter = 0;
|
|
326
|
-
}
|
|
327
|
-
test() {
|
|
328
|
-
this.counter++;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
model = createModel(new Demo());
|
|
333
|
-
|
|
334
|
-
model.$watch("counter", () => {
|
|
335
|
-
called = true;
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
expect(model.counter).toEqual(0);
|
|
339
|
-
expect(called).toBeFalse();
|
|
340
|
-
|
|
341
|
-
model.test();
|
|
342
|
-
await wait();
|
|
343
|
-
|
|
344
|
-
expect(model.counter).toEqual(1);
|
|
345
|
-
expect(called).toBeTrue();
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
it("can trigger watch from a constuctor function", async () => {
|
|
349
|
-
let called = false;
|
|
350
|
-
function Demo() {
|
|
351
|
-
this.counter = 0;
|
|
352
|
-
this.test = function () {
|
|
353
|
-
this.counter++;
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
model = createModel(new Demo());
|
|
358
|
-
|
|
359
|
-
model.$watch("counter", () => {
|
|
360
|
-
called = true;
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
expect(model.counter).toEqual(0);
|
|
364
|
-
expect(called).toBeFalse();
|
|
365
|
-
|
|
366
|
-
model.test();
|
|
367
|
-
await wait();
|
|
368
|
-
|
|
369
|
-
expect(model.counter).toEqual(1);
|
|
370
|
-
expect(called).toBeTrue();
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
it("can trigger watch from an POJO object ", async () => {
|
|
374
|
-
let called = false;
|
|
375
|
-
const demo = {
|
|
376
|
-
counter: 0,
|
|
377
|
-
test: function () {
|
|
378
|
-
this.counter++;
|
|
379
|
-
},
|
|
380
|
-
};
|
|
381
|
-
|
|
382
|
-
model = createModel(demo);
|
|
383
|
-
|
|
384
|
-
model.$watch("counter", () => {
|
|
385
|
-
called = true;
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
expect(model.counter).toEqual(0);
|
|
389
|
-
expect(called).toBeFalse();
|
|
390
|
-
|
|
391
|
-
model.test();
|
|
392
|
-
await wait();
|
|
393
|
-
|
|
394
|
-
expect(model.counter).toEqual(1);
|
|
395
|
-
expect(called).toBeTrue();
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
it("calls the listener function when the watched value is iniatized", async () => {
|
|
399
|
-
model.counter = 0;
|
|
400
|
-
|
|
401
|
-
model.$watch("someValue", () => model.counter++);
|
|
402
|
-
expect(model.counter).toBe(0);
|
|
403
|
-
|
|
404
|
-
model.someValue = "b";
|
|
405
|
-
await wait();
|
|
406
|
-
expect(model.counter).toBe(1);
|
|
407
|
-
|
|
408
|
-
model.someValue = "b";
|
|
409
|
-
await wait();
|
|
410
|
-
expect(model.counter).toBe(1);
|
|
411
|
-
|
|
412
|
-
model.someValue = "c";
|
|
413
|
-
await wait();
|
|
414
|
-
expect(model.counter).toBe(2);
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
it("calls the listener function when the watched value is destroyed", async () => {
|
|
418
|
-
model.counter = 0;
|
|
419
|
-
|
|
420
|
-
model.$watch("someValue", () => model.counter++);
|
|
421
|
-
expect(model.counter).toBe(0);
|
|
422
|
-
|
|
423
|
-
model.someValue = "b";
|
|
424
|
-
await wait();
|
|
425
|
-
expect(model.counter).toBe(1);
|
|
426
|
-
|
|
427
|
-
delete model.someValue;
|
|
428
|
-
await wait();
|
|
429
|
-
expect(model.counter).toBe(2);
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
it("can call multiple the listener functions when the watched value changes", async () => {
|
|
433
|
-
model.someValue = "a";
|
|
434
|
-
model.counter = 0;
|
|
435
|
-
|
|
436
|
-
model.$watch("someValue", () => {
|
|
437
|
-
model.counter++;
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
model.$watch("someValue", () => model.counter++);
|
|
441
|
-
|
|
442
|
-
expect(model.counter).toBe(0);
|
|
443
|
-
|
|
444
|
-
model.someValue = "b";
|
|
445
|
-
await wait();
|
|
446
|
-
expect(model.counter).toBe(2);
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
it("calls only the listeners registerred at the moment the watched value changes", async () => {
|
|
450
|
-
model.someValue = "a";
|
|
451
|
-
model.counter = 0;
|
|
452
|
-
|
|
453
|
-
model.$watch("someValue", () => model.counter++);
|
|
454
|
-
expect(model.counter).toBe(0);
|
|
455
|
-
|
|
456
|
-
model.someValue = "b";
|
|
457
|
-
await wait();
|
|
458
|
-
expect(model.counter).toBe(1);
|
|
459
|
-
|
|
460
|
-
model.$watch("someValue", () => {
|
|
461
|
-
model.counter++;
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
model.someValue = "b";
|
|
465
|
-
await wait();
|
|
466
|
-
|
|
467
|
-
expect(model.counter).toBe(1);
|
|
468
|
-
|
|
469
|
-
model.someValue = "c";
|
|
470
|
-
await wait();
|
|
471
|
-
|
|
472
|
-
expect(model.counter).toBe(3);
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
it("correctly handles NaNs", async () => {
|
|
476
|
-
model.counter = 0;
|
|
477
|
-
model.$watch("number", function (newValue, oldValue, model) {
|
|
478
|
-
model.counter++;
|
|
479
|
-
});
|
|
480
|
-
model.number = 0 / 0;
|
|
481
|
-
await wait();
|
|
482
|
-
expect(model.number).toBeNaN();
|
|
483
|
-
expect(model.counter).toBe(1);
|
|
484
|
-
|
|
485
|
-
model.number = NaN;
|
|
486
|
-
await wait();
|
|
487
|
-
expect(model.number).toBeNaN();
|
|
488
|
-
expect(model.counter).toBe(1);
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
it("calls listener with undefined old value the first time", async () => {
|
|
492
|
-
var oldValueGiven;
|
|
493
|
-
var newValueGiven;
|
|
494
|
-
model.$watch("someValue", function (newValue, oldValue, model) {
|
|
495
|
-
newValueGiven = newValue;
|
|
496
|
-
oldValueGiven = oldValue;
|
|
497
|
-
});
|
|
498
|
-
model.someValue = 123;
|
|
499
|
-
await wait();
|
|
500
|
-
|
|
501
|
-
expect(oldValueGiven).toBe(undefined);
|
|
502
|
-
expect(newValueGiven).toBe(123);
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
it("calls listener with new value and old value the first time if defined", async () => {
|
|
506
|
-
var oldValueGiven;
|
|
507
|
-
var newValueGiven;
|
|
508
|
-
model.someValue = 123;
|
|
509
|
-
|
|
510
|
-
model.$watch("someValue", function (newValue, oldValue, model) {
|
|
511
|
-
newValueGiven = newValue;
|
|
512
|
-
oldValueGiven = oldValue;
|
|
513
|
-
});
|
|
514
|
-
model.someValue = 321;
|
|
515
|
-
await wait();
|
|
516
|
-
|
|
517
|
-
expect(oldValueGiven).toBe(123);
|
|
518
|
-
expect(newValueGiven).toBe(321);
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
it("calls listener with with the instance of a model as 3rd argument", async () => {
|
|
522
|
-
var modelInstance;
|
|
523
|
-
model.someValue = 123;
|
|
524
|
-
|
|
525
|
-
model.$watch("someValue", function (_1, _2, m) {
|
|
526
|
-
modelInstance = m;
|
|
527
|
-
});
|
|
528
|
-
model.someValue = 321;
|
|
529
|
-
await wait();
|
|
530
|
-
|
|
531
|
-
expect(modelInstance).toBeDefined();
|
|
532
|
-
expect(modelInstance).toEqual(model);
|
|
533
|
-
});
|
|
534
|
-
|
|
535
|
-
it("triggers chained watchers in the same model change", async () => {
|
|
536
|
-
model.$watch("nameUpper", function (newValue) {
|
|
537
|
-
if (newValue) {
|
|
538
|
-
model.initial = newValue.substring(0, 1) + ".";
|
|
539
|
-
}
|
|
540
|
-
});
|
|
541
|
-
model.$watch("name", function (newValue) {
|
|
542
|
-
if (newValue) {
|
|
543
|
-
model.nameUpper = newValue.toUpperCase();
|
|
544
|
-
}
|
|
545
|
-
});
|
|
546
|
-
model.name = "Jane";
|
|
547
|
-
await wait();
|
|
548
|
-
expect(model.initial).toBe("J.");
|
|
549
|
-
|
|
550
|
-
model.name = "Bob";
|
|
551
|
-
await wait();
|
|
552
|
-
expect(model.initial).toBe("B.");
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
it("can register nested watches", async () => {
|
|
556
|
-
model.counter = 0;
|
|
557
|
-
model.aValue = "abc";
|
|
558
|
-
model.$watch("aValue", () => {
|
|
559
|
-
model.$watch("bValue", () => {
|
|
560
|
-
model.counter++;
|
|
561
|
-
});
|
|
562
|
-
});
|
|
563
|
-
model.aValue = "2";
|
|
564
|
-
await wait();
|
|
565
|
-
expect(model.counter).toBe(0);
|
|
566
|
-
|
|
567
|
-
model.bValue = "3";
|
|
568
|
-
await wait();
|
|
569
|
-
expect(model.counter).toBe(1);
|
|
570
|
-
|
|
571
|
-
model.aValue = "6";
|
|
572
|
-
await wait();
|
|
573
|
-
expect(model.counter).toBe(1);
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
it("should delegate exceptions", async () => {
|
|
577
|
-
model.$watch("a", () => {
|
|
578
|
-
throw new Error("abc");
|
|
579
|
-
});
|
|
580
|
-
model.a = 1;
|
|
581
|
-
await wait();
|
|
582
|
-
expect(logs[0]).toMatch(/abc/);
|
|
583
|
-
});
|
|
584
|
-
|
|
585
|
-
it("should fire watches in order of addition", async () => {
|
|
586
|
-
// this is not an external guarantee, just our own sanity
|
|
587
|
-
logs = "";
|
|
588
|
-
model.$watch("a", () => {
|
|
589
|
-
logs += "a";
|
|
590
|
-
});
|
|
591
|
-
model.$watch("b", () => {
|
|
592
|
-
logs += "b";
|
|
593
|
-
});
|
|
594
|
-
// constant expressions have slightly different handling as they are executed in priority
|
|
595
|
-
model.$watch("1", () => {
|
|
596
|
-
logs += "1";
|
|
597
|
-
});
|
|
598
|
-
model.$watch("c", () => {
|
|
599
|
-
logs += "c";
|
|
600
|
-
});
|
|
601
|
-
model.$watch("2", () => {
|
|
602
|
-
logs += "2";
|
|
603
|
-
});
|
|
604
|
-
model.a = 1;
|
|
605
|
-
model.b = 1;
|
|
606
|
-
model.c = 1;
|
|
607
|
-
await wait();
|
|
608
|
-
expect(logs).toEqual("12abc");
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
it("should repeat watch cycle while model changes are identified", async () => {
|
|
612
|
-
logs = "";
|
|
613
|
-
model.$watch("c", (v) => {
|
|
614
|
-
model.d = v;
|
|
615
|
-
logs += "c";
|
|
616
|
-
});
|
|
617
|
-
model.$watch("b", (v) => {
|
|
618
|
-
model.c = v;
|
|
619
|
-
logs += "b";
|
|
620
|
-
});
|
|
621
|
-
model.$watch("a", (v) => {
|
|
622
|
-
model.b = v;
|
|
623
|
-
logs += "a";
|
|
624
|
-
});
|
|
625
|
-
await wait();
|
|
626
|
-
logs = "";
|
|
627
|
-
model.a = 1;
|
|
628
|
-
await wait();
|
|
629
|
-
expect(model.b).toEqual(1);
|
|
630
|
-
expect(model.c).toEqual(1);
|
|
631
|
-
expect(model.d).toEqual(1);
|
|
632
|
-
expect(logs).toEqual("abc");
|
|
633
|
-
});
|
|
634
|
-
|
|
635
|
-
describe("constants", () => {
|
|
636
|
-
it("does not watch constants", async () => {
|
|
637
|
-
model.$watch("1", () => {});
|
|
638
|
-
expect(model.$$watchersCount).toBe(0);
|
|
639
|
-
await wait();
|
|
640
|
-
expect(model.$$watchersCount).toBe(0);
|
|
641
|
-
});
|
|
642
|
-
|
|
643
|
-
const cases = [
|
|
644
|
-
{ expression: "1", expected: 1 },
|
|
645
|
-
{ expression: "'a'", expected: "a" },
|
|
646
|
-
{ expression: "[1,2,3]", expected: [1, 2, 3] },
|
|
647
|
-
{ expression: "false", expected: false },
|
|
648
|
-
{ expression: "null", expected: null },
|
|
649
|
-
{ expression: '{x: 1}["x"]', expected: 1 },
|
|
650
|
-
{ expression: "2 + 2", expected: 4 },
|
|
651
|
-
{ expression: "2 / 0", expected: Infinity },
|
|
652
|
-
{ expression: "false || 2", expected: 2 },
|
|
653
|
-
{ expression: "false && 2", expected: false },
|
|
654
|
-
];
|
|
655
|
-
|
|
656
|
-
cases.forEach(async ({ expression, expected }) => {
|
|
657
|
-
it("passes constants to listener cb " + expression, async () => {
|
|
658
|
-
let res;
|
|
659
|
-
model.$watch(expression, (val) => {
|
|
660
|
-
res = val;
|
|
661
|
-
});
|
|
662
|
-
|
|
663
|
-
await wait();
|
|
664
|
-
expect(res).toEqual(expected);
|
|
665
|
-
});
|
|
666
|
-
});
|
|
667
|
-
});
|
|
668
|
-
|
|
669
|
-
describe("expressions", () => {
|
|
670
|
-
it("adds watches expressions", async () => {
|
|
671
|
-
expect(model.$$watchersCount).toBe(0);
|
|
672
|
-
model.$watch("foo", () => {});
|
|
673
|
-
|
|
674
|
-
await wait();
|
|
675
|
-
expect(model.$$watchersCount).toBe(1);
|
|
676
|
-
});
|
|
677
|
-
|
|
678
|
-
it("should not fire upon $watch registration on initial registeration", async () => {
|
|
679
|
-
logs = "";
|
|
680
|
-
model.a = 1;
|
|
681
|
-
model.$watch("a", () => {
|
|
682
|
-
logs += "a";
|
|
683
|
-
});
|
|
684
|
-
model.$watch("b", () => {
|
|
685
|
-
logs += "b";
|
|
686
|
-
});
|
|
687
|
-
await wait();
|
|
688
|
-
expect(logs).toEqual("");
|
|
689
|
-
});
|
|
690
|
-
|
|
691
|
-
it("invokes a callback on property change", async () => {
|
|
692
|
-
let newV, oldV, target;
|
|
693
|
-
model.$watch("foo", (a, b, c) => {
|
|
694
|
-
newV = a;
|
|
695
|
-
oldV = b;
|
|
696
|
-
target = c;
|
|
697
|
-
});
|
|
698
|
-
|
|
699
|
-
model.foo = 1;
|
|
700
|
-
await wait();
|
|
701
|
-
expect(newV).toEqual(1);
|
|
702
|
-
expect(oldV).toBeUndefined();
|
|
703
|
-
expect(target).toEqual(model.$target);
|
|
704
|
-
|
|
705
|
-
model.foo = 2;
|
|
706
|
-
await wait();
|
|
707
|
-
expect(newV).toEqual(2);
|
|
708
|
-
expect(oldV).toEqual(1);
|
|
709
|
-
expect(target).toEqual(model.$target);
|
|
710
|
-
|
|
711
|
-
model.foo = [];
|
|
712
|
-
await wait();
|
|
713
|
-
expect(newV).toEqual([]);
|
|
714
|
-
expect(oldV).toEqual(2);
|
|
715
|
-
expect(target).toEqual(model.$target);
|
|
716
|
-
});
|
|
717
|
-
|
|
718
|
-
it("calls the listener function when the watched value changes", async () => {
|
|
719
|
-
model.someValue = "a";
|
|
720
|
-
model.counter = 0;
|
|
721
|
-
model.$watch("someValue", function (newValue, oldValue, model) {
|
|
722
|
-
model.counter++;
|
|
723
|
-
});
|
|
724
|
-
expect(model.counter).toBe(0);
|
|
725
|
-
|
|
726
|
-
model.someValue = "1";
|
|
727
|
-
await wait();
|
|
728
|
-
expect(model.counter).toBe(1);
|
|
729
|
-
|
|
730
|
-
model.someValue = "2";
|
|
731
|
-
await wait();
|
|
732
|
-
expect(model.counter).toBe(2);
|
|
733
|
-
});
|
|
734
|
-
|
|
735
|
-
it("should watch and fire on simple property change", async () => {
|
|
736
|
-
const spy = jasmine.createSpy();
|
|
737
|
-
model.$watch("name", spy);
|
|
738
|
-
|
|
739
|
-
spy.calls.reset();
|
|
740
|
-
|
|
741
|
-
expect(spy).not.toHaveBeenCalled();
|
|
742
|
-
model.name = "misko";
|
|
743
|
-
await wait();
|
|
744
|
-
expect(spy).toHaveBeenCalledWith("misko", undefined, model);
|
|
745
|
-
});
|
|
746
|
-
|
|
747
|
-
it("should watch and fire on corect expression change", async () => {
|
|
748
|
-
const spy = jasmine.createSpy();
|
|
749
|
-
model.$watch("name.first", spy);
|
|
750
|
-
|
|
751
|
-
spy.calls.reset();
|
|
752
|
-
|
|
753
|
-
model.name = {};
|
|
754
|
-
expect(spy).not.toHaveBeenCalled();
|
|
755
|
-
|
|
756
|
-
model.first = "misko";
|
|
757
|
-
await wait();
|
|
758
|
-
expect(spy).not.toHaveBeenCalled();
|
|
759
|
-
|
|
760
|
-
model.name.first = "misko";
|
|
761
|
-
await wait();
|
|
762
|
-
expect(spy).toHaveBeenCalled();
|
|
763
|
-
});
|
|
764
|
-
});
|
|
765
|
-
|
|
766
|
-
describe("apply expression", () => {
|
|
767
|
-
it("adds watches expressions", async () => {
|
|
768
|
-
expect(model.$$watchersCount).toBe(0);
|
|
769
|
-
model.$watch("foo = 1", () => {});
|
|
770
|
-
|
|
771
|
-
await wait();
|
|
772
|
-
expect(model.$$watchersCount).toBe(1);
|
|
773
|
-
});
|
|
774
|
-
|
|
775
|
-
it("applies a property change and continues watching the models", async () => {
|
|
776
|
-
expect(model.$$watchersCount).toBe(0);
|
|
777
|
-
model.$watch("foo = 2", () => {});
|
|
778
|
-
|
|
779
|
-
await wait();
|
|
780
|
-
expect(model.$$watchersCount).toBe(1);
|
|
781
|
-
expect(model.foo).toBe(2);
|
|
782
|
-
|
|
783
|
-
model.$watch("foo = 3", () => {});
|
|
784
|
-
|
|
785
|
-
await wait();
|
|
786
|
-
expect(model.$$watchersCount).toBe(2);
|
|
787
|
-
expect(model.foo).toBe(3);
|
|
788
|
-
});
|
|
789
|
-
|
|
790
|
-
it("should apply a change and not increase watchers if no listener function", async () => {
|
|
791
|
-
expect(model.$$watchersCount).toBe(0);
|
|
792
|
-
model.$watch("foo = 2");
|
|
793
|
-
|
|
794
|
-
await wait();
|
|
795
|
-
expect(model.$$watchersCount).toBe(0);
|
|
796
|
-
expect(model.foo).toBe(2);
|
|
797
|
-
|
|
798
|
-
model.$watch("foo = 3");
|
|
799
|
-
|
|
800
|
-
await wait();
|
|
801
|
-
expect(model.$$watchersCount).toBe(0);
|
|
802
|
-
expect(model.foo).toBe(3);
|
|
803
|
-
});
|
|
804
|
-
});
|
|
805
|
-
|
|
806
|
-
describe("filters", () => {
|
|
807
|
-
it("applies filters to constants", async () => {
|
|
808
|
-
expect(model.$$watchersCount).toBe(0);
|
|
809
|
-
let res;
|
|
810
|
-
model.$watch("'abcd'|limitTo:3", (val) => {
|
|
811
|
-
res = val;
|
|
812
|
-
});
|
|
813
|
-
await wait();
|
|
814
|
-
expect(res).toEqual("abc");
|
|
815
|
-
|
|
816
|
-
model.$watch("'abcd'|limitTo:3|limitTo:2", (val) => {
|
|
817
|
-
res = val;
|
|
818
|
-
});
|
|
819
|
-
|
|
820
|
-
await wait();
|
|
821
|
-
expect(res).toEqual("ab");
|
|
822
|
-
|
|
823
|
-
model.$watch("'abcd'|limitTo:3|limitTo:2|limitTo:1", (val) => {
|
|
824
|
-
res = val;
|
|
825
|
-
});
|
|
826
|
-
|
|
827
|
-
await wait();
|
|
828
|
-
expect(res).toEqual("a");
|
|
829
|
-
});
|
|
830
|
-
});
|
|
831
|
-
|
|
832
|
-
describe("$watch on constants", () => {
|
|
833
|
-
beforeEach(() => (logs = []));
|
|
834
|
-
it("should not $watch constant literals ", () => {
|
|
835
|
-
model.$watch("[]", () => {});
|
|
836
|
-
model.$watch("{}", () => {});
|
|
837
|
-
model.$watch("1", () => {});
|
|
838
|
-
model.$watch('"foo"', () => {});
|
|
839
|
-
expect(model.$$watchersCount).toEqual(0);
|
|
840
|
-
});
|
|
841
|
-
|
|
842
|
-
it("should not $watch filtered literals", () => {
|
|
843
|
-
model.$watch('[1] | filter:"x"', () => {});
|
|
844
|
-
model.$watch("1 | limitTo:2", () => {});
|
|
845
|
-
expect(model.$$watchersCount).toEqual(0);
|
|
846
|
-
});
|
|
847
|
-
|
|
848
|
-
it("should ignore $watch of constant expressions", () => {
|
|
849
|
-
model.$watch("1 + 1", () => {});
|
|
850
|
-
model.$watch('"a" + "b"', () => {});
|
|
851
|
-
model.$watch('"ab".length', () => {});
|
|
852
|
-
model.$watch("[].length", () => {});
|
|
853
|
-
model.$watch("(1 + 1) | limitTo:2", () => {});
|
|
854
|
-
expect(model.$$watchersCount).toEqual(0);
|
|
855
|
-
});
|
|
856
|
-
});
|
|
857
|
-
|
|
858
|
-
describe("$watch on onetime", () => {
|
|
859
|
-
it("should clean up stable watches on the watch queue", async () => {
|
|
860
|
-
let count = 0;
|
|
861
|
-
|
|
862
|
-
model.$watch("::foo", () => {
|
|
863
|
-
count++;
|
|
864
|
-
});
|
|
865
|
-
expect(model.$$watchersCount).toEqual(1);
|
|
866
|
-
expect(count).toEqual(0);
|
|
867
|
-
|
|
868
|
-
model.foo = "foo";
|
|
869
|
-
await wait();
|
|
870
|
-
expect(model.$$watchersCount).toEqual(0);
|
|
871
|
-
expect(count).toEqual(1);
|
|
872
|
-
});
|
|
873
|
-
|
|
874
|
-
it("should clean up stable watches from $watch collection", async () => {
|
|
875
|
-
let count = 0;
|
|
876
|
-
model.$watch("::foo", () => {
|
|
877
|
-
count++;
|
|
878
|
-
});
|
|
879
|
-
expect(model.$$watchersCount).toEqual(1);
|
|
880
|
-
|
|
881
|
-
model.foo = [];
|
|
882
|
-
|
|
883
|
-
await wait();
|
|
884
|
-
expect(count).toEqual(1);
|
|
885
|
-
expect(model.$$watchersCount).toEqual(0);
|
|
886
|
-
});
|
|
887
|
-
|
|
888
|
-
xit("should clean up stable watches from $watch array literals", async () => {
|
|
889
|
-
let count = 0;
|
|
890
|
-
model.$watch("::[foo, bar]", () => {
|
|
891
|
-
count++;
|
|
892
|
-
});
|
|
893
|
-
expect(model.$$watchersCount).toEqual(1);
|
|
894
|
-
|
|
895
|
-
expect(model.$$watchersCount).toEqual(1);
|
|
896
|
-
expect(count).toEqual(0);
|
|
897
|
-
|
|
898
|
-
model.foo = 1;
|
|
899
|
-
await wait();
|
|
900
|
-
expect(count).toEqual(0);
|
|
901
|
-
expect(model.$$watchersCount).toEqual(1);
|
|
902
|
-
|
|
903
|
-
model.foo = 2;
|
|
904
|
-
await wait();
|
|
905
|
-
expect(count).toEqual(0);
|
|
906
|
-
expect(model.$$watchersCount).toEqual(1);
|
|
907
|
-
|
|
908
|
-
model.bar = 3;
|
|
909
|
-
await wait();
|
|
910
|
-
expect(count).toEqual(1);
|
|
911
|
-
expect(model.$$watchersCount).toEqual(0);
|
|
912
|
-
});
|
|
913
|
-
|
|
914
|
-
it("should clean up stable watches from $watchGroup", async () => {
|
|
915
|
-
model.$watchGroup(["::foo", "::bar"], () => {});
|
|
916
|
-
expect(model.$$watchersCount).toEqual(2);
|
|
917
|
-
model.foo = "foo";
|
|
918
|
-
await wait();
|
|
919
|
-
expect(model.$$watchersCount).toEqual(1);
|
|
920
|
-
|
|
921
|
-
model.bar = "bar";
|
|
922
|
-
await wait();
|
|
923
|
-
expect(model.$$watchersCount).toEqual(0);
|
|
924
|
-
});
|
|
925
|
-
});
|
|
926
|
-
|
|
927
|
-
describe("watching objects", () => {
|
|
928
|
-
it("should watch objects", async () => {
|
|
929
|
-
logs = "";
|
|
930
|
-
model.a = { c: 2 };
|
|
931
|
-
model.$watch("a", (value) => {
|
|
932
|
-
logs += "success";
|
|
933
|
-
expect(value).toEqual(model.a);
|
|
934
|
-
});
|
|
935
|
-
|
|
936
|
-
model.a.c = "1";
|
|
937
|
-
|
|
938
|
-
await wait();
|
|
939
|
-
expect(logs).toEqual("success");
|
|
940
|
-
});
|
|
941
|
-
|
|
942
|
-
it("calls the listener function registered via function when a value is created as an object", async () => {
|
|
943
|
-
model.counter = 0;
|
|
944
|
-
|
|
945
|
-
model.$watch("someValue", () => {
|
|
946
|
-
model.counter++;
|
|
947
|
-
});
|
|
948
|
-
await wait();
|
|
949
|
-
|
|
950
|
-
expect(model.counter).toBe(0);
|
|
951
|
-
|
|
952
|
-
model.someValue = {};
|
|
953
|
-
await wait();
|
|
954
|
-
|
|
955
|
-
expect(model.counter).toBe(1);
|
|
956
|
-
});
|
|
957
|
-
|
|
958
|
-
it("calls the listener function registered via expression when a value is created as an object", async () => {
|
|
959
|
-
model.counter = 0;
|
|
960
|
-
|
|
961
|
-
model.$watch("someValue", () => {
|
|
962
|
-
model.counter++;
|
|
963
|
-
});
|
|
964
|
-
await wait();
|
|
965
|
-
|
|
966
|
-
expect(model.counter).toBe(0);
|
|
967
|
-
|
|
968
|
-
model.someValue = {};
|
|
969
|
-
await wait();
|
|
970
|
-
|
|
971
|
-
expect(model.counter).toBe(1);
|
|
972
|
-
});
|
|
973
|
-
|
|
974
|
-
it("calls the listener function registered via function when a value is created on a nested object", async () => {
|
|
975
|
-
model.counter = 0;
|
|
976
|
-
model.a = { someValue: 1 };
|
|
977
|
-
model.$watch("a.someValue", () => {
|
|
978
|
-
model.counter++;
|
|
979
|
-
});
|
|
980
|
-
|
|
981
|
-
model.a.someValue = 2;
|
|
982
|
-
|
|
983
|
-
await wait();
|
|
984
|
-
expect(model.counter).toBe(1);
|
|
985
|
-
|
|
986
|
-
model.a.someValue = 3;
|
|
987
|
-
await wait();
|
|
988
|
-
expect(model.counter).toBe(2);
|
|
989
|
-
});
|
|
990
|
-
|
|
991
|
-
it("calls the listener function registered via expression when a value is created on a nested object", async () => {
|
|
992
|
-
model.counter = 0;
|
|
993
|
-
model.a = { someValue: 1 };
|
|
994
|
-
|
|
995
|
-
model.$watch("a.someValue", () => {
|
|
996
|
-
model.counter++;
|
|
997
|
-
});
|
|
998
|
-
|
|
999
|
-
model.a.someValue = 2;
|
|
1000
|
-
|
|
1001
|
-
await wait();
|
|
1002
|
-
expect(model.counter).toBe(1);
|
|
1003
|
-
|
|
1004
|
-
model.a.someValue = 3;
|
|
1005
|
-
await wait();
|
|
1006
|
-
expect(model.counter).toBe(2);
|
|
1007
|
-
});
|
|
1008
|
-
|
|
1009
|
-
it("calls the listener function when a nested value is created on an empty wrapper object", async () => {
|
|
1010
|
-
model.counter = 0;
|
|
1011
|
-
model.someValue = {};
|
|
1012
|
-
|
|
1013
|
-
model.$watch("someValue.b", () => {
|
|
1014
|
-
model.counter++;
|
|
1015
|
-
});
|
|
1016
|
-
await wait();
|
|
1017
|
-
|
|
1018
|
-
expect(model.counter).toBe(0);
|
|
1019
|
-
|
|
1020
|
-
model.someValue = { b: 2 };
|
|
1021
|
-
await wait();
|
|
1022
|
-
|
|
1023
|
-
expect(model.counter).toBe(1);
|
|
1024
|
-
});
|
|
1025
|
-
|
|
1026
|
-
it("calls the listener function when a nested value is created on an undefined wrapper object", async () => {
|
|
1027
|
-
model.counter = 0;
|
|
1028
|
-
model.someValue = undefined;
|
|
1029
|
-
|
|
1030
|
-
model.$watch("someValue.b", async () => {
|
|
1031
|
-
model.counter++;
|
|
1032
|
-
});
|
|
1033
|
-
await wait();
|
|
1034
|
-
|
|
1035
|
-
expect(model.counter).toBe(0);
|
|
1036
|
-
|
|
1037
|
-
model.someValue = { b: 2 };
|
|
1038
|
-
await wait();
|
|
1039
|
-
|
|
1040
|
-
expect(model.counter).toBe(1);
|
|
1041
|
-
|
|
1042
|
-
model.someValue.b = 3;
|
|
1043
|
-
await wait();
|
|
1044
|
-
|
|
1045
|
-
expect(model.counter).toBe(2);
|
|
1046
|
-
});
|
|
1047
|
-
|
|
1048
|
-
it("calls the listener function when a nested value is created from a wrapper object", async () => {
|
|
1049
|
-
model.someValue = { b: 1 };
|
|
1050
|
-
model.counter = 0;
|
|
1051
|
-
|
|
1052
|
-
model.$watch("someValue.b", () => model.counter++);
|
|
1053
|
-
await wait();
|
|
1054
|
-
|
|
1055
|
-
expect(model.counter).toBe(0);
|
|
1056
|
-
|
|
1057
|
-
model.someValue = { b: 2 };
|
|
1058
|
-
await wait();
|
|
1059
|
-
|
|
1060
|
-
expect(model.counter).toBe(1);
|
|
1061
|
-
model.someValue = { c: 2 };
|
|
1062
|
-
await wait();
|
|
1063
|
-
|
|
1064
|
-
expect(model.counter).toBe(2);
|
|
1065
|
-
|
|
1066
|
-
model.someValue = { b: 2 };
|
|
1067
|
-
await wait();
|
|
1068
|
-
|
|
1069
|
-
expect(model.counter).toBe(3);
|
|
1070
|
-
|
|
1071
|
-
model.someValue = undefined;
|
|
1072
|
-
await wait();
|
|
1073
|
-
|
|
1074
|
-
expect(model.counter).toBe(4);
|
|
1075
|
-
});
|
|
1076
|
-
|
|
1077
|
-
it("calls the listener function when a deeply nested watched value changes", async () => {
|
|
1078
|
-
model.counter = 0;
|
|
1079
|
-
model.someValue = { b: { c: { d: 1 } } };
|
|
1080
|
-
|
|
1081
|
-
model.$watch("someValue.b.c.d", function (newValue, oldValue, model) {
|
|
1082
|
-
model.counter++;
|
|
1083
|
-
});
|
|
1084
|
-
await wait();
|
|
1085
|
-
|
|
1086
|
-
expect(model.counter).toBe(0);
|
|
1087
|
-
|
|
1088
|
-
model.someValue.b.c.d = 2;
|
|
1089
|
-
await wait();
|
|
1090
|
-
|
|
1091
|
-
expect(model.counter).toBe(1);
|
|
1092
|
-
|
|
1093
|
-
model.someValue = { b: { c: { d: 3 } } };
|
|
1094
|
-
await wait();
|
|
1095
|
-
|
|
1096
|
-
expect(model.counter).toBe(2);
|
|
1097
|
-
});
|
|
1098
|
-
|
|
1099
|
-
it("call the listener function on correct listener", async () => {
|
|
1100
|
-
model.counter = 0;
|
|
1101
|
-
model.someValue = { b: { c: 1 } };
|
|
1102
|
-
|
|
1103
|
-
model.$watch("someValue.b.c", function (newValue, oldValue, model) {
|
|
1104
|
-
model.counter++;
|
|
1105
|
-
});
|
|
1106
|
-
|
|
1107
|
-
model.c = 5;
|
|
1108
|
-
await wait();
|
|
1109
|
-
|
|
1110
|
-
expect(model.counter).toBe(0);
|
|
1111
|
-
});
|
|
1112
|
-
|
|
1113
|
-
it("calls the listener function when a deeply nested watched value is initially undefined", async () => {
|
|
1114
|
-
model.counter = 0;
|
|
1115
|
-
model.someValue = { b: { c: undefined } };
|
|
1116
|
-
|
|
1117
|
-
model.$watch("someValue.b.c.d", function (newValue, oldValue, model) {
|
|
1118
|
-
model.counter++;
|
|
1119
|
-
});
|
|
1120
|
-
await wait();
|
|
1121
|
-
|
|
1122
|
-
expect(model.counter).toBe(0);
|
|
1123
|
-
|
|
1124
|
-
model.someValue = { b: { c: { d: 2 } } };
|
|
1125
|
-
await wait();
|
|
1126
|
-
|
|
1127
|
-
expect(model.counter).toBe(1);
|
|
1128
|
-
|
|
1129
|
-
model.someValue.b.c.d = 3;
|
|
1130
|
-
await wait();
|
|
1131
|
-
|
|
1132
|
-
expect(model.counter).toBe(2);
|
|
1133
|
-
});
|
|
1134
|
-
});
|
|
1135
|
-
|
|
1136
|
-
describe("inherited $watch", () => {
|
|
1137
|
-
it("should decrement the watcherCount when destroying a child model", () => {
|
|
1138
|
-
const child1 = model.$new();
|
|
1139
|
-
const child2 = model.$new();
|
|
1140
|
-
const grandChild1 = child1.$new();
|
|
1141
|
-
const grandChild2 = child2.$new();
|
|
1142
|
-
child1.$watch("a", () => {});
|
|
1143
|
-
child2.$watch("a", () => {});
|
|
1144
|
-
grandChild1.$watch("a", () => {});
|
|
1145
|
-
grandChild2.$watch("a", () => {});
|
|
1146
|
-
|
|
1147
|
-
expect(model.$$watchersCount).toBe(4);
|
|
1148
|
-
expect(child1.$$watchersCount).toBe(2);
|
|
1149
|
-
expect(child2.$$watchersCount).toBe(2);
|
|
1150
|
-
expect(grandChild1.$$watchersCount).toBe(1);
|
|
1151
|
-
expect(grandChild2.$$watchersCount).toBe(1);
|
|
1152
|
-
|
|
1153
|
-
grandChild2.$destroy();
|
|
1154
|
-
expect(child2.$$watchersCount).toBe(1);
|
|
1155
|
-
expect(model.$$watchersCount).toBe(3);
|
|
1156
|
-
child1.$destroy();
|
|
1157
|
-
expect(model.$$watchersCount).toBe(1);
|
|
1158
|
-
});
|
|
1159
|
-
|
|
1160
|
-
it("should decrement the watcherCount when calling the remove function", () => {
|
|
1161
|
-
const child1 = model.$new();
|
|
1162
|
-
const child2 = model.$new();
|
|
1163
|
-
const grandChild1 = child1.$new();
|
|
1164
|
-
const grandChild2 = child2.$new();
|
|
1165
|
-
let remove1 = child1.$watch("a", () => {});
|
|
1166
|
-
child2.$watch("a", () => {});
|
|
1167
|
-
grandChild1.$watch("a", () => {});
|
|
1168
|
-
let remove2 = grandChild2.$watch("a", () => {});
|
|
1169
|
-
|
|
1170
|
-
remove2();
|
|
1171
|
-
expect(grandChild2.$$watchersCount).toBe(0);
|
|
1172
|
-
expect(child2.$$watchersCount).toBe(1);
|
|
1173
|
-
expect(model.$$watchersCount).toBe(3);
|
|
1174
|
-
remove1();
|
|
1175
|
-
expect(grandChild1.$$watchersCount).toBe(1);
|
|
1176
|
-
expect(child1.$$watchersCount).toBe(1);
|
|
1177
|
-
expect(model.$$watchersCount).toBe(2);
|
|
1178
|
-
|
|
1179
|
-
// Execute everything a second time to be sure that calling the remove function
|
|
1180
|
-
// several times, it only decrements the counter once
|
|
1181
|
-
remove2();
|
|
1182
|
-
expect(child2.$$watchersCount).toBe(1);
|
|
1183
|
-
expect(model.$$watchersCount).toBe(2);
|
|
1184
|
-
remove1();
|
|
1185
|
-
expect(child1.$$watchersCount).toBe(1);
|
|
1186
|
-
expect(model.$$watchersCount).toBe(2);
|
|
1187
|
-
});
|
|
1188
|
-
|
|
1189
|
-
it("should call child $watchers in addition order", async () => {
|
|
1190
|
-
logs = "";
|
|
1191
|
-
const childA = model.$new();
|
|
1192
|
-
childA.$watch("a", () => {
|
|
1193
|
-
logs += "a";
|
|
1194
|
-
});
|
|
1195
|
-
childA.$watch("a", () => {
|
|
1196
|
-
logs += "b";
|
|
1197
|
-
});
|
|
1198
|
-
childA.$watch("a", () => {
|
|
1199
|
-
logs += "c";
|
|
1200
|
-
});
|
|
1201
|
-
childA.a = 1;
|
|
1202
|
-
await wait();
|
|
1203
|
-
expect(logs).toEqual("abc");
|
|
1204
|
-
});
|
|
1205
|
-
|
|
1206
|
-
it("should share listeners with parent", async () => {
|
|
1207
|
-
logs = "";
|
|
1208
|
-
const childA = model.$new();
|
|
1209
|
-
const childB = model.$new();
|
|
1210
|
-
|
|
1211
|
-
model.$watch("a", () => {
|
|
1212
|
-
logs += "r";
|
|
1213
|
-
});
|
|
1214
|
-
|
|
1215
|
-
childA.$watch("a", () => {
|
|
1216
|
-
logs += "a";
|
|
1217
|
-
});
|
|
1218
|
-
childB.$watch("a", () => {
|
|
1219
|
-
logs += "b";
|
|
1220
|
-
});
|
|
1221
|
-
|
|
1222
|
-
// init
|
|
1223
|
-
model.a = 1;
|
|
1224
|
-
await wait();
|
|
1225
|
-
expect(logs).toBe("rab");
|
|
1226
|
-
|
|
1227
|
-
logs = "";
|
|
1228
|
-
childA.a = 3;
|
|
1229
|
-
await wait();
|
|
1230
|
-
expect(logs).toBe("rab");
|
|
1231
|
-
|
|
1232
|
-
logs = "";
|
|
1233
|
-
childA.a = 4;
|
|
1234
|
-
await wait();
|
|
1235
|
-
expect(logs).toBe("rab");
|
|
1236
|
-
});
|
|
1237
|
-
|
|
1238
|
-
it("should repeat watch cycle from the root element", async () => {
|
|
1239
|
-
logs = "";
|
|
1240
|
-
const child = model.$new();
|
|
1241
|
-
model.$watch("c", () => {
|
|
1242
|
-
logs += "a";
|
|
1243
|
-
});
|
|
1244
|
-
child.$watch("c", () => {
|
|
1245
|
-
logs += "b";
|
|
1246
|
-
});
|
|
1247
|
-
model.c = 1;
|
|
1248
|
-
child.c = 2;
|
|
1249
|
-
await wait();
|
|
1250
|
-
expect(logs).toEqual("abab");
|
|
1251
|
-
});
|
|
1252
|
-
});
|
|
1253
|
-
|
|
1254
|
-
it("should watch functions", async () => {
|
|
1255
|
-
model.$watch("fn", (fn) => {
|
|
1256
|
-
logs.push(fn());
|
|
1257
|
-
});
|
|
1258
|
-
|
|
1259
|
-
model.fn = function () {
|
|
1260
|
-
return "a";
|
|
1261
|
-
};
|
|
1262
|
-
await wait();
|
|
1263
|
-
expect(logs).toEqual(["a"]);
|
|
1264
|
-
model.fn = function () {
|
|
1265
|
-
return "b";
|
|
1266
|
-
};
|
|
1267
|
-
await wait();
|
|
1268
|
-
expect(logs).toEqual(["a", "b"]);
|
|
1269
|
-
});
|
|
1270
|
-
|
|
1271
|
-
it("should prevent $watch recursion", async () => {
|
|
1272
|
-
let callCount = 0;
|
|
1273
|
-
model.$watch("name", () => {
|
|
1274
|
-
callCount++;
|
|
1275
|
-
expect(() => {}).toThrowMatching(/Maximum call stack size exceeded/);
|
|
1276
|
-
});
|
|
1277
|
-
model.name = "a";
|
|
1278
|
-
await wait();
|
|
1279
|
-
expect(callCount).toEqual(1);
|
|
1280
|
-
});
|
|
1281
|
-
|
|
1282
|
-
it("should allow a watch to be added while in a digest", async () => {
|
|
1283
|
-
const watch1 = jasmine.createSpy("watch1");
|
|
1284
|
-
const watch2 = jasmine.createSpy("watch2");
|
|
1285
|
-
model.$watch("foo", () => {
|
|
1286
|
-
model.$watch("foo", watch1);
|
|
1287
|
-
model.$watch("foo", watch2);
|
|
1288
|
-
});
|
|
1289
|
-
model.$apply("foo = true");
|
|
1290
|
-
await wait();
|
|
1291
|
-
expect(watch1).toHaveBeenCalled();
|
|
1292
|
-
expect(watch2).toHaveBeenCalled();
|
|
1293
|
-
});
|
|
1294
|
-
|
|
1295
|
-
it("should not skip watchers when adding new watchers during digest", async () => {
|
|
1296
|
-
const watch1 = jasmine.createSpy("watch1");
|
|
1297
|
-
const watch2 = jasmine.createSpy("watch2");
|
|
1298
|
-
model.$watch("foo", () => {
|
|
1299
|
-
model.$watch("foo", watch1);
|
|
1300
|
-
model.$watch("foo", watch2);
|
|
1301
|
-
});
|
|
1302
|
-
model.foo = "a";
|
|
1303
|
-
await wait();
|
|
1304
|
-
expect(watch1).toHaveBeenCalled();
|
|
1305
|
-
expect(watch2).toHaveBeenCalled();
|
|
1306
|
-
});
|
|
1307
|
-
|
|
1308
|
-
it("should not skip watchers when adding new watchers during property update", async () => {
|
|
1309
|
-
const watch1 = jasmine.createSpy("watch1");
|
|
1310
|
-
const watch2 = jasmine.createSpy("watch2");
|
|
1311
|
-
model.$watch("foo", () => {
|
|
1312
|
-
model.$watch("foo", watch1);
|
|
1313
|
-
model.$watch("foo", watch2);
|
|
1314
|
-
});
|
|
1315
|
-
model.foo = 2;
|
|
1316
|
-
await wait();
|
|
1317
|
-
expect(watch1).toHaveBeenCalled();
|
|
1318
|
-
expect(watch2).toHaveBeenCalled();
|
|
1319
|
-
});
|
|
1320
|
-
|
|
1321
|
-
describe("$watch deregistration", () => {
|
|
1322
|
-
beforeEach(() => (logs = []));
|
|
1323
|
-
it("should return a function that allows listeners to be deregistered", async () => {
|
|
1324
|
-
const listener = jasmine.createSpy("watch listener");
|
|
1325
|
-
let listenerRemove;
|
|
1326
|
-
|
|
1327
|
-
listenerRemove = model.$watch("foo", listener);
|
|
1328
|
-
|
|
1329
|
-
expect(listener).not.toHaveBeenCalled();
|
|
1330
|
-
expect(listenerRemove).toBeDefined();
|
|
1331
|
-
|
|
1332
|
-
model.foo = "bar";
|
|
1333
|
-
await wait();
|
|
1334
|
-
expect(listener).toHaveBeenCalled();
|
|
1335
|
-
|
|
1336
|
-
listener.calls.reset();
|
|
1337
|
-
listenerRemove();
|
|
1338
|
-
model.foo = "baz";
|
|
1339
|
-
await wait();
|
|
1340
|
-
expect(listener).not.toHaveBeenCalled();
|
|
1341
|
-
});
|
|
1342
|
-
|
|
1343
|
-
it("should allow a watch to be deregistered while in a digest", async () => {
|
|
1344
|
-
let remove1;
|
|
1345
|
-
let remove2;
|
|
1346
|
-
model.$watch("remove", () => {
|
|
1347
|
-
remove1();
|
|
1348
|
-
remove2();
|
|
1349
|
-
});
|
|
1350
|
-
remove1 = model.$watch("thing", () => {});
|
|
1351
|
-
remove2 = model.$watch("thing", () => {});
|
|
1352
|
-
expect(async () => {
|
|
1353
|
-
model.$apply("remove = true");
|
|
1354
|
-
await wait();
|
|
1355
|
-
}).not.toThrow();
|
|
1356
|
-
});
|
|
1357
|
-
});
|
|
1358
|
-
|
|
1359
|
-
describe("watching arrays", () => {
|
|
1360
|
-
it("can watch arrays", async () => {
|
|
1361
|
-
model.aValue = [1, 2, 3];
|
|
1362
|
-
model.counter = 0;
|
|
1363
|
-
model.$watch("aValue", function (newValue, oldValue, m) {
|
|
1364
|
-
m.counter++;
|
|
1365
|
-
});
|
|
1366
|
-
expect(model.counter).toBe(0);
|
|
1367
|
-
model.aValue.push(4);
|
|
1368
|
-
await wait();
|
|
1369
|
-
expect(model.counter).toBe(1);
|
|
1370
|
-
|
|
1371
|
-
model.aValue.pop();
|
|
1372
|
-
await wait();
|
|
1373
|
-
expect(model.counter).toBe(2);
|
|
1374
|
-
});
|
|
1375
|
-
|
|
1376
|
-
it("can pass the new value of the array as well as the previous value of the dropped item", async () => {
|
|
1377
|
-
model.aValue = [];
|
|
1378
|
-
var oldValueGiven;
|
|
1379
|
-
var newValueGiven;
|
|
1380
|
-
model.$watch("aValue", function (newValue, oldValue) {
|
|
1381
|
-
newValueGiven = newValue;
|
|
1382
|
-
oldValueGiven = oldValue;
|
|
1383
|
-
});
|
|
1384
|
-
|
|
1385
|
-
model.aValue.push(4);
|
|
1386
|
-
await wait();
|
|
1387
|
-
expect(newValueGiven).toEqual([4]);
|
|
1388
|
-
expect(oldValueGiven).toBe(undefined);
|
|
1389
|
-
|
|
1390
|
-
model.aValue.push(5);
|
|
1391
|
-
await wait();
|
|
1392
|
-
expect(newValueGiven).toEqual([4, 5]);
|
|
1393
|
-
expect(oldValueGiven).toBe(undefined);
|
|
1394
|
-
|
|
1395
|
-
model.aValue[1] = 2;
|
|
1396
|
-
await wait();
|
|
1397
|
-
expect(newValueGiven).toEqual([4, 2]);
|
|
1398
|
-
expect(oldValueGiven).toBe(5);
|
|
1399
|
-
});
|
|
1400
|
-
|
|
1401
|
-
it("can detect removal of items", async () => {
|
|
1402
|
-
model.aValue = [2, 3];
|
|
1403
|
-
var oldValueGiven;
|
|
1404
|
-
var newValueGiven;
|
|
1405
|
-
model.$watch("aValue", function (newValue, oldValue) {
|
|
1406
|
-
newValueGiven = newValue;
|
|
1407
|
-
oldValueGiven = oldValue;
|
|
1408
|
-
});
|
|
1409
|
-
|
|
1410
|
-
model.aValue.pop();
|
|
1411
|
-
await wait();
|
|
1412
|
-
expect(newValueGiven).toEqual([2]);
|
|
1413
|
-
expect(oldValueGiven).toEqual([2, 3]);
|
|
1414
|
-
});
|
|
1415
|
-
|
|
1416
|
-
it("should return oldCollection === newCollection only on the first listener call", async () => {
|
|
1417
|
-
// first time should be identical
|
|
1418
|
-
model.aValue = ["a", "b"];
|
|
1419
|
-
model.counter = 0;
|
|
1420
|
-
var newValueGiven;
|
|
1421
|
-
model.$watch("aValue", function (newValue, oldValue, m) {
|
|
1422
|
-
newValueGiven = newValue;
|
|
1423
|
-
m.counter++;
|
|
1424
|
-
});
|
|
1425
|
-
await wait();
|
|
1426
|
-
expect(model.counter).toBe(0);
|
|
1427
|
-
|
|
1428
|
-
model.aValue[1] = "c";
|
|
1429
|
-
await wait();
|
|
1430
|
-
expect(newValueGiven).toEqual(["a", "c"]);
|
|
1431
|
-
expect(model.counter).toBe(1);
|
|
1432
|
-
});
|
|
1433
|
-
|
|
1434
|
-
it("should trigger when property changes into array", async () => {
|
|
1435
|
-
model.aValue = "test";
|
|
1436
|
-
model.counter = 0;
|
|
1437
|
-
var newValue, oldValue;
|
|
1438
|
-
model.$watch("aValue", function (newV, oldV, m) {
|
|
1439
|
-
m.counter++;
|
|
1440
|
-
newValue = newV;
|
|
1441
|
-
oldValue = oldV;
|
|
1442
|
-
});
|
|
1443
|
-
|
|
1444
|
-
model.aValue = [];
|
|
1445
|
-
await wait();
|
|
1446
|
-
expect(model.counter).toBe(1);
|
|
1447
|
-
expect(newValue).toEqual([]);
|
|
1448
|
-
expect(oldValue).toEqual("test");
|
|
1449
|
-
|
|
1450
|
-
model.aValue = {};
|
|
1451
|
-
await wait();
|
|
1452
|
-
expect(model.counter).toBe(2);
|
|
1453
|
-
expect(newValue).toEqual({});
|
|
1454
|
-
expect(oldValue).toEqual([]);
|
|
1455
|
-
|
|
1456
|
-
model.aValue = [];
|
|
1457
|
-
await wait();
|
|
1458
|
-
expect(model.counter).toBe(3);
|
|
1459
|
-
expect(newValue).toEqual([]);
|
|
1460
|
-
expect(oldValue).toEqual({});
|
|
1461
|
-
|
|
1462
|
-
model.aValue = {};
|
|
1463
|
-
await wait();
|
|
1464
|
-
expect(model.counter).toBe(4);
|
|
1465
|
-
|
|
1466
|
-
model.aValue = undefined;
|
|
1467
|
-
await wait();
|
|
1468
|
-
expect(model.counter).toBe(5);
|
|
1469
|
-
expect(newValue).toEqual(undefined);
|
|
1470
|
-
expect(oldValue).toEqual({});
|
|
1471
|
-
});
|
|
1472
|
-
|
|
1473
|
-
it("should allow deregistration", async () => {
|
|
1474
|
-
model.obj = [];
|
|
1475
|
-
count = 0;
|
|
1476
|
-
let deregister = model.$watch("obj", (newVal) => {
|
|
1477
|
-
logs.push(newVal);
|
|
1478
|
-
count++;
|
|
1479
|
-
});
|
|
1480
|
-
|
|
1481
|
-
model.obj.push("a");
|
|
1482
|
-
await wait();
|
|
1483
|
-
expect(logs.length).toBe(1);
|
|
1484
|
-
expect(count).toEqual(1);
|
|
1485
|
-
|
|
1486
|
-
model.obj.push("a");
|
|
1487
|
-
await wait();
|
|
1488
|
-
expect(logs.length).toBe(2);
|
|
1489
|
-
expect(count).toEqual(2);
|
|
1490
|
-
|
|
1491
|
-
deregister();
|
|
1492
|
-
model.obj.push("a");
|
|
1493
|
-
await wait();
|
|
1494
|
-
expect(logs.length).toBe(2);
|
|
1495
|
-
expect(count).toEqual(2);
|
|
1496
|
-
});
|
|
1497
|
-
|
|
1498
|
-
// it("should not trigger change when object in collection changes", () => {
|
|
1499
|
-
// model.obj = [{}];
|
|
1500
|
-
|
|
1501
|
-
// expect(logs).toEqual([
|
|
1502
|
-
// { newVal: [{}], oldVal: [{}], identical: true },
|
|
1503
|
-
// ]);
|
|
1504
|
-
|
|
1505
|
-
// logs = [];
|
|
1506
|
-
// model.obj[0].name = "foo";
|
|
1507
|
-
|
|
1508
|
-
// expect(logs).toEqual([]);
|
|
1509
|
-
// });
|
|
1510
|
-
|
|
1511
|
-
// it("should watch array properties", () => {
|
|
1512
|
-
// model.obj = [];
|
|
1513
|
-
|
|
1514
|
-
// expect(logs).toEqual([{ newVal: [], oldVal: [], identical: true }]);
|
|
1515
|
-
|
|
1516
|
-
// logs = [];
|
|
1517
|
-
// model.obj.push("a");
|
|
1518
|
-
|
|
1519
|
-
// expect(logs).toEqual([{ newVal: ["a"], oldVal: [] }]);
|
|
1520
|
-
|
|
1521
|
-
// logs = [];
|
|
1522
|
-
// model.obj[0] = "b";
|
|
1523
|
-
|
|
1524
|
-
// expect(logs).toEqual([{ newVal: ["b"], oldVal: ["a"] }]);
|
|
1525
|
-
|
|
1526
|
-
// logs = [];
|
|
1527
|
-
// model.obj.push([]);
|
|
1528
|
-
// model.obj.push({});
|
|
1529
|
-
|
|
1530
|
-
// expect(logs).toEqual([{ newVal: ["b", [], {}], oldVal: ["b"] }]);
|
|
1531
|
-
|
|
1532
|
-
// logs = [];
|
|
1533
|
-
// const temp = model.obj[1];
|
|
1534
|
-
// model.obj[1] = model.obj[2];
|
|
1535
|
-
// model.obj[2] = temp;
|
|
1536
|
-
|
|
1537
|
-
// expect(logs).toEqual([
|
|
1538
|
-
// { newVal: ["b", {}, []], oldVal: ["b", [], {}] },
|
|
1539
|
-
// ]);
|
|
1540
|
-
|
|
1541
|
-
// logs = [];
|
|
1542
|
-
// model.obj.shift();
|
|
1543
|
-
|
|
1544
|
-
// expect(logs).toEqual([{ newVal: [{}, []], oldVal: ["b", {}, []] }]);
|
|
1545
|
-
// });
|
|
1546
|
-
|
|
1547
|
-
// it("should not infinitely digest when current value is NaN", () => {
|
|
1548
|
-
// model.obj = [NaN];
|
|
1549
|
-
// expect(() => {
|
|
1550
|
-
|
|
1551
|
-
// }).not.toThrow();
|
|
1552
|
-
// });
|
|
1553
|
-
|
|
1554
|
-
// it("should watch array-like objects like arrays", () => {
|
|
1555
|
-
// logs = [];
|
|
1556
|
-
// model.obj = document.getElementsByTagName("src");
|
|
1557
|
-
|
|
1558
|
-
// expect(logs.length).toBeTruthy();
|
|
1559
|
-
// });
|
|
1560
|
-
});
|
|
1561
|
-
|
|
1562
|
-
describe("watching other proxies", () => {
|
|
1563
|
-
it("should detect changes on another proxy", async () => {
|
|
1564
|
-
let model1 = createModel();
|
|
1565
|
-
let model2 = createModel({ b: 2 });
|
|
1566
|
-
let count = 0;
|
|
1567
|
-
|
|
1568
|
-
model1.service = model2;
|
|
1569
|
-
model1.$watch("service.b", () => {
|
|
1570
|
-
count++;
|
|
1571
|
-
});
|
|
1572
|
-
|
|
1573
|
-
model2.$watch("b", () => {
|
|
1574
|
-
count++;
|
|
1575
|
-
});
|
|
1576
|
-
|
|
1577
|
-
model2.b = 1;
|
|
1578
|
-
await wait();
|
|
1579
|
-
|
|
1580
|
-
expect(count).toBe(2);
|
|
1581
|
-
});
|
|
1582
|
-
});
|
|
1583
|
-
|
|
1584
|
-
describe("$watch", () => {
|
|
1585
|
-
describe("constiable", () => {
|
|
1586
|
-
let deregister;
|
|
1587
|
-
beforeEach(() => {
|
|
1588
|
-
logs = [];
|
|
1589
|
-
deregister = model.$watch("obj", (newVal, oldVal) => {
|
|
1590
|
-
const msg = { newVal, oldVal };
|
|
1591
|
-
|
|
1592
|
-
if (newVal === oldVal) {
|
|
1593
|
-
msg.identical = true;
|
|
1594
|
-
}
|
|
1595
|
-
logs.push(msg);
|
|
1596
|
-
});
|
|
1597
|
-
});
|
|
1598
|
-
|
|
1599
|
-
describe("object", () => {
|
|
1600
|
-
it("should return oldCollection === newCollection only on the first listener call", () => {
|
|
1601
|
-
model.obj = { a: "b" };
|
|
1602
|
-
// first time should be identical
|
|
1603
|
-
|
|
1604
|
-
expect(logs).toEqual([
|
|
1605
|
-
{ newVal: { a: "b" }, oldVal: { a: "b" }, identical: true },
|
|
1606
|
-
]);
|
|
1607
|
-
logs = [];
|
|
1608
|
-
|
|
1609
|
-
// second time not identical
|
|
1610
|
-
model.obj.a = "c";
|
|
1611
|
-
|
|
1612
|
-
expect(logs).toEqual([{ newVal: { a: "c" }, oldVal: { a: "b" } }]);
|
|
1613
|
-
});
|
|
1614
|
-
|
|
1615
|
-
it("should trigger when property changes into object", () => {
|
|
1616
|
-
model.obj = "test";
|
|
1617
|
-
|
|
1618
|
-
expect(logs).toEqual([
|
|
1619
|
-
{ newVal: "test", oldVal: "test", identical: true },
|
|
1620
|
-
]);
|
|
1621
|
-
logs = [];
|
|
1622
|
-
|
|
1623
|
-
model.obj = {};
|
|
1624
|
-
|
|
1625
|
-
expect(logs).toEqual([{ newVal: {}, oldVal: "test" }]);
|
|
1626
|
-
});
|
|
1627
|
-
|
|
1628
|
-
it("should not trigger change when object in collection changes", () => {
|
|
1629
|
-
model.obj = { name: {} };
|
|
1630
|
-
|
|
1631
|
-
expect(logs).toEqual([
|
|
1632
|
-
{ newVal: { name: {} }, oldVal: { name: {} }, identical: true },
|
|
1633
|
-
]);
|
|
1634
|
-
logs = [];
|
|
1635
|
-
|
|
1636
|
-
model.obj.name.bar = "foo";
|
|
1637
|
-
|
|
1638
|
-
expect(logs).toEqual([]);
|
|
1639
|
-
});
|
|
1640
|
-
|
|
1641
|
-
it("should watch object properties", () => {
|
|
1642
|
-
model.obj = {};
|
|
1643
|
-
|
|
1644
|
-
expect(logs).toEqual([{ newVal: {}, oldVal: {}, identical: true }]);
|
|
1645
|
-
logs = [];
|
|
1646
|
-
model.obj.a = "A";
|
|
1647
|
-
|
|
1648
|
-
expect(logs).toEqual([{ newVal: { a: "A" }, oldVal: {} }]);
|
|
1649
|
-
|
|
1650
|
-
logs = [];
|
|
1651
|
-
model.obj.a = "B";
|
|
1652
|
-
|
|
1653
|
-
expect(logs).toEqual([{ newVal: { a: "B" }, oldVal: { a: "A" } }]);
|
|
1654
|
-
|
|
1655
|
-
logs = [];
|
|
1656
|
-
model.obj.b = [];
|
|
1657
|
-
model.obj.c = {};
|
|
1658
|
-
|
|
1659
|
-
expect(logs).toEqual([
|
|
1660
|
-
{ newVal: { a: "B", b: [], c: {} }, oldVal: { a: "B" } },
|
|
1661
|
-
]);
|
|
1662
|
-
|
|
1663
|
-
logs = [];
|
|
1664
|
-
const temp = model.obj.a;
|
|
1665
|
-
model.obj.a = model.obj.b;
|
|
1666
|
-
model.obj.c = temp;
|
|
1667
|
-
|
|
1668
|
-
expect(logs).toEqual([
|
|
1669
|
-
{
|
|
1670
|
-
newVal: { a: [], b: [], c: "B" },
|
|
1671
|
-
oldVal: { a: "B", b: [], c: {} },
|
|
1672
|
-
},
|
|
1673
|
-
]);
|
|
1674
|
-
|
|
1675
|
-
logs = [];
|
|
1676
|
-
delete model.obj.a;
|
|
1677
|
-
|
|
1678
|
-
expect(logs).toEqual([
|
|
1679
|
-
{ newVal: { b: [], c: "B" }, oldVal: { a: [], b: [], c: "B" } },
|
|
1680
|
-
]);
|
|
1681
|
-
});
|
|
1682
|
-
|
|
1683
|
-
it("should not infinitely digest when current value is NaN", () => {
|
|
1684
|
-
model.obj = { a: NaN };
|
|
1685
|
-
expect(() => {}).not.toThrow();
|
|
1686
|
-
});
|
|
1687
|
-
|
|
1688
|
-
it("should handle objects created using `Object.create(null)`", () => {
|
|
1689
|
-
model.obj = Object.create(null);
|
|
1690
|
-
model.obj.a = "a";
|
|
1691
|
-
model.obj.b = "b";
|
|
1692
|
-
|
|
1693
|
-
expect(logs[0].newVal).toEqual(
|
|
1694
|
-
extend(Object.create(null), { a: "a", b: "b" }),
|
|
1695
|
-
);
|
|
1696
|
-
|
|
1697
|
-
delete model.obj.b;
|
|
1698
|
-
|
|
1699
|
-
expect(logs[0].newVal).toEqual(
|
|
1700
|
-
extend(Object.create(null), { a: "a" }),
|
|
1701
|
-
);
|
|
1702
|
-
});
|
|
1703
|
-
});
|
|
1704
|
-
});
|
|
1705
|
-
|
|
1706
|
-
describe("literal", () => {
|
|
1707
|
-
describe("array", () => {
|
|
1708
|
-
beforeEach(() => {
|
|
1709
|
-
logs = [];
|
|
1710
|
-
model.$watch("[obj]", (newVal, oldVal) => {
|
|
1711
|
-
const msg = { newVal, oldVal };
|
|
1712
|
-
|
|
1713
|
-
if (newVal === oldVal) {
|
|
1714
|
-
msg.identical = true;
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1717
|
-
logs.push(msg);
|
|
1718
|
-
});
|
|
1719
|
-
});
|
|
1720
|
-
|
|
1721
|
-
it("should return oldCollection === newCollection only on the first listener call", () => {
|
|
1722
|
-
// first time should be identical
|
|
1723
|
-
model.obj = "a";
|
|
1724
|
-
|
|
1725
|
-
expect(logs).toEqual([
|
|
1726
|
-
{ newVal: ["a"], oldVal: ["a"], identical: true },
|
|
1727
|
-
]);
|
|
1728
|
-
logs = [];
|
|
1729
|
-
|
|
1730
|
-
// second time should be different
|
|
1731
|
-
model.obj = "b";
|
|
1732
|
-
|
|
1733
|
-
expect(logs).toEqual([{ newVal: ["b"], oldVal: ["a"] }]);
|
|
1734
|
-
});
|
|
1735
|
-
|
|
1736
|
-
it("should trigger when property changes into array", () => {
|
|
1737
|
-
model.obj = "test";
|
|
1738
|
-
|
|
1739
|
-
expect(logs).toEqual([
|
|
1740
|
-
{ newVal: ["test"], oldVal: ["test"], identical: true },
|
|
1741
|
-
]);
|
|
1742
|
-
|
|
1743
|
-
logs = [];
|
|
1744
|
-
model.obj = [];
|
|
1745
|
-
|
|
1746
|
-
expect(logs).toEqual([{ newVal: [[]], oldVal: ["test"] }]);
|
|
1747
|
-
|
|
1748
|
-
logs = [];
|
|
1749
|
-
model.obj = {};
|
|
1750
|
-
|
|
1751
|
-
expect(logs).toEqual([{ newVal: [{}], oldVal: [[]] }]);
|
|
1752
|
-
|
|
1753
|
-
logs = [];
|
|
1754
|
-
model.obj = [];
|
|
1755
|
-
|
|
1756
|
-
expect(logs).toEqual([{ newVal: [[]], oldVal: [{}] }]);
|
|
1757
|
-
|
|
1758
|
-
logs = [];
|
|
1759
|
-
model.obj = undefined;
|
|
1760
|
-
|
|
1761
|
-
expect(logs).toEqual([{ newVal: [undefined], oldVal: [[]] }]);
|
|
1762
|
-
});
|
|
1763
|
-
|
|
1764
|
-
it("should not trigger change when object in collection changes", () => {
|
|
1765
|
-
model.obj = {};
|
|
1766
|
-
|
|
1767
|
-
expect(logs).toEqual([
|
|
1768
|
-
{ newVal: [{}], oldVal: [{}], identical: true },
|
|
1769
|
-
]);
|
|
1770
|
-
|
|
1771
|
-
logs = [];
|
|
1772
|
-
model.obj.name = "foo";
|
|
1773
|
-
|
|
1774
|
-
expect(logs).toEqual([]);
|
|
1775
|
-
});
|
|
1776
|
-
|
|
1777
|
-
it("should not infinitely digest when current value is NaN", () => {
|
|
1778
|
-
model.obj = NaN;
|
|
1779
|
-
expect(() => {}).not.toThrow();
|
|
1780
|
-
});
|
|
1781
|
-
});
|
|
1782
|
-
|
|
1783
|
-
describe("object", () => {
|
|
1784
|
-
beforeEach(() => {
|
|
1785
|
-
logs = [];
|
|
1786
|
-
model.$watch("{a: obj}", (newVal, oldVal) => {
|
|
1787
|
-
const msg = { newVal, oldVal };
|
|
1788
|
-
|
|
1789
|
-
if (newVal === oldVal) {
|
|
1790
|
-
msg.identical = true;
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
logs.push(msg);
|
|
1794
|
-
});
|
|
1795
|
-
});
|
|
1796
|
-
|
|
1797
|
-
it("should return oldCollection === newCollection only on the first listener call", () => {
|
|
1798
|
-
model.obj = "b";
|
|
1799
|
-
// first time should be identical
|
|
1800
|
-
|
|
1801
|
-
expect(logs).toEqual([
|
|
1802
|
-
{ newVal: { a: "b" }, oldVal: { a: "b" }, identical: true },
|
|
1803
|
-
]);
|
|
1804
|
-
|
|
1805
|
-
// second time not identical
|
|
1806
|
-
logs = [];
|
|
1807
|
-
model.obj = "c";
|
|
1808
|
-
|
|
1809
|
-
expect(logs).toEqual([{ newVal: { a: "c" }, oldVal: { a: "b" } }]);
|
|
1810
|
-
});
|
|
1811
|
-
|
|
1812
|
-
it("should trigger when property changes into object", () => {
|
|
1813
|
-
model.obj = "test";
|
|
1814
|
-
|
|
1815
|
-
expect(logs).toEqual([
|
|
1816
|
-
{ newVal: { a: "test" }, oldVal: { a: "test" }, identical: true },
|
|
1817
|
-
]);
|
|
1818
|
-
|
|
1819
|
-
logs = [];
|
|
1820
|
-
model.obj = {};
|
|
1821
|
-
|
|
1822
|
-
expect(logs).toEqual([
|
|
1823
|
-
{ newVal: { a: {} }, oldVal: { a: "test" } },
|
|
1824
|
-
]);
|
|
1825
|
-
});
|
|
1826
|
-
|
|
1827
|
-
it("should not trigger change when object in collection changes", () => {
|
|
1828
|
-
model.obj = { name: "foo" };
|
|
1829
|
-
|
|
1830
|
-
expect(logs).toEqual([
|
|
1831
|
-
{
|
|
1832
|
-
newVal: { a: { name: "foo" } },
|
|
1833
|
-
oldVal: { a: { name: "foo" } },
|
|
1834
|
-
identical: true,
|
|
1835
|
-
},
|
|
1836
|
-
]);
|
|
1837
|
-
|
|
1838
|
-
logs = [];
|
|
1839
|
-
model.obj.name = "bar";
|
|
1840
|
-
|
|
1841
|
-
expect(logs).toEqual([]);
|
|
1842
|
-
});
|
|
1843
|
-
|
|
1844
|
-
it("should watch object properties", () => {
|
|
1845
|
-
model.obj = {};
|
|
1846
|
-
|
|
1847
|
-
expect(logs).toEqual([
|
|
1848
|
-
{ newVal: { a: {} }, oldVal: { a: {} }, identical: true },
|
|
1849
|
-
]);
|
|
1850
|
-
|
|
1851
|
-
logs = [];
|
|
1852
|
-
model.obj = "A";
|
|
1853
|
-
|
|
1854
|
-
expect(logs).toEqual([{ newVal: { a: "A" }, oldVal: { a: {} } }]);
|
|
1855
|
-
|
|
1856
|
-
logs = [];
|
|
1857
|
-
model.obj = "B";
|
|
1858
|
-
|
|
1859
|
-
expect(logs).toEqual([{ newVal: { a: "B" }, oldVal: { a: "A" } }]);
|
|
1860
|
-
|
|
1861
|
-
logs = [];
|
|
1862
|
-
model.obj = [];
|
|
1863
|
-
|
|
1864
|
-
expect(logs).toEqual([{ newVal: { a: [] }, oldVal: { a: "B" } }]);
|
|
1865
|
-
|
|
1866
|
-
logs = [];
|
|
1867
|
-
delete model.obj;
|
|
1868
|
-
|
|
1869
|
-
expect(logs).toEqual([
|
|
1870
|
-
{ newVal: { a: undefined }, oldVal: { a: [] } },
|
|
1871
|
-
]);
|
|
1872
|
-
});
|
|
1873
|
-
|
|
1874
|
-
it("should not infinitely digest when current value is NaN", () => {
|
|
1875
|
-
model.obj = NaN;
|
|
1876
|
-
expect(() => {}).not.toThrow();
|
|
1877
|
-
});
|
|
1878
|
-
});
|
|
1879
|
-
|
|
1880
|
-
describe("object computed property", () => {
|
|
1881
|
-
beforeEach(() => {
|
|
1882
|
-
logs = [];
|
|
1883
|
-
model.$watch("{[key]: obj}", (newVal, oldVal) => {
|
|
1884
|
-
const msg = { newVal, oldVal };
|
|
1885
|
-
|
|
1886
|
-
if (newVal === oldVal) {
|
|
1887
|
-
msg.identical = true;
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
|
-
logs.push(msg);
|
|
1891
|
-
});
|
|
1892
|
-
});
|
|
1893
|
-
|
|
1894
|
-
it('should default to "undefined" key', () => {
|
|
1895
|
-
model.obj = "test";
|
|
1896
|
-
|
|
1897
|
-
expect(logs).toEqual([
|
|
1898
|
-
{
|
|
1899
|
-
newVal: { undefined: "test" },
|
|
1900
|
-
oldVal: { undefined: "test" },
|
|
1901
|
-
identical: true,
|
|
1902
|
-
},
|
|
1903
|
-
]);
|
|
1904
|
-
});
|
|
1905
|
-
|
|
1906
|
-
it("should trigger when key changes", () => {
|
|
1907
|
-
model.key = "a";
|
|
1908
|
-
model.obj = "test";
|
|
1909
|
-
|
|
1910
|
-
expect(logs).toEqual([
|
|
1911
|
-
{ newVal: { a: "test" }, oldVal: { a: "test" }, identical: true },
|
|
1912
|
-
]);
|
|
1913
|
-
|
|
1914
|
-
logs = [];
|
|
1915
|
-
model.key = "b";
|
|
1916
|
-
|
|
1917
|
-
expect(logs).toEqual([
|
|
1918
|
-
{ newVal: { b: "test" }, oldVal: { a: "test" } },
|
|
1919
|
-
]);
|
|
1920
|
-
|
|
1921
|
-
logs = [];
|
|
1922
|
-
model.key = true;
|
|
1923
|
-
|
|
1924
|
-
expect(logs).toEqual([
|
|
1925
|
-
{ newVal: { true: "test" }, oldVal: { b: "test" } },
|
|
1926
|
-
]);
|
|
1927
|
-
});
|
|
1928
|
-
|
|
1929
|
-
it("should not trigger when key changes but stringified key does not", () => {
|
|
1930
|
-
model.key = 1;
|
|
1931
|
-
model.obj = "test";
|
|
1932
|
-
|
|
1933
|
-
expect(logs).toEqual([
|
|
1934
|
-
{ newVal: { 1: "test" }, oldVal: { 1: "test" }, identical: true },
|
|
1935
|
-
]);
|
|
1936
|
-
|
|
1937
|
-
logs = [];
|
|
1938
|
-
model.key = "1";
|
|
1939
|
-
|
|
1940
|
-
expect(logs).toEqual([]);
|
|
1941
|
-
|
|
1942
|
-
model.key = true;
|
|
1943
|
-
|
|
1944
|
-
expect(logs).toEqual([
|
|
1945
|
-
{ newVal: { true: "test" }, oldVal: { 1: "test" } },
|
|
1946
|
-
]);
|
|
1947
|
-
|
|
1948
|
-
logs = [];
|
|
1949
|
-
model.key = "true";
|
|
1950
|
-
|
|
1951
|
-
expect(logs).toEqual([]);
|
|
1952
|
-
|
|
1953
|
-
logs = [];
|
|
1954
|
-
model.key = {};
|
|
1955
|
-
|
|
1956
|
-
expect(logs).toEqual([
|
|
1957
|
-
{
|
|
1958
|
-
newVal: { "[object Object]": "test" },
|
|
1959
|
-
oldVal: { true: "test" },
|
|
1960
|
-
},
|
|
1961
|
-
]);
|
|
1962
|
-
|
|
1963
|
-
logs = [];
|
|
1964
|
-
model.key = {};
|
|
1965
|
-
|
|
1966
|
-
expect(logs).toEqual([]);
|
|
1967
|
-
});
|
|
1968
|
-
|
|
1969
|
-
it("should not trigger change when object in collection changes", () => {
|
|
1970
|
-
model.key = "a";
|
|
1971
|
-
model.obj = { name: "foo" };
|
|
1972
|
-
|
|
1973
|
-
expect(logs).toEqual([
|
|
1974
|
-
{
|
|
1975
|
-
newVal: { a: { name: "foo" } },
|
|
1976
|
-
oldVal: { a: { name: "foo" } },
|
|
1977
|
-
identical: true,
|
|
1978
|
-
},
|
|
1979
|
-
]);
|
|
1980
|
-
logs = [];
|
|
1981
|
-
|
|
1982
|
-
model.obj.name = "bar";
|
|
1983
|
-
|
|
1984
|
-
expect(logs).toEqual([]);
|
|
1985
|
-
});
|
|
1986
|
-
|
|
1987
|
-
it("should not infinitely digest when key value is NaN", () => {
|
|
1988
|
-
model.key = NaN;
|
|
1989
|
-
model.obj = NaN;
|
|
1990
|
-
expect(() => {}).not.toThrow();
|
|
1991
|
-
});
|
|
1992
|
-
});
|
|
1993
|
-
});
|
|
1994
|
-
});
|
|
1995
|
-
|
|
1996
|
-
logs = [];
|
|
1997
|
-
function setupWatches(model, log) {
|
|
1998
|
-
model.$watch(() => {
|
|
1999
|
-
logs.push("w1");
|
|
2000
|
-
return model.w1;
|
|
2001
|
-
}, log("w1action"));
|
|
2002
|
-
model.$watch(() => {
|
|
2003
|
-
logs.push("w2");
|
|
2004
|
-
return model.w2;
|
|
2005
|
-
}, log("w2action"));
|
|
2006
|
-
model.$watch(() => {
|
|
2007
|
-
logs.push("w3");
|
|
2008
|
-
return model.w3;
|
|
2009
|
-
}, log("w3action"));
|
|
2010
|
-
console.error(logs.length);
|
|
2011
|
-
logs = [];
|
|
2012
|
-
}
|
|
2013
|
-
});
|
|
2014
|
-
|
|
2015
|
-
describe("$eval", () => {
|
|
2016
|
-
it("should eval an expression and modify the model", () => {
|
|
2017
|
-
expect(model.$eval("a=1")).toEqual(1);
|
|
2018
|
-
expect(model.a).toEqual(1);
|
|
2019
|
-
|
|
2020
|
-
model.$eval((self) => {
|
|
2021
|
-
self.b = 2;
|
|
2022
|
-
});
|
|
2023
|
-
expect(model.b).toEqual(2);
|
|
2024
|
-
});
|
|
2025
|
-
|
|
2026
|
-
it("executes $eval'ed function and returns result", function () {
|
|
2027
|
-
model.aValue = 42;
|
|
2028
|
-
var result = model.$eval(function (model) {
|
|
2029
|
-
return model.aValue;
|
|
2030
|
-
});
|
|
2031
|
-
expect(result).toBe(42);
|
|
2032
|
-
});
|
|
2033
|
-
|
|
2034
|
-
it("passes the second $eval argument straight through", function () {
|
|
2035
|
-
model.aValue = 42;
|
|
2036
|
-
var result = model.$eval(function (model, arg) {
|
|
2037
|
-
return model.aValue + arg;
|
|
2038
|
-
}, 2);
|
|
2039
|
-
expect(result).toBe(44);
|
|
2040
|
-
});
|
|
2041
|
-
|
|
2042
|
-
it("should allow passing locals to the expression", () => {
|
|
2043
|
-
expect(model.$eval("a+1", { a: 2 })).toBe(3);
|
|
2044
|
-
|
|
2045
|
-
model.$eval(
|
|
2046
|
-
(model, locals) => {
|
|
2047
|
-
model.c = locals.b + 4;
|
|
2048
|
-
},
|
|
2049
|
-
{ b: 3 },
|
|
2050
|
-
);
|
|
2051
|
-
expect(model.c).toBe(7);
|
|
2052
|
-
});
|
|
2053
|
-
});
|
|
2054
|
-
|
|
2055
|
-
describe("$apply", () => {
|
|
2056
|
-
beforeEach(() => (logs = []));
|
|
2057
|
-
|
|
2058
|
-
it("should eval an expression, modify the model and trigger the watches", async () => {
|
|
2059
|
-
let counter = 0;
|
|
2060
|
-
model.$watch("a", () => {
|
|
2061
|
-
counter++;
|
|
2062
|
-
});
|
|
2063
|
-
|
|
2064
|
-
model.$apply("a=1");
|
|
2065
|
-
await wait();
|
|
2066
|
-
expect(counter).toEqual(1);
|
|
2067
|
-
});
|
|
2068
|
-
|
|
2069
|
-
it("should update the model and add values", async () => {
|
|
2070
|
-
model.$apply("a=1");
|
|
2071
|
-
await wait();
|
|
2072
|
-
expect(model.a).toEqual(1);
|
|
2073
|
-
});
|
|
2074
|
-
|
|
2075
|
-
it("should update the model and remove values", async () => {
|
|
2076
|
-
model.a = 2;
|
|
2077
|
-
model.$apply("a=null");
|
|
2078
|
-
await wait();
|
|
2079
|
-
expect(model.a).toBeNull();
|
|
2080
|
-
});
|
|
2081
|
-
|
|
2082
|
-
it("should update the model and modify objects", async () => {
|
|
2083
|
-
model.$apply("a={b: 2}");
|
|
2084
|
-
await wait();
|
|
2085
|
-
expect(model.a.b).toEqual(2);
|
|
2086
|
-
|
|
2087
|
-
model.$apply("a.b = 3");
|
|
2088
|
-
await wait();
|
|
2089
|
-
expect(model.a.b).toEqual(3);
|
|
2090
|
-
|
|
2091
|
-
model.$apply("a={c: 2}");
|
|
2092
|
-
await wait();
|
|
2093
|
-
expect(model.a.c).toEqual(2);
|
|
2094
|
-
expect(model.a.b).toBeUndefined();
|
|
2095
|
-
});
|
|
2096
|
-
|
|
2097
|
-
it("should update arrays", async () => {
|
|
2098
|
-
model.a = [];
|
|
2099
|
-
model.$watch("a", () => count++);
|
|
2100
|
-
|
|
2101
|
-
model.$apply("a.push(1)");
|
|
2102
|
-
|
|
2103
|
-
await wait();
|
|
2104
|
-
expect(model.a).toEqual([1]);
|
|
2105
|
-
expect(count).toEqual(1);
|
|
2106
|
-
|
|
2107
|
-
model.$apply("a.push(2)");
|
|
2108
|
-
|
|
2109
|
-
await wait();
|
|
2110
|
-
expect(model.a).toEqual([1, 2]);
|
|
2111
|
-
expect(count).toEqual(2);
|
|
2112
|
-
});
|
|
2113
|
-
|
|
2114
|
-
it("executes $apply'ed function and starts the digest", async () => {
|
|
2115
|
-
model.aValue = "someValue";
|
|
2116
|
-
model.counter = 0;
|
|
2117
|
-
model.$watch("aValue", () => model.counter++);
|
|
2118
|
-
expect(model.counter).toBe(0);
|
|
2119
|
-
|
|
2120
|
-
model.$apply(function (model) {
|
|
2121
|
-
model.aValue = "someOtherValue";
|
|
2122
|
-
});
|
|
2123
|
-
await wait();
|
|
2124
|
-
|
|
2125
|
-
expect(model.counter).toBe(1);
|
|
2126
|
-
});
|
|
2127
|
-
|
|
2128
|
-
it("should apply expression with full lifecycle", async () => {
|
|
2129
|
-
let log = "";
|
|
2130
|
-
const child = model.$new();
|
|
2131
|
-
model.$watch("a", (a) => {
|
|
2132
|
-
log += "1";
|
|
2133
|
-
});
|
|
2134
|
-
|
|
2135
|
-
child.$apply("a = 0");
|
|
2136
|
-
await wait();
|
|
2137
|
-
expect(log).toEqual("1");
|
|
2138
|
-
});
|
|
2139
|
-
|
|
2140
|
-
// it("should catch exceptions", () => {
|
|
2141
|
-
// let log = "";
|
|
2142
|
-
// const child = model.$new();
|
|
2143
|
-
// model.$watch("a", (a) => {
|
|
2144
|
-
// log += "1";
|
|
2145
|
-
// });
|
|
2146
|
-
// model.a = 0;
|
|
2147
|
-
// child.$apply(() => {
|
|
2148
|
-
// throw new Error("MyError");
|
|
2149
|
-
// });
|
|
2150
|
-
// expect(log).toEqual("1");
|
|
2151
|
-
// expect(logs[0].message).toEqual("MyError");
|
|
2152
|
-
// });
|
|
2153
|
-
|
|
2154
|
-
// it("should log exceptions from $digest", () => {
|
|
2155
|
-
// model.$watch("a", () => {
|
|
2156
|
-
// model.b++;
|
|
2157
|
-
// });
|
|
2158
|
-
// model.$watch("b", () => {
|
|
2159
|
-
// model.a++;
|
|
2160
|
-
// });
|
|
2161
|
-
// model.a = model.b = 0;
|
|
2162
|
-
|
|
2163
|
-
// expect(() => {
|
|
2164
|
-
// model.$apply();
|
|
2165
|
-
// }).toThrow();
|
|
2166
|
-
|
|
2167
|
-
// expect(logs[0]).toBeDefined();
|
|
2168
|
-
|
|
2169
|
-
// expect(model.$$phase).toBe(0);
|
|
2170
|
-
// });
|
|
2171
|
-
|
|
2172
|
-
// describe("exceptions", () => {
|
|
2173
|
-
// let log;
|
|
2174
|
-
|
|
2175
|
-
// beforeEach(() => {
|
|
2176
|
-
// logs = [];
|
|
2177
|
-
// log = "";
|
|
2178
|
-
// model.$watch(() => {
|
|
2179
|
-
// log += "$digest;";
|
|
2180
|
-
// });
|
|
2181
|
-
//
|
|
2182
|
-
// log = "";
|
|
2183
|
-
// });
|
|
2184
|
-
|
|
2185
|
-
// it("should execute and return value and update", () => {
|
|
2186
|
-
// model.name = "abc";
|
|
2187
|
-
// expect(model.$apply((model) => model.name)).toEqual("abc");
|
|
2188
|
-
// expect(log).toEqual("$digest;");
|
|
2189
|
-
// expect(logs).toEqual([]);
|
|
2190
|
-
// });
|
|
2191
|
-
|
|
2192
|
-
// it("should catch exception and update", () => {
|
|
2193
|
-
// const error = new Error("MyError");
|
|
2194
|
-
// model.$apply(() => {
|
|
2195
|
-
// throw error;
|
|
2196
|
-
// });
|
|
2197
|
-
// expect(log).toEqual("$digest;");
|
|
2198
|
-
// expect(logs).toEqual([error]);
|
|
2199
|
-
// });
|
|
2200
|
-
// });
|
|
2201
|
-
|
|
2202
|
-
// describe("recursive $apply protection", () => {
|
|
2203
|
-
// beforeEach(() => (logs = []));
|
|
2204
|
-
|
|
2205
|
-
// it("should throw an exception if $apply is called while an $apply is in progress", () => {
|
|
2206
|
-
// model.$apply(() => {
|
|
2207
|
-
// model.$apply();
|
|
2208
|
-
// });
|
|
2209
|
-
// expect(logs[0].message.match(/progress/g).length).toBeTruthy();
|
|
2210
|
-
// });
|
|
2211
|
-
|
|
2212
|
-
// it("should not clear the state when calling $apply during an $apply", () => {
|
|
2213
|
-
// model.$apply(() => {
|
|
2214
|
-
// model.$apply();
|
|
2215
|
-
// expect(logs[0].message.match(/progress/g).length).toBeTruthy();
|
|
2216
|
-
// logs = [];
|
|
2217
|
-
// model.$apply();
|
|
2218
|
-
// expect(logs[0].message.match(/progress/g).length).toBeTruthy();
|
|
2219
|
-
// });
|
|
2220
|
-
// logs = [];
|
|
2221
|
-
// model.$apply();
|
|
2222
|
-
// expect(logs).toEqual([]);
|
|
2223
|
-
// });
|
|
2224
|
-
|
|
2225
|
-
// it("should throw an exception if $apply is called while flushing evalAsync queue", () => {
|
|
2226
|
-
// model.$apply(() => {
|
|
2227
|
-
// model.$evalAsync(() => {
|
|
2228
|
-
// model.$apply();
|
|
2229
|
-
// });
|
|
2230
|
-
// });
|
|
2231
|
-
// expect(logs[0].message.match(/progress/g).length).toBeTruthy();
|
|
2232
|
-
// });
|
|
2233
|
-
|
|
2234
|
-
// it("should throw an exception if $apply is called while a watch is being initialized", () => {
|
|
2235
|
-
// const childmodel1 = model.$new();
|
|
2236
|
-
// childmodel1.$watch("x", () => {
|
|
2237
|
-
// childmodel1.$apply();
|
|
2238
|
-
// });
|
|
2239
|
-
// childmodel1.$apply();
|
|
2240
|
-
// expect(logs[0].message.match(/progress/g).length).toBeTruthy();
|
|
2241
|
-
// });
|
|
2242
|
-
|
|
2243
|
-
// it("should thrown an exception if $apply in called from a watch fn (after init)", () => {
|
|
2244
|
-
// const childmodel2 = model.$new();
|
|
2245
|
-
// childmodel2.$apply(() => {
|
|
2246
|
-
// childmodel2.$watch("x", (newVal, oldVal) => {
|
|
2247
|
-
// if (newVal !== oldVal) {
|
|
2248
|
-
// childmodel2.$apply();
|
|
2249
|
-
// }
|
|
2250
|
-
// });
|
|
2251
|
-
// });
|
|
2252
|
-
// childmodel2.$apply(() => {
|
|
2253
|
-
// childmodel2.x = "something";
|
|
2254
|
-
// });
|
|
2255
|
-
|
|
2256
|
-
// expect(logs[0].message.match(/progress/g).length).toBeTruthy();
|
|
2257
|
-
// });
|
|
2258
|
-
// });
|
|
2259
|
-
});
|
|
2260
|
-
|
|
2261
|
-
// describe("$applyAsync", () => {
|
|
2262
|
-
// beforeEach(() => (logs = []));
|
|
2263
|
-
// fit("should evaluate in the context of specific $model", () => {
|
|
2264
|
-
// const scope = model.$new();
|
|
2265
|
-
// let id = scope.$applyAsync('x = "CODE ORANGE"');
|
|
2266
|
-
|
|
2267
|
-
// $browser.cancel(id);
|
|
2268
|
-
// setTimeout(() => {
|
|
2269
|
-
// expect(scope.x).toBe("CODE ORANGE");
|
|
2270
|
-
// expect(scope.x).toBeUndefined();
|
|
2271
|
-
// });
|
|
2272
|
-
|
|
2273
|
-
// expect(scope.x).toBeUndefined();
|
|
2274
|
-
// });
|
|
2275
|
-
|
|
2276
|
-
// it("should evaluate queued expressions in order", () => {
|
|
2277
|
-
// model.x = [];
|
|
2278
|
-
// let id1 = model.$applyAsync('x.push("expr1")');
|
|
2279
|
-
// let id2 = model.$applyAsync('x.push("expr2")');
|
|
2280
|
-
|
|
2281
|
-
// $browser.cancel(id1);
|
|
2282
|
-
// $browser.cancel(id2);
|
|
2283
|
-
// setTimeout(() => {
|
|
2284
|
-
// expect(model.x).toEqual(["expr1", "expr2"]);
|
|
2285
|
-
// });
|
|
2286
|
-
// expect(model.x).toEqual([]);
|
|
2287
|
-
// });
|
|
2288
|
-
|
|
2289
|
-
// it("should evaluate subsequently queued items in same turn", () => {
|
|
2290
|
-
// model.x = [];
|
|
2291
|
-
// let id = model.$applyAsync(() => {
|
|
2292
|
-
// model.x.push("expr1");
|
|
2293
|
-
// model.$applyAsync('x.push("expr2")');
|
|
2294
|
-
// expect($browser.deferredFns.length).toBe(0);
|
|
2295
|
-
// });
|
|
2296
|
-
|
|
2297
|
-
// $browser.cancel(id);
|
|
2298
|
-
// setTimeout(() => {
|
|
2299
|
-
// expect(model.x).toEqual(["expr1", "expr2"]);
|
|
2300
|
-
// });
|
|
2301
|
-
// expect(model.x).toEqual([]);
|
|
2302
|
-
// });
|
|
2303
|
-
|
|
2304
|
-
// it("should pass thrown exceptions to $exceptionHandler", () => {
|
|
2305
|
-
// let id = model.$applyAsync(() => {
|
|
2306
|
-
// throw "OOPS";
|
|
2307
|
-
// });
|
|
2308
|
-
|
|
2309
|
-
// $browser.cancel(id);
|
|
2310
|
-
// expect(logs).toEqual([]);
|
|
2311
|
-
// setTimeout(() => expect(logs[0]).toEqual("OOPS"));
|
|
2312
|
-
// });
|
|
2313
|
-
|
|
2314
|
-
// it("should evaluate subsequent expressions after an exception is thrown", () => {
|
|
2315
|
-
// let id = model.$applyAsync(() => {
|
|
2316
|
-
// throw "OOPS";
|
|
2317
|
-
// });
|
|
2318
|
-
// let id2 = model.$applyAsync('x = "All good!"');
|
|
2319
|
-
|
|
2320
|
-
// $browser.cancel(id);
|
|
2321
|
-
// $browser.cancel(id2);
|
|
2322
|
-
// setTimeout(() => expect(model.x).toBe("All good!"));
|
|
2323
|
-
// expect(model.x).toBeUndefined();
|
|
2324
|
-
// });
|
|
2325
|
-
|
|
2326
|
-
// it("should be cancelled if a model digest occurs before the next tick", () => {
|
|
2327
|
-
// const cancel = spyOn($browser, "cancel").and.callThrough();
|
|
2328
|
-
// const expression = jasmine.createSpy("expr");
|
|
2329
|
-
|
|
2330
|
-
// model.$applyAsync(expression);
|
|
2331
|
-
|
|
2332
|
-
// expect(expression).toHaveBeenCalled();
|
|
2333
|
-
// expect(cancel).toHaveBeenCalled();
|
|
2334
|
-
// expression.calls.reset();
|
|
2335
|
-
// cancel.calls.reset();
|
|
2336
|
-
|
|
2337
|
-
// // assert that another digest won't call the function again
|
|
2338
|
-
|
|
2339
|
-
// expect(expression).not.toHaveBeenCalled();
|
|
2340
|
-
// expect(cancel).not.toHaveBeenCalled();
|
|
2341
|
-
// });
|
|
2342
|
-
// });
|
|
2343
|
-
|
|
2344
|
-
describe("$postUpdate", () => {
|
|
2345
|
-
beforeEach(() => (logs = []));
|
|
2346
|
-
it("should process callbacks as a queue (FIFO) when the model is digested", async () => {
|
|
2347
|
-
let signature = "";
|
|
2348
|
-
|
|
2349
|
-
model.$postUpdate(() => {
|
|
2350
|
-
signature += "A";
|
|
2351
|
-
model.$postUpdate(() => {
|
|
2352
|
-
signature += "D";
|
|
2353
|
-
});
|
|
2354
|
-
});
|
|
2355
|
-
|
|
2356
|
-
model.$postUpdate(() => {
|
|
2357
|
-
signature += "B";
|
|
2358
|
-
});
|
|
2359
|
-
|
|
2360
|
-
model.$postUpdate(() => {
|
|
2361
|
-
signature += "C";
|
|
2362
|
-
});
|
|
2363
|
-
|
|
2364
|
-
expect(signature).toBe("");
|
|
2365
|
-
expect($postUpdateQueue.length).toBe(3);
|
|
2366
|
-
|
|
2367
|
-
model.$watch("a", () => {});
|
|
2368
|
-
model.a = 1;
|
|
2369
|
-
|
|
2370
|
-
await wait();
|
|
2371
|
-
|
|
2372
|
-
expect(signature).toBe("ABCD");
|
|
2373
|
-
});
|
|
2374
|
-
|
|
2375
|
-
it("should support $apply calls nested in $postUpdate callbacks", async () => {
|
|
2376
|
-
let signature = "";
|
|
2377
|
-
|
|
2378
|
-
model.$postUpdate(() => {
|
|
2379
|
-
signature += "A";
|
|
2380
|
-
});
|
|
2381
|
-
|
|
2382
|
-
model.$postUpdate(() => {
|
|
2383
|
-
signature += "B";
|
|
2384
|
-
model.$postUpdate(() => {
|
|
2385
|
-
signature += "D";
|
|
2386
|
-
});
|
|
2387
|
-
model.$apply("a = 2");
|
|
2388
|
-
});
|
|
2389
|
-
|
|
2390
|
-
model.$postUpdate(() => {
|
|
2391
|
-
signature += "C";
|
|
2392
|
-
});
|
|
2393
|
-
expect(signature).toBe("");
|
|
2394
|
-
|
|
2395
|
-
model.$watch("a", () => {});
|
|
2396
|
-
model.a = 1;
|
|
2397
|
-
await wait();
|
|
2398
|
-
|
|
2399
|
-
expect(signature).toBe("ABCD");
|
|
2400
|
-
});
|
|
2401
|
-
|
|
2402
|
-
it("should run a $postUpdate call on all child models when a parent model is digested", async () => {
|
|
2403
|
-
const parent = model.$new();
|
|
2404
|
-
const child = parent.$new();
|
|
2405
|
-
let count = 0;
|
|
2406
|
-
|
|
2407
|
-
model.$postUpdate(() => {
|
|
2408
|
-
count++;
|
|
2409
|
-
});
|
|
2410
|
-
|
|
2411
|
-
parent.$postUpdate(() => {
|
|
2412
|
-
count++;
|
|
2413
|
-
});
|
|
2414
|
-
|
|
2415
|
-
child.$postUpdate(() => {
|
|
2416
|
-
count++;
|
|
2417
|
-
});
|
|
2418
|
-
|
|
2419
|
-
expect(count).toBe(0);
|
|
2420
|
-
|
|
2421
|
-
model.$watch("a", () => {});
|
|
2422
|
-
model.a = 1;
|
|
2423
|
-
await wait();
|
|
2424
|
-
|
|
2425
|
-
expect(count).toBe(3);
|
|
2426
|
-
});
|
|
2427
|
-
|
|
2428
|
-
it("should run a $postUpdate call even if the child model is isolated", async () => {
|
|
2429
|
-
const parent = model.$new();
|
|
2430
|
-
const child = parent.$new(true);
|
|
2431
|
-
let signature = "";
|
|
2432
|
-
|
|
2433
|
-
parent.$postUpdate(() => {
|
|
2434
|
-
signature += "A";
|
|
2435
|
-
});
|
|
2436
|
-
|
|
2437
|
-
child.$postUpdate(() => {
|
|
2438
|
-
signature += "B";
|
|
2439
|
-
});
|
|
2440
|
-
|
|
2441
|
-
expect(signature).toBe("");
|
|
2442
|
-
model.$watch("a", () => {});
|
|
2443
|
-
model.a = 1;
|
|
2444
|
-
await wait();
|
|
2445
|
-
expect(signature).toBe("AB");
|
|
2446
|
-
});
|
|
2447
|
-
});
|
|
2448
|
-
|
|
2449
|
-
describe("events", () => {
|
|
2450
|
-
describe("$on", () => {
|
|
2451
|
-
it("should add listener to list of listerner", () => {
|
|
2452
|
-
const child = model.$new();
|
|
2453
|
-
function eventFn() {}
|
|
2454
|
-
child.$on("abc", eventFn);
|
|
2455
|
-
expect(child.$handler.$$listeners.get("abc").length).toEqual(1);
|
|
2456
|
-
|
|
2457
|
-
child.$on("abc", eventFn);
|
|
2458
|
-
expect(child.$handler.$$listeners.get("abc").length).toEqual(2);
|
|
2459
|
-
});
|
|
2460
|
-
|
|
2461
|
-
it("should return a deregistration function", () => {
|
|
2462
|
-
const child = model.$new();
|
|
2463
|
-
function eventFn() {}
|
|
2464
|
-
let res = child.$on("abc", eventFn);
|
|
2465
|
-
expect(isDefined(res)).toBeDefined();
|
|
2466
|
-
});
|
|
2467
|
-
|
|
2468
|
-
it("should return a deregistration function that removes a listener", () => {
|
|
2469
|
-
const child = model.$new();
|
|
2470
|
-
function eventFn() {}
|
|
2471
|
-
let res = child.$on("abc", eventFn);
|
|
2472
|
-
expect(isDefined(res)).toBeDefined();
|
|
2473
|
-
expect(child.$handler.$$listeners.get("abc").length).toEqual(1);
|
|
2474
|
-
let res2 = child.$on("abc", eventFn);
|
|
2475
|
-
expect(child.$handler.$$listeners.get("abc").length).toEqual(2);
|
|
2476
|
-
res();
|
|
2477
|
-
expect(child.$handler.$$listeners.get("abc").length).toEqual(1);
|
|
2478
|
-
res2();
|
|
2479
|
-
expect(child.$handler.$$listeners.has("abc")).toBeFalse();
|
|
2480
|
-
});
|
|
2481
|
-
|
|
2482
|
-
it("should add listener for both $emit and $broadcast events", () => {
|
|
2483
|
-
logs = "";
|
|
2484
|
-
const child = model.$new();
|
|
2485
|
-
|
|
2486
|
-
function eventFn() {
|
|
2487
|
-
logs += "X";
|
|
2488
|
-
}
|
|
2489
|
-
|
|
2490
|
-
child.$on("abc", eventFn);
|
|
2491
|
-
expect(logs).toEqual("");
|
|
2492
|
-
|
|
2493
|
-
child.$emit("abc");
|
|
2494
|
-
expect(logs).toEqual("X");
|
|
2495
|
-
|
|
2496
|
-
child.$broadcast("abc");
|
|
2497
|
-
expect(logs).toEqual("XX");
|
|
2498
|
-
});
|
|
2499
|
-
|
|
2500
|
-
describe("deregistration", () => {
|
|
2501
|
-
it("should return a function that deregisters the listener", () => {
|
|
2502
|
-
let log = "";
|
|
2503
|
-
const child = model.$new();
|
|
2504
|
-
let listenerRemove;
|
|
2505
|
-
|
|
2506
|
-
function eventFn() {
|
|
2507
|
-
log += "X";
|
|
2508
|
-
}
|
|
2509
|
-
|
|
2510
|
-
listenerRemove = child.$on("abc", eventFn);
|
|
2511
|
-
expect(log).toEqual("");
|
|
2512
|
-
expect(listenerRemove).toBeDefined();
|
|
2513
|
-
|
|
2514
|
-
child.$emit("abc");
|
|
2515
|
-
child.$broadcast("abc");
|
|
2516
|
-
expect(log).toEqual("XX");
|
|
2517
|
-
|
|
2518
|
-
expect(child.$handler.$$listeners.get("abc").length).toBe(1);
|
|
2519
|
-
|
|
2520
|
-
log = "";
|
|
2521
|
-
listenerRemove();
|
|
2522
|
-
child.$emit("abc");
|
|
2523
|
-
child.$broadcast("abc");
|
|
2524
|
-
expect(log).toEqual("");
|
|
2525
|
-
expect(model.$handler.$$listeners.get("abc")).toBeUndefined();
|
|
2526
|
-
});
|
|
2527
|
-
|
|
2528
|
-
it("should deallocate the listener array entry", () => {
|
|
2529
|
-
const remove1 = model.$on("abc", () => {});
|
|
2530
|
-
model.$on("abc", () => {});
|
|
2531
|
-
|
|
2532
|
-
expect(model.$handler.$$listeners.get("abc").length).toBe(2);
|
|
2533
|
-
|
|
2534
|
-
remove1();
|
|
2535
|
-
|
|
2536
|
-
expect(model.$handler.$$listeners.get("abc").length).toBe(1);
|
|
2537
|
-
});
|
|
2538
|
-
|
|
2539
|
-
it("should call next listener after removing the current listener via its own handler", () => {
|
|
2540
|
-
const listener1 = jasmine.createSpy("listener1").and.callFake(() => {
|
|
2541
|
-
remove1();
|
|
2542
|
-
});
|
|
2543
|
-
let remove1 = model.$on("abc", listener1);
|
|
2544
|
-
|
|
2545
|
-
const listener2 = jasmine.createSpy("listener2");
|
|
2546
|
-
const remove2 = model.$on("abc", listener2);
|
|
2547
|
-
|
|
2548
|
-
const listener3 = jasmine.createSpy("listener3");
|
|
2549
|
-
const remove3 = model.$on("abc", listener3);
|
|
2550
|
-
|
|
2551
|
-
model.$broadcast("abc");
|
|
2552
|
-
expect(listener1).toHaveBeenCalled();
|
|
2553
|
-
expect(listener2).toHaveBeenCalled();
|
|
2554
|
-
expect(listener3).toHaveBeenCalled();
|
|
2555
|
-
|
|
2556
|
-
listener1.calls.reset();
|
|
2557
|
-
listener2.calls.reset();
|
|
2558
|
-
listener3.calls.reset();
|
|
2559
|
-
|
|
2560
|
-
model.$broadcast("abc");
|
|
2561
|
-
expect(listener1).not.toHaveBeenCalled();
|
|
2562
|
-
expect(listener2).toHaveBeenCalled();
|
|
2563
|
-
expect(listener3).toHaveBeenCalled();
|
|
2564
|
-
});
|
|
2565
|
-
|
|
2566
|
-
it("should call all subsequent listeners when a previous listener is removed via a handler", () => {
|
|
2567
|
-
const listener1 = jasmine.createSpy();
|
|
2568
|
-
const remove1 = model.$on("abc", listener1);
|
|
2569
|
-
|
|
2570
|
-
const listener2 = jasmine.createSpy().and.callFake(remove1);
|
|
2571
|
-
const remove2 = model.$on("abc", listener2);
|
|
2572
|
-
|
|
2573
|
-
const listener3 = jasmine.createSpy();
|
|
2574
|
-
const remove3 = model.$on("abc", listener3);
|
|
2575
|
-
|
|
2576
|
-
model.$broadcast("abc");
|
|
2577
|
-
expect(listener1).toHaveBeenCalled();
|
|
2578
|
-
expect(listener2).toHaveBeenCalled();
|
|
2579
|
-
expect(listener3).toHaveBeenCalled();
|
|
2580
|
-
|
|
2581
|
-
listener1.calls.reset();
|
|
2582
|
-
listener2.calls.reset();
|
|
2583
|
-
listener3.calls.reset();
|
|
2584
|
-
|
|
2585
|
-
model.$broadcast("abc");
|
|
2586
|
-
expect(listener1).not.toHaveBeenCalled();
|
|
2587
|
-
expect(listener2).toHaveBeenCalled();
|
|
2588
|
-
expect(listener3).toHaveBeenCalled();
|
|
2589
|
-
});
|
|
2590
|
-
|
|
2591
|
-
it("should not call listener when removed by previous", () => {
|
|
2592
|
-
const listener1 = jasmine.createSpy("listener1");
|
|
2593
|
-
const remove1 = model.$on("abc", listener1);
|
|
2594
|
-
|
|
2595
|
-
const listener2 = jasmine.createSpy("listener2").and.callFake(() => {
|
|
2596
|
-
remove3();
|
|
2597
|
-
});
|
|
2598
|
-
const remove2 = model.$on("abc", listener2);
|
|
2599
|
-
|
|
2600
|
-
const listener3 = jasmine.createSpy("listener3");
|
|
2601
|
-
let remove3 = model.$on("abc", listener3);
|
|
2602
|
-
|
|
2603
|
-
const listener4 = jasmine.createSpy("listener4");
|
|
2604
|
-
const remove4 = model.$on("abc", listener4);
|
|
2605
|
-
|
|
2606
|
-
model.$broadcast("abc");
|
|
2607
|
-
expect(listener1).toHaveBeenCalled();
|
|
2608
|
-
expect(listener2).toHaveBeenCalled();
|
|
2609
|
-
expect(listener3).not.toHaveBeenCalled();
|
|
2610
|
-
expect(listener4).toHaveBeenCalled();
|
|
2611
|
-
|
|
2612
|
-
listener1.calls.reset();
|
|
2613
|
-
listener2.calls.reset();
|
|
2614
|
-
listener3.calls.reset();
|
|
2615
|
-
listener4.calls.reset();
|
|
2616
|
-
|
|
2617
|
-
model.$broadcast("abc");
|
|
2618
|
-
expect(listener1).toHaveBeenCalled();
|
|
2619
|
-
expect(listener2).toHaveBeenCalled();
|
|
2620
|
-
expect(listener3).not.toHaveBeenCalled();
|
|
2621
|
-
expect(listener4).toHaveBeenCalled();
|
|
2622
|
-
});
|
|
2623
|
-
});
|
|
2624
|
-
});
|
|
2625
|
-
|
|
2626
|
-
describe("$emit", () => {
|
|
2627
|
-
let log;
|
|
2628
|
-
let child;
|
|
2629
|
-
let grandChild;
|
|
2630
|
-
let greatGrandChild;
|
|
2631
|
-
|
|
2632
|
-
function logger(event) {
|
|
2633
|
-
log += `${event.currentScope.id}>`;
|
|
2634
|
-
}
|
|
2635
|
-
|
|
2636
|
-
beforeEach(() => {
|
|
2637
|
-
log = "";
|
|
2638
|
-
logs = [];
|
|
2639
|
-
child = model.$new();
|
|
2640
|
-
grandChild = child.$new();
|
|
2641
|
-
greatGrandChild = grandChild.$new();
|
|
2642
|
-
|
|
2643
|
-
model.id = 0;
|
|
2644
|
-
child.id = 1;
|
|
2645
|
-
grandChild.id = 2;
|
|
2646
|
-
greatGrandChild.id = 3;
|
|
2647
|
-
|
|
2648
|
-
model.$on("myEvent", logger);
|
|
2649
|
-
child.$on("myEvent", logger);
|
|
2650
|
-
grandChild.$on("myEvent", logger);
|
|
2651
|
-
greatGrandChild.$on("myEvent", logger);
|
|
2652
|
-
});
|
|
2653
|
-
|
|
2654
|
-
it("should do nothing on empty listener", () => {
|
|
2655
|
-
logs = "";
|
|
2656
|
-
const child = model.$new();
|
|
2657
|
-
|
|
2658
|
-
function eventFn() {
|
|
2659
|
-
logs += "X";
|
|
2660
|
-
}
|
|
2661
|
-
|
|
2662
|
-
child.$on("abc", eventFn);
|
|
2663
|
-
expect(logs).toEqual("");
|
|
2664
|
-
|
|
2665
|
-
child.$emit("none");
|
|
2666
|
-
expect(logs).toEqual("");
|
|
2667
|
-
});
|
|
2668
|
-
|
|
2669
|
-
it("should bubble event up to the root model", () => {
|
|
2670
|
-
grandChild.$emit("myEvent");
|
|
2671
|
-
expect(log).toEqual("2>1>0>");
|
|
2672
|
-
});
|
|
2673
|
-
|
|
2674
|
-
it("should allow all events on the same model to run even if stopPropagation is called", () => {
|
|
2675
|
-
child.$on("myEvent", logger);
|
|
2676
|
-
grandChild.$on("myEvent", (e) => {
|
|
2677
|
-
e.stopPropagation();
|
|
2678
|
-
});
|
|
2679
|
-
grandChild.$on("myEvent", logger);
|
|
2680
|
-
grandChild.$on("myEvent", logger);
|
|
2681
|
-
grandChild.$emit("myEvent");
|
|
2682
|
-
expect(log).toEqual("2>2>2>");
|
|
2683
|
-
});
|
|
2684
|
-
|
|
2685
|
-
it("should dispatch exceptions to the $exceptionHandler", () => {
|
|
2686
|
-
child.$on("myEvent", () => {
|
|
2687
|
-
throw "bubbleException";
|
|
2688
|
-
});
|
|
2689
|
-
grandChild.$emit("myEvent");
|
|
2690
|
-
expect(log).toEqual("2>1>0>");
|
|
2691
|
-
expect(logs).toEqual(["bubbleException"]);
|
|
2692
|
-
});
|
|
2693
|
-
|
|
2694
|
-
it("should allow stopping event propagation", () => {
|
|
2695
|
-
child.$on("myEvent", (event) => {
|
|
2696
|
-
event.stopPropagation();
|
|
2697
|
-
});
|
|
2698
|
-
grandChild.$emit("myEvent");
|
|
2699
|
-
expect(log).toEqual("2>1>");
|
|
2700
|
-
});
|
|
2701
|
-
|
|
2702
|
-
it("should forward method arguments", () => {
|
|
2703
|
-
child.$on("abc", (event, arg1, arg2) => {
|
|
2704
|
-
expect(event.name).toBe("abc");
|
|
2705
|
-
expect(arg1).toBe("arg1");
|
|
2706
|
-
expect(arg2).toBe("arg2");
|
|
2707
|
-
});
|
|
2708
|
-
child.$emit("abc", "arg1", "arg2");
|
|
2709
|
-
});
|
|
2710
|
-
|
|
2711
|
-
it("should allow removing event listener inside a listener on $emit", () => {
|
|
2712
|
-
const spy1 = jasmine.createSpy("1st listener");
|
|
2713
|
-
const spy2 = jasmine.createSpy("2nd listener");
|
|
2714
|
-
const spy3 = jasmine.createSpy("3rd listener");
|
|
2715
|
-
|
|
2716
|
-
const remove1 = child.$on("evt", spy1);
|
|
2717
|
-
const remove2 = child.$on("evt", spy2);
|
|
2718
|
-
const remove3 = child.$on("evt", spy3);
|
|
2719
|
-
|
|
2720
|
-
spy1.and.callFake(remove1);
|
|
2721
|
-
|
|
2722
|
-
expect(child.$handler.$$listeners.get("evt").length).toBe(3);
|
|
2723
|
-
|
|
2724
|
-
// should call all listeners and remove 1st
|
|
2725
|
-
child.$emit("evt");
|
|
2726
|
-
expect(spy1).toHaveBeenCalled();
|
|
2727
|
-
expect(spy2).toHaveBeenCalled();
|
|
2728
|
-
expect(spy3).toHaveBeenCalled();
|
|
2729
|
-
expect(child.$handler.$$listeners.get("evt").length).toBe(2);
|
|
2730
|
-
|
|
2731
|
-
spy1.calls.reset();
|
|
2732
|
-
spy2.calls.reset();
|
|
2733
|
-
spy3.calls.reset();
|
|
2734
|
-
|
|
2735
|
-
// // should call only 2nd because 1st was already removed and 2nd removes 3rd
|
|
2736
|
-
spy2.and.callFake(remove3);
|
|
2737
|
-
child.$emit("evt");
|
|
2738
|
-
expect(spy1).not.toHaveBeenCalled();
|
|
2739
|
-
expect(spy2).toHaveBeenCalled();
|
|
2740
|
-
expect(spy3).not.toHaveBeenCalled();
|
|
2741
|
-
expect(child.$handler.$$listeners.get("evt").length).toBe(1);
|
|
2742
|
-
});
|
|
2743
|
-
|
|
2744
|
-
it("should allow removing event listener inside a listener on $broadcast", () => {
|
|
2745
|
-
const spy1 = jasmine.createSpy("1st listener");
|
|
2746
|
-
const spy2 = jasmine.createSpy("2nd listener");
|
|
2747
|
-
const spy3 = jasmine.createSpy("3rd listener");
|
|
2748
|
-
|
|
2749
|
-
const remove1 = child.$on("evt", spy1);
|
|
2750
|
-
const remove2 = child.$on("evt", spy2);
|
|
2751
|
-
const remove3 = child.$on("evt", spy3);
|
|
2752
|
-
|
|
2753
|
-
spy1.and.callFake(remove1);
|
|
2754
|
-
|
|
2755
|
-
expect(child.$handler.$$listeners.get("evt").length).toBe(3);
|
|
2756
|
-
|
|
2757
|
-
// should call all listeners and remove 1st
|
|
2758
|
-
child.$broadcast("evt");
|
|
2759
|
-
expect(spy1).toHaveBeenCalled();
|
|
2760
|
-
expect(spy2).toHaveBeenCalled();
|
|
2761
|
-
expect(spy3).toHaveBeenCalled();
|
|
2762
|
-
expect(child.$handler.$$listeners.get("evt").length).toBe(2);
|
|
2763
|
-
|
|
2764
|
-
spy1.calls.reset();
|
|
2765
|
-
spy2.calls.reset();
|
|
2766
|
-
spy3.calls.reset();
|
|
2767
|
-
|
|
2768
|
-
// should call only 2nd because 1st was already removed and 2nd removes 3rd
|
|
2769
|
-
spy2.and.callFake(remove3);
|
|
2770
|
-
child.$broadcast("evt");
|
|
2771
|
-
expect(spy1).not.toHaveBeenCalled();
|
|
2772
|
-
expect(spy2).toHaveBeenCalled();
|
|
2773
|
-
expect(spy3).not.toHaveBeenCalled();
|
|
2774
|
-
expect(child.$handler.$$listeners.get("evt").length).toBe(1);
|
|
2775
|
-
});
|
|
2776
|
-
|
|
2777
|
-
describe("event object", () => {
|
|
2778
|
-
it("should have methods/properties", () => {
|
|
2779
|
-
let eventFired = false;
|
|
2780
|
-
|
|
2781
|
-
child.$on("myEvent", (e) => {
|
|
2782
|
-
expect(e.targetScope).toBe(grandChild.$handler.$target);
|
|
2783
|
-
expect(e.currentScope).toBe(child.$handler.$target);
|
|
2784
|
-
expect(e.name).toBe("myEvent");
|
|
2785
|
-
eventFired = true;
|
|
2786
|
-
});
|
|
2787
|
-
grandChild.$emit("myEvent");
|
|
2788
|
-
expect(eventFired).toBe(true);
|
|
2789
|
-
});
|
|
2790
|
-
|
|
2791
|
-
it("should have its `currentScope` property set to null after emit", () => {
|
|
2792
|
-
let event;
|
|
2793
|
-
|
|
2794
|
-
child.$on("myEvent", (e) => {
|
|
2795
|
-
event = e;
|
|
2796
|
-
});
|
|
2797
|
-
grandChild.$emit("myEvent");
|
|
2798
|
-
|
|
2799
|
-
expect(event.currentScope).toBe(null);
|
|
2800
|
-
expect(event.targetScope).toBe(grandChild.$target);
|
|
2801
|
-
expect(event.name).toBe("myEvent");
|
|
2802
|
-
});
|
|
2803
|
-
|
|
2804
|
-
it("should have preventDefault method and defaultPrevented property", () => {
|
|
2805
|
-
let event = grandChild.$emit("myEvent");
|
|
2806
|
-
expect(event.defaultPrevented).toBe(false);
|
|
2807
|
-
|
|
2808
|
-
child.$on("myEvent", (event) => {
|
|
2809
|
-
event.preventDefault();
|
|
2810
|
-
});
|
|
2811
|
-
event = grandChild.$emit("myEvent");
|
|
2812
|
-
expect(event.defaultPrevented).toBe(true);
|
|
2813
|
-
expect(event.currentScope).toBe(null);
|
|
2814
|
-
});
|
|
2815
|
-
});
|
|
2816
|
-
});
|
|
2817
|
-
|
|
2818
|
-
describe("$broadcast", () => {
|
|
2819
|
-
describe("event propagation", () => {
|
|
2820
|
-
let log;
|
|
2821
|
-
let child1;
|
|
2822
|
-
let child2;
|
|
2823
|
-
let child3;
|
|
2824
|
-
let grandChild11;
|
|
2825
|
-
let grandChild21;
|
|
2826
|
-
let grandChild22;
|
|
2827
|
-
let grandChild23;
|
|
2828
|
-
let greatGrandChild211;
|
|
2829
|
-
|
|
2830
|
-
function logger(event) {
|
|
2831
|
-
log += `${event.currentScope.id}>`;
|
|
2832
|
-
}
|
|
2833
|
-
|
|
2834
|
-
beforeEach(() => {
|
|
2835
|
-
log = "";
|
|
2836
|
-
child1 = model.$new();
|
|
2837
|
-
child2 = model.$new();
|
|
2838
|
-
child3 = model.$new();
|
|
2839
|
-
grandChild11 = child1.$new();
|
|
2840
|
-
grandChild21 = child2.$new();
|
|
2841
|
-
grandChild22 = child2.$new();
|
|
2842
|
-
grandChild23 = child2.$new();
|
|
2843
|
-
greatGrandChild211 = grandChild21.$new();
|
|
2844
|
-
|
|
2845
|
-
model.id = 0;
|
|
2846
|
-
child1.id = 1;
|
|
2847
|
-
child2.id = 2;
|
|
2848
|
-
child3.id = 3;
|
|
2849
|
-
grandChild11.id = 11;
|
|
2850
|
-
grandChild21.id = 21;
|
|
2851
|
-
grandChild22.id = 22;
|
|
2852
|
-
grandChild23.id = 23;
|
|
2853
|
-
greatGrandChild211.id = 211;
|
|
2854
|
-
|
|
2855
|
-
model.$on("myEvent", logger);
|
|
2856
|
-
child1.$on("myEvent", logger);
|
|
2857
|
-
child2.$on("myEvent", logger);
|
|
2858
|
-
child3.$on("myEvent", logger);
|
|
2859
|
-
grandChild11.$on("myEvent", logger);
|
|
2860
|
-
grandChild21.$on("myEvent", logger);
|
|
2861
|
-
grandChild22.$on("myEvent", logger);
|
|
2862
|
-
grandChild23.$on("myEvent", logger);
|
|
2863
|
-
greatGrandChild211.$on("myEvent", logger);
|
|
2864
|
-
|
|
2865
|
-
// R
|
|
2866
|
-
// / | \
|
|
2867
|
-
// 1 2 3
|
|
2868
|
-
// / / | \
|
|
2869
|
-
// 11 21 22 23
|
|
2870
|
-
// |
|
|
2871
|
-
// 211
|
|
2872
|
-
});
|
|
2873
|
-
|
|
2874
|
-
it("should broadcast an event from the root model", () => {
|
|
2875
|
-
model.$broadcast("myEvent");
|
|
2876
|
-
expect(log).toBe("0>1>11>2>21>211>22>23>3>");
|
|
2877
|
-
});
|
|
2878
|
-
|
|
2879
|
-
it("should broadcast an event from a child model", () => {
|
|
2880
|
-
child2.$broadcast("myEvent");
|
|
2881
|
-
expect(log).toBe("2>21>211>22>23>");
|
|
2882
|
-
});
|
|
2883
|
-
|
|
2884
|
-
it("should broadcast an event from a leaf model with a sibling", () => {
|
|
2885
|
-
grandChild22.$broadcast("myEvent");
|
|
2886
|
-
expect(log).toBe("22>");
|
|
2887
|
-
});
|
|
2888
|
-
|
|
2889
|
-
it("should broadcast an event from a leaf model without a sibling", () => {
|
|
2890
|
-
grandChild23.$broadcast("myEvent");
|
|
2891
|
-
expect(log).toBe("23>");
|
|
2892
|
-
});
|
|
2893
|
-
|
|
2894
|
-
it("should not not fire any listeners for other events", () => {
|
|
2895
|
-
model.$broadcast("fooEvent");
|
|
2896
|
-
expect(log).toBe("");
|
|
2897
|
-
});
|
|
2898
|
-
|
|
2899
|
-
it("should return event object", () => {
|
|
2900
|
-
const result = child1.$broadcast("some");
|
|
2901
|
-
|
|
2902
|
-
expect(result).toBeDefined();
|
|
2903
|
-
expect(result.name).toBe("some");
|
|
2904
|
-
expect(result.targetScope).toBe(child1.$target);
|
|
2905
|
-
});
|
|
2906
|
-
});
|
|
2907
|
-
|
|
2908
|
-
describe("listener", () => {
|
|
2909
|
-
it("should receive event object", () => {
|
|
2910
|
-
const child = model.$new();
|
|
2911
|
-
let eventFired = false;
|
|
2912
|
-
|
|
2913
|
-
child.$on("fooEvent", (event) => {
|
|
2914
|
-
eventFired = true;
|
|
2915
|
-
expect(event.name).toBe("fooEvent");
|
|
2916
|
-
expect(event.targetScope).toBe(model.$target);
|
|
2917
|
-
expect(event.currentScope).toBe(child.$target);
|
|
2918
|
-
});
|
|
2919
|
-
model.$broadcast("fooEvent");
|
|
2920
|
-
|
|
2921
|
-
expect(eventFired).toBe(true);
|
|
2922
|
-
});
|
|
2923
|
-
|
|
2924
|
-
it("should have the event's `currentScope` property set to null after broadcast", () => {
|
|
2925
|
-
const child = model.$new();
|
|
2926
|
-
let event;
|
|
2927
|
-
|
|
2928
|
-
child.$on("fooEvent", (e) => {
|
|
2929
|
-
event = e;
|
|
2930
|
-
});
|
|
2931
|
-
model.$broadcast("fooEvent");
|
|
2932
|
-
|
|
2933
|
-
expect(event.name).toBe("fooEvent");
|
|
2934
|
-
expect(event.targetScope).toBe(model.$target);
|
|
2935
|
-
expect(event.currentScope).toBe(null);
|
|
2936
|
-
});
|
|
2937
|
-
|
|
2938
|
-
it("should support passing messages as constargs", () => {
|
|
2939
|
-
const child = model.$new();
|
|
2940
|
-
let args;
|
|
2941
|
-
|
|
2942
|
-
child.$on("fooEvent", function () {
|
|
2943
|
-
args = arguments;
|
|
2944
|
-
});
|
|
2945
|
-
model.$broadcast("fooEvent", "do", "re", "me", "fa");
|
|
2946
|
-
|
|
2947
|
-
expect(args.length).toBe(5);
|
|
2948
|
-
expect(sliceArgs(args, 1)).toEqual(["do", "re", "me", "fa"]);
|
|
2949
|
-
});
|
|
2950
|
-
});
|
|
2951
|
-
});
|
|
2952
|
-
|
|
2953
|
-
it("should allow recursive $emit/$broadcast", () => {
|
|
2954
|
-
let callCount = 0;
|
|
2955
|
-
model.$on("evt", ($event, arg0) => {
|
|
2956
|
-
callCount++;
|
|
2957
|
-
if (arg0 !== 1234) {
|
|
2958
|
-
model.$emit("evt", 1234);
|
|
2959
|
-
model.$broadcast("evt", 1234);
|
|
2960
|
-
}
|
|
2961
|
-
});
|
|
2962
|
-
|
|
2963
|
-
model.$emit("evt");
|
|
2964
|
-
model.$broadcast("evt");
|
|
2965
|
-
expect(callCount).toBe(6);
|
|
2966
|
-
});
|
|
2967
|
-
|
|
2968
|
-
it("should allow recursive $emit/$broadcast between parent/child", () => {
|
|
2969
|
-
const child = model.$new();
|
|
2970
|
-
let calls = "";
|
|
2971
|
-
|
|
2972
|
-
model.$on("evt", ($event, arg0) => {
|
|
2973
|
-
calls += "r"; // For "root".
|
|
2974
|
-
if (arg0 === "fromChild") {
|
|
2975
|
-
model.$broadcast("evt", "fromRoot2");
|
|
2976
|
-
}
|
|
2977
|
-
});
|
|
2978
|
-
|
|
2979
|
-
child.$on("evt", ($event, arg0) => {
|
|
2980
|
-
calls += "c"; // For "child".
|
|
2981
|
-
if (arg0 === "fromRoot1") {
|
|
2982
|
-
child.$emit("evt", "fromChild");
|
|
2983
|
-
}
|
|
2984
|
-
});
|
|
2985
|
-
|
|
2986
|
-
model.$broadcast("evt", "fromRoot1");
|
|
2987
|
-
expect(calls).toBe("rccrrc");
|
|
2988
|
-
});
|
|
2989
|
-
});
|
|
2990
|
-
|
|
2991
|
-
describe("doc examples", () => {
|
|
2992
|
-
it("should properly fire off watch listeners upon model changes", async () => {
|
|
2993
|
-
// <docs tag="docs1">
|
|
2994
|
-
const scope = model.$new();
|
|
2995
|
-
scope.salutation = "Hello";
|
|
2996
|
-
scope.name = "World";
|
|
2997
|
-
await wait();
|
|
2998
|
-
expect(scope.greeting).toEqual(undefined);
|
|
2999
|
-
|
|
3000
|
-
scope.$watch("name", () => {
|
|
3001
|
-
scope.greeting = `${scope.salutation} ${scope.name}!`;
|
|
3002
|
-
});
|
|
3003
|
-
|
|
3004
|
-
expect(scope.greeting).toEqual(undefined);
|
|
3005
|
-
expect(scope.greeting).toEqual(undefined);
|
|
3006
|
-
|
|
3007
|
-
scope.name = "Misko";
|
|
3008
|
-
await wait();
|
|
3009
|
-
expect(scope.greeting).toEqual("Hello Misko!");
|
|
3010
|
-
});
|
|
3011
|
-
});
|
|
3012
|
-
});
|