@furystack/utils 8.1.8 → 8.1.10
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [8.1.10] - 2026-02-11
|
|
4
|
+
|
|
5
|
+
### 🧪 Tests
|
|
6
|
+
|
|
7
|
+
- Wrapped `ObservableValue` instances in `using()` in all observable-value tests to ensure cleanup runs even when assertions fail
|
|
8
|
+
|
|
9
|
+
### ⬆️ Dependencies
|
|
10
|
+
|
|
11
|
+
- Bump `vitest` from `^4.0.17` to `^4.0.18`
|
|
12
|
+
|
|
13
|
+
## [8.1.9] - 2026-01-26
|
|
14
|
+
|
|
15
|
+
### 🔧 Chores
|
|
16
|
+
|
|
17
|
+
- Standardized author format, improved keywords, removed obsolete `gitHead`, added `engines` (Node 22+) and `sideEffects: false`
|
|
18
|
+
|
|
3
19
|
## [8.1.8] - 2026-01-22
|
|
4
20
|
|
|
5
21
|
### ⬆️ Dependencies
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observable-value.spec.d.ts","sourceRoot":"","sources":["../src/observable-value.spec.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"observable-value.spec.d.ts","sourceRoot":"","sources":["../src/observable-value.spec.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,eAAO,MAAM,eAAe,yCAwM1B,CAAA"}
|
|
@@ -1,50 +1,56 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
2
|
import { ObservableValue } from './observable-value.js';
|
|
3
|
+
import { using } from './using.js';
|
|
3
4
|
/**
|
|
4
5
|
* Observable Value tests
|
|
5
6
|
*/
|
|
6
7
|
export const observableTests = describe('Observable', () => {
|
|
7
8
|
it('should be constructed with an undefined initial value', () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
using(new ObservableValue(undefined), (v) => {
|
|
10
|
+
expect(v).toBeInstanceOf(ObservableValue);
|
|
11
|
+
expect(v.getValue()).toBe(undefined);
|
|
12
|
+
});
|
|
11
13
|
});
|
|
12
14
|
it('should be constructed with initial value', () => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
using(new ObservableValue(1), (v) => {
|
|
16
|
+
expect(v.getValue()).toBe(1);
|
|
17
|
+
});
|
|
15
18
|
});
|
|
16
19
|
describe('Subscription callback', () => {
|
|
17
20
|
it('should be triggered only when a value is changed', () => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
using(new ObservableValue(1), (v) => {
|
|
22
|
+
const doneCallback = vi.fn();
|
|
23
|
+
v.subscribe(() => {
|
|
24
|
+
expect(v.getValue()).toBe(2);
|
|
25
|
+
doneCallback();
|
|
26
|
+
});
|
|
27
|
+
v.setValue(1);
|
|
28
|
+
v.setValue(1);
|
|
29
|
+
v.setValue(2);
|
|
30
|
+
expect(doneCallback).toBeCalledTimes(1);
|
|
23
31
|
});
|
|
24
|
-
v.setValue(1);
|
|
25
|
-
v.setValue(1);
|
|
26
|
-
v.setValue(2);
|
|
27
|
-
expect(doneCallback).toBeCalledTimes(1);
|
|
28
32
|
});
|
|
29
33
|
it('should be triggered only on change', () => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
using(new ObservableValue(1), (v) => {
|
|
35
|
+
const doneCallback = vi.fn();
|
|
36
|
+
v.subscribe((value) => {
|
|
37
|
+
expect(value).toBe(2);
|
|
38
|
+
doneCallback();
|
|
39
|
+
});
|
|
40
|
+
v.setValue(2);
|
|
41
|
+
expect(doneCallback).toBeCalledTimes(1);
|
|
35
42
|
});
|
|
36
|
-
v.setValue(2);
|
|
37
|
-
expect(doneCallback).toBeCalledTimes(1);
|
|
38
43
|
});
|
|
39
44
|
it('should be triggered only on change in async manner', () => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
using(new ObservableValue(1), (v) => {
|
|
46
|
+
const doneCallback = vi.fn();
|
|
47
|
+
v.subscribe(async (value) => {
|
|
48
|
+
expect(value).toBe(2);
|
|
49
|
+
doneCallback();
|
|
50
|
+
});
|
|
51
|
+
v.setValue(2);
|
|
52
|
+
expect(doneCallback).toBeCalledTimes(1);
|
|
45
53
|
});
|
|
46
|
-
v.setValue(2);
|
|
47
|
-
expect(doneCallback).toBeCalledTimes(1);
|
|
48
54
|
});
|
|
49
55
|
});
|
|
50
56
|
describe('Unsubscribe', () => {
|
|
@@ -53,13 +59,14 @@ export const observableTests = describe('Observable', () => {
|
|
|
53
59
|
const doneCallback = vi.fn((value) => {
|
|
54
60
|
expect(value).toBe(2);
|
|
55
61
|
});
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
using(new ObservableValue(1), (v) => {
|
|
63
|
+
const observer1 = v.subscribe(shouldNotCall);
|
|
64
|
+
v.subscribe(doneCallback);
|
|
65
|
+
v.unsubscribe(observer1);
|
|
66
|
+
v.setValue(2);
|
|
67
|
+
expect(doneCallback).toBeCalledTimes(1);
|
|
68
|
+
expect(shouldNotCall).not.toBeCalled();
|
|
69
|
+
});
|
|
63
70
|
});
|
|
64
71
|
it('should remove the subscription on Observable dispose', () => {
|
|
65
72
|
const callback1 = () => {
|
|
@@ -77,14 +84,15 @@ export const observableTests = describe('Observable', () => {
|
|
|
77
84
|
expect(v.isDisposed).toBe(true);
|
|
78
85
|
});
|
|
79
86
|
it('should remove the subscription on Observer dispose', () => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
using(new ObservableValue(1), (v) => {
|
|
88
|
+
const callback1 = () => {
|
|
89
|
+
/** */
|
|
90
|
+
};
|
|
91
|
+
const observer = v.subscribe(callback1);
|
|
92
|
+
expect(v.getObservers().length).toBe(1);
|
|
93
|
+
observer[Symbol.dispose]();
|
|
94
|
+
expect(v.getObservers().length).toBe(0);
|
|
95
|
+
});
|
|
88
96
|
});
|
|
89
97
|
it('should throw an error for setValue() when the observer has been disposed', () => {
|
|
90
98
|
const v = new ObservableValue(1);
|
|
@@ -110,50 +118,53 @@ export const observableTests = describe('Observable', () => {
|
|
|
110
118
|
doneCallback();
|
|
111
119
|
}
|
|
112
120
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
using(new ObservableValue(1), (v) => {
|
|
122
|
+
const observer = v.subscribe(() => new Alma().Callback());
|
|
123
|
+
v.subscribe(() => new Alma().Callback());
|
|
124
|
+
expect(v.getObservers().length).toBe(2);
|
|
125
|
+
observer[Symbol.dispose]();
|
|
126
|
+
expect(v.getObservers().length).toBe(1);
|
|
127
|
+
v.setValue(3);
|
|
128
|
+
expect(doneCallback).toBeCalledTimes(1);
|
|
129
|
+
});
|
|
121
130
|
});
|
|
122
131
|
});
|
|
123
132
|
describe('Custom Compare function', () => {
|
|
124
133
|
it('Should compare the values with the custom compare function', () => {
|
|
125
|
-
|
|
134
|
+
using(new ObservableValue({ value: 2 }, {
|
|
126
135
|
compare: (a, b) => a.value !== b.value,
|
|
136
|
+
}), (v) => {
|
|
137
|
+
const onChange = vi.fn();
|
|
138
|
+
v.subscribe(onChange);
|
|
139
|
+
v.setValue({ value: 2 });
|
|
140
|
+
expect(v.getValue()).toEqual({ value: 2 });
|
|
141
|
+
expect(onChange).not.toBeCalled();
|
|
142
|
+
v.setValue({ value: 3 });
|
|
143
|
+
expect(v.getValue()).toEqual({ value: 3 });
|
|
144
|
+
expect(onChange).toBeCalledTimes(1);
|
|
145
|
+
expect(onChange).toBeCalledWith({ value: 3 });
|
|
146
|
+
v.setValue({ value: 3 });
|
|
147
|
+
expect(v.getValue()).toEqual({ value: 3 });
|
|
148
|
+
expect(onChange).toBeCalledTimes(1);
|
|
127
149
|
});
|
|
128
|
-
const onChange = vi.fn();
|
|
129
|
-
v.subscribe(onChange);
|
|
130
|
-
v.setValue({ value: 2 });
|
|
131
|
-
expect(v.getValue()).toEqual({ value: 2 });
|
|
132
|
-
expect(onChange).not.toBeCalled();
|
|
133
|
-
v.setValue({ value: 3 });
|
|
134
|
-
expect(v.getValue()).toEqual({ value: 3 });
|
|
135
|
-
expect(onChange).toBeCalledTimes(1);
|
|
136
|
-
expect(onChange).toBeCalledWith({ value: 3 });
|
|
137
|
-
v.setValue({ value: 3 });
|
|
138
|
-
expect(v.getValue()).toEqual({ value: 3 });
|
|
139
|
-
expect(onChange).toBeCalledTimes(1);
|
|
140
150
|
});
|
|
141
151
|
});
|
|
142
152
|
describe('Filtered subscriptions', () => {
|
|
143
153
|
it('should not trigger the callback if the filter returns false', () => {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
154
|
+
using(new ObservableValue({ shouldNotify: true, value: 1 }), (v) => {
|
|
155
|
+
const onChange = vi.fn();
|
|
156
|
+
v.subscribe(onChange, {
|
|
157
|
+
filter: (nextValue) => nextValue.shouldNotify,
|
|
158
|
+
});
|
|
159
|
+
v.setValue({ shouldNotify: false, value: 1 });
|
|
160
|
+
expect(onChange).not.toBeCalled();
|
|
161
|
+
v.setValue({ shouldNotify: false, value: 2 });
|
|
162
|
+
expect(onChange).not.toBeCalled();
|
|
163
|
+
expect(v.getValue()).toEqual({ shouldNotify: false, value: 2 });
|
|
164
|
+
v.setValue({ shouldNotify: true, value: 3 });
|
|
165
|
+
expect(onChange).toBeCalledTimes(1);
|
|
166
|
+
expect(onChange).toBeCalledWith({ shouldNotify: true, value: 3 });
|
|
148
167
|
});
|
|
149
|
-
v.setValue({ shouldNotify: false, value: 1 });
|
|
150
|
-
expect(onChange).not.toBeCalled();
|
|
151
|
-
v.setValue({ shouldNotify: false, value: 2 });
|
|
152
|
-
expect(onChange).not.toBeCalled();
|
|
153
|
-
expect(v.getValue()).toEqual({ shouldNotify: false, value: 2 });
|
|
154
|
-
v.setValue({ shouldNotify: true, value: 3 });
|
|
155
|
-
expect(onChange).toBeCalledTimes(1);
|
|
156
|
-
expect(onChange).toBeCalledWith({ shouldNotify: true, value: 3 });
|
|
157
168
|
});
|
|
158
169
|
});
|
|
159
170
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observable-value.spec.js","sourceRoot":"","sources":["../src/observable-value.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"observable-value.spec.js","sourceRoot":"","sources":["../src/observable-value.spec.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@furystack/utils",
|
|
3
|
-
"version": "8.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "8.1.10",
|
|
4
|
+
"description": "Utility functions and helpers for FuryStack including observables, events, and disposables",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"build
|
|
7
|
+
"build": "tsc --outDir ./esm"
|
|
8
8
|
},
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
+
"types": "./esm/index.d.ts",
|
|
11
12
|
"import": "./esm/index.js"
|
|
12
13
|
}
|
|
13
14
|
},
|
|
14
15
|
"files": [
|
|
15
16
|
"esm",
|
|
16
|
-
"types",
|
|
17
17
|
"src"
|
|
18
18
|
],
|
|
19
19
|
"repository": {
|
|
@@ -21,8 +21,12 @@
|
|
|
21
21
|
"url": "https://github.com/furystack/furystack.git"
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|
|
24
|
-
"
|
|
25
|
-
"
|
|
24
|
+
"FuryStack",
|
|
25
|
+
"utilities",
|
|
26
|
+
"observable",
|
|
27
|
+
"events",
|
|
28
|
+
"debounce",
|
|
29
|
+
"disposable"
|
|
26
30
|
],
|
|
27
31
|
"publishConfig": {
|
|
28
32
|
"access": "public"
|
|
@@ -35,6 +39,10 @@
|
|
|
35
39
|
"homepage": "https://github.com/furystack/furystack",
|
|
36
40
|
"devDependencies": {
|
|
37
41
|
"typescript": "^5.9.3",
|
|
38
|
-
"vitest": "^4.0.
|
|
39
|
-
}
|
|
42
|
+
"vitest": "^4.0.18"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=22.0.0"
|
|
46
|
+
},
|
|
47
|
+
"sideEffects": false
|
|
40
48
|
}
|
|
@@ -1,58 +1,64 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest'
|
|
2
2
|
import { ObservableValue } from './observable-value.js'
|
|
3
|
+
import { using } from './using.js'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Observable Value tests
|
|
6
7
|
*/
|
|
7
8
|
export const observableTests = describe('Observable', () => {
|
|
8
9
|
it('should be constructed with an undefined initial value', () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
using(new ObservableValue(undefined), (v) => {
|
|
11
|
+
expect(v).toBeInstanceOf(ObservableValue)
|
|
12
|
+
expect(v.getValue()).toBe(undefined)
|
|
13
|
+
})
|
|
12
14
|
})
|
|
13
15
|
|
|
14
16
|
it('should be constructed with initial value', () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
using(new ObservableValue(1), (v) => {
|
|
18
|
+
expect(v.getValue()).toBe(1)
|
|
19
|
+
})
|
|
17
20
|
})
|
|
18
21
|
|
|
19
22
|
describe('Subscription callback', () => {
|
|
20
23
|
it('should be triggered only when a value is changed', () => {
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
using(new ObservableValue(1), (v) => {
|
|
25
|
+
const doneCallback = vi.fn()
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
v.subscribe(() => {
|
|
28
|
+
expect(v.getValue()).toBe(2)
|
|
29
|
+
doneCallback()
|
|
30
|
+
})
|
|
31
|
+
v.setValue(1)
|
|
32
|
+
v.setValue(1)
|
|
33
|
+
v.setValue(2)
|
|
34
|
+
expect(doneCallback).toBeCalledTimes(1)
|
|
27
35
|
})
|
|
28
|
-
v.setValue(1)
|
|
29
|
-
v.setValue(1)
|
|
30
|
-
v.setValue(2)
|
|
31
|
-
expect(doneCallback).toBeCalledTimes(1)
|
|
32
36
|
})
|
|
33
37
|
|
|
34
38
|
it('should be triggered only on change', () => {
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
using(new ObservableValue(1), (v) => {
|
|
40
|
+
const doneCallback = vi.fn()
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
v.subscribe((value) => {
|
|
43
|
+
expect(value).toBe(2)
|
|
44
|
+
doneCallback()
|
|
45
|
+
})
|
|
46
|
+
v.setValue(2)
|
|
47
|
+
expect(doneCallback).toBeCalledTimes(1)
|
|
41
48
|
})
|
|
42
|
-
v.setValue(2)
|
|
43
|
-
expect(doneCallback).toBeCalledTimes(1)
|
|
44
49
|
})
|
|
45
50
|
|
|
46
51
|
it('should be triggered only on change in async manner', () => {
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
using(new ObservableValue(1), (v) => {
|
|
53
|
+
const doneCallback = vi.fn()
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
v.subscribe(async (value) => {
|
|
56
|
+
expect(value).toBe(2)
|
|
57
|
+
doneCallback()
|
|
58
|
+
})
|
|
59
|
+
v.setValue(2)
|
|
60
|
+
expect(doneCallback).toBeCalledTimes(1)
|
|
53
61
|
})
|
|
54
|
-
v.setValue(2)
|
|
55
|
-
expect(doneCallback).toBeCalledTimes(1)
|
|
56
62
|
})
|
|
57
63
|
})
|
|
58
64
|
|
|
@@ -64,15 +70,16 @@ export const observableTests = describe('Observable', () => {
|
|
|
64
70
|
expect(value).toBe(2)
|
|
65
71
|
})
|
|
66
72
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
using(new ObservableValue(1), (v) => {
|
|
74
|
+
const observer1 = v.subscribe(shouldNotCall)
|
|
75
|
+
v.subscribe(doneCallback)
|
|
70
76
|
|
|
71
|
-
|
|
72
|
-
|
|
77
|
+
v.unsubscribe(observer1)
|
|
78
|
+
v.setValue(2)
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
expect(doneCallback).toBeCalledTimes(1)
|
|
81
|
+
expect(shouldNotCall).not.toBeCalled()
|
|
82
|
+
})
|
|
76
83
|
})
|
|
77
84
|
|
|
78
85
|
it('should remove the subscription on Observable dispose', () => {
|
|
@@ -93,14 +100,15 @@ export const observableTests = describe('Observable', () => {
|
|
|
93
100
|
})
|
|
94
101
|
|
|
95
102
|
it('should remove the subscription on Observer dispose', () => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
using(new ObservableValue(1), (v) => {
|
|
104
|
+
const callback1 = () => {
|
|
105
|
+
/** */
|
|
106
|
+
}
|
|
107
|
+
const observer = v.subscribe(callback1)
|
|
108
|
+
expect(v.getObservers().length).toBe(1)
|
|
109
|
+
observer[Symbol.dispose]()
|
|
110
|
+
expect(v.getObservers().length).toBe(0)
|
|
111
|
+
})
|
|
104
112
|
})
|
|
105
113
|
|
|
106
114
|
it('should throw an error for setValue() when the observer has been disposed', () => {
|
|
@@ -133,62 +141,68 @@ export const observableTests = describe('Observable', () => {
|
|
|
133
141
|
doneCallback()
|
|
134
142
|
}
|
|
135
143
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
using(new ObservableValue(1), (v) => {
|
|
145
|
+
const observer = v.subscribe(() => new Alma().Callback())
|
|
146
|
+
v.subscribe(() => new Alma().Callback())
|
|
147
|
+
expect(v.getObservers().length).toBe(2)
|
|
148
|
+
observer[Symbol.dispose]()
|
|
149
|
+
expect(v.getObservers().length).toBe(1)
|
|
150
|
+
v.setValue(3)
|
|
151
|
+
|
|
152
|
+
expect(doneCallback).toBeCalledTimes(1)
|
|
153
|
+
})
|
|
145
154
|
})
|
|
146
155
|
})
|
|
147
156
|
|
|
148
157
|
describe('Custom Compare function', () => {
|
|
149
158
|
it('Should compare the values with the custom compare function', () => {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
159
|
+
using(
|
|
160
|
+
new ObservableValue(
|
|
161
|
+
{ value: 2 },
|
|
162
|
+
{
|
|
163
|
+
compare: (a, b) => a.value !== b.value,
|
|
164
|
+
},
|
|
165
|
+
),
|
|
166
|
+
(v) => {
|
|
167
|
+
const onChange = vi.fn()
|
|
168
|
+
v.subscribe(onChange)
|
|
169
|
+
|
|
170
|
+
v.setValue({ value: 2 })
|
|
171
|
+
expect(v.getValue()).toEqual({ value: 2 })
|
|
172
|
+
expect(onChange).not.toBeCalled()
|
|
173
|
+
|
|
174
|
+
v.setValue({ value: 3 })
|
|
175
|
+
expect(v.getValue()).toEqual({ value: 3 })
|
|
176
|
+
expect(onChange).toBeCalledTimes(1)
|
|
177
|
+
expect(onChange).toBeCalledWith({ value: 3 })
|
|
178
|
+
|
|
179
|
+
v.setValue({ value: 3 })
|
|
180
|
+
expect(v.getValue()).toEqual({ value: 3 })
|
|
181
|
+
expect(onChange).toBeCalledTimes(1)
|
|
154
182
|
},
|
|
155
183
|
)
|
|
156
|
-
const onChange = vi.fn()
|
|
157
|
-
v.subscribe(onChange)
|
|
158
|
-
|
|
159
|
-
v.setValue({ value: 2 })
|
|
160
|
-
expect(v.getValue()).toEqual({ value: 2 })
|
|
161
|
-
expect(onChange).not.toBeCalled()
|
|
162
|
-
|
|
163
|
-
v.setValue({ value: 3 })
|
|
164
|
-
expect(v.getValue()).toEqual({ value: 3 })
|
|
165
|
-
expect(onChange).toBeCalledTimes(1)
|
|
166
|
-
expect(onChange).toBeCalledWith({ value: 3 })
|
|
167
|
-
|
|
168
|
-
v.setValue({ value: 3 })
|
|
169
|
-
expect(v.getValue()).toEqual({ value: 3 })
|
|
170
|
-
expect(onChange).toBeCalledTimes(1)
|
|
171
184
|
})
|
|
172
185
|
})
|
|
173
186
|
|
|
174
187
|
describe('Filtered subscriptions', () => {
|
|
175
188
|
it('should not trigger the callback if the filter returns false', () => {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
189
|
+
using(new ObservableValue({ shouldNotify: true, value: 1 }), (v) => {
|
|
190
|
+
const onChange = vi.fn()
|
|
191
|
+
v.subscribe(onChange, {
|
|
192
|
+
filter: (nextValue) => nextValue.shouldNotify,
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
v.setValue({ shouldNotify: false, value: 1 })
|
|
196
|
+
expect(onChange).not.toBeCalled()
|
|
197
|
+
|
|
198
|
+
v.setValue({ shouldNotify: false, value: 2 })
|
|
199
|
+
expect(onChange).not.toBeCalled()
|
|
200
|
+
expect(v.getValue()).toEqual({ shouldNotify: false, value: 2 })
|
|
201
|
+
|
|
202
|
+
v.setValue({ shouldNotify: true, value: 3 })
|
|
203
|
+
expect(onChange).toBeCalledTimes(1)
|
|
204
|
+
expect(onChange).toBeCalledWith({ shouldNotify: true, value: 3 })
|
|
180
205
|
})
|
|
181
|
-
|
|
182
|
-
v.setValue({ shouldNotify: false, value: 1 })
|
|
183
|
-
expect(onChange).not.toBeCalled()
|
|
184
|
-
|
|
185
|
-
v.setValue({ shouldNotify: false, value: 2 })
|
|
186
|
-
expect(onChange).not.toBeCalled()
|
|
187
|
-
expect(v.getValue()).toEqual({ shouldNotify: false, value: 2 })
|
|
188
|
-
|
|
189
|
-
v.setValue({ shouldNotify: true, value: 3 })
|
|
190
|
-
expect(onChange).toBeCalledTimes(1)
|
|
191
|
-
expect(onChange).toBeCalledWith({ shouldNotify: true, value: 3 })
|
|
192
206
|
})
|
|
193
207
|
})
|
|
194
208
|
})
|