@ray-js/lamp-schedule-core 1.0.1-beta-10 → 1.0.2-beta-1

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 (36) hide show
  1. package/lib/conflict/ConflictResolver.js +48 -21
  2. package/lib/conflict/__test__/ConflictResolver.test.js +49 -0
  3. package/lib/conflict/__test__/scheduleDataManager.test.js +66 -0
  4. package/lib/conflict/__test__/transform.test.js +5 -1
  5. package/lib/conflict/index.js +27 -7
  6. package/lib/conflict/scheduleDataManager.js +28 -33
  7. package/lib/context/rhythms/actions.d.ts +13 -17
  8. package/lib/context/rhythms/reducer.d.ts +2 -23
  9. package/lib/context/rhythms/reducer.js +7 -8
  10. package/lib/context/schedule/reducer.d.ts +5 -2
  11. package/lib/dpParser/__test__/autoDispatch.test.d.ts +1 -0
  12. package/lib/dpParser/__test__/autoDispatch.test.js +45 -0
  13. package/lib/dpParser/__test__/rhythms.test.js +90 -14
  14. package/lib/dpParser/__test__/rtcTimer.test.js +35 -0
  15. package/lib/dpParser/__test__/sleep.test.js +17 -0
  16. package/lib/dpParser/__test__/wakeup.test.js +17 -4
  17. package/lib/dpParser/__test__/wakeupSigmesh.test.d.ts +1 -0
  18. package/lib/dpParser/__test__/wakeupSigmesh.test.js +126 -0
  19. package/lib/hooks/__test__/useBaseLightDp.test.d.ts +1 -0
  20. package/lib/hooks/__test__/useBaseLightDp.test.js +251 -0
  21. package/lib/hooks/__test__/useCommonSupport.test.d.ts +1 -0
  22. package/lib/hooks/__test__/useCommonSupport.test.js +204 -0
  23. package/lib/hooks/__test__/useTimerFlushList.test.d.ts +1 -0
  24. package/lib/hooks/__test__/useTimerFlushList.test.js +117 -0
  25. package/lib/hooks/__test__/useTimerOperate.test.js +239 -5
  26. package/lib/hooks/__test__/useTimerOperateLocal.test.js +161 -53
  27. package/lib/types/rhythms.d.ts +25 -13
  28. package/lib/types/ty.d.ts +3 -0
  29. package/lib/utils/ScheduleDataSync.js +4 -1
  30. package/lib/utils/ScheduleLogger.js +1 -1
  31. package/lib/utils/__test__/ScheduleDataSync.test.d.ts +11 -0
  32. package/lib/utils/__test__/ScheduleDataSync.test.js +137 -0
  33. package/lib/utils/__test__/ScheduleEmit.test.d.ts +1 -0
  34. package/lib/utils/__test__/ScheduleEmit.test.js +35 -0
  35. package/lib/utils/__test__/ScheduleSupport.test.js +288 -154
  36. package/package.json +1 -1
@@ -121,6 +121,26 @@ describe('RtcTimerFormatter', () => {
121
121
  }
122
122
  });
123
123
  });
124
+ it('should parse a colour light timer with dual white params (dataType=09)', () => {
125
+ // ID: 85 (status=true, timerId=5)
126
+ // loops: 02 (Mon), time: 0064 (100 mins -> 01:40)
127
+ // deviceAction: 09 (dual white)
128
+ // bright_value: 0x46 (70), temp_value: 0x1E (30)
129
+ // bright_value1: 0x3C (60), temp_value1: 0x14 (20)
130
+
131
+ expect(formatterInstance.parser('85010200006409461E3C14')).toEqual({
132
+ timerId: '5',
133
+ status: true,
134
+ loops: '0100000',
135
+ time: '01:40',
136
+ dps: {
137
+ bright_value: 70,
138
+ temp_value: 30,
139
+ bright_value1: 60,
140
+ temp_value1: 20
141
+ }
142
+ });
143
+ });
124
144
  });
125
145
  describe('formatter', () => {
126
146
  it('should format a power (switch_led) timer to DP string', () => {
@@ -200,6 +220,21 @@ describe('RtcTimerFormatter', () => {
200
220
  }
201
221
  })).toBe('8401020000640400f0501e4b28');
202
222
  });
223
+ it('should format a timer with dual white params (dataType=09)', () => {
224
+ const result = formatterInstance.formatter({
225
+ timerId: '5',
226
+ status: true,
227
+ loops: '0100000',
228
+ time: '01:40',
229
+ dps: {
230
+ bright_value: 70,
231
+ temp_value: 30,
232
+ bright_value1: 60,
233
+ temp_value1: 20
234
+ }
235
+ });
236
+ expect(result.toLowerCase()).toBe('85010200006409461e3c14');
237
+ });
203
238
  it('should format a timer to be deleted (status=false, no dps, specific id)', () => {
204
239
  // The formatter is designed to create full timer strings.
205
240
  // To delete a timer, one typically sends a short command with just ID and status=false.
@@ -1,4 +1,5 @@
1
1
  import { SleepParser } from '../sleep';
2
+ import { sleepParser as sleepParserCommon } from '../sleep/sleepCommon';
2
3
  describe('SleepParser', () => {
3
4
  const parser = new SleepParser();
4
5
  it('should return default value when parsing empty string', () => {
@@ -68,4 +69,20 @@ describe('SleepParser', () => {
68
69
  '0120050e500028640a0000');
69
70
  expect(result.nodes.length).toBe(4);
70
71
  });
72
+ it('should delegate parser and formatter to sleepParserCommon implementation', () => {
73
+ const parserSpy = jest.spyOn(sleepParserCommon, 'parser');
74
+ const formatterSpy = jest.spyOn(sleepParserCommon, 'formatter');
75
+ const input = '0000';
76
+ parser.parser(input);
77
+ expect(parserSpy).toHaveBeenCalledWith(input);
78
+ const data = {
79
+ version: 0,
80
+ length: 0,
81
+ nodes: []
82
+ };
83
+ parser.formatter(data);
84
+ expect(formatterSpy).toHaveBeenCalledWith(data);
85
+ parserSpy.mockRestore();
86
+ formatterSpy.mockRestore();
87
+ });
71
88
  });
@@ -1,4 +1,5 @@
1
1
  import { WakeUpParser } from '../wakeup';
2
+ import { wakeupParser as wakeupParserCommon } from '../wakeup/wakeupCommon';
2
3
  describe('WakeUpParser', () => {
3
4
  const parser = new WakeUpParser();
4
5
  it('should return default value when parsing empty string', () => {
@@ -62,8 +63,20 @@ describe('WakeUpParser', () => {
62
63
  '0120050e500000640a000005');
63
64
  expect(result.nodes.length).toBe(4);
64
65
  });
65
-
66
- // 注意: Sigmesh 相关的测试需要模拟 support.isSigMeshDevice() 返回 true
67
- // 由于当前 SleepParser WakeUpParser 的实现中 Sigmesh 部分被注释掉了,
68
- // 我们暂时无法直接测试 Sigmesh 的逻辑。如果需要测试,需要解除注释并可能需要 mock `getSupportIns`。
66
+ it('should delegate parser and formatter to wakeupParserCommon implementation', () => {
67
+ const parserSpy = jest.spyOn(wakeupParserCommon, 'parser');
68
+ const formatterSpy = jest.spyOn(wakeupParserCommon, 'formatter');
69
+ const input = '0000';
70
+ parser.parser(input);
71
+ expect(parserSpy).toHaveBeenCalledWith(input);
72
+ const data = {
73
+ version: 0,
74
+ number: 0,
75
+ nodes: []
76
+ };
77
+ parser.formatter(data);
78
+ expect(formatterSpy).toHaveBeenCalledWith(data);
79
+ parserSpy.mockRestore();
80
+ formatterSpy.mockRestore();
81
+ });
69
82
  });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,126 @@
1
+ import "core-js/modules/esnext.iterator.map.js";
2
+ jest.mock('@ray-js/panel-sdk/lib/utils', () => ({
3
+ generateDpStrStep: jest.fn(str => {
4
+ let index = 0;
5
+ return len => {
6
+ const segment = str.slice(index, index + len);
7
+ index += len;
8
+ return {
9
+ value: parseInt(segment, 16)
10
+ };
11
+ };
12
+ }),
13
+ numToHexString: jest.fn(num => num.toString(16).padStart(2, '0'))
14
+ }));
15
+ import { wakeupParserSigmesh, WakeUpSigmesh } from '../wakeup/wakeupSigmesh';
16
+ const loopsToHex = loops => {
17
+ const binary = loops.split('').reverse().join('');
18
+ return parseInt(binary, 2);
19
+ };
20
+ const buildDpStr = function (nodes) {
21
+ let version = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
22
+ let dataMode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
23
+ const header = [version, dataMode, nodes.length].map(v => v.toString(16).padStart(2, '0')).join('');
24
+ const body = nodes.map(node => [node.onOff, node.loops, node.step, node.hour, node.minute, node.brightness, node.temperature, node.duration].map(v => v.toString(16).padStart(2, '0')).join('')).join('');
25
+ return `${header}${body}`;
26
+ };
27
+ describe('WakeUpSigmesh parser & formatter', () => {
28
+ beforeEach(() => {
29
+ jest.clearAllMocks();
30
+ });
31
+ it('returns default value when dp string is empty', () => {
32
+ expect(wakeupParserSigmesh.parser('')).toEqual(new WakeUpSigmesh().defaultValue);
33
+ });
34
+ it('returns default value when dp string length invalid', () => {
35
+ // header + incomplete node data (not multiple of 8)
36
+
37
+ expect(wakeupParserSigmesh.parser('0102011234')).toEqual(new WakeUpSigmesh().defaultValue);
38
+ });
39
+ it('parses valid dp string into nodes', () => {
40
+ const nodes = [{
41
+ onOff: 1,
42
+ loops: loopsToHex('1000000'),
43
+ step: 3,
44
+ hour: 6,
45
+ minute: 30,
46
+ brightness: 80,
47
+ temperature: 90,
48
+ duration: 12
49
+ }, {
50
+ onOff: 0,
51
+ loops: loopsToHex('0100000'),
52
+ step: 5,
53
+ hour: 7,
54
+ minute: 45,
55
+ brightness: 60,
56
+ temperature: 70,
57
+ duration: 8
58
+ }];
59
+ const dpStr = buildDpStr(nodes, 1, 2);
60
+ const result = wakeupParserSigmesh.parser(dpStr);
61
+ expect(result.version).toBe(1);
62
+ expect(result.dataMode).toBe(2);
63
+ expect(result.length).toBe(2);
64
+ expect(result.nodes).toHaveLength(2);
65
+ expect(result.nodes[0]).toMatchObject({
66
+ onOff: true,
67
+ loops: '1000000',
68
+ step: 3,
69
+ hour: 6,
70
+ minute: 30,
71
+ brightness: 80,
72
+ temperature: 90,
73
+ duration: 12,
74
+ index: 0
75
+ });
76
+ expect(result.nodes[1]).toMatchObject({
77
+ onOff: false,
78
+ loops: '0100000',
79
+ index: 1
80
+ });
81
+ });
82
+ it('formats nodes back to dp string', () => {
83
+ const result = wakeupParserSigmesh.formatter({
84
+ version: 1,
85
+ dataMode: '03',
86
+ length: 1,
87
+ nodes: [{
88
+ onOff: true,
89
+ loops: '1000000',
90
+ step: 10,
91
+ hour: 5,
92
+ minute: 15,
93
+ brightness: 90,
94
+ temperature: 50,
95
+ duration: 20,
96
+ index: 0
97
+ }]
98
+ });
99
+ expect(result).toBe(buildDpStr([{
100
+ onOff: 1,
101
+ loops: loopsToHex('1000000'),
102
+ step: 10,
103
+ hour: 5,
104
+ minute: 15,
105
+ brightness: 90,
106
+ temperature: 50,
107
+ duration: 20
108
+ }], 1, 3));
109
+ });
110
+ it('round-trips dp string through parser and formatter', () => {
111
+ const nodes = [{
112
+ onOff: 1,
113
+ loops: loopsToHex('1111111'),
114
+ step: 2,
115
+ hour: 12,
116
+ minute: 0,
117
+ brightness: 100,
118
+ temperature: 40,
119
+ duration: 24
120
+ }];
121
+ const dpStr = buildDpStr(nodes, 2, 3);
122
+ const parsed = wakeupParserSigmesh.parser(dpStr);
123
+ const formatted = wakeupParserSigmesh.formatter(parsed);
124
+ expect(formatted).toBe(dpStr);
125
+ });
126
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,251 @@
1
+ import { act, renderHook } from '@testing-library/react-hooks';
2
+ import { useBaseLightDp, getDpDataByMesh, fetchDpData, useFetchDpDataByMesh, useFetchDpData } from '../useBaseLightDp';
3
+ import { DP_CHANGE_EVENT_KEY } from '../../constant';
4
+ import { devIdOrGroupIdCache } from '../../utils/ScheduleCache';
5
+ import { getDpIdByDpCode } from '../../utils/ScheduleUtils';
6
+ import { getDpState, setDpState } from '../../utils/dpState';
7
+ import { isInitFn, useSupport } from '../useCommonSupport';
8
+ import { updateDeviceDp } from '../../conflict/updateDeviceDp';
9
+ import { queryDps } from '@ray-js/ray';
10
+ jest.mock('../../utils/ScheduleLogger', () => ({
11
+ scheduleLogger: {
12
+ debug: jest.fn(),
13
+ warn: jest.fn(),
14
+ error: jest.fn(),
15
+ info: jest.fn()
16
+ }
17
+ }));
18
+ jest.mock('../../utils/ScheduleCache', () => ({
19
+ devIdOrGroupIdCache: {
20
+ get: jest.fn().mockReturnValue({
21
+ devId: 'device-1',
22
+ groupId: ''
23
+ })
24
+ }
25
+ }));
26
+ const listeners = {};
27
+ jest.mock('../../utils/ScheduleEmit', () => ({
28
+ emitter: {
29
+ on: jest.fn((event, cb) => {
30
+ listeners[event] = cb;
31
+ }),
32
+ off: jest.fn(event => {
33
+ delete listeners[event];
34
+ })
35
+ }
36
+ }));
37
+ jest.mock('../../conflict/updateDeviceDp', () => ({
38
+ updateDeviceDp: jest.fn()
39
+ }));
40
+ jest.mock('../../utils/ScheduleUtils', () => ({
41
+ getDpIdByDpCode: jest.fn()
42
+ }));
43
+ jest.mock('../../utils/dpState', () => ({
44
+ getDpState: jest.fn(),
45
+ setDpState: jest.fn()
46
+ }));
47
+ jest.mock('../useCommonSupport', () => ({
48
+ isInitFn: jest.fn(),
49
+ useSupport: jest.fn()
50
+ }));
51
+ jest.mock('@ray-js/ray', () => ({
52
+ queryDps: jest.fn()
53
+ }));
54
+ describe('useBaseLightDp', () => {
55
+ beforeEach(() => {
56
+ jest.clearAllMocks();
57
+ devIdOrGroupIdCache.get.mockReturnValue({
58
+ devId: 'device-1',
59
+ groupId: ''
60
+ });
61
+ isInitFn.mockReturnValue(true);
62
+ getDpIdByDpCode.mockReturnValue(10);
63
+ getDpState.mockReturnValue(undefined);
64
+ });
65
+ it('subscribes to emitter and updates state when dp changes', () => {
66
+ const {
67
+ result
68
+ } = renderHook(() => useBaseLightDp('bright_value', 0));
69
+ act(() => {
70
+ var _listeners$DP_CHANGE_;
71
+ (_listeners$DP_CHANGE_ = listeners[DP_CHANGE_EVENT_KEY]) === null || _listeners$DP_CHANGE_ === void 0 || _listeners$DP_CHANGE_.call(listeners, {
72
+ dps: {
73
+ 10: 50
74
+ }
75
+ });
76
+ });
77
+ expect(setDpState).toHaveBeenCalledWith('bright_value', 50);
78
+ expect(result.current.dpValue).toBe(50);
79
+ });
80
+ it('filters duplicate emitter values', () => {
81
+ const {
82
+ result
83
+ } = renderHook(() => useBaseLightDp('bright_value', 0));
84
+ act(() => {
85
+ var _listeners$DP_CHANGE_2, _listeners$DP_CHANGE_3;
86
+ (_listeners$DP_CHANGE_2 = listeners[DP_CHANGE_EVENT_KEY]) === null || _listeners$DP_CHANGE_2 === void 0 || _listeners$DP_CHANGE_2.call(listeners, {
87
+ dps: {
88
+ 10: 60
89
+ }
90
+ });
91
+ (_listeners$DP_CHANGE_3 = listeners[DP_CHANGE_EVENT_KEY]) === null || _listeners$DP_CHANGE_3 === void 0 || _listeners$DP_CHANGE_3.call(listeners, {
92
+ dps: {
93
+ 10: 60
94
+ }
95
+ });
96
+ });
97
+ expect(result.current.dpValue).toBe(60);
98
+ expect(setDpState).toHaveBeenCalledTimes(1);
99
+ });
100
+ it('loads initial dp value from cache when available', () => {
101
+ getDpState.mockReturnValue(70);
102
+ const {
103
+ result
104
+ } = renderHook(() => useBaseLightDp('bright_value'));
105
+ expect(result.current.dpValue).toBe(70);
106
+ });
107
+ it('updateDp dispatches dp command when dpId exists', () => {
108
+ const {
109
+ result
110
+ } = renderHook(() => useBaseLightDp('bright_value'));
111
+ act(() => {
112
+ result.current.updateDp(90);
113
+ });
114
+ expect(updateDeviceDp).toHaveBeenCalledWith('device-1', '', {
115
+ 10: 90
116
+ });
117
+ });
118
+ it('updateDp graceful when dpId missing', () => {
119
+ getDpIdByDpCode.mockReturnValue(undefined);
120
+ const errorSpy = jest.fn();
121
+ const {
122
+ result
123
+ } = renderHook(() => useBaseLightDp('unknown'));
124
+ act(() => {
125
+ result.current.updateDp(1, errorSpy);
126
+ });
127
+ expect(updateDeviceDp).not.toHaveBeenCalled();
128
+ expect(errorSpy).not.toHaveBeenCalled();
129
+ });
130
+ it('updateDp handles exception with callback', () => {
131
+ getDpIdByDpCode.mockImplementation(() => {
132
+ throw new Error('failed');
133
+ });
134
+ const errorSpy = jest.fn();
135
+ const {
136
+ result
137
+ } = renderHook(() => useBaseLightDp('error_dp'));
138
+ act(() => {
139
+ result.current.updateDp(1, errorSpy);
140
+ });
141
+ expect(errorSpy).toHaveBeenCalled();
142
+ });
143
+ });
144
+ describe('getDpDataByMesh', () => {
145
+ beforeEach(() => {
146
+ jest.clearAllMocks();
147
+ devIdOrGroupIdCache.get.mockReturnValue({
148
+ devId: 'device-1',
149
+ groupId: ''
150
+ });
151
+ getDpIdByDpCode.mockImplementation(code => code === 'bright_value' ? 1 : null);
152
+ });
153
+ it('logs error when dpCodes is not array', () => {
154
+ getDpDataByMesh(null);
155
+ expect(queryDps).not.toHaveBeenCalled();
156
+ });
157
+ it('warns when groupId present', () => {
158
+ devIdOrGroupIdCache.get.mockReturnValue({
159
+ devId: 'device-1',
160
+ groupId: 'group-1'
161
+ });
162
+ getDpDataByMesh(['switch']);
163
+ expect(queryDps).not.toHaveBeenCalled();
164
+ });
165
+ it('warns when deviceId missing', () => {
166
+ devIdOrGroupIdCache.get.mockReturnValue({
167
+ devId: '',
168
+ groupId: ''
169
+ });
170
+ getDpDataByMesh(['switch']);
171
+ expect(queryDps).not.toHaveBeenCalled();
172
+ });
173
+ it('queries dp when ids resolved', () => {
174
+ getDpDataByMesh(['bright_value']);
175
+ expect(queryDps).toHaveBeenCalledWith(expect.objectContaining({
176
+ deviceId: 'device-1',
177
+ dpIds: ['1']
178
+ }));
179
+ });
180
+ });
181
+ describe('fetchDpData', () => {
182
+ beforeEach(() => {
183
+ jest.clearAllMocks();
184
+ devIdOrGroupIdCache.get.mockReturnValue({
185
+ devId: 'device-1',
186
+ groupId: ''
187
+ });
188
+ getDpIdByDpCode.mockImplementation(code => code === 'bright_value' ? 2 : null);
189
+ });
190
+ it('validates dpCodes argument', () => {
191
+ fetchDpData(null);
192
+ expect(queryDps).not.toHaveBeenCalled();
193
+ });
194
+ it('requires deviceId', () => {
195
+ devIdOrGroupIdCache.get.mockReturnValue({
196
+ devId: '',
197
+ groupId: ''
198
+ });
199
+ fetchDpData(['switch']);
200
+ expect(queryDps).not.toHaveBeenCalled();
201
+ });
202
+ it('runs query when dp ids exist', () => {
203
+ fetchDpData(['bright_value']);
204
+ expect(queryDps).toHaveBeenCalledWith(expect.objectContaining({
205
+ deviceId: 'device-1',
206
+ dpIds: ['2']
207
+ }));
208
+ });
209
+ });
210
+ describe('useFetch hooks', () => {
211
+ beforeEach(() => {
212
+ jest.clearAllMocks();
213
+ getDpIdByDpCode.mockReturnValue(3);
214
+ devIdOrGroupIdCache.get.mockReturnValue({
215
+ devId: 'device-1',
216
+ groupId: ''
217
+ });
218
+ useSupport.mockReturnValue({
219
+ isSigMeshDevice: () => true,
220
+ deviceType: 'sigmesh'
221
+ });
222
+ });
223
+ it('useFetchDpDataByMesh triggers fetch on mount and refresh', () => {
224
+ const {
225
+ result
226
+ } = renderHook(() => useFetchDpDataByMesh(['bright_value']));
227
+ expect(queryDps).toHaveBeenCalledTimes(1);
228
+ act(() => {
229
+ result.current.refresh();
230
+ });
231
+ expect(queryDps).toHaveBeenCalledTimes(2);
232
+ });
233
+ it('useFetchDpDataByMesh skips when not sigmesh', () => {
234
+ useSupport.mockReturnValue({
235
+ isSigMeshDevice: () => false,
236
+ deviceType: 'wifi'
237
+ });
238
+ renderHook(() => useFetchDpDataByMesh(['bright_value']));
239
+ expect(queryDps).not.toHaveBeenCalled();
240
+ });
241
+ it('useFetchDpData triggers fetch on mount and refresh', () => {
242
+ const {
243
+ result
244
+ } = renderHook(() => useFetchDpData(['bright_value']));
245
+ expect(queryDps).toHaveBeenCalledTimes(1);
246
+ act(() => {
247
+ result.current.refresh();
248
+ });
249
+ expect(queryDps).toHaveBeenCalledTimes(2);
250
+ });
251
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,204 @@
1
+ import { act, renderHook } from '@testing-library/react-hooks';
2
+ import { useScheduleInit, useSupport, useCommonSupport, resetIsInit } from '../useCommonSupport';
3
+ import { emitter } from '../../utils/ScheduleEmit';
4
+ const initStorageMock = jest.fn().mockResolvedValue(undefined);
5
+ const getGroupDpsInfosMock = jest.fn().mockResolvedValue({});
6
+ const registerDeviceListListenerMock = jest.fn();
7
+ const registerGroupChangeMock = jest.fn();
8
+ const onDpDataChangeMock = jest.fn();
9
+ const onGroupDpDataChangeEventMock = jest.fn();
10
+ const offDpDataChangeMock = jest.fn();
11
+ const offGroupDpDataChangeEventMock = jest.fn();
12
+ const getDeviceInfoMock = jest.fn();
13
+ const getTimerListWithFlushMock = jest.fn();
14
+ const initDpStateMock = jest.fn();
15
+ jest.mock('../../context/timer/context', () => ({
16
+ useTimerContext: jest.fn().mockReturnValue({
17
+ dispatch: jest.fn(),
18
+ actions: {}
19
+ })
20
+ }));
21
+ const supportInitMock = jest.fn();
22
+ const supportIsSupportDpMock = jest.fn();
23
+ jest.mock('../../utils/ScheduleSupport', () => ({
24
+ Support: jest.fn(() => ({
25
+ init: supportInitMock,
26
+ isSupportDp: supportIsSupportDpMock
27
+ }))
28
+ }));
29
+ jest.mock('../../utils/storage', () => ({
30
+ initStorage: function () {
31
+ return initStorageMock(...arguments);
32
+ }
33
+ }));
34
+ jest.mock('../../utils/dpState', () => ({
35
+ initDpState: function () {
36
+ return initDpStateMock(...arguments);
37
+ }
38
+ }));
39
+ jest.mock('../../hooks/useTimerOperateLocal', () => ({
40
+ getTimerListWithFlush: function () {
41
+ return getTimerListWithFlushMock(...arguments);
42
+ }
43
+ }));
44
+ jest.mock('../../utils/ScheduleUtils', () => ({
45
+ getDpCodeByDpId: dpId => `code_${dpId}`
46
+ }));
47
+ jest.mock('@ray-js/ray', () => ({
48
+ getDeviceInfo: function () {
49
+ return getDeviceInfoMock(...arguments);
50
+ },
51
+ getGroupDpsInfos: function () {
52
+ return getGroupDpsInfosMock(...arguments);
53
+ },
54
+ registerDeviceListListener: function () {
55
+ return registerDeviceListListenerMock(...arguments);
56
+ },
57
+ registerGroupChange: function () {
58
+ return registerGroupChangeMock(...arguments);
59
+ },
60
+ onDpDataChange: function () {
61
+ return onDpDataChangeMock(...arguments);
62
+ },
63
+ onGroupDpDataChangeEvent: function () {
64
+ return onGroupDpDataChangeEventMock(...arguments);
65
+ },
66
+ offDpDataChange: function () {
67
+ return offDpDataChangeMock(...arguments);
68
+ },
69
+ offGroupDpDataChangeEvent: function () {
70
+ return offGroupDpDataChangeEventMock(...arguments);
71
+ }
72
+ }));
73
+ jest.mock('../../utils/ScheduleLogger', () => {
74
+ const loggerMock = {
75
+ info: jest.fn(),
76
+ debug: jest.fn(),
77
+ warn: jest.fn(),
78
+ error: jest.fn(),
79
+ setLogLevel: jest.fn(),
80
+ setLogPrefix: jest.fn(),
81
+ formatMessage: jest.fn()
82
+ };
83
+ return {
84
+ scheduleLogger: loggerMock,
85
+ ScheduleLogger: class {
86
+ info = (() => loggerMock.info)();
87
+ debug = (() => loggerMock.debug)();
88
+ warn = (() => loggerMock.warn)();
89
+ error = (() => loggerMock.error)();
90
+ setLogLevel = (() => loggerMock.setLogLevel)();
91
+ setLogPrefix = (() => loggerMock.setLogPrefix)();
92
+ formatMessage = (() => loggerMock.formatMessage)();
93
+ }
94
+ };
95
+ });
96
+ describe('useCommonSupport suite', () => {
97
+ beforeEach(() => {
98
+ jest.clearAllMocks();
99
+ resetIsInit();
100
+ supportInitMock.mockResolvedValue(true);
101
+ supportIsSupportDpMock.mockImplementation(code => code === 'a' || code === 'code_1');
102
+ registerDeviceListListenerMock.mockImplementation(_ref => {
103
+ let {
104
+ success
105
+ } = _ref;
106
+ return success === null || success === void 0 ? void 0 : success();
107
+ });
108
+ registerGroupChangeMock.mockImplementation(_ref2 => {
109
+ let {
110
+ success
111
+ } = _ref2;
112
+ return success === null || success === void 0 ? void 0 : success();
113
+ });
114
+ getDeviceInfoMock.mockImplementation(_ref3 => {
115
+ let {
116
+ success
117
+ } = _ref3;
118
+ return success === null || success === void 0 ? void 0 : success({
119
+ dps: {
120
+ 1: true
121
+ }
122
+ });
123
+ });
124
+ getGroupDpsInfosMock.mockResolvedValue({
125
+ 1: true
126
+ });
127
+ });
128
+ it('initializes device support and sets ready state', async () => {
129
+ const {
130
+ result
131
+ } = renderHook(() => useScheduleInit({
132
+ devId: 'dev-1'
133
+ }));
134
+ await act(async () => {
135
+ await Promise.resolve();
136
+ });
137
+ expect(result.current.isReady).toBe(true);
138
+ expect(initStorageMock).toHaveBeenCalledWith('dev-1', undefined);
139
+ expect(getDeviceInfoMock).toHaveBeenCalled();
140
+ });
141
+ it('initializes group support and fetches group dps', async () => {
142
+ const {
143
+ result
144
+ } = renderHook(() => useScheduleInit({
145
+ devId: '',
146
+ groupId: 'group-1'
147
+ }));
148
+ await act(async () => {
149
+ await Promise.resolve();
150
+ });
151
+ expect(result.current.isReady).toBe(true);
152
+ expect(getGroupDpsInfosMock).toHaveBeenCalledWith('group-1');
153
+ expect(initDpStateMock).toHaveBeenCalled();
154
+ });
155
+ it('handles support init failure', async () => {
156
+ supportInitMock.mockRejectedValueOnce(new Error('fail'));
157
+ const {
158
+ result
159
+ } = renderHook(() => useScheduleInit({
160
+ devId: 'dev-1'
161
+ }));
162
+ await act(async () => {
163
+ await Promise.resolve();
164
+ });
165
+ expect(result.current.isReady).toBe(false);
166
+ });
167
+ it('useSupport updates after initDone event', async () => {
168
+ const {
169
+ result: initResult
170
+ } = renderHook(() => useScheduleInit({
171
+ devId: 'dev-1'
172
+ }));
173
+ await act(async () => {
174
+ await Promise.resolve();
175
+ });
176
+ expect(initResult.current.isReady).toBe(true);
177
+ const {
178
+ result
179
+ } = renderHook(() => useSupport());
180
+ act(() => {
181
+ emitter.emit('initDone');
182
+ });
183
+ expect(result.current).not.toBeNull();
184
+ });
185
+ it('useCommonSupport respects checkType and dp list', async () => {
186
+ const {
187
+ result: initResult
188
+ } = renderHook(() => useScheduleInit({
189
+ devId: 'dev-1'
190
+ }));
191
+ await act(async () => {
192
+ await Promise.resolve();
193
+ });
194
+ expect(initResult.current.isReady).toBe(true);
195
+ const {
196
+ result: someResult
197
+ } = renderHook(() => useCommonSupport(['a']));
198
+ expect(someResult.current.isSupport).toBe(true);
199
+ const {
200
+ result: everyResult
201
+ } = renderHook(() => useCommonSupport(['a', 'b'], ['a', 'b'], 'every'));
202
+ expect(everyResult.current.isSupport).toBe(false);
203
+ });
204
+ });
@@ -0,0 +1 @@
1
+ export {};