UNPKG

10.4 kBJavaScriptView Raw
1describe("Scope", function() {
2 var scope, fallback;
3
4 before(function() {
5 scope = new Temple.Scope();
6 });
7
8 beforeEach(function() {
9 scope.set("foo", "bar");
10 fallback = new Temple.Model({ bar: "baz" });
11 scope.addModel(fallback);
12 });
13
14 afterEach(function() {
15 scope.stopObserving();
16 scope.removeModel(fallback);
17 fallback = null;
18 });
19
20 it("creates a model on constructor if a model isn't passed", function() {
21 expect(scope.models[0]).to.be.instanceof(Temple.Model);
22 });
23
24 it("get(path) executes function value iff value at path is function", function() {
25 scope.set("foo", function() {
26 expect(this).to.equal(scope);
27 return "Hello World";
28 });
29
30 expect(scope.get("foo")).to.equal("Hello World");
31 });
32
33 it("adds fallback model", function() {
34 expect(scope.models[1]).to.deep.equal(fallback);
35 });
36
37 it("removes fallback model", function() {
38 scope.removeModel(fallback);
39 expect(scope.models).to.have.length(1);
40 });
41
42 it("scope returns fallback value at path iff model value at path is undefined", function() {
43 expect(scope.get("foo")).to.equal("bar");
44 expect(scope.get("bar")).to.equal("baz");
45 });
46
47 it("if path is prefixed with `this`, model returns exact value at path", function() {
48 expect(scope.get("this.foo")).to.equal("bar");
49 expect(scope.get("this.bar")).to.be.undefined;
50 });
51
52 describe("#observe()", function() {
53
54 it("successfully adds observer", function() {
55 var fn = function(){};
56 scope.observe("foo", fn);
57 expect(scope._observers.some(function(o) {
58 return o.fn === fn;
59 })).to.be.ok;
60 });
61
62 it("successfully removes observer", function() {
63 var fn = function() { throw new Error("Observer wasn't removed!"); }
64 scope.observe("foo", fn);
65
66 expect(function() {
67 scope.set("foo", "baz");
68 }).to.throw(Error);
69
70 scope.stopObserving("foo", fn);
71 scope.set("foo", "bar");
72 });
73
74 it("calling stopObserving() without arguments clears all observers", function() {
75 scope.observe("foo", function() { throw new Error("Observer wasn't removed!"); });
76 expect(scope._observers).to.have.length(1);
77 scope.stopObserving();
78 scope.set("foo", "baz");
79 expect(scope._observers).to.have.length(0);
80 });
81
82 it("calling stopObserving(path) clears all observers with matching path", function() {
83 var fn = function() { throw new Error("Observer wasn't removed!"); }
84 scope.observe("foo", fn);
85 scope.observe("foo", fn);
86 scope.observe("bar", fn);
87 expect(scope._observers).to.have.length(3);
88 scope.stopObserving("foo");
89 scope.set("foo", "baz");
90 expect(scope._observers).to.have.length(1);
91 });
92
93 it("calling stopObserving(null, fn) clears all observers with matching function", function() {
94 var fn = function() { throw new Error("Observer wasn't removed!"); }
95 scope.observe("foo", fn);
96 scope.observe("bar", fn);
97 scope.observe("baz", function(){});
98 expect(scope._observers).to.have.length(3);
99 scope.stopObserving(null, fn);
100 scope.set("foo", "baz");
101 expect(scope._observers).to.have.length(1);
102 });
103
104 it("observes nothing when nothing changes", function() {
105 scope.observe("foo", function() { throw new Error("A change was observed."); });
106 scope.set("foo", "bar");
107 });
108
109 it("observes static path changes", function() {
110 var seen = false;
111 scope.observe("foo.bar", function(chg) {
112 expect(this).to.equal(scope);
113
114 expect(chg).to.deep.equal({
115 model: scope.getModel("foo.bar"),
116 previousModel: scope.getModel("foo.bar"),
117 path: "foo.bar",
118 type: "add",
119 value: "baz",
120 oldValue: undefined
121 });
122
123 seen = true;
124 });
125
126 scope.set("foo", { bar: "baz" });
127 expect(seen).to.be.ok;
128 });
129
130 it("observes changes only once", function() {
131 var seen = 0;
132 scope.observe("foo", function() { seen++; });
133 scope.set("foo", { bar: "baz" });
134 expect(seen).to.equal(1);
135 });
136
137 it("observes unset", function() {
138 var seen = false;
139 scope.observe("foo", function(chg) {
140 expect(chg).to.deep.equal({
141 model: scope.getModel("foo"),
142 previousModel: scope.getModel("foo"),
143 path: "foo",
144 type: "delete",
145 value: undefined,
146 oldValue: "bar"
147 });
148
149 seen = true;
150 });
151
152 scope.unset("foo");
153 expect(seen).to.be.ok;
154 });
155
156 it("calling get() in an observer returns the new value", function() {
157 var seen = false;
158 scope.observe("foo.bar", function(chg) {
159 expect(this.get(chg.path)).to.equal(chg.value);
160 seen = true;
161 });
162
163 scope.set("foo.bar", "baz");
164 expect(seen).to.be.ok;
165 });
166
167 it("observes empty path", function() {
168 var seen = false;
169 scope.observe("", function(chg) {
170 expect(chg).to.deep.equal({
171 model: scope.getModel(),
172 previousModel: scope.getModel(),
173 path: "",
174 type: "update",
175 value: "foo",
176 oldValue: { foo: "bar" }
177 });
178
179 seen = true;
180 });
181
182 scope.set([], "foo");
183 expect(seen).to.be.ok;
184 });
185
186 it("observes dynamic path: *", function() {
187 var seen = false;
188 scope.observe("*", function(chg) {
189 expect(chg).to.deep.equal({
190 model: scope.getModel("foo"),
191 previousModel: scope.getModel("foo"),
192 path: "foo",
193 type: "update",
194 value: { bar: "baz" },
195 oldValue: "bar"
196 });
197
198 seen = true;
199 });
200
201 scope.set("foo", { bar: "baz" });
202 expect(seen).to.be.ok;
203 });
204
205 it("observes dynamic path: *.bar.baz", function() {
206 var seen = false;
207 scope.observe("*.bar.baz", function(chg) {
208 expect(chg).to.deep.equal({
209 model: scope.getModel("foo.bar.baz"),
210 previousModel: scope.getModel("foo.bar.baz"),
211 path: "foo.bar.baz",
212 type: "add",
213 value: "buz",
214 oldValue: undefined
215 });
216
217 seen = true;
218 });
219
220 scope.set("foo.bar.baz", "buz");
221 expect(seen).to.be.ok;
222 });
223
224 it("observes dynamic path: foo.*.baz", function() {
225 var seen = false;
226 scope.observe("foo.*.baz", function(chg) {
227 expect(chg).to.deep.equal({
228 model: scope.getModel("foo.bar.baz"),
229 previousModel: scope.getModel("foo.bar.baz"),
230 path: "foo.bar.baz",
231 type: "add",
232 value: "buz",
233 oldValue: undefined
234 });
235
236 seen = true;
237 });
238
239 scope.set("foo.bar.baz", "buz");
240 expect(seen).to.be.ok;
241 });
242
243 it("observes dynamic path: foo.bar.*", function() {
244 var seen = false;
245 scope.observe("foo.bar.*", function(chg) {
246 expect(chg).to.deep.equal({
247 model: scope.getModel("foo.bar.baz"),
248 previousModel: scope.getModel("foo.bar.baz"),
249 path: "foo.bar.baz",
250 type: "add",
251 value: "buz",
252 oldValue: undefined
253 });
254
255 seen = true;
256 });
257
258 scope.set("foo.bar.baz", "buz");
259 expect(seen).to.be.ok;
260 });
261
262 it("observes dynamic path: **", function() {
263 var seen = false;
264 scope.set("foo", { bar: "baz" });
265
266 scope.observe("**", function(chg) {
267 expect(chg).to.deep.equal({
268 model: scope.getModel("foo.bar"),
269 previousModel: scope.getModel("foo.bar"),
270 path: "foo.bar",
271 type: "update",
272 value: { baz: "buz" },
273 oldValue: "baz"
274 });
275
276 seen = true;
277 });
278
279 scope.set("foo.bar", { baz: "buz" });
280 expect(seen).to.be.ok;
281 });
282
283 it("observes dynamic path: **.baz", function() {
284 var seen = false;
285
286 scope.observe("**.baz", function(chg) {
287 expect(chg).to.deep.equal({
288 model: scope.getModel("foo.bar.baz"),
289 previousModel: scope.getModel("foo.bar.baz"),
290 path: "foo.bar.baz",
291 type: "add",
292 value: "buz",
293 oldValue: undefined
294 });
295
296 seen = true;
297 });
298
299 scope.set("foo.bar.baz", "buz");
300 expect(seen).to.be.ok;
301 });
302
303 it("observes dynamic path: foo.**.baz", function() {
304 var seen = false;
305 scope.observe("foo.**.baz", function(chg) {
306 expect(chg).to.deep.equal({
307 model: scope.getModel("foo.bar.bun.baz"),
308 previousModel: scope.getModel("foo.bar.bun.baz"),
309 path: "foo.bar.bun.baz",
310 type: "add",
311 value: "buz",
312 oldValue: undefined
313 });
314
315 seen = true;
316 });
317
318 scope.set("foo.bar.bun.baz", "buz");
319 expect(seen).to.be.ok;
320 });
321
322 it("observes dynamic path: foo.**", function() {
323 var seen = false;
324 scope.set("foo.bar.baz", "buz");
325
326 scope.observe("foo.**", function(chg) {
327 expect(chg).to.deep.equal({
328 model: scope.getModel("foo.bar.baz"),
329 previousModel: scope.getModel("foo.bar.baz"),
330 path: "foo.bar.baz",
331 type: "update",
332 value: "bun",
333 oldValue: "buz"
334 });
335
336 seen = true;
337 });
338
339 scope.set("foo.bar.baz", "bun");
340 expect(seen).to.be.ok;
341 });
342
343 it("observing path foo.** captures changes at path foo", function() {
344 var seen = false;
345 scope.observe("foo.**", function(chg) {
346 expect(chg).to.deep.equal({
347 model: scope.getModel("foo"),
348 previousModel: scope.getModel("foo"),
349 path: "foo",
350 type: "update",
351 value: "buz",
352 oldValue: "bar"
353 });
354
355 seen = true;
356 });
357
358 scope.set("foo", "buz");
359 expect(seen).to.be.ok;
360 });
361
362 it("observes changes to fallback value", function() {
363 var seen = false;
364
365 scope.observe("bar", function(chg) {
366 expect(this).to.equal(scope);
367
368 expect(chg).to.deep.equal({
369 model: fallback.getModel("bar"),
370 previousModel: fallback.getModel("bar"),
371 path: "bar",
372 type: "update",
373 value: "bam",
374 oldValue: "baz"
375 });
376
377 seen = true;
378 });
379
380 fallback.set("bar", "bam");
381 expect(seen).to.be.ok;
382 });
383
384 it("observes changes to local value when the value was found in fallback", function() {
385 var seen = false;
386
387 scope.observe("bar", function(chg) {
388 expect(chg).to.deep.equal({
389 model: scope.getModel("bar"),
390 previousModel: fallback.getModel("bar"),
391 path: "bar",
392 type: "update",
393 value: "bam",
394 oldValue: "baz"
395 });
396
397 seen = true;
398 });
399
400 scope.set("bar", "bam");
401 expect(seen).to.be.ok;
402 });
403
404 it("doesn't observes changes to fallback when the value is in local model", function() {
405 scope.observe("foo", function(chg) {
406 throw new Error("A change was observed.");
407 });
408
409 fallback.set("foo", "bam");
410 });
411
412 it("observes unset on local value, falling back on a secondary value", function() {
413 var seen = false;
414 fallback.set("foo", "bug");
415
416 scope.observe("foo", function(chg) {
417 expect(chg).to.deep.equal({
418 model: fallback.getModel("foo"),
419 previousModel: scope.getModel("foo"),
420 path: "foo",
421 type: "update",
422 value: "bug",
423 oldValue: "bar"
424 });
425
426 seen = true;
427 });
428
429 scope.unset("foo");
430 expect(seen).to.be.ok;
431 });
432 });
433
434});
\No newline at end of file