@taicode/common-web 1.1.5 → 1.1.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.
|
@@ -44,12 +44,30 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
44
44
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
45
45
|
};
|
|
46
46
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
47
|
-
import { act } from 'react';
|
|
47
|
+
import React, { act } from 'react';
|
|
48
48
|
import { Service } from '@taicode/common-base';
|
|
49
49
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
50
50
|
import { render, renderHook, waitFor } from '@testing-library/react';
|
|
51
51
|
import { observable, makeObservable, runInAction, action } from 'mobx';
|
|
52
|
-
import { useService, ServiceProvider } from './service';
|
|
52
|
+
import { useService, useLocalService, ServiceProvider } from './service';
|
|
53
|
+
class TestErrorBoundary extends React.Component {
|
|
54
|
+
constructor() {
|
|
55
|
+
super(...arguments);
|
|
56
|
+
this.state = { error: null };
|
|
57
|
+
}
|
|
58
|
+
static getDerivedStateFromError(error) {
|
|
59
|
+
return { error };
|
|
60
|
+
}
|
|
61
|
+
componentDidCatch(error) {
|
|
62
|
+
this.props.onError(error);
|
|
63
|
+
}
|
|
64
|
+
render() {
|
|
65
|
+
if (this.state.error) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return this.props.children;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
53
71
|
// 创建测试用的服务类
|
|
54
72
|
let TestService = (() => {
|
|
55
73
|
var _a, _TestService_count_accessor_storage, _TestService_users_accessor_storage, _TestService_inited_accessor_storage;
|
|
@@ -169,6 +187,143 @@ let SimpleService = (() => {
|
|
|
169
187
|
})(),
|
|
170
188
|
_a;
|
|
171
189
|
})();
|
|
190
|
+
// 局部服务测试类
|
|
191
|
+
let LocalService = (() => {
|
|
192
|
+
var _a, _LocalService_data_accessor_storage, _LocalService_counter_accessor_storage, _LocalService_inited_accessor_storage;
|
|
193
|
+
let _classSuper = Service;
|
|
194
|
+
let _instanceExtraInitializers = [];
|
|
195
|
+
let _data_decorators;
|
|
196
|
+
let _data_initializers = [];
|
|
197
|
+
let _data_extraInitializers = [];
|
|
198
|
+
let _counter_decorators;
|
|
199
|
+
let _counter_initializers = [];
|
|
200
|
+
let _counter_extraInitializers = [];
|
|
201
|
+
let _inited_decorators;
|
|
202
|
+
let _inited_initializers = [];
|
|
203
|
+
let _inited_extraInitializers = [];
|
|
204
|
+
let _increment_decorators;
|
|
205
|
+
let _setData_decorators;
|
|
206
|
+
return _a = class LocalService extends _classSuper {
|
|
207
|
+
get data() { return __classPrivateFieldGet(this, _LocalService_data_accessor_storage, "f"); }
|
|
208
|
+
set data(value) { __classPrivateFieldSet(this, _LocalService_data_accessor_storage, value, "f"); }
|
|
209
|
+
get counter() { return __classPrivateFieldGet(this, _LocalService_counter_accessor_storage, "f"); }
|
|
210
|
+
set counter(value) { __classPrivateFieldSet(this, _LocalService_counter_accessor_storage, value, "f"); }
|
|
211
|
+
get inited() { return __classPrivateFieldGet(this, _LocalService_inited_accessor_storage, "f"); }
|
|
212
|
+
set inited(value) { __classPrivateFieldSet(this, _LocalService_inited_accessor_storage, value, "f"); }
|
|
213
|
+
constructor() {
|
|
214
|
+
super();
|
|
215
|
+
_LocalService_data_accessor_storage.set(this, (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _data_initializers, 'local')));
|
|
216
|
+
_LocalService_counter_accessor_storage.set(this, (__runInitializers(this, _data_extraInitializers), __runInitializers(this, _counter_initializers, 0)));
|
|
217
|
+
_LocalService_inited_accessor_storage.set(this, (__runInitializers(this, _counter_extraInitializers), __runInitializers(this, _inited_initializers, false)));
|
|
218
|
+
__runInitializers(this, _inited_extraInitializers);
|
|
219
|
+
makeObservable(this);
|
|
220
|
+
}
|
|
221
|
+
async init() {
|
|
222
|
+
runInAction(() => {
|
|
223
|
+
this.data = 'initialized';
|
|
224
|
+
});
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
increment() {
|
|
228
|
+
this.counter++;
|
|
229
|
+
}
|
|
230
|
+
setData(newData) {
|
|
231
|
+
this.data = newData;
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
_LocalService_data_accessor_storage = new WeakMap(),
|
|
235
|
+
_LocalService_counter_accessor_storage = new WeakMap(),
|
|
236
|
+
_LocalService_inited_accessor_storage = new WeakMap(),
|
|
237
|
+
(() => {
|
|
238
|
+
var _b;
|
|
239
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
|
|
240
|
+
_data_decorators = [observable];
|
|
241
|
+
_counter_decorators = [observable];
|
|
242
|
+
_inited_decorators = [observable];
|
|
243
|
+
_increment_decorators = [action];
|
|
244
|
+
_setData_decorators = [action];
|
|
245
|
+
__esDecorate(_a, null, _data_decorators, { kind: "accessor", name: "data", static: false, private: false, access: { has: obj => "data" in obj, get: obj => obj.data, set: (obj, value) => { obj.data = value; } }, metadata: _metadata }, _data_initializers, _data_extraInitializers);
|
|
246
|
+
__esDecorate(_a, null, _counter_decorators, { kind: "accessor", name: "counter", static: false, private: false, access: { has: obj => "counter" in obj, get: obj => obj.counter, set: (obj, value) => { obj.counter = value; } }, metadata: _metadata }, _counter_initializers, _counter_extraInitializers);
|
|
247
|
+
__esDecorate(_a, null, _inited_decorators, { kind: "accessor", name: "inited", static: false, private: false, access: { has: obj => "inited" in obj, get: obj => obj.inited, set: (obj, value) => { obj.inited = value; } }, metadata: _metadata }, _inited_initializers, _inited_extraInitializers);
|
|
248
|
+
__esDecorate(_a, null, _increment_decorators, { kind: "method", name: "increment", static: false, private: false, access: { has: obj => "increment" in obj, get: obj => obj.increment }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
249
|
+
__esDecorate(_a, null, _setData_decorators, { kind: "method", name: "setData", static: false, private: false, access: { has: obj => "setData" in obj, get: obj => obj.setData }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
250
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
251
|
+
})(),
|
|
252
|
+
_a;
|
|
253
|
+
})();
|
|
254
|
+
// 依赖注入测试服务类 - 简化版本,不使用装饰器
|
|
255
|
+
let DependentService = (() => {
|
|
256
|
+
var _a, _DependentService_combinedData_accessor_storage, _DependentService_inited_accessor_storage;
|
|
257
|
+
let _classSuper = Service;
|
|
258
|
+
let _combinedData_decorators;
|
|
259
|
+
let _combinedData_initializers = [];
|
|
260
|
+
let _combinedData_extraInitializers = [];
|
|
261
|
+
let _inited_decorators;
|
|
262
|
+
let _inited_initializers = [];
|
|
263
|
+
let _inited_extraInitializers = [];
|
|
264
|
+
return _a = class DependentService extends _classSuper {
|
|
265
|
+
get combinedData() { return __classPrivateFieldGet(this, _DependentService_combinedData_accessor_storage, "f"); }
|
|
266
|
+
set combinedData(value) { __classPrivateFieldSet(this, _DependentService_combinedData_accessor_storage, value, "f"); }
|
|
267
|
+
get inited() { return __classPrivateFieldGet(this, _DependentService_inited_accessor_storage, "f"); }
|
|
268
|
+
set inited(value) { __classPrivateFieldSet(this, _DependentService_inited_accessor_storage, value, "f"); }
|
|
269
|
+
constructor() {
|
|
270
|
+
super();
|
|
271
|
+
_DependentService_combinedData_accessor_storage.set(this, __runInitializers(this, _combinedData_initializers, ''));
|
|
272
|
+
_DependentService_inited_accessor_storage.set(this, (__runInitializers(this, _combinedData_extraInitializers), __runInitializers(this, _inited_initializers, false)));
|
|
273
|
+
__runInitializers(this, _inited_extraInitializers);
|
|
274
|
+
makeObservable(this);
|
|
275
|
+
}
|
|
276
|
+
async init() {
|
|
277
|
+
runInAction(() => {
|
|
278
|
+
this.combinedData = `dependent-simple`;
|
|
279
|
+
});
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
_DependentService_combinedData_accessor_storage = new WeakMap(),
|
|
284
|
+
_DependentService_inited_accessor_storage = new WeakMap(),
|
|
285
|
+
(() => {
|
|
286
|
+
var _b;
|
|
287
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
|
|
288
|
+
_combinedData_decorators = [observable];
|
|
289
|
+
_inited_decorators = [observable];
|
|
290
|
+
__esDecorate(_a, null, _combinedData_decorators, { kind: "accessor", name: "combinedData", static: false, private: false, access: { has: obj => "combinedData" in obj, get: obj => obj.combinedData, set: (obj, value) => { obj.combinedData = value; } }, metadata: _metadata }, _combinedData_initializers, _combinedData_extraInitializers);
|
|
291
|
+
__esDecorate(_a, null, _inited_decorators, { kind: "accessor", name: "inited", static: false, private: false, access: { has: obj => "inited" in obj, get: obj => obj.inited, set: (obj, value) => { obj.inited = value; } }, metadata: _metadata }, _inited_initializers, _inited_extraInitializers);
|
|
292
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
293
|
+
})(),
|
|
294
|
+
_a;
|
|
295
|
+
})();
|
|
296
|
+
// 普通类(不继承 Service)
|
|
297
|
+
let PlainClass = (() => {
|
|
298
|
+
var _a, _PlainClass_value_accessor_storage;
|
|
299
|
+
let _instanceExtraInitializers = [];
|
|
300
|
+
let _value_decorators;
|
|
301
|
+
let _value_initializers = [];
|
|
302
|
+
let _value_extraInitializers = [];
|
|
303
|
+
let _updateValue_decorators;
|
|
304
|
+
return _a = class PlainClass {
|
|
305
|
+
get value() { return __classPrivateFieldGet(this, _PlainClass_value_accessor_storage, "f"); }
|
|
306
|
+
set value(value) { __classPrivateFieldSet(this, _PlainClass_value_accessor_storage, value, "f"); }
|
|
307
|
+
constructor() {
|
|
308
|
+
_PlainClass_value_accessor_storage.set(this, (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _value_initializers, 'plain')));
|
|
309
|
+
__runInitializers(this, _value_extraInitializers);
|
|
310
|
+
makeObservable(this);
|
|
311
|
+
}
|
|
312
|
+
updateValue() {
|
|
313
|
+
this.value = 'updated';
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
_PlainClass_value_accessor_storage = new WeakMap(),
|
|
317
|
+
(() => {
|
|
318
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
319
|
+
_value_decorators = [observable];
|
|
320
|
+
_updateValue_decorators = [action];
|
|
321
|
+
__esDecorate(_a, null, _value_decorators, { kind: "accessor", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, _value_initializers, _value_extraInitializers);
|
|
322
|
+
__esDecorate(_a, null, _updateValue_decorators, { kind: "method", name: "updateValue", static: false, private: false, access: { has: obj => "updateValue" in obj, get: obj => obj.updateValue }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
323
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
324
|
+
})(),
|
|
325
|
+
_a;
|
|
326
|
+
})();
|
|
172
327
|
// 创建测试用的 Provider 组件
|
|
173
328
|
function createTestProvider(services) {
|
|
174
329
|
return function TestProvider({ children }) {
|
|
@@ -232,6 +387,63 @@ describe('service integration', () => {
|
|
|
232
387
|
expect(result.current.count).toBe(0);
|
|
233
388
|
expect(result.current.value).toBe('initial');
|
|
234
389
|
});
|
|
390
|
+
it('在未提供 selector 时应该返回完整服务实例并响应更新', async () => {
|
|
391
|
+
const TestProvider = createTestProvider([TestService]);
|
|
392
|
+
const { result } = renderHook(() => useService(TestService), { wrapper: TestProvider });
|
|
393
|
+
const firstInstance = result.current;
|
|
394
|
+
expect(firstInstance.count).toBe(0);
|
|
395
|
+
act(() => {
|
|
396
|
+
firstInstance.increment();
|
|
397
|
+
});
|
|
398
|
+
await waitFor(() => {
|
|
399
|
+
expect(result.current.count).toBe(1);
|
|
400
|
+
});
|
|
401
|
+
expect(result.current).toBe(firstInstance);
|
|
402
|
+
});
|
|
403
|
+
it('当 selector 返回服务实例时应该退化为监听全部属性', async () => {
|
|
404
|
+
const TestProvider = createTestProvider([TestService]);
|
|
405
|
+
const { result } = renderHook(() => ({
|
|
406
|
+
serviceViaSelector: useService(TestService, service => service),
|
|
407
|
+
counter: useService(TestService, service => service.count)
|
|
408
|
+
}), { wrapper: TestProvider });
|
|
409
|
+
const initialServiceRef = result.current.serviceViaSelector;
|
|
410
|
+
expect(initialServiceRef.count).toBe(0);
|
|
411
|
+
act(() => {
|
|
412
|
+
initialServiceRef.increment();
|
|
413
|
+
});
|
|
414
|
+
await waitFor(() => {
|
|
415
|
+
expect(result.current.counter).toBe(1);
|
|
416
|
+
expect(result.current.serviceViaSelector.count).toBe(1);
|
|
417
|
+
});
|
|
418
|
+
expect(result.current.serviceViaSelector).toBe(initialServiceRef);
|
|
419
|
+
});
|
|
420
|
+
it('useService 的 selector 应该能够响应其他服务的 observable 变化', async () => {
|
|
421
|
+
const TestProvider = createTestProvider([TestService, AnotherService]);
|
|
422
|
+
const { result } = renderHook(() => {
|
|
423
|
+
const globalService = useService(TestService, service => service);
|
|
424
|
+
const anotherSelection = useService(AnotherService, service => ({
|
|
425
|
+
service,
|
|
426
|
+
combined: `${service.value}-${globalService.count}`
|
|
427
|
+
}));
|
|
428
|
+
return {
|
|
429
|
+
globalService,
|
|
430
|
+
anotherSelection
|
|
431
|
+
};
|
|
432
|
+
}, { wrapper: TestProvider });
|
|
433
|
+
expect(result.current.anotherSelection.combined).toBe('initial-0');
|
|
434
|
+
act(() => {
|
|
435
|
+
result.current.anotherSelection.service.setValue('changed');
|
|
436
|
+
});
|
|
437
|
+
await waitFor(() => {
|
|
438
|
+
expect(result.current.anotherSelection.combined).toBe('changed-0');
|
|
439
|
+
});
|
|
440
|
+
act(() => {
|
|
441
|
+
result.current.globalService.increment();
|
|
442
|
+
});
|
|
443
|
+
await waitFor(() => {
|
|
444
|
+
expect(result.current.anotherSelection.combined).toBe('changed-1');
|
|
445
|
+
});
|
|
446
|
+
});
|
|
235
447
|
});
|
|
236
448
|
describe('ServiceProvider', () => {
|
|
237
449
|
it('应该能够渲染子组件', () => {
|
|
@@ -309,6 +521,207 @@ describe('service integration', () => {
|
|
|
309
521
|
expect(result.current).toBe(false); // 因为初始化失败,inited 应该保持 false
|
|
310
522
|
});
|
|
311
523
|
});
|
|
524
|
+
it('在服务已初始化时不会重复调用 init', async () => {
|
|
525
|
+
const initSpy = vi.fn(async () => true);
|
|
526
|
+
let PreInitedService = (() => {
|
|
527
|
+
var _a, _PreInitedService_inited_accessor_storage;
|
|
528
|
+
let _classSuper = Service;
|
|
529
|
+
let _inited_decorators;
|
|
530
|
+
let _inited_initializers = [];
|
|
531
|
+
let _inited_extraInitializers = [];
|
|
532
|
+
return _a = class PreInitedService extends _classSuper {
|
|
533
|
+
get inited() { return __classPrivateFieldGet(this, _PreInitedService_inited_accessor_storage, "f"); }
|
|
534
|
+
set inited(value) { __classPrivateFieldSet(this, _PreInitedService_inited_accessor_storage, value, "f"); }
|
|
535
|
+
constructor() {
|
|
536
|
+
super();
|
|
537
|
+
_PreInitedService_inited_accessor_storage.set(this, __runInitializers(this, _inited_initializers, true));
|
|
538
|
+
this.init = (__runInitializers(this, _inited_extraInitializers), initSpy);
|
|
539
|
+
makeObservable(this);
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
_PreInitedService_inited_accessor_storage = new WeakMap(),
|
|
543
|
+
(() => {
|
|
544
|
+
var _b;
|
|
545
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
|
|
546
|
+
_inited_decorators = [observable];
|
|
547
|
+
__esDecorate(_a, null, _inited_decorators, { kind: "accessor", name: "inited", static: false, private: false, access: { has: obj => "inited" in obj, get: obj => obj.inited, set: (obj, value) => { obj.inited = value; } }, metadata: _metadata }, _inited_initializers, _inited_extraInitializers);
|
|
548
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
549
|
+
})(),
|
|
550
|
+
_a;
|
|
551
|
+
})();
|
|
552
|
+
const TestProvider = createTestProvider([PreInitedService]);
|
|
553
|
+
const { result } = renderHook(() => useService(PreInitedService, service => ({
|
|
554
|
+
inited: service.inited,
|
|
555
|
+
service
|
|
556
|
+
})), { wrapper: TestProvider });
|
|
557
|
+
await waitFor(() => {
|
|
558
|
+
expect(result.current.inited).toBe(true);
|
|
559
|
+
});
|
|
560
|
+
expect(initSpy).not.toHaveBeenCalled();
|
|
561
|
+
});
|
|
562
|
+
it('应该正确处理同步 init 的服务', async () => {
|
|
563
|
+
let SyncInitService = (() => {
|
|
564
|
+
var _a, _SyncInitService_inited_accessor_storage, _SyncInitService_value_accessor_storage;
|
|
565
|
+
let _inited_decorators;
|
|
566
|
+
let _inited_initializers = [];
|
|
567
|
+
let _inited_extraInitializers = [];
|
|
568
|
+
let _value_decorators;
|
|
569
|
+
let _value_initializers = [];
|
|
570
|
+
let _value_extraInitializers = [];
|
|
571
|
+
return _a = class SyncInitService {
|
|
572
|
+
get inited() { return __classPrivateFieldGet(this, _SyncInitService_inited_accessor_storage, "f"); }
|
|
573
|
+
set inited(value) { __classPrivateFieldSet(this, _SyncInitService_inited_accessor_storage, value, "f"); }
|
|
574
|
+
get value() { return __classPrivateFieldGet(this, _SyncInitService_value_accessor_storage, "f"); }
|
|
575
|
+
set value(value) { __classPrivateFieldSet(this, _SyncInitService_value_accessor_storage, value, "f"); }
|
|
576
|
+
constructor() {
|
|
577
|
+
_SyncInitService_inited_accessor_storage.set(this, __runInitializers(this, _inited_initializers, false));
|
|
578
|
+
_SyncInitService_value_accessor_storage.set(this, (__runInitializers(this, _inited_extraInitializers), __runInitializers(this, _value_initializers, 'pending')));
|
|
579
|
+
__runInitializers(this, _value_extraInitializers);
|
|
580
|
+
makeObservable(this);
|
|
581
|
+
}
|
|
582
|
+
init() {
|
|
583
|
+
runInAction(() => {
|
|
584
|
+
this.value = 'ready';
|
|
585
|
+
this.inited = true;
|
|
586
|
+
});
|
|
587
|
+
return true;
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
_SyncInitService_inited_accessor_storage = new WeakMap(),
|
|
591
|
+
_SyncInitService_value_accessor_storage = new WeakMap(),
|
|
592
|
+
(() => {
|
|
593
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
594
|
+
_inited_decorators = [observable];
|
|
595
|
+
_value_decorators = [observable];
|
|
596
|
+
__esDecorate(_a, null, _inited_decorators, { kind: "accessor", name: "inited", static: false, private: false, access: { has: obj => "inited" in obj, get: obj => obj.inited, set: (obj, value) => { obj.inited = value; } }, metadata: _metadata }, _inited_initializers, _inited_extraInitializers);
|
|
597
|
+
__esDecorate(_a, null, _value_decorators, { kind: "accessor", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, _value_initializers, _value_extraInitializers);
|
|
598
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
599
|
+
})(),
|
|
600
|
+
_a;
|
|
601
|
+
})();
|
|
602
|
+
const TestProvider = createTestProvider([SyncInitService]);
|
|
603
|
+
const { result } = renderHook(() => useService(SyncInitService, service => ({
|
|
604
|
+
inited: service.inited,
|
|
605
|
+
value: service.value
|
|
606
|
+
})), { wrapper: TestProvider });
|
|
607
|
+
await waitFor(() => {
|
|
608
|
+
expect(result.current.inited).toBe(true);
|
|
609
|
+
expect(result.current.value).toBe('ready');
|
|
610
|
+
});
|
|
611
|
+
});
|
|
612
|
+
it('应该为多个服务分别调用 init', async () => {
|
|
613
|
+
const firstInit = vi.fn(async () => true);
|
|
614
|
+
const secondInit = vi.fn(async () => true);
|
|
615
|
+
let FirstInitService = (() => {
|
|
616
|
+
var _a, _FirstInitService_inited_accessor_storage;
|
|
617
|
+
let _classSuper = Service;
|
|
618
|
+
let _inited_decorators;
|
|
619
|
+
let _inited_initializers = [];
|
|
620
|
+
let _inited_extraInitializers = [];
|
|
621
|
+
return _a = class FirstInitService extends _classSuper {
|
|
622
|
+
get inited() { return __classPrivateFieldGet(this, _FirstInitService_inited_accessor_storage, "f"); }
|
|
623
|
+
set inited(value) { __classPrivateFieldSet(this, _FirstInitService_inited_accessor_storage, value, "f"); }
|
|
624
|
+
constructor() {
|
|
625
|
+
super();
|
|
626
|
+
_FirstInitService_inited_accessor_storage.set(this, __runInitializers(this, _inited_initializers, false));
|
|
627
|
+
this.init = (__runInitializers(this, _inited_extraInitializers), firstInit);
|
|
628
|
+
makeObservable(this);
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
_FirstInitService_inited_accessor_storage = new WeakMap(),
|
|
632
|
+
(() => {
|
|
633
|
+
var _b;
|
|
634
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
|
|
635
|
+
_inited_decorators = [observable];
|
|
636
|
+
__esDecorate(_a, null, _inited_decorators, { kind: "accessor", name: "inited", static: false, private: false, access: { has: obj => "inited" in obj, get: obj => obj.inited, set: (obj, value) => { obj.inited = value; } }, metadata: _metadata }, _inited_initializers, _inited_extraInitializers);
|
|
637
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
638
|
+
})(),
|
|
639
|
+
_a;
|
|
640
|
+
})();
|
|
641
|
+
let SecondInitService = (() => {
|
|
642
|
+
var _a, _SecondInitService_inited_accessor_storage;
|
|
643
|
+
let _classSuper = Service;
|
|
644
|
+
let _inited_decorators;
|
|
645
|
+
let _inited_initializers = [];
|
|
646
|
+
let _inited_extraInitializers = [];
|
|
647
|
+
return _a = class SecondInitService extends _classSuper {
|
|
648
|
+
get inited() { return __classPrivateFieldGet(this, _SecondInitService_inited_accessor_storage, "f"); }
|
|
649
|
+
set inited(value) { __classPrivateFieldSet(this, _SecondInitService_inited_accessor_storage, value, "f"); }
|
|
650
|
+
constructor() {
|
|
651
|
+
super();
|
|
652
|
+
_SecondInitService_inited_accessor_storage.set(this, __runInitializers(this, _inited_initializers, false));
|
|
653
|
+
this.init = (__runInitializers(this, _inited_extraInitializers), secondInit);
|
|
654
|
+
makeObservable(this);
|
|
655
|
+
}
|
|
656
|
+
},
|
|
657
|
+
_SecondInitService_inited_accessor_storage = new WeakMap(),
|
|
658
|
+
(() => {
|
|
659
|
+
var _b;
|
|
660
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
|
|
661
|
+
_inited_decorators = [observable];
|
|
662
|
+
__esDecorate(_a, null, _inited_decorators, { kind: "accessor", name: "inited", static: false, private: false, access: { has: obj => "inited" in obj, get: obj => obj.inited, set: (obj, value) => { obj.inited = value; } }, metadata: _metadata }, _inited_initializers, _inited_extraInitializers);
|
|
663
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
664
|
+
})(),
|
|
665
|
+
_a;
|
|
666
|
+
})();
|
|
667
|
+
const TestProvider = createTestProvider([FirstInitService, SecondInitService]);
|
|
668
|
+
const { result } = renderHook(() => ({
|
|
669
|
+
firstInited: useService(FirstInitService, service => service.inited),
|
|
670
|
+
secondInited: useService(SecondInitService, service => service.inited)
|
|
671
|
+
}), { wrapper: TestProvider });
|
|
672
|
+
await waitFor(() => {
|
|
673
|
+
expect(result.current.firstInited).toBe(true);
|
|
674
|
+
expect(result.current.secondInited).toBe(true);
|
|
675
|
+
});
|
|
676
|
+
expect(firstInit).toHaveBeenCalledTimes(1);
|
|
677
|
+
expect(secondInit).toHaveBeenCalledTimes(1);
|
|
678
|
+
});
|
|
679
|
+
it('在 init 返回非布尔值时应该抛出错误', async () => {
|
|
680
|
+
var _a;
|
|
681
|
+
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
682
|
+
let InvalidReturnService = (() => {
|
|
683
|
+
var _a, _InvalidReturnService_inited_accessor_storage;
|
|
684
|
+
let _classSuper = Service;
|
|
685
|
+
let _inited_decorators;
|
|
686
|
+
let _inited_initializers = [];
|
|
687
|
+
let _inited_extraInitializers = [];
|
|
688
|
+
return _a = class InvalidReturnService extends _classSuper {
|
|
689
|
+
get inited() { return __classPrivateFieldGet(this, _InvalidReturnService_inited_accessor_storage, "f"); }
|
|
690
|
+
set inited(value) { __classPrivateFieldSet(this, _InvalidReturnService_inited_accessor_storage, value, "f"); }
|
|
691
|
+
constructor() {
|
|
692
|
+
super();
|
|
693
|
+
_InvalidReturnService_inited_accessor_storage.set(this, __runInitializers(this, _inited_initializers, false));
|
|
694
|
+
__runInitializers(this, _inited_extraInitializers);
|
|
695
|
+
makeObservable(this);
|
|
696
|
+
}
|
|
697
|
+
async init() {
|
|
698
|
+
return 'invalid';
|
|
699
|
+
}
|
|
700
|
+
},
|
|
701
|
+
_InvalidReturnService_inited_accessor_storage = new WeakMap(),
|
|
702
|
+
(() => {
|
|
703
|
+
var _b;
|
|
704
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
|
|
705
|
+
_inited_decorators = [observable];
|
|
706
|
+
__esDecorate(_a, null, _inited_decorators, { kind: "accessor", name: "inited", static: false, private: false, access: { has: obj => "inited" in obj, get: obj => obj.inited, set: (obj, value) => { obj.inited = value; } }, metadata: _metadata }, _inited_initializers, _inited_extraInitializers);
|
|
707
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
708
|
+
})(),
|
|
709
|
+
_a;
|
|
710
|
+
})();
|
|
711
|
+
const TestProvider = createTestProvider([InvalidReturnService]);
|
|
712
|
+
const capturedErrors = [];
|
|
713
|
+
const Wrapper = ({ children }) => (_jsx(TestErrorBoundary, { onError: error => capturedErrors.push(error), children: _jsx(TestProvider, { children: children }) }));
|
|
714
|
+
try {
|
|
715
|
+
renderHook(() => useService(InvalidReturnService, service => service.inited), { wrapper: Wrapper });
|
|
716
|
+
await waitFor(() => {
|
|
717
|
+
expect(capturedErrors[0]).toBeInstanceOf(Error);
|
|
718
|
+
});
|
|
719
|
+
expect((_a = capturedErrors[0]) === null || _a === void 0 ? void 0 : _a.message).toBe('Service init must return a boolean value.');
|
|
720
|
+
}
|
|
721
|
+
finally {
|
|
722
|
+
errorSpy.mockRestore();
|
|
723
|
+
}
|
|
724
|
+
});
|
|
312
725
|
});
|
|
313
726
|
describe('边界情况', () => {
|
|
314
727
|
it('useService 应该能够处理选择器返回 undefined 的情况', () => {
|
|
@@ -355,4 +768,632 @@ describe('service integration', () => {
|
|
|
355
768
|
expect(renderCount).toBeGreaterThanOrEqual(initialRenderCount);
|
|
356
769
|
});
|
|
357
770
|
});
|
|
771
|
+
describe('useLocalService', () => {
|
|
772
|
+
it('应该能够创建局部服务实例', async () => {
|
|
773
|
+
const TestProvider = createTestProvider([TestService]);
|
|
774
|
+
const { result } = renderHook(() => useLocalService(LocalService, service => service.data), { wrapper: TestProvider });
|
|
775
|
+
// 初始状态应该是已经初始化的,因为初始化是同步的
|
|
776
|
+
expect(result.current).toBe('initialized');
|
|
777
|
+
});
|
|
778
|
+
it('应该在没有 ServiceProvider 时抛出错误', () => {
|
|
779
|
+
expect(() => {
|
|
780
|
+
renderHook(() => useLocalService(LocalService, service => service.data));
|
|
781
|
+
}).toThrow('Must be a child of ServiceProvider.');
|
|
782
|
+
});
|
|
783
|
+
it('应该自动初始化局部服务实例', async () => {
|
|
784
|
+
const TestProvider = createTestProvider([TestService]);
|
|
785
|
+
const { result } = renderHook(() => useLocalService(LocalService, service => ({
|
|
786
|
+
data: service.data,
|
|
787
|
+
inited: service.inited
|
|
788
|
+
})), { wrapper: TestProvider });
|
|
789
|
+
// 等待初始化完成
|
|
790
|
+
await waitFor(() => {
|
|
791
|
+
expect(result.current.inited).toBe(true);
|
|
792
|
+
expect(result.current.data).toBe('initialized');
|
|
793
|
+
});
|
|
794
|
+
});
|
|
795
|
+
it('应该在服务数据变化时触发重新渲染', async () => {
|
|
796
|
+
const TestProvider = createTestProvider([TestService]);
|
|
797
|
+
const { result } = renderHook(() => useLocalService(LocalService, service => ({
|
|
798
|
+
counter: service.counter,
|
|
799
|
+
service
|
|
800
|
+
})), { wrapper: TestProvider });
|
|
801
|
+
expect(result.current.counter).toBe(0);
|
|
802
|
+
// 修改服务数据
|
|
803
|
+
act(() => {
|
|
804
|
+
result.current.service.increment();
|
|
805
|
+
});
|
|
806
|
+
await waitFor(() => {
|
|
807
|
+
expect(result.current.counter).toBe(1);
|
|
808
|
+
});
|
|
809
|
+
});
|
|
810
|
+
it('应该在组件重渲染时保持服务实例引用稳定', () => {
|
|
811
|
+
const TestProvider = createTestProvider([TestService]);
|
|
812
|
+
const { result, rerender } = renderHook(() => useLocalService(LocalService, service => service), { wrapper: TestProvider });
|
|
813
|
+
const firstInstance = result.current;
|
|
814
|
+
rerender();
|
|
815
|
+
const secondInstance = result.current;
|
|
816
|
+
expect(firstInstance).toBe(secondInstance);
|
|
817
|
+
});
|
|
818
|
+
it('应该为不同的 hook 调用创建不同的服务实例', () => {
|
|
819
|
+
const TestProvider = createTestProvider([TestService]);
|
|
820
|
+
const { result } = renderHook(() => ({
|
|
821
|
+
service1: useLocalService(LocalService, service => service),
|
|
822
|
+
service2: useLocalService(LocalService, service => service)
|
|
823
|
+
}), { wrapper: TestProvider });
|
|
824
|
+
expect(result.current.service1).not.toBe(result.current.service2);
|
|
825
|
+
});
|
|
826
|
+
it('应该支持依赖注入全局服务', async () => {
|
|
827
|
+
const TestProvider = createTestProvider([TestService]);
|
|
828
|
+
const { result } = renderHook(() => ({
|
|
829
|
+
localService: useLocalService(DependentService, service => service),
|
|
830
|
+
globalService: useService(TestService, service => service)
|
|
831
|
+
}), { wrapper: TestProvider });
|
|
832
|
+
// 修改全局服务的数据
|
|
833
|
+
act(() => {
|
|
834
|
+
result.current.globalService.increment();
|
|
835
|
+
result.current.globalService.increment();
|
|
836
|
+
});
|
|
837
|
+
// 等待局部服务初始化完成
|
|
838
|
+
await waitFor(() => {
|
|
839
|
+
expect(result.current.localService.inited).toBe(true);
|
|
840
|
+
expect(result.current.localService.combinedData).toBe('dependent-simple');
|
|
841
|
+
}, { timeout: 3000 });
|
|
842
|
+
});
|
|
843
|
+
it('应该能够处理复杂的选择器', async () => {
|
|
844
|
+
const TestProvider = createTestProvider([TestService]);
|
|
845
|
+
let serviceRef = null;
|
|
846
|
+
const { result } = renderHook(() => useLocalService(LocalService, service => {
|
|
847
|
+
serviceRef = service; // 保存服务引用
|
|
848
|
+
return {
|
|
849
|
+
hasData: service.data.length > 0,
|
|
850
|
+
upperData: service.data.toUpperCase(),
|
|
851
|
+
rawData: service.data, // 添加原始数据用于调试
|
|
852
|
+
};
|
|
853
|
+
}), { wrapper: TestProvider });
|
|
854
|
+
await waitFor(() => {
|
|
855
|
+
expect(result.current.hasData).toBe(true);
|
|
856
|
+
expect(result.current.upperData).toBe('INITIALIZED');
|
|
857
|
+
});
|
|
858
|
+
// 修改数据 - 使用选择器内部捕获的服务实例
|
|
859
|
+
act(() => {
|
|
860
|
+
serviceRef.setData('modified');
|
|
861
|
+
});
|
|
862
|
+
await waitFor(() => {
|
|
863
|
+
expect(result.current.upperData).toBe('MODIFIED');
|
|
864
|
+
});
|
|
865
|
+
});
|
|
866
|
+
it('应该能够处理选择器返回 undefined 的情况', () => {
|
|
867
|
+
const TestProvider = createTestProvider([TestService]);
|
|
868
|
+
const { result } = renderHook(() => useLocalService(LocalService, () => undefined), { wrapper: TestProvider });
|
|
869
|
+
expect(result.current).toBeUndefined();
|
|
870
|
+
});
|
|
871
|
+
it('应该能够处理局部服务初始化失败的情况', async () => {
|
|
872
|
+
// 创建一个初始化会失败的局部服务
|
|
873
|
+
let FailingLocalService = (() => {
|
|
874
|
+
var _a, _FailingLocalService_inited_accessor_storage;
|
|
875
|
+
let _classSuper = Service;
|
|
876
|
+
let _inited_decorators;
|
|
877
|
+
let _inited_initializers = [];
|
|
878
|
+
let _inited_extraInitializers = [];
|
|
879
|
+
return _a = class FailingLocalService extends _classSuper {
|
|
880
|
+
get inited() { return __classPrivateFieldGet(this, _FailingLocalService_inited_accessor_storage, "f"); }
|
|
881
|
+
set inited(value) { __classPrivateFieldSet(this, _FailingLocalService_inited_accessor_storage, value, "f"); }
|
|
882
|
+
constructor() {
|
|
883
|
+
super();
|
|
884
|
+
_FailingLocalService_inited_accessor_storage.set(this, __runInitializers(this, _inited_initializers, false));
|
|
885
|
+
__runInitializers(this, _inited_extraInitializers);
|
|
886
|
+
makeObservable(this);
|
|
887
|
+
}
|
|
888
|
+
async init() {
|
|
889
|
+
throw new Error('Init failed');
|
|
890
|
+
}
|
|
891
|
+
},
|
|
892
|
+
_FailingLocalService_inited_accessor_storage = new WeakMap(),
|
|
893
|
+
(() => {
|
|
894
|
+
var _b;
|
|
895
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
|
|
896
|
+
_inited_decorators = [observable];
|
|
897
|
+
__esDecorate(_a, null, _inited_decorators, { kind: "accessor", name: "inited", static: false, private: false, access: { has: obj => "inited" in obj, get: obj => obj.inited, set: (obj, value) => { obj.inited = value; } }, metadata: _metadata }, _inited_initializers, _inited_extraInitializers);
|
|
898
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
899
|
+
})(),
|
|
900
|
+
_a;
|
|
901
|
+
})();
|
|
902
|
+
const TestProvider = createTestProvider([TestService]);
|
|
903
|
+
const { result } = renderHook(() => useLocalService(FailingLocalService, service => service.inited), { wrapper: TestProvider });
|
|
904
|
+
// 等待初始化处理完成,即使失败也应该保持 inited 为 false
|
|
905
|
+
await waitFor(() => {
|
|
906
|
+
expect(result.current).toBe(false);
|
|
907
|
+
});
|
|
908
|
+
});
|
|
909
|
+
it('在 init 返回非布尔值时应该抛出错误', async () => {
|
|
910
|
+
var _a;
|
|
911
|
+
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
912
|
+
let InvalidReturnLocalService = (() => {
|
|
913
|
+
var _a, _InvalidReturnLocalService_inited_accessor_storage;
|
|
914
|
+
let _classSuper = Service;
|
|
915
|
+
let _inited_decorators;
|
|
916
|
+
let _inited_initializers = [];
|
|
917
|
+
let _inited_extraInitializers = [];
|
|
918
|
+
return _a = class InvalidReturnLocalService extends _classSuper {
|
|
919
|
+
get inited() { return __classPrivateFieldGet(this, _InvalidReturnLocalService_inited_accessor_storage, "f"); }
|
|
920
|
+
set inited(value) { __classPrivateFieldSet(this, _InvalidReturnLocalService_inited_accessor_storage, value, "f"); }
|
|
921
|
+
constructor() {
|
|
922
|
+
super();
|
|
923
|
+
_InvalidReturnLocalService_inited_accessor_storage.set(this, __runInitializers(this, _inited_initializers, false));
|
|
924
|
+
__runInitializers(this, _inited_extraInitializers);
|
|
925
|
+
makeObservable(this);
|
|
926
|
+
}
|
|
927
|
+
async init() {
|
|
928
|
+
return 'invalid';
|
|
929
|
+
}
|
|
930
|
+
},
|
|
931
|
+
_InvalidReturnLocalService_inited_accessor_storage = new WeakMap(),
|
|
932
|
+
(() => {
|
|
933
|
+
var _b;
|
|
934
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
|
|
935
|
+
_inited_decorators = [observable];
|
|
936
|
+
__esDecorate(_a, null, _inited_decorators, { kind: "accessor", name: "inited", static: false, private: false, access: { has: obj => "inited" in obj, get: obj => obj.inited, set: (obj, value) => { obj.inited = value; } }, metadata: _metadata }, _inited_initializers, _inited_extraInitializers);
|
|
937
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
938
|
+
})(),
|
|
939
|
+
_a;
|
|
940
|
+
})();
|
|
941
|
+
const TestProvider = createTestProvider([TestService]);
|
|
942
|
+
const capturedErrors = [];
|
|
943
|
+
const Wrapper = ({ children }) => (_jsx(TestErrorBoundary, { onError: error => capturedErrors.push(error), children: _jsx(TestProvider, { children: children }) }));
|
|
944
|
+
try {
|
|
945
|
+
renderHook(() => useLocalService(InvalidReturnLocalService, service => service.inited), { wrapper: Wrapper });
|
|
946
|
+
await waitFor(() => {
|
|
947
|
+
expect(capturedErrors[0]).toBeInstanceOf(Error);
|
|
948
|
+
});
|
|
949
|
+
expect((_a = capturedErrors[0]) === null || _a === void 0 ? void 0 : _a.message).toBe('Service init must return a boolean value.');
|
|
950
|
+
}
|
|
951
|
+
finally {
|
|
952
|
+
errorSpy.mockRestore();
|
|
953
|
+
}
|
|
954
|
+
});
|
|
955
|
+
it('应该能够处理没有实现 Service 接口的局部服务', async () => {
|
|
956
|
+
const TestProvider = createTestProvider([TestService]);
|
|
957
|
+
const { result } = renderHook(() => useLocalService(PlainClass, service => ({
|
|
958
|
+
value: service.value,
|
|
959
|
+
service
|
|
960
|
+
})), { wrapper: TestProvider });
|
|
961
|
+
expect(result.current.value).toBe('plain');
|
|
962
|
+
// 修改数据
|
|
963
|
+
act(() => {
|
|
964
|
+
result.current.service.updateValue();
|
|
965
|
+
});
|
|
966
|
+
await waitFor(() => {
|
|
967
|
+
expect(result.current.value).toBe('updated');
|
|
968
|
+
});
|
|
969
|
+
});
|
|
970
|
+
it('应该在选择器函数变化时正确更新订阅', async () => {
|
|
971
|
+
const TestProvider = createTestProvider([TestService]);
|
|
972
|
+
let useData = true;
|
|
973
|
+
const { result, rerender } = renderHook(() => useLocalService(LocalService, service => ({
|
|
974
|
+
selected: useData ? service.data : service.counter,
|
|
975
|
+
service
|
|
976
|
+
})), { wrapper: TestProvider });
|
|
977
|
+
await waitFor(() => {
|
|
978
|
+
expect(result.current.selected).toBe('initialized');
|
|
979
|
+
});
|
|
980
|
+
// 修改 selector
|
|
981
|
+
useData = false;
|
|
982
|
+
rerender();
|
|
983
|
+
await waitFor(() => {
|
|
984
|
+
expect(result.current.selected).toBe(0);
|
|
985
|
+
});
|
|
986
|
+
// 修改计数器
|
|
987
|
+
act(() => {
|
|
988
|
+
result.current.service.increment();
|
|
989
|
+
});
|
|
990
|
+
await waitFor(() => {
|
|
991
|
+
expect(result.current.selected).toBe(1);
|
|
992
|
+
});
|
|
993
|
+
});
|
|
994
|
+
it('不应该产生全局状态的干扰', async () => {
|
|
995
|
+
const TestProvider = createTestProvider([TestService]);
|
|
996
|
+
let globalServiceRef = null;
|
|
997
|
+
let localServiceRef1 = null;
|
|
998
|
+
let localServiceRef2 = null;
|
|
999
|
+
// 第一个组件:使用全局服务和局部服务
|
|
1000
|
+
const { result: result1 } = renderHook(() => ({
|
|
1001
|
+
globalService: useService(TestService, service => {
|
|
1002
|
+
globalServiceRef = service;
|
|
1003
|
+
return service;
|
|
1004
|
+
}),
|
|
1005
|
+
localService: useLocalService(LocalService, service => {
|
|
1006
|
+
localServiceRef1 = service;
|
|
1007
|
+
return service;
|
|
1008
|
+
})
|
|
1009
|
+
}), { wrapper: TestProvider });
|
|
1010
|
+
// 第二个组件:使用另一个局部服务实例
|
|
1011
|
+
const { result: result2 } = renderHook(() => ({
|
|
1012
|
+
localService: useLocalService(LocalService, service => {
|
|
1013
|
+
localServiceRef2 = service;
|
|
1014
|
+
return service;
|
|
1015
|
+
})
|
|
1016
|
+
}), { wrapper: TestProvider });
|
|
1017
|
+
// 等待初始化完成
|
|
1018
|
+
await waitFor(() => {
|
|
1019
|
+
expect(result1.current.globalService.inited).toBe(true);
|
|
1020
|
+
expect(result1.current.localService.inited).toBe(true);
|
|
1021
|
+
expect(result2.current.localService.inited).toBe(true);
|
|
1022
|
+
});
|
|
1023
|
+
// 验证基本状态
|
|
1024
|
+
expect(globalServiceRef).not.toBeNull();
|
|
1025
|
+
expect(localServiceRef1).not.toBeNull();
|
|
1026
|
+
expect(localServiceRef2).not.toBeNull();
|
|
1027
|
+
// 验证局部服务实例是不同的
|
|
1028
|
+
expect(localServiceRef1).not.toBe(localServiceRef2);
|
|
1029
|
+
// 验证局部服务与全局服务是不同的
|
|
1030
|
+
expect(localServiceRef1).not.toBe(globalServiceRef);
|
|
1031
|
+
expect(localServiceRef2).not.toBe(globalServiceRef);
|
|
1032
|
+
// 修改第一个局部服务的状态
|
|
1033
|
+
act(() => {
|
|
1034
|
+
localServiceRef1.increment();
|
|
1035
|
+
localServiceRef1.setData('local1-changed');
|
|
1036
|
+
});
|
|
1037
|
+
await waitFor(() => {
|
|
1038
|
+
expect(result1.current.localService.counter).toBe(1);
|
|
1039
|
+
expect(result1.current.localService.data).toBe('local1-changed');
|
|
1040
|
+
});
|
|
1041
|
+
// 验证其他服务状态未受影响
|
|
1042
|
+
expect(result2.current.localService.counter).toBe(0);
|
|
1043
|
+
expect(result2.current.localService.data).toBe('initialized');
|
|
1044
|
+
expect(result1.current.globalService.count).toBe(0);
|
|
1045
|
+
// 修改第二个局部服务的状态
|
|
1046
|
+
act(() => {
|
|
1047
|
+
localServiceRef2.increment();
|
|
1048
|
+
localServiceRef2.increment();
|
|
1049
|
+
localServiceRef2.setData('local2-changed');
|
|
1050
|
+
});
|
|
1051
|
+
await waitFor(() => {
|
|
1052
|
+
expect(result2.current.localService.counter).toBe(2);
|
|
1053
|
+
expect(result2.current.localService.data).toBe('local2-changed');
|
|
1054
|
+
});
|
|
1055
|
+
// 验证其他服务状态仍未受影响
|
|
1056
|
+
expect(result1.current.localService.counter).toBe(1);
|
|
1057
|
+
expect(result1.current.localService.data).toBe('local1-changed');
|
|
1058
|
+
expect(result1.current.globalService.count).toBe(0);
|
|
1059
|
+
// 修改全局服务状态
|
|
1060
|
+
act(() => {
|
|
1061
|
+
globalServiceRef.increment();
|
|
1062
|
+
globalServiceRef.addUser('Charlie');
|
|
1063
|
+
});
|
|
1064
|
+
await waitFor(() => {
|
|
1065
|
+
expect(result1.current.globalService.count).toBe(1);
|
|
1066
|
+
expect(result1.current.globalService.users).toEqual(['Alice', 'Bob', 'Charlie']);
|
|
1067
|
+
});
|
|
1068
|
+
// 验证局部服务状态未受全局服务影响
|
|
1069
|
+
expect(result1.current.localService.counter).toBe(1);
|
|
1070
|
+
expect(result1.current.localService.data).toBe('local1-changed');
|
|
1071
|
+
expect(result2.current.localService.counter).toBe(2);
|
|
1072
|
+
expect(result2.current.localService.data).toBe('local2-changed');
|
|
1073
|
+
// 最终验证:每个服务实例都保持独立的状态
|
|
1074
|
+
expect(result1.current.globalService.count).toBe(1);
|
|
1075
|
+
expect(result1.current.globalService.users.length).toBe(3);
|
|
1076
|
+
expect(result1.current.localService.counter).toBe(1);
|
|
1077
|
+
expect(result1.current.localService.data).toBe('local1-changed');
|
|
1078
|
+
expect(result2.current.localService.counter).toBe(2);
|
|
1079
|
+
expect(result2.current.localService.data).toBe('local2-changed');
|
|
1080
|
+
});
|
|
1081
|
+
it('当 selector 返回服务实例时应该退化为监听全部属性', async () => {
|
|
1082
|
+
const TestProvider = createTestProvider([TestService]);
|
|
1083
|
+
const { result } = renderHook(() => useLocalService(LocalService, service => service), { wrapper: TestProvider });
|
|
1084
|
+
const firstInstance = result.current;
|
|
1085
|
+
expect(firstInstance.counter).toBe(0);
|
|
1086
|
+
act(() => {
|
|
1087
|
+
firstInstance.increment();
|
|
1088
|
+
});
|
|
1089
|
+
await waitFor(() => {
|
|
1090
|
+
expect(result.current.counter).toBe(1);
|
|
1091
|
+
});
|
|
1092
|
+
expect(result.current).toBe(firstInstance);
|
|
1093
|
+
});
|
|
1094
|
+
it('应该在卸载后重新创建新的服务实例', async () => {
|
|
1095
|
+
const TestProvider = createTestProvider([TestService]);
|
|
1096
|
+
const { result, unmount } = renderHook(() => useLocalService(LocalService, service => service), { wrapper: TestProvider });
|
|
1097
|
+
const firstInstance = result.current;
|
|
1098
|
+
await waitFor(() => {
|
|
1099
|
+
expect(firstInstance.inited).toBe(true);
|
|
1100
|
+
});
|
|
1101
|
+
unmount();
|
|
1102
|
+
const { result: result2 } = renderHook(() => useLocalService(LocalService, service => service), { wrapper: TestProvider });
|
|
1103
|
+
await waitFor(() => {
|
|
1104
|
+
expect(result2.current.inited).toBe(true);
|
|
1105
|
+
});
|
|
1106
|
+
expect(result2.current).not.toBe(firstInstance);
|
|
1107
|
+
});
|
|
1108
|
+
it('应该只在首次挂载时调用一次 init', async () => {
|
|
1109
|
+
const initSpy = vi.fn(async () => true);
|
|
1110
|
+
let InitOnceLocalService = (() => {
|
|
1111
|
+
var _a, _InitOnceLocalService_inited_accessor_storage;
|
|
1112
|
+
let _classSuper = Service;
|
|
1113
|
+
let _inited_decorators;
|
|
1114
|
+
let _inited_initializers = [];
|
|
1115
|
+
let _inited_extraInitializers = [];
|
|
1116
|
+
return _a = class InitOnceLocalService extends _classSuper {
|
|
1117
|
+
get inited() { return __classPrivateFieldGet(this, _InitOnceLocalService_inited_accessor_storage, "f"); }
|
|
1118
|
+
set inited(value) { __classPrivateFieldSet(this, _InitOnceLocalService_inited_accessor_storage, value, "f"); }
|
|
1119
|
+
constructor() {
|
|
1120
|
+
super();
|
|
1121
|
+
_InitOnceLocalService_inited_accessor_storage.set(this, __runInitializers(this, _inited_initializers, false));
|
|
1122
|
+
this.init = (__runInitializers(this, _inited_extraInitializers), initSpy);
|
|
1123
|
+
makeObservable(this);
|
|
1124
|
+
}
|
|
1125
|
+
},
|
|
1126
|
+
_InitOnceLocalService_inited_accessor_storage = new WeakMap(),
|
|
1127
|
+
(() => {
|
|
1128
|
+
var _b;
|
|
1129
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
|
|
1130
|
+
_inited_decorators = [observable];
|
|
1131
|
+
__esDecorate(_a, null, _inited_decorators, { kind: "accessor", name: "inited", static: false, private: false, access: { has: obj => "inited" in obj, get: obj => obj.inited, set: (obj, value) => { obj.inited = value; } }, metadata: _metadata }, _inited_initializers, _inited_extraInitializers);
|
|
1132
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1133
|
+
})(),
|
|
1134
|
+
_a;
|
|
1135
|
+
})();
|
|
1136
|
+
const TestProvider = createTestProvider([TestService]);
|
|
1137
|
+
const { result, rerender } = renderHook(() => useLocalService(InitOnceLocalService, service => service.inited), { wrapper: TestProvider });
|
|
1138
|
+
await waitFor(() => {
|
|
1139
|
+
expect(result.current).toBe(true);
|
|
1140
|
+
});
|
|
1141
|
+
rerender();
|
|
1142
|
+
await waitFor(() => {
|
|
1143
|
+
expect(result.current).toBe(true);
|
|
1144
|
+
});
|
|
1145
|
+
expect(initSpy).toHaveBeenCalledTimes(1);
|
|
1146
|
+
});
|
|
1147
|
+
it('在同一组件中混用全局与局部的同类服务时应该保持状态独立', async () => {
|
|
1148
|
+
const TestProvider = createTestProvider([TestService]);
|
|
1149
|
+
const { result } = renderHook(() => ({
|
|
1150
|
+
global: useService(TestService, service => ({
|
|
1151
|
+
service,
|
|
1152
|
+
count: service.count,
|
|
1153
|
+
users: [...service.users]
|
|
1154
|
+
})),
|
|
1155
|
+
local: useLocalService(TestService, service => ({
|
|
1156
|
+
service,
|
|
1157
|
+
count: service.count,
|
|
1158
|
+
users: [...service.users]
|
|
1159
|
+
}))
|
|
1160
|
+
}), { wrapper: TestProvider });
|
|
1161
|
+
await waitFor(() => {
|
|
1162
|
+
expect(result.current.global.users).toEqual(['Alice', 'Bob']);
|
|
1163
|
+
expect(result.current.local.users).toEqual(['Alice', 'Bob']);
|
|
1164
|
+
});
|
|
1165
|
+
expect(result.current.global.service).not.toBe(result.current.local.service);
|
|
1166
|
+
act(() => {
|
|
1167
|
+
result.current.global.service.increment();
|
|
1168
|
+
result.current.global.service.addUser('GlobalCharlie');
|
|
1169
|
+
});
|
|
1170
|
+
await waitFor(() => {
|
|
1171
|
+
expect(result.current.global.count).toBe(1);
|
|
1172
|
+
expect(result.current.global.users).toEqual(['Alice', 'Bob', 'GlobalCharlie']);
|
|
1173
|
+
});
|
|
1174
|
+
expect(result.current.local.count).toBe(0);
|
|
1175
|
+
expect(result.current.local.users).toEqual(['Alice', 'Bob']);
|
|
1176
|
+
act(() => {
|
|
1177
|
+
result.current.local.service.increment();
|
|
1178
|
+
result.current.local.service.addUser('LocalCharlie');
|
|
1179
|
+
});
|
|
1180
|
+
await waitFor(() => {
|
|
1181
|
+
expect(result.current.local.count).toBe(1);
|
|
1182
|
+
expect(result.current.local.users).toEqual(['Alice', 'Bob', 'LocalCharlie']);
|
|
1183
|
+
});
|
|
1184
|
+
expect(result.current.global.count).toBe(1);
|
|
1185
|
+
expect(result.current.global.users).toEqual(['Alice', 'Bob', 'GlobalCharlie']);
|
|
1186
|
+
});
|
|
1187
|
+
it('同一服务在全局与局部同时使用时应该分别初始化', async () => {
|
|
1188
|
+
const initSpy = vi.fn(async function () {
|
|
1189
|
+
runInAction(() => {
|
|
1190
|
+
this.inited = true;
|
|
1191
|
+
});
|
|
1192
|
+
return true;
|
|
1193
|
+
});
|
|
1194
|
+
let InitSpyService = (() => {
|
|
1195
|
+
var _a, _InitSpyService_inited_accessor_storage;
|
|
1196
|
+
let _classSuper = Service;
|
|
1197
|
+
let _inited_decorators;
|
|
1198
|
+
let _inited_initializers = [];
|
|
1199
|
+
let _inited_extraInitializers = [];
|
|
1200
|
+
return _a = class InitSpyService extends _classSuper {
|
|
1201
|
+
get inited() { return __classPrivateFieldGet(this, _InitSpyService_inited_accessor_storage, "f"); }
|
|
1202
|
+
set inited(value) { __classPrivateFieldSet(this, _InitSpyService_inited_accessor_storage, value, "f"); }
|
|
1203
|
+
constructor() {
|
|
1204
|
+
super();
|
|
1205
|
+
_InitSpyService_inited_accessor_storage.set(this, __runInitializers(this, _inited_initializers, false));
|
|
1206
|
+
this.init = (__runInitializers(this, _inited_extraInitializers), initSpy);
|
|
1207
|
+
makeObservable(this);
|
|
1208
|
+
}
|
|
1209
|
+
},
|
|
1210
|
+
_InitSpyService_inited_accessor_storage = new WeakMap(),
|
|
1211
|
+
(() => {
|
|
1212
|
+
var _b;
|
|
1213
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
|
|
1214
|
+
_inited_decorators = [observable];
|
|
1215
|
+
__esDecorate(_a, null, _inited_decorators, { kind: "accessor", name: "inited", static: false, private: false, access: { has: obj => "inited" in obj, get: obj => obj.inited, set: (obj, value) => { obj.inited = value; } }, metadata: _metadata }, _inited_initializers, _inited_extraInitializers);
|
|
1216
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1217
|
+
})(),
|
|
1218
|
+
_a;
|
|
1219
|
+
})();
|
|
1220
|
+
const TestProvider = createTestProvider([InitSpyService]);
|
|
1221
|
+
const { result } = renderHook(() => ({
|
|
1222
|
+
global: useService(InitSpyService, service => ({
|
|
1223
|
+
service,
|
|
1224
|
+
inited: service.inited
|
|
1225
|
+
})),
|
|
1226
|
+
local: useLocalService(InitSpyService, service => ({
|
|
1227
|
+
service,
|
|
1228
|
+
inited: service.inited
|
|
1229
|
+
}))
|
|
1230
|
+
}), { wrapper: TestProvider });
|
|
1231
|
+
await waitFor(() => {
|
|
1232
|
+
expect(result.current.global.inited).toBe(true);
|
|
1233
|
+
expect(result.current.local.inited).toBe(true);
|
|
1234
|
+
});
|
|
1235
|
+
expect(result.current.global.service).not.toBe(result.current.local.service);
|
|
1236
|
+
expect(initSpy).toHaveBeenCalledTimes(2);
|
|
1237
|
+
const instances = initSpy.mock.instances;
|
|
1238
|
+
expect(new Set(instances).size).toBe(2);
|
|
1239
|
+
instances.forEach(instance => {
|
|
1240
|
+
expect(instance.inited).toBe(true);
|
|
1241
|
+
});
|
|
1242
|
+
});
|
|
1243
|
+
it('useLocalService 的 selector 应该能够响应全局服务的 observable 变化', async () => {
|
|
1244
|
+
const TestProvider = createTestProvider([TestService]);
|
|
1245
|
+
const { result } = renderHook(() => {
|
|
1246
|
+
const globalService = useService(TestService, service => service);
|
|
1247
|
+
const localSelection = useLocalService(LocalService, service => ({
|
|
1248
|
+
service,
|
|
1249
|
+
combined: `${service.counter}-${globalService.count}`
|
|
1250
|
+
}));
|
|
1251
|
+
return {
|
|
1252
|
+
globalService,
|
|
1253
|
+
localSelection
|
|
1254
|
+
};
|
|
1255
|
+
}, { wrapper: TestProvider });
|
|
1256
|
+
await waitFor(() => {
|
|
1257
|
+
expect(result.current.localSelection.service.inited).toBe(true);
|
|
1258
|
+
});
|
|
1259
|
+
expect(result.current.localSelection.combined).toBe('0-0');
|
|
1260
|
+
act(() => {
|
|
1261
|
+
result.current.globalService.increment();
|
|
1262
|
+
});
|
|
1263
|
+
await waitFor(() => {
|
|
1264
|
+
expect(result.current.localSelection.combined).toBe('0-1');
|
|
1265
|
+
});
|
|
1266
|
+
act(() => {
|
|
1267
|
+
result.current.localSelection.service.increment();
|
|
1268
|
+
});
|
|
1269
|
+
await waitFor(() => {
|
|
1270
|
+
expect(result.current.localSelection.combined).toBe('1-1');
|
|
1271
|
+
});
|
|
1272
|
+
});
|
|
1273
|
+
});
|
|
1274
|
+
describe('useLocalService 可选 selector 功能', () => {
|
|
1275
|
+
it('应该在不传入 selector 时返回完整的服务实例', async () => {
|
|
1276
|
+
const TestProvider = createTestProvider([TestService]);
|
|
1277
|
+
const { result } = renderHook(() => useLocalService(LocalService), { wrapper: TestProvider });
|
|
1278
|
+
await waitFor(() => {
|
|
1279
|
+
expect(result.current.inited).toBe(true);
|
|
1280
|
+
});
|
|
1281
|
+
expect(result.current.data).toBe('initialized');
|
|
1282
|
+
expect(result.current.counter).toBe(0);
|
|
1283
|
+
expect(typeof result.current.increment).toBe('function');
|
|
1284
|
+
});
|
|
1285
|
+
it('应该在不传入 selector 时响应任意属性的变化', async () => {
|
|
1286
|
+
const TestProvider = createTestProvider([TestService]);
|
|
1287
|
+
const { result } = renderHook(() => useLocalService(LocalService), { wrapper: TestProvider });
|
|
1288
|
+
await waitFor(() => {
|
|
1289
|
+
expect(result.current.inited).toBe(true);
|
|
1290
|
+
});
|
|
1291
|
+
// 初始值
|
|
1292
|
+
expect(result.current.data).toBe('initialized');
|
|
1293
|
+
expect(result.current.counter).toBe(0);
|
|
1294
|
+
// 修改计数器
|
|
1295
|
+
act(() => {
|
|
1296
|
+
result.current.increment();
|
|
1297
|
+
});
|
|
1298
|
+
await waitFor(() => {
|
|
1299
|
+
expect(result.current.counter).toBe(1);
|
|
1300
|
+
});
|
|
1301
|
+
// 修改数据
|
|
1302
|
+
act(() => {
|
|
1303
|
+
result.current.setData('updated');
|
|
1304
|
+
});
|
|
1305
|
+
await waitFor(() => {
|
|
1306
|
+
expect(result.current.data).toBe('updated');
|
|
1307
|
+
});
|
|
1308
|
+
});
|
|
1309
|
+
it('应该支持函数重载,有 selector 时返回选择器结果', async () => {
|
|
1310
|
+
const TestProvider = createTestProvider([TestService]);
|
|
1311
|
+
const { result } = renderHook(() => ({
|
|
1312
|
+
service: useLocalService(LocalService),
|
|
1313
|
+
counter: useLocalService(LocalService, s => s.counter),
|
|
1314
|
+
data: useLocalService(LocalService, s => s.data)
|
|
1315
|
+
}), { wrapper: TestProvider });
|
|
1316
|
+
await waitFor(() => {
|
|
1317
|
+
expect(result.current.service.inited).toBe(true);
|
|
1318
|
+
});
|
|
1319
|
+
// 类型验证:service 应该是完整的服务实例
|
|
1320
|
+
expect(typeof result.current.service.increment).toBe('function');
|
|
1321
|
+
expect(typeof result.current.service.setData).toBe('function');
|
|
1322
|
+
// 类型验证:counter 应该是 number 类型
|
|
1323
|
+
expect(typeof result.current.counter).toBe('number');
|
|
1324
|
+
// 类型验证:data 应该是 string 类型
|
|
1325
|
+
expect(typeof result.current.data).toBe('string');
|
|
1326
|
+
expect(result.current.counter).toBe(0);
|
|
1327
|
+
expect(result.current.data).toBe('initialized');
|
|
1328
|
+
});
|
|
1329
|
+
it('应该在不传入 selector 时支持多个属性同时变化的响应', async () => {
|
|
1330
|
+
const TestProvider = createTestProvider([TestService]);
|
|
1331
|
+
const { result } = renderHook(() => useLocalService(LocalService), { wrapper: TestProvider });
|
|
1332
|
+
await waitFor(() => {
|
|
1333
|
+
expect(result.current.inited).toBe(true);
|
|
1334
|
+
});
|
|
1335
|
+
// 初始状态
|
|
1336
|
+
expect(result.current.counter).toBe(0);
|
|
1337
|
+
expect(result.current.data).toBe('initialized');
|
|
1338
|
+
// 同时修改多个属性
|
|
1339
|
+
act(() => {
|
|
1340
|
+
result.current.increment();
|
|
1341
|
+
result.current.setData('changed');
|
|
1342
|
+
});
|
|
1343
|
+
await waitFor(() => {
|
|
1344
|
+
expect(result.current.counter).toBe(1);
|
|
1345
|
+
expect(result.current.data).toBe('changed');
|
|
1346
|
+
});
|
|
1347
|
+
});
|
|
1348
|
+
it('应该正确处理同步 init 的局部服务', async () => {
|
|
1349
|
+
const TestProvider = createTestProvider([TestService]);
|
|
1350
|
+
let SyncInitLocalService = (() => {
|
|
1351
|
+
var _a, _SyncInitLocalService_inited_accessor_storage, _SyncInitLocalService_value_accessor_storage;
|
|
1352
|
+
let _inited_decorators;
|
|
1353
|
+
let _inited_initializers = [];
|
|
1354
|
+
let _inited_extraInitializers = [];
|
|
1355
|
+
let _value_decorators;
|
|
1356
|
+
let _value_initializers = [];
|
|
1357
|
+
let _value_extraInitializers = [];
|
|
1358
|
+
return _a = class SyncInitLocalService {
|
|
1359
|
+
get inited() { return __classPrivateFieldGet(this, _SyncInitLocalService_inited_accessor_storage, "f"); }
|
|
1360
|
+
set inited(value) { __classPrivateFieldSet(this, _SyncInitLocalService_inited_accessor_storage, value, "f"); }
|
|
1361
|
+
get value() { return __classPrivateFieldGet(this, _SyncInitLocalService_value_accessor_storage, "f"); }
|
|
1362
|
+
set value(value) { __classPrivateFieldSet(this, _SyncInitLocalService_value_accessor_storage, value, "f"); }
|
|
1363
|
+
constructor() {
|
|
1364
|
+
_SyncInitLocalService_inited_accessor_storage.set(this, __runInitializers(this, _inited_initializers, false));
|
|
1365
|
+
_SyncInitLocalService_value_accessor_storage.set(this, (__runInitializers(this, _inited_extraInitializers), __runInitializers(this, _value_initializers, 'pending')));
|
|
1366
|
+
__runInitializers(this, _value_extraInitializers);
|
|
1367
|
+
makeObservable(this);
|
|
1368
|
+
}
|
|
1369
|
+
init() {
|
|
1370
|
+
runInAction(() => {
|
|
1371
|
+
this.value = 'ready';
|
|
1372
|
+
this.inited = true;
|
|
1373
|
+
});
|
|
1374
|
+
return true;
|
|
1375
|
+
}
|
|
1376
|
+
},
|
|
1377
|
+
_SyncInitLocalService_inited_accessor_storage = new WeakMap(),
|
|
1378
|
+
_SyncInitLocalService_value_accessor_storage = new WeakMap(),
|
|
1379
|
+
(() => {
|
|
1380
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
1381
|
+
_inited_decorators = [observable];
|
|
1382
|
+
_value_decorators = [observable];
|
|
1383
|
+
__esDecorate(_a, null, _inited_decorators, { kind: "accessor", name: "inited", static: false, private: false, access: { has: obj => "inited" in obj, get: obj => obj.inited, set: (obj, value) => { obj.inited = value; } }, metadata: _metadata }, _inited_initializers, _inited_extraInitializers);
|
|
1384
|
+
__esDecorate(_a, null, _value_decorators, { kind: "accessor", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, _value_initializers, _value_extraInitializers);
|
|
1385
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
1386
|
+
})(),
|
|
1387
|
+
_a;
|
|
1388
|
+
})();
|
|
1389
|
+
const { result } = renderHook(() => useLocalService(SyncInitLocalService, service => ({
|
|
1390
|
+
inited: service.inited,
|
|
1391
|
+
value: service.value
|
|
1392
|
+
})), { wrapper: TestProvider });
|
|
1393
|
+
await waitFor(() => {
|
|
1394
|
+
expect(result.current.inited).toBe(true);
|
|
1395
|
+
expect(result.current.value).toBe('ready');
|
|
1396
|
+
});
|
|
1397
|
+
});
|
|
1398
|
+
});
|
|
358
1399
|
});
|