@blac/core 2.0.0-rc-16 → 2.0.0-rc.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 (157) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/Blac.d.ts +246 -0
  3. package/dist/Blac.d.ts.map +1 -0
  4. package/dist/Blac.js +624 -0
  5. package/dist/Blac.js.map +1 -0
  6. package/dist/Bloc.d.ts +41 -0
  7. package/dist/Bloc.d.ts.map +1 -0
  8. package/dist/Bloc.js +140 -0
  9. package/dist/Bloc.js.map +1 -0
  10. package/dist/BlocBase.d.ts +110 -0
  11. package/dist/BlocBase.d.ts.map +1 -0
  12. package/dist/BlocBase.js +287 -0
  13. package/dist/BlocBase.js.map +1 -0
  14. package/dist/Cubit.d.ts +25 -0
  15. package/dist/Cubit.d.ts.map +1 -0
  16. package/dist/Cubit.js +64 -0
  17. package/dist/Cubit.js.map +1 -0
  18. package/dist/adapter/BlacAdapter.d.ts +67 -0
  19. package/dist/adapter/BlacAdapter.d.ts.map +1 -0
  20. package/dist/adapter/BlacAdapter.js +263 -0
  21. package/dist/adapter/BlacAdapter.js.map +1 -0
  22. package/dist/adapter/ProxyFactory.d.ts +50 -0
  23. package/dist/adapter/ProxyFactory.d.ts.map +1 -0
  24. package/dist/adapter/ProxyFactory.js +150 -0
  25. package/dist/adapter/ProxyFactory.js.map +1 -0
  26. package/{src/adapter/index.ts → dist/adapter/index.d.ts} +1 -0
  27. package/dist/adapter/index.d.ts.map +1 -0
  28. package/dist/adapter/index.js +19 -0
  29. package/dist/adapter/index.js.map +1 -0
  30. package/dist/errors/BlacError.d.ts +38 -0
  31. package/dist/errors/BlacError.d.ts.map +1 -0
  32. package/dist/errors/BlacError.js +55 -0
  33. package/dist/errors/BlacError.js.map +1 -0
  34. package/dist/errors/ErrorManager.d.ts +39 -0
  35. package/dist/errors/ErrorManager.d.ts.map +1 -0
  36. package/dist/errors/ErrorManager.js +91 -0
  37. package/dist/errors/ErrorManager.js.map +1 -0
  38. package/dist/errors/handleError.d.ts +24 -0
  39. package/dist/errors/handleError.d.ts.map +1 -0
  40. package/dist/errors/handleError.js +62 -0
  41. package/dist/errors/handleError.js.map +1 -0
  42. package/dist/errors/index.d.ts +5 -0
  43. package/dist/errors/index.d.ts.map +1 -0
  44. package/dist/errors/index.js +13 -0
  45. package/dist/errors/index.js.map +1 -0
  46. package/{src/events.ts → dist/events.d.ts} +4 -2
  47. package/dist/events.d.ts.map +1 -0
  48. package/dist/events.js +17 -0
  49. package/dist/events.js.map +1 -0
  50. package/dist/index.cjs +38 -0
  51. package/{src/index.ts → dist/index.d.ts} +1 -10
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +38 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/lifecycle/BlocLifecycle.d.ts +51 -0
  56. package/dist/lifecycle/BlocLifecycle.d.ts.map +1 -0
  57. package/dist/lifecycle/BlocLifecycle.js +123 -0
  58. package/dist/lifecycle/BlocLifecycle.js.map +1 -0
  59. package/dist/lifecycle/index.d.ts +2 -0
  60. package/dist/lifecycle/index.d.ts.map +1 -0
  61. package/dist/lifecycle/index.js +18 -0
  62. package/dist/lifecycle/index.js.map +1 -0
  63. package/dist/plugins/BlocPluginRegistry.d.ts +58 -0
  64. package/dist/plugins/BlocPluginRegistry.d.ts.map +1 -0
  65. package/dist/plugins/BlocPluginRegistry.js +201 -0
  66. package/dist/plugins/BlocPluginRegistry.js.map +1 -0
  67. package/dist/plugins/SystemPluginRegistry.d.ts +79 -0
  68. package/dist/plugins/SystemPluginRegistry.d.ts.map +1 -0
  69. package/dist/plugins/SystemPluginRegistry.js +184 -0
  70. package/dist/plugins/SystemPluginRegistry.js.map +1 -0
  71. package/{src/plugins/index.ts → dist/plugins/index.d.ts} +1 -5
  72. package/dist/plugins/index.d.ts.map +1 -0
  73. package/dist/plugins/index.js +26 -0
  74. package/dist/plugins/index.js.map +1 -0
  75. package/dist/plugins/types.d.ts +103 -0
  76. package/dist/plugins/types.d.ts.map +1 -0
  77. package/dist/plugins/types.js +3 -0
  78. package/dist/plugins/types.js.map +1 -0
  79. package/dist/subscription/SubscriptionManager.d.ts +67 -0
  80. package/dist/subscription/SubscriptionManager.d.ts.map +1 -0
  81. package/dist/subscription/SubscriptionManager.js +317 -0
  82. package/dist/subscription/SubscriptionManager.js.map +1 -0
  83. package/{src/subscription/index.ts → dist/subscription/index.d.ts} +1 -0
  84. package/dist/subscription/index.d.ts.map +1 -0
  85. package/dist/subscription/index.js +19 -0
  86. package/dist/subscription/index.js.map +1 -0
  87. package/dist/subscription/types.d.ts +65 -0
  88. package/dist/subscription/types.d.ts.map +1 -0
  89. package/dist/subscription/types.js +3 -0
  90. package/dist/subscription/types.js.map +1 -0
  91. package/dist/testing.d.ts +33 -0
  92. package/dist/testing.d.ts.map +1 -0
  93. package/dist/testing.js +68 -0
  94. package/dist/testing.js.map +1 -0
  95. package/{src/types.ts → dist/types.d.ts} +11 -28
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.js +3 -0
  98. package/dist/types.js.map +1 -0
  99. package/dist/utils/BatchingManager.d.ts +28 -0
  100. package/dist/utils/BatchingManager.d.ts.map +1 -0
  101. package/dist/utils/BatchingManager.js +48 -0
  102. package/dist/utils/BatchingManager.js.map +1 -0
  103. package/dist/utils/RerenderLogger.d.ts +60 -0
  104. package/dist/utils/RerenderLogger.d.ts.map +1 -0
  105. package/dist/utils/RerenderLogger.js +205 -0
  106. package/dist/utils/RerenderLogger.js.map +1 -0
  107. package/dist/utils/generateInstanceId.d.ts +11 -0
  108. package/dist/utils/generateInstanceId.d.ts.map +1 -0
  109. package/dist/utils/generateInstanceId.js +50 -0
  110. package/dist/utils/generateInstanceId.js.map +1 -0
  111. package/dist/utils/shallowEqual.d.ts +9 -0
  112. package/dist/utils/shallowEqual.d.ts.map +1 -0
  113. package/dist/utils/shallowEqual.js +35 -0
  114. package/dist/utils/shallowEqual.js.map +1 -0
  115. package/dist/utils/uuid.d.ts +10 -0
  116. package/dist/utils/uuid.d.ts.map +1 -0
  117. package/dist/utils/uuid.js +24 -0
  118. package/dist/utils/uuid.js.map +1 -0
  119. package/package.json +19 -6
  120. package/src/Blac.ts +0 -802
  121. package/src/Bloc.ts +0 -180
  122. package/src/BlocBase.ts +0 -398
  123. package/src/Cubit.ts +0 -68
  124. package/src/__tests__/Blac.config.test.ts +0 -79
  125. package/src/__tests__/Bloc.event.test.ts +0 -394
  126. package/src/__tests__/BlocBase.subscription.test.ts +0 -349
  127. package/src/__tests__/Cubit.test.ts +0 -462
  128. package/src/__tests__/memory-leaks.test.ts +0 -383
  129. package/src/__tests__/plugins.test.ts +0 -464
  130. package/src/adapter/BlacAdapter.ts +0 -467
  131. package/src/adapter/ProxyFactory.ts +0 -249
  132. package/src/adapter/__tests__/BlacAdapter.test.ts +0 -555
  133. package/src/adapter/__tests__/ProxyFactory.test.ts +0 -655
  134. package/src/errors/BlacError.ts +0 -69
  135. package/src/errors/ErrorManager.ts +0 -101
  136. package/src/errors/handleError.ts +0 -114
  137. package/src/errors/index.ts +0 -13
  138. package/src/lifecycle/BlocLifecycle.ts +0 -156
  139. package/src/lifecycle/index.ts +0 -1
  140. package/src/plugins/BlocPluginRegistry.ts +0 -240
  141. package/src/plugins/SystemPluginRegistry.ts +0 -242
  142. package/src/plugins/__tests__/BlocPluginRegistry.test.ts +0 -450
  143. package/src/plugins/__tests__/SystemPluginRegistry.test.ts +0 -404
  144. package/src/plugins/types.ts +0 -129
  145. package/src/subscription/README.md +0 -132
  146. package/src/subscription/SubscriptionManager.ts +0 -395
  147. package/src/subscription/__tests__/SubscriptionManager.test.ts +0 -355
  148. package/src/subscription/types.ts +0 -90
  149. package/src/testing.ts +0 -246
  150. package/src/utils/BatchingManager.ts +0 -59
  151. package/src/utils/RerenderLogger.ts +0 -265
  152. package/src/utils/__tests__/generateInstanceId.test.ts +0 -104
  153. package/src/utils/__tests__/shallowEqual.test.ts +0 -171
  154. package/src/utils/__tests__/uuid.test.ts +0 -144
  155. package/src/utils/generateInstanceId.ts +0 -54
  156. package/src/utils/shallowEqual.ts +0 -40
  157. package/src/utils/uuid.ts +0 -22
@@ -1,555 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { BlacAdapter } from '../BlacAdapter';
3
- import { Cubit } from '../../Cubit';
4
- import { Blac } from '../../Blac';
5
-
6
- // Test Cubit implementations
7
- class CounterCubit extends Cubit<number> {
8
- static isolated = false;
9
- static keepAlive = false;
10
-
11
- constructor() {
12
- super(0);
13
- }
14
-
15
- increment = () => this.emit(this.state + 1);
16
- decrement = () => this.emit(this.state - 1);
17
- }
18
-
19
- interface UserState {
20
- name: string;
21
- age: number;
22
- profile: {
23
- email: string;
24
- preferences: {
25
- theme: string;
26
- };
27
- };
28
- }
29
-
30
- class UserCubit extends Cubit<UserState> {
31
- constructor() {
32
- super({
33
- name: 'John',
34
- age: 30,
35
- profile: {
36
- email: 'john@example.com',
37
- preferences: {
38
- theme: 'light',
39
- },
40
- },
41
- });
42
- }
43
-
44
- updateName = (name: string) => {
45
- this.patch({ name });
46
- };
47
-
48
- updateTheme = (theme: string) => {
49
- this.emit({
50
- ...this.state,
51
- profile: {
52
- ...this.state.profile,
53
- preferences: { theme },
54
- },
55
- });
56
- };
57
- }
58
-
59
- describe('BlacAdapter', () => {
60
- let blacInstance: Blac;
61
- let componentRef: { current: object };
62
-
63
- beforeEach(() => {
64
- blacInstance = new Blac({ __unsafe_ignore_singleton: true });
65
- componentRef = { current: {} };
66
- vi.clearAllMocks();
67
- });
68
-
69
- afterEach(() => {
70
- vi.restoreAllMocks();
71
- });
72
-
73
- describe('Initialization and Instance Management', () => {
74
- it('should create adapter with proper initialization', () => {
75
- const adapter = new BlacAdapter(
76
- { componentRef, blocConstructor: CounterCubit },
77
- { instanceId: 'test-counter' },
78
- );
79
-
80
- expect(adapter.id).toMatch(/^adapter-/);
81
- expect(adapter.blocConstructor).toBe(CounterCubit);
82
- expect(adapter.componentRef).toBe(componentRef);
83
- expect(adapter.blocInstance).toBeInstanceOf(CounterCubit);
84
- });
85
-
86
- it('should retrieve existing bloc instance when not isolated', () => {
87
- // Create first adapter
88
- const adapter1 = new BlacAdapter(
89
- { componentRef, blocConstructor: CounterCubit },
90
- { instanceId: 'shared-counter' },
91
- );
92
-
93
- // Create second adapter with same id
94
- const componentRef2 = { current: {} };
95
- const adapter2 = new BlacAdapter(
96
- { componentRef: componentRef2, blocConstructor: CounterCubit },
97
- { instanceId: 'shared-counter' },
98
- );
99
-
100
- // Should share the same bloc instance
101
- expect(adapter1.blocInstance).toBe(adapter2.blocInstance);
102
- });
103
-
104
- it('should pass staticProps to bloc constructor', () => {
105
- class PropsCubit extends Cubit<string> {
106
- props?: { initialValue: string };
107
-
108
- constructor(props?: { initialValue: string }) {
109
- super(props?.initialValue || 'default');
110
- this.props = props;
111
- }
112
- }
113
-
114
- const adapter = new BlacAdapter(
115
- { componentRef, blocConstructor: PropsCubit as any },
116
- { staticProps: { initialValue: 'custom' } },
117
- );
118
-
119
- expect(adapter.blocInstance.state).toBe('custom');
120
- expect((adapter.blocInstance as PropsCubit).props).toEqual({
121
- initialValue: 'custom',
122
- });
123
- });
124
- });
125
-
126
- describe('Dependency Tracking - Explicit Dependencies', () => {
127
- it('should track dependencies when dependencies function is provided', () => {
128
- const dependencyFn = vi.fn((bloc: UserCubit) => [
129
- bloc.state.name,
130
- bloc.state.age,
131
- ]);
132
-
133
- const adapter = new BlacAdapter(
134
- { componentRef, blocConstructor: UserCubit },
135
- { dependencies: dependencyFn },
136
- );
137
-
138
- expect(dependencyFn).toHaveBeenCalledWith(adapter.blocInstance);
139
- expect(adapter.options?.dependencies).toBe(dependencyFn);
140
- });
141
-
142
- it('should only trigger onChange when dependencies change', () => {
143
- const onChange = vi.fn();
144
- const adapter = new BlacAdapter(
145
- { componentRef, blocConstructor: UserCubit },
146
- { dependencies: (bloc) => [bloc.state.name] },
147
- );
148
-
149
- const unsubscribe = adapter.createSubscription({ onChange });
150
-
151
- // Change name - should trigger
152
- adapter.blocInstance.updateName('Jane');
153
- expect(onChange).toHaveBeenCalledTimes(1);
154
-
155
- // Change theme - should NOT trigger (not in dependencies)
156
- onChange.mockClear();
157
- adapter.blocInstance.updateTheme('dark');
158
- expect(onChange).not.toHaveBeenCalled();
159
-
160
- unsubscribe();
161
- });
162
-
163
- it('should handle dependency array changes correctly', () => {
164
- const onChange = vi.fn();
165
- let depCount = 1;
166
-
167
- const adapter = new BlacAdapter(
168
- { componentRef, blocConstructor: CounterCubit },
169
- {
170
- dependencies: (bloc) => {
171
- // Variable length dependency array
172
- const deps = [];
173
- for (let i = 0; i < depCount; i++) {
174
- deps.push(bloc.state);
175
- }
176
- return deps;
177
- },
178
- },
179
- );
180
-
181
- const unsubscribe = adapter.createSubscription({ onChange });
182
-
183
- // Initial change
184
- adapter.blocInstance.increment();
185
- expect(onChange).toHaveBeenCalledTimes(1);
186
-
187
- // Change dependency array length
188
- depCount = 2;
189
- onChange.mockClear();
190
- adapter.blocInstance.increment();
191
- expect(onChange).toHaveBeenCalledTimes(1); // Length change triggers update
192
-
193
- unsubscribe();
194
- });
195
- });
196
-
197
- describe('Dependency Tracking - Proxy-based (Automatic)', () => {
198
- it('should track state access through proxy when no explicit dependencies', () => {
199
- const adapter = new BlacAdapter({
200
- componentRef,
201
- blocConstructor: UserCubit,
202
- });
203
-
204
- // Access state through proxy
205
- const proxyState = adapter.getStateProxy();
206
- const name = proxyState.name;
207
- const email = proxyState.profile.email;
208
-
209
- // Verify proxy state works correctly
210
- expect(name).toBe('John');
211
- expect(email).toBe('john@example.com');
212
- });
213
-
214
- it('should track class property access through proxy', () => {
215
- class GetterCubit extends Cubit<number> {
216
- constructor() {
217
- super(0);
218
- }
219
-
220
- get doubled() {
221
- return this.state * 2;
222
- }
223
-
224
- get isPositive() {
225
- return this.state > 0;
226
- }
227
- }
228
-
229
- const adapter = new BlacAdapter({
230
- componentRef,
231
- blocConstructor: GetterCubit,
232
- });
233
-
234
- // Access getters through proxy
235
- const proxyBloc = adapter.getBlocProxy();
236
- const doubled = proxyBloc.doubled;
237
- const isPositive = proxyBloc.isPositive;
238
-
239
- // Verify proxy getters work correctly
240
- expect(doubled).toBe(0);
241
- expect(isPositive).toBe(false);
242
- });
243
-
244
- it('should only notify when tracked values change', () => {
245
- const onChange = vi.fn();
246
- const adapter = new BlacAdapter({
247
- componentRef,
248
- blocConstructor: UserCubit,
249
- });
250
-
251
- // Mount the adapter first
252
- adapter.mount();
253
-
254
- // Create subscription with automatic tracking
255
- const unsubscribe = adapter.createSubscription({ onChange });
256
-
257
- // Access specific property through proxy to track it
258
- const proxyState = adapter.getStateProxy();
259
- const name = proxyState.name; // Track name property
260
-
261
- // Clear onChange calls from initial subscription
262
- onChange.mockClear();
263
-
264
- // Change tracked property - should notify
265
- adapter.blocInstance.updateName('Jane');
266
- expect(onChange).toHaveBeenCalledTimes(1);
267
-
268
- // For automatic tracking, only tracked properties trigger notifications
269
- // Since we only accessed 'name', changing 'theme' should not notify
270
- onChange.mockClear();
271
- adapter.blocInstance.updateTheme('dark');
272
- expect(onChange).not.toHaveBeenCalled();
273
-
274
- unsubscribe();
275
- });
276
-
277
- it('should handle nested property tracking', () => {
278
- const adapter = new BlacAdapter({
279
- componentRef,
280
- blocConstructor: UserCubit,
281
- });
282
-
283
- // Access nested property
284
- const proxyState = adapter.getStateProxy();
285
- const theme = proxyState.profile.preferences.theme;
286
-
287
- // Verify nested property access works
288
- expect(theme).toBe('light');
289
-
290
- // Verify nested proxy returns correct values
291
- expect(proxyState.profile.email).toBe('john@example.com');
292
- expect(proxyState.profile.preferences).toEqual({ theme: 'light' });
293
- });
294
- });
295
-
296
- describe('Lifecycle Management', () => {
297
- it('should handle mount and unmount correctly', () => {
298
- const onMount = vi.fn();
299
- const onUnmount = vi.fn();
300
-
301
- const adapter = new BlacAdapter(
302
- { componentRef, blocConstructor: CounterCubit },
303
- { onMount, onUnmount },
304
- );
305
-
306
- // Mount
307
- adapter.mount();
308
- expect(onMount).toHaveBeenCalledWith(adapter.blocInstance);
309
- expect(adapter.mountTime).toBeGreaterThan(0);
310
-
311
- // Mount again - onMount is called each time
312
- adapter.mount();
313
- expect(onMount).toHaveBeenCalledTimes(2);
314
-
315
- // Unmount
316
- adapter.unmount();
317
- expect(onUnmount).toHaveBeenCalledWith(adapter.blocInstance);
318
- expect(adapter.unmountTime).toBeGreaterThan(0);
319
- });
320
-
321
- it('should handle onMount errors', () => {
322
- const onMount = vi.fn(() => {
323
- throw new Error('Mount error');
324
- });
325
-
326
- const adapter = new BlacAdapter(
327
- { componentRef, blocConstructor: CounterCubit },
328
- { onMount },
329
- );
330
-
331
- expect(() => adapter.mount()).toThrow('Mount error');
332
- });
333
-
334
- it('should not throw on unmount errors', () => {
335
- const onUnmount = vi.fn(() => {
336
- throw new Error('Unmount error');
337
- });
338
-
339
- const adapter = new BlacAdapter(
340
- { componentRef, blocConstructor: CounterCubit },
341
- { onUnmount },
342
- );
343
-
344
- adapter.mount();
345
-
346
- // Should not throw
347
- expect(() => adapter.unmount()).not.toThrow();
348
- });
349
-
350
- it('should refresh dependencies on mount', () => {
351
- const dependencies = vi.fn((bloc: CounterCubit) => [bloc.state]);
352
-
353
- const adapter = new BlacAdapter(
354
- { componentRef, blocConstructor: CounterCubit },
355
- { dependencies },
356
- );
357
-
358
- expect(dependencies).toHaveBeenCalledTimes(1); // Initial call
359
-
360
- adapter.mount();
361
- expect(dependencies).toHaveBeenCalledTimes(2); // Called again on mount
362
- });
363
- });
364
-
365
- describe('Subscription Management', () => {
366
- it('should create and cleanup subscriptions', () => {
367
- const adapter = new BlacAdapter({
368
- componentRef,
369
- blocConstructor: CounterCubit,
370
- });
371
-
372
- const onChange = vi.fn();
373
- const unsubscribe = adapter.createSubscription({ onChange });
374
-
375
- expect(adapter.blocInstance.subscriptionCount).toBe(1);
376
-
377
- // Trigger state change
378
- adapter.blocInstance.increment();
379
- expect(onChange).toHaveBeenCalled();
380
-
381
- // Cleanup
382
- unsubscribe();
383
- expect(adapter.blocInstance.subscriptionCount).toBe(0);
384
- });
385
-
386
- it('should handle first render without dependencies check', () => {
387
- const onChange = vi.fn();
388
- const adapter = new BlacAdapter({
389
- componentRef,
390
- blocConstructor: UserCubit,
391
- });
392
-
393
- // Don't mark as rendered yet
394
- const unsubscribe = adapter.createSubscription({ onChange });
395
-
396
- // First state change should always notify
397
- adapter.blocInstance.updateName('Jane');
398
- expect(onChange).toHaveBeenCalledTimes(1);
399
-
400
- unsubscribe();
401
- });
402
- });
403
-
404
- describe('Proxy Creation and Management', () => {
405
- it('should return raw state when using explicit dependencies', () => {
406
- const adapter = new BlacAdapter(
407
- { componentRef, blocConstructor: UserCubit },
408
- { dependencies: (bloc) => [bloc.state.name] },
409
- );
410
-
411
- const state = adapter.getStateProxy();
412
-
413
- // Should be raw state, not proxy
414
- expect(state).toBe(adapter.blocInstance.state);
415
- });
416
-
417
- it('should return raw bloc instance when using explicit dependencies', () => {
418
- const adapter = new BlacAdapter(
419
- { componentRef, blocConstructor: CounterCubit },
420
- { dependencies: (bloc) => [bloc.state] },
421
- );
422
-
423
- const blocInstance = adapter.getBlocProxy();
424
-
425
- // Should be raw instance, not proxy
426
- expect(blocInstance).toBe(adapter.blocInstance);
427
- });
428
-
429
- it('should create proxies when not using explicit dependencies', () => {
430
- const adapter = new BlacAdapter({
431
- componentRef,
432
- blocConstructor: UserCubit,
433
- });
434
-
435
- const proxyState = adapter.getStateProxy();
436
- const proxyBloc = adapter.getBlocProxy();
437
-
438
- // Should be proxies
439
- expect(proxyState).not.toBe(adapter.blocInstance.state);
440
- expect(proxyBloc).not.toBe(adapter.blocInstance);
441
- });
442
- });
443
-
444
- describe('Consumer Tracking Integration', () => {
445
- it('should properly handle subscription lifecycle', () => {
446
- const adapter = new BlacAdapter({
447
- componentRef,
448
- blocConstructor: CounterCubit,
449
- });
450
-
451
- adapter.mount();
452
-
453
- const onChange = vi.fn();
454
- const unsubscribe = adapter.createSubscription({ onChange });
455
-
456
- // State change should notify
457
- adapter.blocInstance.increment();
458
- expect(onChange).toHaveBeenCalledTimes(1);
459
-
460
- // After unsubscribe, no more notifications
461
- unsubscribe();
462
- adapter.blocInstance.increment();
463
- expect(onChange).toHaveBeenCalledTimes(1);
464
- });
465
-
466
- it('should reset tracking state properly', () => {
467
- const adapter = new BlacAdapter({
468
- componentRef,
469
- blocConstructor: UserCubit,
470
- });
471
-
472
- // Access state to potentially track
473
- const proxyState = adapter.getStateProxy();
474
- const name = proxyState.name;
475
-
476
- // Reset tracking clears internal state
477
- adapter.resetTracking();
478
-
479
- // Verify adapter is still functional after reset
480
- const theme = proxyState.profile.preferences.theme;
481
- expect(theme).toBe('light');
482
- });
483
- });
484
-
485
- describe('Options Updates', () => {
486
- it('should update options after initialization', () => {
487
- const adapter = new BlacAdapter({
488
- componentRef,
489
- blocConstructor: CounterCubit,
490
- });
491
-
492
- expect(adapter.options).toBeUndefined();
493
-
494
- const newOptions = {
495
- dependencies: (bloc: CounterCubit) => [bloc.state],
496
- };
497
-
498
- adapter.options = newOptions;
499
- expect(adapter.options).toBe(newOptions);
500
- });
501
- });
502
-
503
- describe('Edge Cases and Error Handling', () => {
504
- it('should handle missing componentRef gracefully', () => {
505
- // Can't use null as WeakMap key, so test with an empty object instead
506
- const emptyRef = {};
507
- const adapter = new BlacAdapter({
508
- componentRef: { current: emptyRef },
509
- blocConstructor: CounterCubit,
510
- });
511
-
512
- // Should not throw
513
- expect(() => adapter.mount()).not.toThrow();
514
- expect(() =>
515
- adapter.trackAccess(emptyRef, 'state', 'test'),
516
- ).not.toThrow();
517
- });
518
-
519
- it('should handle rapid mount/unmount cycles', () => {
520
- const adapter = new BlacAdapter({
521
- componentRef,
522
- blocConstructor: CounterCubit,
523
- });
524
-
525
- // Rapid mount/unmount
526
- for (let i = 0; i < 10; i++) {
527
- adapter.mount();
528
- adapter.unmount();
529
- }
530
-
531
- expect(adapter.blocInstance.subscriptionCount).toBe(0);
532
- });
533
-
534
- it('should handle value changes with Object.is semantics', () => {
535
- const onChange = vi.fn();
536
- const adapter = new BlacAdapter(
537
- { componentRef, blocConstructor: CounterCubit },
538
- { dependencies: (bloc) => [bloc.state] },
539
- );
540
-
541
- const unsubscribe = adapter.createSubscription({ onChange });
542
-
543
- // Set to NaN
544
- adapter.blocInstance.emit(NaN);
545
- expect(onChange).toHaveBeenCalledTimes(1);
546
-
547
- // Set to NaN again - should not trigger (Object.is(NaN, NaN) === true)
548
- onChange.mockClear();
549
- adapter.blocInstance.emit(NaN);
550
- expect(onChange).not.toHaveBeenCalled();
551
-
552
- unsubscribe();
553
- });
554
- });
555
- });