@blac/react 2.0.0-rc-11 → 2.0.0-rc-14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +2 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.es.js +105 -75
- package/dist/index.es.js.map +1 -1
- package/package.json +12 -12
- package/src/__tests__/rerenderLogging.test.tsx +257 -0
- package/src/__tests__/useBloc.disposal.test.tsx +377 -0
- package/src/__tests__/useBloc.instanceChange.test.tsx +200 -0
- package/src/__tests__/useBloc.props.test.tsx +166 -144
- package/src/__tests__/useBloc.proxyConfig.test.tsx +5 -5
- package/src/__tests__/useBloc.staticProps.test.tsx +297 -0
- package/src/__tests__/useBloc.tracking.test.tsx +7 -3
- package/src/index.ts +1 -0
- package/src/useBloc.ts +108 -33
- package/src/useExternalBlocStore.ts +14 -9
- package/README.md +0 -265
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { act, renderHook } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { BlocConstructorParams, Cubit } from '@blac/core';
|
|
4
|
+
import useBloc from '../useBloc';
|
|
5
|
+
|
|
6
|
+
interface CounterProps {
|
|
7
|
+
initialValue: number;
|
|
8
|
+
step?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class CounterCubit extends Cubit<number> {
|
|
12
|
+
props: BlocConstructorParams<typeof CounterCubit>;
|
|
13
|
+
|
|
14
|
+
constructor(props?: CounterProps) {
|
|
15
|
+
super(props?.initialValue ?? 0);
|
|
16
|
+
this.props = props;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
increment = () => {
|
|
20
|
+
const step = this.props?.step ?? 1;
|
|
21
|
+
this.emit(this.state + step);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe('useBloc instance changes', () => {
|
|
26
|
+
describe('when instanceId changes', () => {
|
|
27
|
+
it('should use a different bloc instance', async () => {
|
|
28
|
+
const { result, rerender } = renderHook(
|
|
29
|
+
({ instanceId }) =>
|
|
30
|
+
useBloc(CounterCubit, {
|
|
31
|
+
instanceId,
|
|
32
|
+
staticProps: { initialValue: 0 },
|
|
33
|
+
}),
|
|
34
|
+
{ initialProps: { instanceId: 'counter-1' } },
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// Wait for initial render
|
|
38
|
+
await act(async () => {
|
|
39
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const firstInstance = result.current[1];
|
|
43
|
+
expect(firstInstance._id).toBe('counter-1');
|
|
44
|
+
expect(firstInstance.props).toEqual({ initialValue: 0 });
|
|
45
|
+
|
|
46
|
+
// Change instanceId
|
|
47
|
+
rerender({ instanceId: 'counter-2' });
|
|
48
|
+
|
|
49
|
+
const secondInstance = result.current[1];
|
|
50
|
+
expect(secondInstance._id).toBe('counter-2');
|
|
51
|
+
expect(secondInstance).not.toBe(firstInstance);
|
|
52
|
+
expect(result.current[0]).toBe(0); // New instance starts at 0
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe('when staticProps change', () => {
|
|
57
|
+
it('should use a different bloc instance when staticProps change', async () => {
|
|
58
|
+
const { result, rerender } = renderHook(
|
|
59
|
+
({ initialValue }) =>
|
|
60
|
+
useBloc(CounterCubit, {
|
|
61
|
+
staticProps: { initialValue },
|
|
62
|
+
}),
|
|
63
|
+
{ initialProps: { initialValue: 10 } },
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// Wait for initial render
|
|
67
|
+
await act(async () => {
|
|
68
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const firstInstance = result.current[1];
|
|
72
|
+
expect(result.current[0]).toBe(10);
|
|
73
|
+
expect(firstInstance._id).toBe('initialValue:10');
|
|
74
|
+
|
|
75
|
+
// Change staticProps
|
|
76
|
+
rerender({ initialValue: 20 });
|
|
77
|
+
|
|
78
|
+
const secondInstance = result.current[1];
|
|
79
|
+
expect(secondInstance).not.toBe(firstInstance);
|
|
80
|
+
expect(result.current[0]).toBe(20); // New instance with new initial value
|
|
81
|
+
expect(secondInstance._id).toBe('initialValue:20');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should use same instance when non-primitive staticProps values change', () => {
|
|
85
|
+
const { result, rerender } = renderHook(
|
|
86
|
+
({ config }) =>
|
|
87
|
+
useBloc(CounterCubit, {
|
|
88
|
+
staticProps: {
|
|
89
|
+
initialValue: 5,
|
|
90
|
+
config, // This will be ignored for instance ID
|
|
91
|
+
} as any,
|
|
92
|
+
}),
|
|
93
|
+
{ initialProps: { config: { debug: true } } },
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const firstInstance = result.current[1];
|
|
97
|
+
expect(firstInstance._id).toBe('initialValue:5');
|
|
98
|
+
|
|
99
|
+
// Change non-primitive prop
|
|
100
|
+
rerender({ config: { debug: false } });
|
|
101
|
+
|
|
102
|
+
const secondInstance = result.current[1];
|
|
103
|
+
expect(secondInstance).toBe(firstInstance); // Same instance
|
|
104
|
+
expect(secondInstance._id).toBe('initialValue:5');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should change instance when primitive staticProps change', () => {
|
|
108
|
+
const { result, rerender } = renderHook(
|
|
109
|
+
({ step }) =>
|
|
110
|
+
useBloc(CounterCubit, {
|
|
111
|
+
staticProps: { initialValue: 0, step },
|
|
112
|
+
}),
|
|
113
|
+
{ initialProps: { step: 1 } },
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const firstInstance = result.current[1];
|
|
117
|
+
expect(firstInstance._id).toBe('initialValue:0|step:1');
|
|
118
|
+
|
|
119
|
+
// Change primitive prop
|
|
120
|
+
rerender({ step: 2 });
|
|
121
|
+
|
|
122
|
+
const secondInstance = result.current[1];
|
|
123
|
+
expect(secondInstance).not.toBe(firstInstance); // Different instance
|
|
124
|
+
expect(secondInstance._id).toBe('initialValue:0|step:2');
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('when using both instanceId and staticProps', () => {
|
|
129
|
+
it('should use explicit instanceId over generated one', () => {
|
|
130
|
+
const { result } = renderHook(() =>
|
|
131
|
+
useBloc(CounterCubit, {
|
|
132
|
+
instanceId: 'my-counter',
|
|
133
|
+
staticProps: { initialValue: 100 },
|
|
134
|
+
}),
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
expect(result.current[1]._id).toBe('my-counter');
|
|
138
|
+
expect(result.current[0]).toBe(100);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should change instance when instanceId changes even if staticProps are same', () => {
|
|
142
|
+
const { result, rerender } = renderHook(
|
|
143
|
+
({ instanceId }) =>
|
|
144
|
+
useBloc(CounterCubit, {
|
|
145
|
+
instanceId,
|
|
146
|
+
staticProps: { initialValue: 50 },
|
|
147
|
+
}),
|
|
148
|
+
{ initialProps: { instanceId: 'counter-a' } },
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const firstInstance = result.current[1];
|
|
152
|
+
|
|
153
|
+
// Change instanceId
|
|
154
|
+
rerender({ instanceId: 'counter-b' });
|
|
155
|
+
|
|
156
|
+
const secondInstance = result.current[1];
|
|
157
|
+
expect(secondInstance).not.toBe(firstInstance);
|
|
158
|
+
expect(secondInstance._id).toBe('counter-b');
|
|
159
|
+
expect(result.current[0]).toBe(50); // Same initial value, different instance
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe('lifecycle hooks', () => {
|
|
164
|
+
it('should call onMount/onUnmount when instance changes', () => {
|
|
165
|
+
const onMount1 = vi.fn();
|
|
166
|
+
const onUnmount1 = vi.fn();
|
|
167
|
+
const onMount2 = vi.fn();
|
|
168
|
+
const onUnmount2 = vi.fn();
|
|
169
|
+
|
|
170
|
+
const { rerender, unmount } = renderHook(
|
|
171
|
+
({ instanceId, onMount, onUnmount }) =>
|
|
172
|
+
useBloc(CounterCubit, { instanceId, onMount, onUnmount }),
|
|
173
|
+
{
|
|
174
|
+
initialProps: {
|
|
175
|
+
instanceId: 'counter-1',
|
|
176
|
+
onMount: onMount1,
|
|
177
|
+
onUnmount: onUnmount1,
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
expect(onMount1).toHaveBeenCalledTimes(1);
|
|
183
|
+
expect(onUnmount1).not.toHaveBeenCalled();
|
|
184
|
+
|
|
185
|
+
// Change instance
|
|
186
|
+
rerender({
|
|
187
|
+
instanceId: 'counter-2',
|
|
188
|
+
onMount: onMount2,
|
|
189
|
+
onUnmount: onUnmount2,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
expect(onUnmount1).toHaveBeenCalledTimes(1);
|
|
193
|
+
expect(onMount2).toHaveBeenCalledTimes(1);
|
|
194
|
+
expect(onUnmount2).not.toHaveBeenCalled();
|
|
195
|
+
|
|
196
|
+
unmount();
|
|
197
|
+
expect(onUnmount2).toHaveBeenCalledTimes(1);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
});
|