aberdeen 0.2.1 → 0.2.2

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.
Files changed (55) hide show
  1. package/dist/aberdeen.d.ts +573 -0
  2. package/dist/aberdeen.js +1756 -0
  3. package/dist/aberdeen.js.map +1 -0
  4. package/dist/prediction.d.ts +29 -0
  5. package/dist/prediction.js +110 -0
  6. package/dist/prediction.js.map +1 -0
  7. package/dist/route.d.ts +16 -0
  8. package/dist/route.js +119 -0
  9. package/dist/route.js.map +1 -0
  10. package/dist/transitions.d.ts +18 -0
  11. package/dist/transitions.js +67 -0
  12. package/dist/transitions.js.map +1 -0
  13. package/package.json +5 -2
  14. package/.github/workflows/deploy.yml +0 -43
  15. package/.vscode/launch.json +0 -23
  16. package/examples/input/index.html +0 -8
  17. package/examples/input/input.css +0 -56
  18. package/examples/input/input.js +0 -66
  19. package/examples/list/index.html +0 -7
  20. package/examples/list/list.js +0 -47
  21. package/examples/router/index.html +0 -8
  22. package/examples/router/page-home.js +0 -12
  23. package/examples/router/page-list.js +0 -35
  24. package/examples/router/page-settings.js +0 -6
  25. package/examples/router/router.js +0 -76
  26. package/examples/router/style.css +0 -88
  27. package/examples/tic-tac-toe/index.html +0 -8
  28. package/examples/tic-tac-toe/tic-tac-toe.css +0 -50
  29. package/examples/tic-tac-toe/tic-tac-toe.js +0 -90
  30. package/src/aberdeen.ts +0 -2037
  31. package/src/prediction.ts +0 -117
  32. package/src/route.ts +0 -121
  33. package/src/transitions.ts +0 -73
  34. package/tests/_fakedom.js +0 -255
  35. package/tests/_init.js +0 -81
  36. package/tests/array.js +0 -109
  37. package/tests/binding.js +0 -106
  38. package/tests/browsers.js +0 -22
  39. package/tests/clean.js +0 -26
  40. package/tests/count.js +0 -105
  41. package/tests/create.js +0 -92
  42. package/tests/destroy.js +0 -270
  43. package/tests/dom.js +0 -219
  44. package/tests/errors.js +0 -114
  45. package/tests/immediate.js +0 -87
  46. package/tests/map.js +0 -76
  47. package/tests/objmap.js +0 -40
  48. package/tests/onEach.js +0 -392
  49. package/tests/prediction.js +0 -97
  50. package/tests/props.js +0 -49
  51. package/tests/schedule.js +0 -44
  52. package/tests/scope.js +0 -277
  53. package/tests/sort.js +0 -105
  54. package/tests/store.js +0 -254
  55. package/tsconfig.json +0 -67
package/tests/destroy.js DELETED
@@ -1,270 +0,0 @@
1
- describe('Destroy event', function() {
2
- it('works for simple deletes', () => {
3
- let store = new Store(true)
4
- mount(document.body, () => {
5
- if (store.get()) node('b', {destroy: "x"})
6
- else node('c', {destroy: "x"})
7
- })
8
- assertBody(`b{}`)
9
- assertEqual(getCounts(), {new: 1, change: 1})
10
-
11
- store.set(false)
12
- passTime(1)
13
- assertBody(`c{} b{@class="x"}`)
14
- assertEqual(getCounts(), {new: 2, change: 3})
15
-
16
- passTime(5000)
17
- assertBody(`c{}`)
18
- assertEqual(getCounts(), {new: 2, change: 4})
19
- });
20
-
21
- it('inserts before deleted item', () => {
22
- let store = new Store(['a'])
23
- mount(document.body, () => {
24
- store.onEach(v => {
25
- node(v.get(), {destroy: "x"})
26
- })
27
- })
28
-
29
- store.set([undefined])
30
- passTime(1)
31
- assertBody(`a{@class="x"}`)
32
-
33
- store.set(['b'])
34
- passTime(1)
35
- assertBody(`b{} a{@class="x"}`)
36
-
37
- passTime(2000)
38
- assertBody(`b{}`)
39
- });
40
-
41
- it('transitions onEach deletes', () => {
42
- let store = new Store(['a', 'b', 'c'])
43
- let mnt = mount(document.body, () => {
44
- store.onEach(v => {
45
- node(v.get(), {destroy: "x"})
46
- })
47
- })
48
- assertBody(`a{} b{} c{}`)
49
- assertEqual(getCounts(), {new: 3, change: 3})
50
-
51
- store.set(1, undefined)
52
- passTime(1)
53
- assertBody(`a{} b{@class="x"} c{}`)
54
- passTime(2000)
55
- assertBody(`a{} c{}`)
56
-
57
- store.set(['a', 'b', 'c', 'd', 'e', 'f'])
58
- passTime(1)
59
- store.set([undefined, 'b', undefined, undefined, 'e', undefined])
60
- passTime(1)
61
- assertBody(`a{@class="x"} b{} c{@class="x"} d{@class="x"} e{} f{@class="x"}`)
62
- store.set(['a2', 'b', undefined, 'd2', 'e', 'f2'])
63
- passTime(1)
64
- assertBody(`a2{} a{@class="x"} b{} d2{} c{@class="x"} d{@class="x"} e{} f2{} f{@class="x"}`)
65
- passTime(2000)
66
- assertBody(`a2{} b{} d2{} e{} f2{}`)
67
- })
68
-
69
- it('deletes in the middle of deleting items', () => {
70
- let store = new Store(['a', 'b', 'c'])
71
- mount(document.body, () => {
72
- store.onEach(v => {
73
- node(v.get(), {destroy: "x"})
74
- })
75
- })
76
- passTime(1)
77
- assertBody(`a{} b{} c{}`)
78
-
79
- store.set(2, undefined)
80
- passTime(500)
81
- assertBody(`a{} b{} c{@class="x"}`)
82
- store.set(1, undefined)
83
- passTime(500)
84
- assertBody(`a{} b{@class="x"} c{@class="x"}`)
85
- store.set(0, undefined)
86
- passTime(500)
87
- assertBody(`a{@class="x"} b{@class="x"} c{@class="x"}`)
88
- passTime(500)
89
- assertBody(`a{@class="x"} b{@class="x"}`)
90
- passTime(500)
91
- assertBody(`a{@class="x"}`)
92
- passTime(500)
93
- assertBody(``)
94
-
95
- store.set([undefined, 'b'])
96
- passTime(1)
97
- assertBody(`b{}`)
98
- });
99
-
100
- it('aborts deletion transition on higher level removal', () => {
101
- let store = new Store(['a'])
102
- mount(document.body, () => {
103
- store.onEach(v => {
104
- node(v.get(), {destroy: "x"})
105
- })
106
- })
107
- passTime(1)
108
- assertBody(`a{}`)
109
-
110
- store.set([])
111
- passTime(1)
112
- assertBody(`a{@class="x"}`)
113
- store.set(undefined)
114
- passTime(2001)
115
- assertBody(``)
116
-
117
- // what happens when the whole store is removed?
118
- // the held elements should be removed immediately... are they? and does the timeout then cause havoc?
119
- });
120
-
121
- it('transitions removal of an entire onEach', () => {
122
- let store = new Store(['a'])
123
- mount(document.body, () => {
124
- store.onEach(v => {
125
- node(v.get(), {destroy: "x"})
126
- })
127
- })
128
- passTime(1)
129
- assertBody(`a{}`)
130
- store.set(undefined)
131
- passTime(1000)
132
- assertBody(`a{@class="x"}`)
133
- passTime(1000)
134
- assertBody(``)
135
- });
136
-
137
- it('insert new elements after a recently deleted item', () => {
138
- let store = new Store({b: true, c: false})
139
- mount(document.body, () => {
140
- node('a')
141
- observe(() => {
142
- if (store.get('b')) node('b', {destroy: 'y'})
143
- if (store.get('c')) node('c')
144
- })
145
- })
146
- assertBody(`a{} b{}`)
147
-
148
- store.set('b', false)
149
- passTime(1)
150
- assertBody(`a{} b{@class="y"}`)
151
-
152
- passTime(2000)
153
- assertBody(`a{}`)
154
-
155
- // This should trigger lazy deletion of the DeletionScope
156
- store.set('c', true)
157
- passTime(1)
158
- assertBody(`a{} c{}`)
159
- })
160
-
161
- it('remove elements before and after a deleting element', () => {
162
- let store = new Store({a: true, b: true, c: true})
163
- mount(document.body, () => {
164
- store.onEach(el => {
165
- if (el.get()) node(el.index(), el.index()=='b' ? {destroy: 'y'}: null)
166
- })
167
- })
168
- assertBody(`a{} b{} c{}`)
169
-
170
- store.set('b', false)
171
- passTime(1)
172
- assertBody(`a{} b{@class="y"} c{}`)
173
-
174
- store.set('a', false)
175
- passTime(1)
176
- assertBody(`b{@class="y"} c{}`)
177
-
178
- store.set('c', false)
179
- passTime(1)
180
- assertBody(`b{@class="y"}`)
181
-
182
- passTime(2000)
183
- assertBody(``)
184
- })
185
-
186
- it('remove middle elements before and after a deleting element', () => {
187
- let store = new Store({a: true, b: true, c: true, d: true, e: true})
188
- mount(document.body, () => {
189
- store.onEach(el => {
190
- if (el.get()) node(el.index(), el.index()=='c' ? {destroy: 'y'}: null)
191
- })
192
- })
193
- assertBody(`a{} b{} c{} d{} e{}`)
194
-
195
- store.set('c', false)
196
- passTime(1)
197
- assertBody(`a{} b{} c{@class="y"} d{} e{}`)
198
-
199
- store.set('b', false)
200
- passTime(1)
201
- assertBody(`a{} c{@class="y"} d{} e{}`)
202
-
203
- store.set('d', false)
204
- passTime(1)
205
- assertBody(`a{} c{@class="y"} e{}`)
206
-
207
- passTime(2000)
208
- assertBody(`a{} e{}`)
209
- })
210
-
211
- it('remove elements before and after a deleting element', () => {
212
- let store = new Store({a: true, b: true, c: true})
213
- mount(document.body, () => {
214
- store.onEach(el => {
215
- if (el.get()) node(el.index(), el.index()=='b' ? {destroy: 'y'}: null)
216
- })
217
- })
218
- assertBody(`a{} b{} c{}`)
219
-
220
- store.set('b', false)
221
- passTime(1)
222
- assertBody(`a{} b{@class="y"} c{}`)
223
-
224
- store.set('a', false)
225
- passTime(1)
226
- assertBody(`b{@class="y"} c{}`)
227
-
228
- store.set('c', false)
229
- passTime(1)
230
- assertBody(`b{@class="y"}`)
231
-
232
- passTime(2000)
233
- assertBody(``)
234
- })
235
-
236
- it('performs a shrink animation', () => {
237
- let store = new Store(true)
238
- mount(document.body, () => {
239
- if (store.get()) node('a', {destroy: shrink})
240
- })
241
-
242
- assertBody(`a{}`)
243
-
244
- store.set(false)
245
- passTime(1)
246
- assert(getBody().startsWith('a{'))
247
- assert(getBody().indexOf('scaleY')>=0 && getBody().indexOf('scaleX')<0)
248
- passTime(2000)
249
- assertBody(``)
250
- })
251
-
252
- it('performs a horizontal shrink animation', () => {
253
- let store = new Store(true)
254
- mount(document.body, () => {
255
- node('div', {style: {display: 'flex', flexDirection: 'row-reverse'}}, () => {
256
- if (store.get()) node('a', {destroy: shrink})
257
- })
258
- })
259
-
260
- assertBody(`div{:display="flex" :flexDirection="row-reverse" a{}}`)
261
-
262
- store.set(false)
263
- passTime(1)
264
- assert(getBody().indexOf('scaleX')>=0 && getBody().indexOf('scaleY')<0)
265
-
266
- passTime(2000)
267
- assertBody(`div{:display="flex" :flexDirection="row-reverse"}`)
268
- })
269
-
270
- })
package/tests/dom.js DELETED
@@ -1,219 +0,0 @@
1
- describe('DOM creator', function() {
2
- it('adds nodes', () => {
3
- mount(document.body, () => {
4
- node('p')
5
- })
6
- passTime();
7
- assertBody(`p{}`)
8
- });
9
-
10
- it('adds classes', () => {
11
- mount(document.body, () => {
12
- node('p.a.b')
13
- })
14
- passTime();
15
- assertBody(`p{@class="a b"}`)
16
- });
17
-
18
- it('sets attributes', () => {
19
- mount(document.body, () => {
20
- node('div', {class: 'C', text: "T"}, {id: 'I', index: 1})
21
- })
22
- passTime();
23
- assertBody(`div{@class="C" @id="I" @index="1" "T"}`)
24
- });
25
-
26
- it('sets properties', () => {
27
- mount(document.body, () => {
28
- node('p', {className: 'C', value: 3})
29
- })
30
- passTime();
31
- assertBody(`p{@class="C" value=3}`)
32
- });
33
-
34
- it('nests elements', () => {
35
- mount(document.body, () => {
36
- node('p', () => {
37
- node('a', () => {
38
- node('i', () => {
39
- text('contents')
40
- })
41
- })
42
- })
43
- })
44
- passTime();
45
- assertBody(`p{a{i{"contents"}}}`)
46
- });
47
-
48
- it('sets properties from the inner scope', () => {
49
- mount(document.body, () => {
50
- node('a', () => {
51
- prop('href', '/')
52
- prop({
53
- target: '_blank',
54
- disabled: true,
55
- })
56
- })
57
- })
58
- passTime();
59
- assertBody(`a{@href="/" @target="_blank" disabled=true}`)
60
- });
61
-
62
- it('sets style objects', () => {
63
- mount(document.body, () => {
64
- node('a', {style: 'color: red;'})
65
- node('b', {style: {color: 'green'}})
66
- node('c', () => {
67
- prop({style: {color: 'orange'}})
68
- })
69
- node('d', () => {
70
- prop('style', {color: 'purple'})
71
- })
72
- node('e', () => {
73
- prop('style', 'color: magento;')
74
- })
75
- node('f', () => {
76
- prop({style: 'color: cyan;'})
77
- })
78
-
79
- })
80
- assertBody(`a{@style="color: red;"} b{:color="green"} c{:color="orange"} d{:color="purple"} e{@style="color: magento;"} f{@style="color: cyan;"}`)
81
- })
82
-
83
- it('unmounts', () => {
84
- let store = new Store('Hej world')
85
- let cnt = 0
86
- mount(document.body, () => {
87
- cnt++
88
- node('p', store.get())
89
- })
90
- assertBody(`p{"Hej world"}`)
91
-
92
- unmount()
93
- assertBody(``)
94
-
95
- store.set('Updated')
96
- passTime()
97
- assertEqual(cnt, 1)
98
- })
99
-
100
- it('creates text nodes', () => {
101
- let index = new Store(0)
102
- let cases = [
103
- ['test', `"test"`],
104
- ['', `""`],
105
- [0, `"0"`],
106
- [null, ``],
107
- [undefined, ``],
108
- [false, `"false"`],
109
- ]
110
- mount(document.body, () => {
111
- text(cases[index.get()][0])
112
- })
113
-
114
- while(true) {
115
- passTime()
116
- assertBody(cases[index.peek()][1])
117
- if (index.peek() >= cases.length-1) {
118
- break
119
- }
120
- index.set(index.peek()+1)
121
- }
122
- })
123
-
124
- it('adds preexisting elements to the DOM', () => {
125
- mount(document.body, () => {
126
- let el = document.createElement('video')
127
- el.classList.add("test")
128
- node(el)
129
- })
130
- assertBody(`video{@class="test"}`)
131
- })
132
-
133
- it('handles nontypical options well', () => {
134
- let cases = [
135
- [`div{}`, () => node("")],
136
- [`div{}`, () => node(".")],
137
- [`div{@class="a b c"}`, () => node(".a.b.c")],
138
- [`div{"1234"}`, () => node(undefined, 1234)],
139
- [`_!@#*{"replacement"}`, () => node("_!@#*", null, undefined, {}, "original", 1234, "replacement")],
140
- ]
141
- for(let c of cases) {
142
- mount(document.body, () => {
143
- c[1]()
144
- })
145
- assertBody(c[0])
146
- unmount()
147
- }
148
- mount(document.body, () => {
149
- assertThrow("Unexpected argument", () => node("span", []))
150
- assertThrow("Unexpected argument", () => node("span", new Error()))
151
- assertThrow("Unexpected argument", () => node("span", true))
152
- })
153
- })
154
-
155
- it('dumps all basic values', () => {
156
- let store = new Store([true,false,null,undefined,-12,3.14,"test",'"quote"'])
157
- mount(document.body, () => store.dump())
158
- assertBody(`"<array>" ul{li{"0: " "true"} li{"1: " "false"} li{"2: " "null"} li{"4: " "-12"} li{"5: " "3.14"} li{"6: " "\\"test\\""} li{"7: " "\\"\\\\\\"quote\\\\\\"\\""}}`)
159
- })
160
-
161
- it('dumps maps, objects and arrays', () => {
162
- let store = new Store(new Map([[3,4],['a','b']]))
163
- mount(document.body, () => store.dump())
164
- assertBody(`"<map>" ul{li{"\\"a\\": " "\\"b\\""} li{"3: " "4"}}`)
165
-
166
- store.set({3: 4, a: 'b'})
167
- passTime()
168
- assertBody(`"<object>" ul{li{"\\"3\\": " "4"} li{"\\"a\\": " "\\"b\\""}}`)
169
-
170
- store.set([4, undefined, 'b'])
171
- passTime()
172
- assertBody(`"<array>" ul{li{"0: " "4"} li{"2: " "\\"b\\""}}`)
173
- })
174
-
175
- it('adds html', () => {
176
- let store = new Store('test')
177
- mount(document.body, () => {
178
- node('main', () => {
179
- node('hr')
180
- observe(() => {
181
- html(store.get())
182
- })
183
- node('img')
184
- })
185
- })
186
- assertBody(`main{hr{} fake-emulated-html{"test"} img{}}`)
187
-
188
- store.set("")
189
- passTime()
190
- assertBody(`main{hr{} img{}}`)
191
-
192
- store.set(123)
193
- passTime()
194
- assertBody(`main{hr{} fake-emulated-html{"123"} img{}}`)
195
-
196
- assertThrow("Operation not permitted outside of a mount() scope", () => html("test"))
197
- observe(() => {
198
- assertThrow("Operation not permitted outside of a mount() scope", () => html("test"))
199
- })
200
- })
201
-
202
- it('only unlinks the top parent of the tree being removed', () => {
203
- let store = new Store(true)
204
- mount(document.body, () => {
205
- if (store.get()) node('main', () => {
206
- node('a')
207
- node('b')
208
- node('c')
209
- })
210
- })
211
- assertBody(`main{a{} b{} c{}}`)
212
- assertEqual(getCounts(), {new: 4, change: 4})
213
-
214
- store.set(false)
215
- passTime()
216
- assertBody(``)
217
- assertEqual(getCounts(), {new: 4, change: 5})
218
- })
219
- });
package/tests/errors.js DELETED
@@ -1,114 +0,0 @@
1
- describe('Error handling', () => {
2
- it('continues rendering after an error', () => {
3
- let error = new Store(false)
4
- mount(document.body, () => {
5
- node('a', () => {
6
- node('b')
7
- if (error.get()) {
8
- throw Error('FakeError')
9
- }
10
- node('c')
11
- })
12
- node('d')
13
- })
14
- passTime()
15
- assertBody(`a{b{} c{}} d{}`)
16
- error.set(true)
17
- assertThrow('FakeError', passTime)
18
- assertBody(`a{b{}} d{}`)
19
- })
20
-
21
-
22
- it('throws when doing DOM operations outside of mount', () => {
23
- let ops = [
24
- () => node('div'),
25
- () => text('hi'),
26
- () => prop('hi'),
27
- () => getParentElement(),
28
- ]
29
- for(let op of ops) {
30
- assertThrow('outside of a mount', op)
31
- }
32
- assertThrow(() => clean(()=>"test"))
33
-
34
- observe(() => {
35
- for(let op of ops) {
36
- assertThrow('outside of a mount', op)
37
- }
38
- })
39
- })
40
-
41
-
42
- it('continue rendering after an error in onEach', () => {
43
- let store = new Store(['a','b','c'])
44
- mount(document.body, () => {
45
- store.onEach(item => {
46
- if (item.index()%2) noSuchFunction()
47
- text(item.get())
48
- })
49
- })
50
- assertThrow(passTime)
51
- assertBody(`"a" "c"`)
52
-
53
- store.push('d')
54
- store.push('e')
55
- assertThrow(passTime)
56
- assertBody(`"a" "c" "e"`)
57
- })
58
-
59
- it('continue rendering after an error in onEach sort', () => {
60
- let store = new Store(['a','b','c'])
61
- mount(document.body, () => {
62
- store.onEach(item => {
63
- text(item.get())
64
- }, item => {
65
- if (item.index()%2) noSuchFunction()
66
- return -item.index()
67
- })
68
- })
69
- assertThrow(passTime)
70
- assertBody(`"c" "a"`)
71
-
72
- store.push('d')
73
- store.push('e')
74
- assertThrow(passTime)
75
- assertBody(`"e" "c" "a"`)
76
- })
77
-
78
- it('throws when indexing a non-indexable type', () => {
79
- let store = new Store(3)
80
- assertThrow('Value 3 is not a collection', () => store.ref('a'))
81
- assertThrow('Value 3 is not a collection', () => store.makeRef('a'))
82
- })
83
-
84
- it('throws when onEach() is invoked wrong', () => {
85
- let store1 = new Store()
86
- let store2 = new Store()
87
- assertThrow('Operation not permitted outside', () => store1.onEach(item=>{}))
88
- store1.set(5)
89
- observe(() => {
90
- assertThrow('neither a collection nor undefined', () => store1.onEach(item=>{}))
91
- assertThrow('function as its last argument', () => store1.onEach())
92
-
93
- store2.onEach('a', 3, true, item => {
94
- assert(false, "Should not be invoked")
95
- })
96
- })
97
- passTime()
98
- })
99
-
100
- it('throws when passing invalid Store arguments', () => {
101
- assertThrow('1st parameter should be an ObsCollection', () => new Store(3, true))
102
- })
103
-
104
- it('breaks up long update->observe recursions', () => {
105
- let store = new Store({a: 0, b: 0})
106
- observe(() => {
107
- store.set('a', store.get('b')+1)
108
- })
109
- observe(() => {
110
- store.set('b', store.get('a')+1)
111
- })
112
- assertThrow('recursive', passTime)
113
- })
114
- })
@@ -1,87 +0,0 @@
1
- describe('Immediate observe', function() {
2
-
3
- it('runs immediately', () => {
4
- let store = new Store({a: 1})
5
- let count = 0
6
- immediateObserve(() => {
7
- store.set('b', store.get('a') * 2)
8
- count++
9
- })
10
- assertEqual(store.get('b'), 2)
11
- assertEqual(count, 1)
12
-
13
- store.set('a', 3)
14
- assertEqual(store.get('b'), 6)
15
- assertEqual(count, 2)
16
-
17
- passTime() // shouldn't change anything
18
- assertEqual(store.get('b'), 6)
19
- assertEqual(count, 2)
20
- });
21
-
22
- it('stabilizes dependent values', () => {
23
- let store = new Store({num: 1})
24
- immediateObserve(() => { // num to str
25
- let num = store.get("num")
26
- if (typeof num === 'number') {
27
- store.set('str', "x".repeat(num))
28
- } else {
29
- store.set('num', 0) // will call this observer recursively
30
- }
31
- })
32
- immediateObserve(() => { // str to num
33
- let str = store.get('str')
34
- if (typeof str === 'string') {
35
- store.set('str', "x".repeat(str.length)) // replace str chars by 'x'
36
- store.set('num', str.length) // may call this observer recursively
37
- } else {
38
- store.set('str', "") // will call this observer recursively
39
- }
40
- })
41
- assertEqual(store.get(), {num: 1, str: 'x'})
42
-
43
- store.set('num', 3)
44
- assertEqual(store.get(), {num: 3, str: 'xxx'})
45
-
46
- store.set('num', '')
47
- assertEqual(store.get(), {num: 0, str: ''})
48
-
49
- store.set('str', 'af123')
50
- assertEqual(store.get(), {num: 5, str: 'xxxxx'})
51
- })
52
-
53
- it('stops when it goes out of scope', () => {
54
- let store = new Store({a: 1})
55
- observe(() => {
56
- if (store.get('stop')) return
57
- immediateObserve(() => {
58
- store.set('b', store.get('a') * 2)
59
- })
60
- })
61
- assertEqual(store.get('b'), 2)
62
-
63
- store.set('a', 3)
64
- assertEqual(store.get('b'), 6)
65
-
66
- store.set('stop', true)
67
- passTime() // allow the deferred observe to rerun, expiring the immediate observe
68
-
69
- store.set('a', 5)
70
- assertEqual(store.get('b'), 6)
71
- })
72
-
73
- it('throws an error if a loop does not stabilize', () => {
74
- let store = new Store({a: 1})
75
- immediateObserve(() => {
76
- store.set('b', store.get('a') + 1)
77
- })
78
- // This will start an infinite recursion, which should be broken up.
79
- immediateObserve(() => {
80
- store.set('a', store.get('b') + 1)
81
- })
82
- // The error for the above is to be thrown async.
83
- assertThrow('recursive updates', () => {
84
- passTime()
85
- })
86
- })
87
- })