@miot-rn/common-component 1.0.2 → 1.0.4

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 (39) hide show
  1. package/dist/service/specs/index.js +63 -32
  2. package/dist/service/specs/spec.js +6 -0
  3. package/dist/service/specs/std-spec.js +31 -22
  4. package/dist/service/specs/subscribe-logging.test.d.ts +17 -0
  5. package/dist/service/specs/subscribe-logging.test.js +217 -0
  6. package/dist/service/track/TrackFlatList.d.ts +3 -0
  7. package/dist/service/track/TrackFlatList.js +19 -0
  8. package/dist/service/track/TrackScrollContext.d.ts +10 -0
  9. package/dist/service/track/TrackScrollContext.js +2 -0
  10. package/dist/service/track/TrackScrollView.d.ts +3 -0
  11. package/dist/service/track/TrackScrollView.js +20 -0
  12. package/dist/service/track/TrackService.d.ts +10 -0
  13. package/dist/service/track/TrackService.js +104 -0
  14. package/dist/service/track/index.d.ts +12 -0
  15. package/dist/service/track/index.js +9 -0
  16. package/dist/service/track/intersect.d.ts +8 -0
  17. package/dist/service/track/intersect.js +15 -0
  18. package/dist/service/track/intersect.test.d.ts +1 -0
  19. package/dist/service/track/intersect.test.js +189 -0
  20. package/dist/service/track/types.d.ts +16 -0
  21. package/dist/service/track/types.js +1 -0
  22. package/dist/service/track/useCardTrack.d.ts +14 -0
  23. package/dist/service/track/useCardTrack.js +61 -0
  24. package/dist/service/track/useExposeOnVisible.d.ts +11 -0
  25. package/dist/service/track/useExposeOnVisible.js +74 -0
  26. package/dist/service/track/usePageTrack.d.ts +7 -0
  27. package/dist/service/track/usePageTrack.js +101 -0
  28. package/dist/service/track/useTrack.d.ts +7 -0
  29. package/dist/service/track/useTrack.js +23 -0
  30. package/dist/service/track/useTrackScrollProvider.d.ts +24 -0
  31. package/dist/service/track/useTrackScrollProvider.js +81 -0
  32. package/dist/specs/instance-parser.js +13 -11
  33. package/dist/store/useGlobalSpecManager.d.ts +5 -2
  34. package/dist/store/useGlobalSpecManager.js +402 -63
  35. package/dist/store/useGlobalSpecManager.test.d.ts +1 -0
  36. package/dist/store/useGlobalSpecManager.test.js +247 -0
  37. package/dist/utils/subscribe-log.d.ts +1 -0
  38. package/dist/utils/subscribe-log.js +37 -0
  39. package/package.json +2 -2
@@ -0,0 +1,247 @@
1
+ /// <reference types="jest" />
2
+
3
+ import useGlobalSpecManager, { toKey } from "./useGlobalSpecManager";
4
+ import { setProps, subscribe } from "../service/specs/index.js";
5
+ jest.mock("../service/specs/index.js", () => ({
6
+ getProps: jest.fn(),
7
+ setProps: jest.fn(),
8
+ doAction: jest.fn(),
9
+ subscribe: jest.fn()
10
+ }), {
11
+ virtual: true
12
+ });
13
+ jest.mock("../utils/spec.js", () => ({
14
+ encodeProp: prop => {
15
+ const type = prop.eiid != null ? 'event' : prop.aiid != null ? 'action' : 'prop';
16
+ const id = prop.eiid ?? prop.aiid ?? prop.piid;
17
+ return `${type}.${prop.siid}.${id}`;
18
+ }
19
+ }), {
20
+ virtual: true
21
+ });
22
+ jest.mock("../utils/objects.js", () => ({
23
+ deepEqual: (left, right) => JSON.stringify(left) === JSON.stringify(right)
24
+ }), {
25
+ virtual: true
26
+ });
27
+ const spec = {
28
+ siid: 2,
29
+ piid: 1
30
+ };
31
+ const key = toKey(spec);
32
+ const baseSetSpecs = useGlobalSpecManager.getState().setSpecs;
33
+ let setSpecsRequests = [];
34
+ const getSpecState = () => useGlobalSpecManager.getState();
35
+ const resetManager = () => {
36
+ useGlobalSpecManager.setState({
37
+ specsMetaInfo: {},
38
+ specsState: {},
39
+ pendingKeys: new Set(),
40
+ eventListeners: {},
41
+ subscribedSpecs: new Set(),
42
+ specUpdateListeners: []
43
+ });
44
+ };
45
+ const subscribeToSpec = async () => {
46
+ let onUpdate;
47
+ subscribe.mockImplementationOnce(async (_specs, listener) => {
48
+ onUpdate = listener;
49
+ return {
50
+ unsubscribe: jest.fn()
51
+ };
52
+ });
53
+ await useGlobalSpecManager.getState().subscribeSpecs([spec]);
54
+ if (!onUpdate) {
55
+ throw new Error('subscribe callback was not registered');
56
+ }
57
+ return onUpdate;
58
+ };
59
+ const flushPromises = async () => {
60
+ await Promise.resolve();
61
+ jest.advanceTimersByTime(0);
62
+ await Promise.resolve();
63
+ jest.advanceTimersByTime(0);
64
+ await Promise.resolve();
65
+ };
66
+ const sentValues = () => {
67
+ const calls = setProps.mock.calls;
68
+ return calls.map(call => call[0][0].value);
69
+ };
70
+ describe('useGlobalSpecManager spec updates', () => {
71
+ beforeEach(() => {
72
+ jest.useFakeTimers();
73
+ jest.clearAllMocks();
74
+ resetManager();
75
+ setSpecsRequests = [];
76
+ useGlobalSpecManager.setState({
77
+ setSpecs: specs => {
78
+ const request = baseSetSpecs(specs);
79
+ setSpecsRequests.push(request);
80
+ return request;
81
+ }
82
+ });
83
+ setProps.mockResolvedValue([{
84
+ code: 0,
85
+ specDataSource: 'set-response'
86
+ }]);
87
+ });
88
+ afterEach(() => {
89
+ jest.runOnlyPendingTimers();
90
+ jest.useRealTimers();
91
+ });
92
+ it('sends 1 and 3, then displays pushed value 4 when the push arrives after trailing set', async () => {
93
+ const onUpdate = await subscribeToSpec();
94
+ await useGlobalSpecManager.getState().setSpec({
95
+ ...spec,
96
+ value: 1
97
+ });
98
+ jest.advanceTimersByTime(100);
99
+ await useGlobalSpecManager.getState().setSpec({
100
+ ...spec,
101
+ value: 2
102
+ });
103
+ jest.advanceTimersByTime(100);
104
+ await useGlobalSpecManager.getState().setSpec({
105
+ ...spec,
106
+ value: 3
107
+ });
108
+ jest.advanceTimersByTime(1010);
109
+ expect(sentValues()).toEqual([1, 3]);
110
+ await setSpecsRequests[1];
111
+ onUpdate({
112
+ ...spec,
113
+ value: 4,
114
+ updateTime: 1010,
115
+ specDataSource: 'device-push'
116
+ });
117
+ jest.advanceTimersByTime(2000);
118
+ await flushPromises();
119
+ expect(getSpecState().specsState[key]).toBe(4);
120
+ });
121
+ it('delays a push received 1000ms after a second leading set, then displays the pushed value', async () => {
122
+ const onUpdate = await subscribeToSpec();
123
+ await useGlobalSpecManager.getState().setSpec({
124
+ ...spec,
125
+ value: 1
126
+ });
127
+ jest.advanceTimersByTime(1010);
128
+ await useGlobalSpecManager.getState().setSpec({
129
+ ...spec,
130
+ value: 2
131
+ });
132
+ expect(sentValues()).toEqual([1, 2]);
133
+ jest.advanceTimersByTime(1000);
134
+ onUpdate({
135
+ ...spec,
136
+ value: 3,
137
+ updateTime: 2010,
138
+ specDataSource: 'device-push'
139
+ });
140
+ expect(getSpecState().specsState[key]).toBe(2);
141
+ jest.advanceTimersByTime(1000);
142
+ await flushPromises();
143
+ expect(getSpecState().specsState[key]).toBe(3);
144
+ });
145
+ it('sends 1 and 2, and ignores an intermediate pushed value 3', async () => {
146
+ const onUpdate = await subscribeToSpec();
147
+ await useGlobalSpecManager.getState().setSpec({
148
+ ...spec,
149
+ value: 1
150
+ });
151
+ jest.advanceTimersByTime(100);
152
+ await useGlobalSpecManager.getState().setSpec({
153
+ ...spec,
154
+ value: 2
155
+ });
156
+ jest.advanceTimersByTime(400);
157
+ onUpdate({
158
+ ...spec,
159
+ value: 3,
160
+ updateTime: 500,
161
+ specDataSource: 'device-push'
162
+ });
163
+ jest.advanceTimersByTime(600);
164
+ expect(sentValues()).toEqual([1, 2]);
165
+ await setSpecsRequests[1];
166
+ jest.advanceTimersByTime(2000);
167
+ await flushPromises();
168
+ expect(getSpecState().specsState[key]).toBe(2);
169
+ });
170
+ it('sends 1 and eventually displays pushed value 3 when there is no trailing set', async () => {
171
+ const onUpdate = await subscribeToSpec();
172
+ await useGlobalSpecManager.getState().setSpec({
173
+ ...spec,
174
+ value: 1
175
+ });
176
+ jest.advanceTimersByTime(20);
177
+ onUpdate({
178
+ ...spec,
179
+ value: 3,
180
+ updateTime: 20,
181
+ specDataSource: 'device-push'
182
+ });
183
+ expect(sentValues()).toEqual([1]);
184
+ jest.advanceTimersByTime(2000);
185
+ await flushPromises();
186
+ expect(getSpecState().specsState[key]).toBe(3);
187
+ });
188
+ it('sends 1 and 3, with trailing value 3 overriding a push of 4 received after 10ms', async () => {
189
+ const onUpdate = await subscribeToSpec();
190
+ await useGlobalSpecManager.getState().setSpec({
191
+ ...spec,
192
+ value: 1
193
+ });
194
+ jest.advanceTimersByTime(100);
195
+ await useGlobalSpecManager.getState().setSpec({
196
+ ...spec,
197
+ value: 2
198
+ });
199
+ jest.advanceTimersByTime(100);
200
+ await useGlobalSpecManager.getState().setSpec({
201
+ ...spec,
202
+ value: 3
203
+ });
204
+ jest.advanceTimersByTime(10);
205
+ onUpdate({
206
+ ...spec,
207
+ value: 4,
208
+ updateTime: 210,
209
+ specDataSource: 'device-push'
210
+ });
211
+ jest.advanceTimersByTime(990);
212
+ expect(sentValues()).toEqual([1, 3]);
213
+ await setSpecsRequests[1];
214
+ expect(getSpecState().specsState[key]).toBe(3);
215
+ });
216
+ it('sends only the leading and final values for five rapid updates', async () => {
217
+ await subscribeToSpec();
218
+ await useGlobalSpecManager.getState().setSpec({
219
+ ...spec,
220
+ value: 1
221
+ });
222
+ jest.advanceTimersByTime(100);
223
+ await useGlobalSpecManager.getState().setSpec({
224
+ ...spec,
225
+ value: 2
226
+ });
227
+ jest.advanceTimersByTime(100);
228
+ await useGlobalSpecManager.getState().setSpec({
229
+ ...spec,
230
+ value: 3
231
+ });
232
+ jest.advanceTimersByTime(100);
233
+ await useGlobalSpecManager.getState().setSpec({
234
+ ...spec,
235
+ value: 4
236
+ });
237
+ jest.advanceTimersByTime(100);
238
+ await useGlobalSpecManager.getState().setSpec({
239
+ ...spec,
240
+ value: 5
241
+ });
242
+ jest.advanceTimersByTime(1000);
243
+ expect(sentValues()).toEqual([1, 5]);
244
+ await setSpecsRequests[1];
245
+ expect(getSpecState().specsState[key]).toBe(5);
246
+ });
247
+ });
@@ -0,0 +1 @@
1
+ export declare function reportSubLog(line: string, level?: 'log' | 'error'): void;
@@ -0,0 +1,37 @@
1
+ /* eslint-disable no-console, global-require, @typescript-eslint/no-var-requires */
2
+
3
+ /**
4
+ * 订阅链路日志:同时写 console 和用户反馈日志。
5
+ *
6
+ * console 只有连着调试工具才看得见,测试同学复现「偶现收不到订阅推送」后捞不到;
7
+ * 只有 Service.smarthome.reportLog 才会落到可上传的反馈日志里。
8
+ * 订阅链路的静默失败只能靠现场日志定位,因此这条链路必须双写。
9
+ *
10
+ * 入参是已经拼好的整行日志(而不是分段字段),这样各调用点的字符串保持原样:
11
+ * 既让 console 与反馈日志内容完全一致,也不影响按 console 输出断言的既有用例。
12
+ *
13
+ * 注意:这里刻意用惰性 require 而非顶层 import 'miot'。
14
+ * 'miot' 由插件宿主在运行时提供,本仓库并未安装(单测里是 jest.mock(..., { virtual: true })),
15
+ * 顶层 import 会让所有引入本文件的模块在未 mock 'miot' 的用例里直接解析失败。
16
+ * 请勿"顺手"改成顶层 import。
17
+ *
18
+ * @param line 已格式化的日志行,约定以 [SPEC-SUB] 开头,便于在反馈日志里 grep
19
+ * @param level console 输出级别,保持与各调用点原有的严重级别一致
20
+ */
21
+ export function reportSubLog(line, level = 'log') {
22
+ if (level === 'error') {
23
+ console.error(line);
24
+ } else {
25
+ console.log(line);
26
+ }
27
+ try {
28
+ const {
29
+ Device,
30
+ Service
31
+ } = require('miot');
32
+ Service.smarthome.reportLog(Device.model, line);
33
+ } catch (e) {
34
+ // 上报失败绝不能影响订阅链路本身,降级为 console
35
+ console.log(`[SPEC-SUB][reportSubLog] 反馈日志上报失败: ${e?.message}`);
36
+ }
37
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miot-rn/common-component",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "scripts": {
5
5
  "build": "rm -rf dist && rm -f tsconfig.tsbuildinfo && tsc && babel src -d dist --config-file ../../babel.config.js --extensions '.ts,.tsx' --verbose",
6
6
  "lint": "eslint src/**/*.ts",
@@ -23,5 +23,5 @@
23
23
  "react-native": "0.61.0",
24
24
  "zustand": "^4.4.1"
25
25
  },
26
- "gitHead": "2920def2cc542a8d0efcf100814e477830d94bb3"
26
+ "gitHead": "6b073a3112c245f3984c25378074473d5153c235"
27
27
  }