@pyreon/state-tree 0.11.5 → 0.11.7
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/README.md +63 -63
- package/lib/devtools.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/types/index.d.ts +1 -1
- package/package.json +14 -14
- package/src/devtools.ts +1 -1
- package/src/index.ts +6 -6
- package/src/instance.ts +8 -8
- package/src/middleware.ts +3 -3
- package/src/model.ts +4 -4
- package/src/patch.ts +14 -14
- package/src/registry.ts +2 -2
- package/src/snapshot.ts +6 -6
- package/src/tests/comprehensive.test.ts +109 -109
- package/src/tests/devtools.test.ts +43 -43
- package/src/tests/edge-cases.test.ts +138 -138
- package/src/tests/model.test.ts +157 -157
- package/src/types.ts +3 -3
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
onModelChange,
|
|
7
7
|
registerInstance,
|
|
8
8
|
unregisterInstance,
|
|
9
|
-
} from
|
|
10
|
-
import { model } from
|
|
9
|
+
} from '../devtools'
|
|
10
|
+
import { model } from '../index'
|
|
11
11
|
|
|
12
12
|
const Counter = model({
|
|
13
13
|
state: { count: 0 },
|
|
@@ -18,97 +18,97 @@ const Counter = model({
|
|
|
18
18
|
|
|
19
19
|
afterEach(() => _resetDevtools())
|
|
20
20
|
|
|
21
|
-
describe(
|
|
22
|
-
test(
|
|
21
|
+
describe('state-tree devtools', () => {
|
|
22
|
+
test('getActiveModels returns empty initially', () => {
|
|
23
23
|
expect(getActiveModels()).toEqual([])
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
-
test(
|
|
26
|
+
test('registerInstance makes model visible', () => {
|
|
27
27
|
const counter = Counter.create()
|
|
28
|
-
registerInstance(
|
|
29
|
-
expect(getActiveModels()).toEqual([
|
|
28
|
+
registerInstance('app-counter', counter)
|
|
29
|
+
expect(getActiveModels()).toEqual(['app-counter'])
|
|
30
30
|
})
|
|
31
31
|
|
|
32
|
-
test(
|
|
32
|
+
test('getModelInstance returns the registered instance', () => {
|
|
33
33
|
const counter = Counter.create()
|
|
34
|
-
registerInstance(
|
|
35
|
-
expect(getModelInstance(
|
|
34
|
+
registerInstance('app-counter', counter)
|
|
35
|
+
expect(getModelInstance('app-counter')).toBe(counter)
|
|
36
36
|
})
|
|
37
37
|
|
|
38
|
-
test(
|
|
39
|
-
expect(getModelInstance(
|
|
38
|
+
test('getModelInstance returns undefined for unregistered name', () => {
|
|
39
|
+
expect(getModelInstance('nope')).toBeUndefined()
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
-
test(
|
|
42
|
+
test('unregisterInstance removes the model', () => {
|
|
43
43
|
const counter = Counter.create()
|
|
44
|
-
registerInstance(
|
|
45
|
-
unregisterInstance(
|
|
44
|
+
registerInstance('app-counter', counter)
|
|
45
|
+
unregisterInstance('app-counter')
|
|
46
46
|
expect(getActiveModels()).toEqual([])
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
-
test(
|
|
49
|
+
test('getModelSnapshot returns current snapshot', () => {
|
|
50
50
|
const counter = Counter.create({ count: 5 })
|
|
51
|
-
registerInstance(
|
|
52
|
-
expect(getModelSnapshot(
|
|
51
|
+
registerInstance('app-counter', counter)
|
|
52
|
+
expect(getModelSnapshot('app-counter')).toEqual({ count: 5 })
|
|
53
53
|
})
|
|
54
54
|
|
|
55
|
-
test(
|
|
55
|
+
test('getModelSnapshot reflects mutations', () => {
|
|
56
56
|
const counter = Counter.create()
|
|
57
|
-
registerInstance(
|
|
57
|
+
registerInstance('app-counter', counter)
|
|
58
58
|
counter.inc()
|
|
59
59
|
counter.inc()
|
|
60
|
-
expect(getModelSnapshot(
|
|
60
|
+
expect(getModelSnapshot('app-counter')).toEqual({ count: 2 })
|
|
61
61
|
})
|
|
62
62
|
|
|
63
|
-
test(
|
|
64
|
-
expect(getModelSnapshot(
|
|
63
|
+
test('getModelSnapshot returns undefined for unregistered name', () => {
|
|
64
|
+
expect(getModelSnapshot('nope')).toBeUndefined()
|
|
65
65
|
})
|
|
66
66
|
|
|
67
|
-
test(
|
|
67
|
+
test('onModelChange fires on register', () => {
|
|
68
68
|
const calls: number[] = []
|
|
69
69
|
const unsub = onModelChange(() => calls.push(1))
|
|
70
70
|
|
|
71
71
|
const counter = Counter.create()
|
|
72
|
-
registerInstance(
|
|
72
|
+
registerInstance('app-counter', counter)
|
|
73
73
|
expect(calls.length).toBe(1)
|
|
74
74
|
|
|
75
75
|
unsub()
|
|
76
76
|
})
|
|
77
77
|
|
|
78
|
-
test(
|
|
78
|
+
test('onModelChange fires on unregister', () => {
|
|
79
79
|
const counter = Counter.create()
|
|
80
|
-
registerInstance(
|
|
80
|
+
registerInstance('app-counter', counter)
|
|
81
81
|
|
|
82
82
|
const calls: number[] = []
|
|
83
83
|
const unsub = onModelChange(() => calls.push(1))
|
|
84
|
-
unregisterInstance(
|
|
84
|
+
unregisterInstance('app-counter')
|
|
85
85
|
expect(calls.length).toBe(1)
|
|
86
86
|
|
|
87
87
|
unsub()
|
|
88
88
|
})
|
|
89
89
|
|
|
90
|
-
test(
|
|
90
|
+
test('onModelChange unsubscribe stops notifications', () => {
|
|
91
91
|
const calls: number[] = []
|
|
92
92
|
const unsub = onModelChange(() => calls.push(1))
|
|
93
93
|
unsub()
|
|
94
94
|
|
|
95
|
-
registerInstance(
|
|
95
|
+
registerInstance('app-counter', Counter.create())
|
|
96
96
|
expect(calls.length).toBe(0)
|
|
97
97
|
})
|
|
98
98
|
|
|
99
|
-
test(
|
|
100
|
-
registerInstance(
|
|
101
|
-
registerInstance(
|
|
102
|
-
expect(getActiveModels().sort()).toEqual([
|
|
99
|
+
test('multiple instances are tracked', () => {
|
|
100
|
+
registerInstance('a', Counter.create())
|
|
101
|
+
registerInstance('b', Counter.create())
|
|
102
|
+
expect(getActiveModels().sort()).toEqual(['a', 'b'])
|
|
103
103
|
})
|
|
104
104
|
|
|
105
105
|
test("getModelInstance returns undefined and cleans up when WeakRef target is GC'd", () => {
|
|
106
106
|
// We simulate a GC'd WeakRef by monkey-patching the registered WeakRef's deref.
|
|
107
107
|
const counter = Counter.create()
|
|
108
|
-
registerInstance(
|
|
108
|
+
registerInstance('gc-test', counter)
|
|
109
109
|
|
|
110
110
|
// Verify it's accessible
|
|
111
|
-
expect(getModelInstance(
|
|
111
|
+
expect(getModelInstance('gc-test')).toBe(counter)
|
|
112
112
|
|
|
113
113
|
// Now register a new entry with a fake WeakRef-like object that returns undefined.
|
|
114
114
|
// Since _activeModels is a Map<string, WeakRef<object>>, we can re-register
|
|
@@ -135,27 +135,27 @@ describe("state-tree devtools", () => {
|
|
|
135
135
|
|
|
136
136
|
try {
|
|
137
137
|
const c2 = Counter.create()
|
|
138
|
-
registerInstance(
|
|
138
|
+
registerInstance('gc-victim', c2)
|
|
139
139
|
|
|
140
140
|
// Before GC
|
|
141
|
-
expect(getModelInstance(
|
|
142
|
-
expect(getActiveModels()).toContain(
|
|
141
|
+
expect(getModelInstance('gc-victim')).toBe(c2)
|
|
142
|
+
expect(getActiveModels()).toContain('gc-victim')
|
|
143
143
|
|
|
144
144
|
// Simulate GC
|
|
145
145
|
collected = true
|
|
146
146
|
|
|
147
147
|
// getActiveModels cleans up dead refs first (line 43 branch)
|
|
148
|
-
expect(getActiveModels()).not.toContain(
|
|
148
|
+
expect(getActiveModels()).not.toContain('gc-victim')
|
|
149
149
|
|
|
150
150
|
// Re-register to test getModelInstance's GC cleanup path (lines 55-57)
|
|
151
|
-
registerInstance(
|
|
151
|
+
registerInstance('gc-victim-2', Counter.create())
|
|
152
152
|
collected = true
|
|
153
153
|
|
|
154
154
|
// getModelInstance hits lines 55-57: instance is undefined, deletes entry, returns undefined
|
|
155
|
-
expect(getModelInstance(
|
|
155
|
+
expect(getModelInstance('gc-victim-2')).toBeUndefined()
|
|
156
156
|
|
|
157
157
|
// getModelSnapshot returns undefined for GC'd instance
|
|
158
|
-
expect(getModelSnapshot(
|
|
158
|
+
expect(getModelSnapshot('gc-victim-2')).toBeUndefined()
|
|
159
159
|
} finally {
|
|
160
160
|
globalThis.WeakRef = OriginalWeakRef
|
|
161
161
|
}
|