react-native-reanimated-carousel 5.0.0-beta.6 → 5.0.0-beta.8
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/README.md +32 -2
- package/lib/commonjs/components/CarouselLayout.js +1 -1
- package/lib/commonjs/components/CarouselLayout.js.map +1 -1
- package/lib/commonjs/components/ItemRenderer.js +1 -1
- package/lib/commonjs/components/ItemRenderer.js.map +1 -1
- package/lib/commonjs/components/ScrollViewGesture.js +1 -1
- package/lib/commonjs/components/ScrollViewGesture.js.map +1 -1
- package/lib/commonjs/hooks/useOnProgressChange.js +1 -1
- package/lib/commonjs/hooks/useOnProgressChange.js.map +1 -1
- package/lib/commonjs/hooks/usePropsErrorBoundary.js +1 -1
- package/lib/commonjs/hooks/usePropsErrorBoundary.js.map +1 -1
- package/lib/commonjs/hooks/useVisibleRanges.js +1 -1
- package/lib/commonjs/hooks/useVisibleRanges.js.map +1 -1
- package/lib/module/components/CarouselLayout.js +1 -1
- package/lib/module/components/CarouselLayout.js.map +1 -1
- package/lib/module/components/ItemRenderer.js +1 -1
- package/lib/module/components/ItemRenderer.js.map +1 -1
- package/lib/module/components/ScrollViewGesture.js +1 -1
- package/lib/module/components/ScrollViewGesture.js.map +1 -1
- package/lib/module/hooks/useOnProgressChange.js +1 -1
- package/lib/module/hooks/useOnProgressChange.js.map +1 -1
- package/lib/module/hooks/usePropsErrorBoundary.js +1 -1
- package/lib/module/hooks/usePropsErrorBoundary.js.map +1 -1
- package/lib/module/hooks/useVisibleRanges.js +1 -1
- package/lib/module/hooks/useVisibleRanges.js.map +1 -1
- package/lib/typescript/components/CarouselLayout.d.ts.map +1 -1
- package/lib/typescript/components/ItemRenderer.d.ts +1 -0
- package/lib/typescript/components/ItemRenderer.d.ts.map +1 -1
- package/lib/typescript/components/ScrollViewGesture.d.ts.map +1 -1
- package/lib/typescript/hooks/usePropsErrorBoundary.d.ts.map +1 -1
- package/lib/typescript/hooks/useVisibleRanges.d.ts +6 -0
- package/lib/typescript/hooks/useVisibleRanges.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +1 -1
- package/package.json +4 -2
- package/src/components/CarouselLayout.tsx +4 -4
- package/src/components/ItemRenderer.tsx +11 -6
- package/src/components/ScrollViewGesture.tsx +8 -11
- package/src/hooks/useOnProgressChange.ts +1 -1
- package/src/hooks/usePropsErrorBoundary.ts +4 -3
- package/src/hooks/useVisibleRanges.tsx +80 -54
- package/src/types.ts +1 -1
- package/src/components/Carousel.test.tsx +0 -1215
- package/src/components/LazyView.test.tsx +0 -61
- package/src/components/Pagination/Pagination.test.tsx +0 -178
- package/src/components/rnr-demo.test.tsx +0 -53
- package/src/hooks/useAutoPlay.test.ts +0 -194
- package/src/hooks/useCarouselController.test.tsx +0 -1158
- package/src/hooks/useCheckMounted.test.ts +0 -47
- package/src/hooks/useCommonVariables.test.tsx +0 -384
- package/src/hooks/useInitProps.test.tsx +0 -134
- package/src/hooks/useLayoutConfig.test.tsx +0 -247
- package/src/hooks/useOffsetX.test.ts +0 -54
- package/src/hooks/useOnProgressChange.test.tsx +0 -207
- package/src/hooks/usePanGestureProxy.test.tsx +0 -368
- package/src/hooks/useUpdateGestureConfig.test.ts +0 -89
- package/src/hooks/useVisibleRanges.test.tsx +0 -347
- package/src/layouts/parallax.test.ts +0 -239
- package/src/layouts/stack.test.ts +0 -252
- package/src/store/index.test.tsx +0 -314
- package/src/utils/compute-gesture-translation.test.ts +0 -70
- package/src/utils/compute-offset-if-data-changed.test.ts +0 -133
- package/src/utils/compute-offset-if-size-changed.test.ts +0 -78
- package/src/utils/computed-with-auto-fill-data.test.ts +0 -298
- package/src/utils/deal-with-animation.test.ts +0 -181
- package/src/utils/handleroffset-direction.test.ts +0 -124
- package/src/utils/index.test.ts +0 -90
- package/src/utils/log.test.ts +0 -134
- package/src/utils/sanitize-animation-style.test.ts +0 -40
|
@@ -1,1158 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { useSharedValue } from "react-native-reanimated";
|
|
3
|
-
|
|
4
|
-
import { act, renderHook } from "@testing-library/react-hooks";
|
|
5
|
-
|
|
6
|
-
import { useImperativeHandle, useRef } from "react";
|
|
7
|
-
import { View } from "react-native";
|
|
8
|
-
import { GlobalStateContext, IContext } from "../store";
|
|
9
|
-
import { ICarouselInstance } from "../types";
|
|
10
|
-
import { useCarouselController } from "./useCarouselController";
|
|
11
|
-
import { TCarouselSizePhase } from "./useCommonVariables";
|
|
12
|
-
|
|
13
|
-
// Mock Reanimated
|
|
14
|
-
jest.mock("react-native-reanimated", () => {
|
|
15
|
-
const mockAnimatedReaction = jest.fn((deps, cb) => {
|
|
16
|
-
const depsResult = deps();
|
|
17
|
-
cb(depsResult);
|
|
18
|
-
return () => {};
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
useSharedValue: jest.fn((initialValue) => ({
|
|
23
|
-
value: initialValue,
|
|
24
|
-
})),
|
|
25
|
-
useDerivedValue: jest.fn((callback) => ({
|
|
26
|
-
value: callback(),
|
|
27
|
-
})),
|
|
28
|
-
useAnimatedReaction: mockAnimatedReaction,
|
|
29
|
-
withTiming: jest.fn((toValue, config, callback) => {
|
|
30
|
-
if (callback) callback(true);
|
|
31
|
-
|
|
32
|
-
return toValue;
|
|
33
|
-
}),
|
|
34
|
-
mockAnimatedReaction,
|
|
35
|
-
Easing: {
|
|
36
|
-
bezier: () => ({
|
|
37
|
-
factory: () => 0,
|
|
38
|
-
}),
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
jest.mock("react-native-worklets", () => {
|
|
44
|
-
const mockScheduleOnRN = jest.fn((fn, ...args) => fn(...args));
|
|
45
|
-
return {
|
|
46
|
-
scheduleOnRN: mockScheduleOnRN,
|
|
47
|
-
mockScheduleOnRN,
|
|
48
|
-
};
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// Get mock functions for testing
|
|
52
|
-
const { mockAnimatedReaction } = jest.requireMock("react-native-reanimated");
|
|
53
|
-
|
|
54
|
-
const { mockScheduleOnRN } = jest.requireMock("react-native-worklets");
|
|
55
|
-
// Update the React mock to include useRef
|
|
56
|
-
jest.mock("react", () => {
|
|
57
|
-
const originalModule = jest.requireActual("react");
|
|
58
|
-
return {
|
|
59
|
-
...originalModule,
|
|
60
|
-
useRef: jest.fn((initialValue) => ({ current: initialValue })),
|
|
61
|
-
useImperativeHandle: jest.fn((ref, createHandle) => createHandle()),
|
|
62
|
-
};
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// Add mock for GlobalStateContext
|
|
66
|
-
const mockGlobalState: IContext = {
|
|
67
|
-
props: {
|
|
68
|
-
overscrollEnabled: true,
|
|
69
|
-
loop: true,
|
|
70
|
-
pagingEnabled: true,
|
|
71
|
-
snapEnabled: true,
|
|
72
|
-
enabled: true,
|
|
73
|
-
scrollAnimationDuration: 500,
|
|
74
|
-
withAnimation: undefined,
|
|
75
|
-
dataLength: 5,
|
|
76
|
-
data: Array.from({ length: 5 }, (_, i) => i),
|
|
77
|
-
width: 300,
|
|
78
|
-
height: 300,
|
|
79
|
-
renderItem: () => <View style={{ flex: 1 }} />,
|
|
80
|
-
autoFillData: false,
|
|
81
|
-
defaultIndex: 0,
|
|
82
|
-
autoPlayInterval: 0,
|
|
83
|
-
rawData: [],
|
|
84
|
-
rawDataLength: 0,
|
|
85
|
-
},
|
|
86
|
-
common: {
|
|
87
|
-
size: 300,
|
|
88
|
-
sizeExplicit: true,
|
|
89
|
-
validLength: 5,
|
|
90
|
-
handlerOffset: useSharedValue(0),
|
|
91
|
-
resolvedSize: useSharedValue<number | null>(300),
|
|
92
|
-
sizePhase: useSharedValue<TCarouselSizePhase>("ready"),
|
|
93
|
-
},
|
|
94
|
-
layout: {
|
|
95
|
-
// @ts-ignore
|
|
96
|
-
containerSize: { value: { width: 300, height: 300 } },
|
|
97
|
-
// @ts-ignore
|
|
98
|
-
itemDimensions: { value: {} },
|
|
99
|
-
updateItemDimensions: jest.fn(),
|
|
100
|
-
updateContainerSize: jest.fn(),
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// Add wrapper for renderHook
|
|
105
|
-
const wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
|
|
106
|
-
<GlobalStateContext.Provider value={mockGlobalState}>{children}</GlobalStateContext.Provider>
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
describe("useCarouselController", () => {
|
|
110
|
-
let mockHandlerOffset: ReturnType<typeof useSharedValue<number>>;
|
|
111
|
-
let ref: ReturnType<typeof useRef>;
|
|
112
|
-
let defaultProps: any;
|
|
113
|
-
|
|
114
|
-
beforeEach(() => {
|
|
115
|
-
jest.clearAllMocks();
|
|
116
|
-
mockHandlerOffset = useSharedValue(0);
|
|
117
|
-
ref = useRef<ICarouselInstance>(null!);
|
|
118
|
-
defaultProps = {
|
|
119
|
-
ref,
|
|
120
|
-
size: 300,
|
|
121
|
-
loop: true,
|
|
122
|
-
dataLength: 5,
|
|
123
|
-
handlerOffset: mockHandlerOffset,
|
|
124
|
-
autoFillData: false,
|
|
125
|
-
duration: 300,
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
mockHandlerOffset.value = 0;
|
|
129
|
-
mockAnimatedReaction.mockImplementation((deps: () => any, cb: (depsResult: any) => void) => {
|
|
130
|
-
const depsResult = deps();
|
|
131
|
-
cb(depsResult);
|
|
132
|
-
return () => {};
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it("should initialize with default index", () => {
|
|
137
|
-
mockHandlerOffset.value = -600; // size * 2
|
|
138
|
-
const { result } = renderHook(
|
|
139
|
-
() =>
|
|
140
|
-
useCarouselController({
|
|
141
|
-
...defaultProps,
|
|
142
|
-
defaultIndex: 2,
|
|
143
|
-
}),
|
|
144
|
-
{ wrapper }
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
expect(result.current.getCurrentIndex()).toBe(2);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it("should move to next slide", () => {
|
|
151
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
152
|
-
|
|
153
|
-
act(() => {
|
|
154
|
-
result.current.next();
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
expect(mockHandlerOffset.value).toBe(-300); // size * 1
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it("should move to previous slide", () => {
|
|
161
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
162
|
-
|
|
163
|
-
act(() => {
|
|
164
|
-
result.current.prev();
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
expect(mockHandlerOffset.value).toBe(300); // size * -1
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it("should handle loop behavior correctly", () => {
|
|
171
|
-
const { result } = renderHook(
|
|
172
|
-
() =>
|
|
173
|
-
useCarouselController({
|
|
174
|
-
...defaultProps,
|
|
175
|
-
loop: true,
|
|
176
|
-
}),
|
|
177
|
-
{ wrapper }
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
// Move to last slide
|
|
181
|
-
act(() => {
|
|
182
|
-
result.current.scrollTo({ index: 4 });
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
// Try to go next (should loop to first)
|
|
186
|
-
act(() => {
|
|
187
|
-
result.current.next();
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
expect(mockHandlerOffset.value).toBe(-1500); // size * 5
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it("should prevent movement when loop is disabled and at bounds", () => {
|
|
194
|
-
const { result } = renderHook(
|
|
195
|
-
() =>
|
|
196
|
-
useCarouselController({
|
|
197
|
-
...defaultProps,
|
|
198
|
-
loop: false,
|
|
199
|
-
}),
|
|
200
|
-
{ wrapper }
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
// Try to go previous at start
|
|
204
|
-
act(() => {
|
|
205
|
-
result.current.prev();
|
|
206
|
-
});
|
|
207
|
-
expect(mockHandlerOffset.value).toBe(0);
|
|
208
|
-
|
|
209
|
-
// Go to end
|
|
210
|
-
act(() => {
|
|
211
|
-
result.current.scrollTo({ index: 4 });
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// Try to go next at end
|
|
215
|
-
act(() => {
|
|
216
|
-
result.current.next();
|
|
217
|
-
});
|
|
218
|
-
expect(mockHandlerOffset.value).toBe(-1200); // size * 4
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it("should scroll to specific index", () => {
|
|
222
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
223
|
-
|
|
224
|
-
act(() => {
|
|
225
|
-
result.current.scrollTo({ index: 3 });
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
expect(mockHandlerOffset.value).toBe(-900); // size * 3
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it("should keep negative offsets when scrollTo() moves backward in non-loop mode", () => {
|
|
232
|
-
const { result } = renderHook(
|
|
233
|
-
() =>
|
|
234
|
-
useCarouselController({
|
|
235
|
-
...defaultProps,
|
|
236
|
-
loop: false,
|
|
237
|
-
}),
|
|
238
|
-
{ wrapper }
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
act(() => {
|
|
242
|
-
result.current.scrollTo({ index: 3, animated: false });
|
|
243
|
-
});
|
|
244
|
-
expect(mockHandlerOffset.value).toBe(-900);
|
|
245
|
-
|
|
246
|
-
act(() => {
|
|
247
|
-
result.current.scrollTo({ index: 2, animated: false });
|
|
248
|
-
});
|
|
249
|
-
expect(mockHandlerOffset.value).toBe(-600);
|
|
250
|
-
|
|
251
|
-
act(() => {
|
|
252
|
-
result.current.scrollTo({ index: 1, animated: false });
|
|
253
|
-
});
|
|
254
|
-
expect(mockHandlerOffset.value).toBe(-300);
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it("should keep negative offsets when animated backward scrollTo() runs in non-loop mode", () => {
|
|
258
|
-
const onFinished = jest.fn();
|
|
259
|
-
const { result } = renderHook(
|
|
260
|
-
() =>
|
|
261
|
-
useCarouselController({
|
|
262
|
-
...defaultProps,
|
|
263
|
-
loop: false,
|
|
264
|
-
}),
|
|
265
|
-
{ wrapper }
|
|
266
|
-
);
|
|
267
|
-
|
|
268
|
-
act(() => {
|
|
269
|
-
result.current.scrollTo({ index: 3, animated: true });
|
|
270
|
-
});
|
|
271
|
-
expect(mockHandlerOffset.value).toBe(-900);
|
|
272
|
-
|
|
273
|
-
act(() => {
|
|
274
|
-
result.current.scrollTo({ index: 2, animated: true, onFinished });
|
|
275
|
-
});
|
|
276
|
-
expect(mockHandlerOffset.value).toBe(-600);
|
|
277
|
-
expect(onFinished).toHaveBeenCalled();
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it("should map scrollTo({ index: 0 }) to zero offset from end in non-loop mode", () => {
|
|
281
|
-
const { result } = renderHook(
|
|
282
|
-
() =>
|
|
283
|
-
useCarouselController({
|
|
284
|
-
...defaultProps,
|
|
285
|
-
loop: false,
|
|
286
|
-
}),
|
|
287
|
-
{ wrapper }
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
act(() => {
|
|
291
|
-
result.current.scrollTo({ index: 4, animated: false });
|
|
292
|
-
});
|
|
293
|
-
expect(mockHandlerOffset.value).toBe(-1200);
|
|
294
|
-
|
|
295
|
-
act(() => {
|
|
296
|
-
result.current.scrollTo({ index: 0, animated: false });
|
|
297
|
-
});
|
|
298
|
-
expect(Math.abs(mockHandlerOffset.value)).toBe(0);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it("should handle animation callbacks", () => {
|
|
302
|
-
const onFinished = jest.fn();
|
|
303
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
304
|
-
|
|
305
|
-
act(() => {
|
|
306
|
-
result.current.next({
|
|
307
|
-
animated: true,
|
|
308
|
-
onFinished,
|
|
309
|
-
});
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
expect(onFinished).toHaveBeenCalled();
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
it("should respect animation duration", () => {
|
|
316
|
-
const { result } = renderHook(
|
|
317
|
-
() =>
|
|
318
|
-
useCarouselController({
|
|
319
|
-
...defaultProps,
|
|
320
|
-
duration: 500,
|
|
321
|
-
}),
|
|
322
|
-
{ wrapper }
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
const onFinished = jest.fn();
|
|
326
|
-
act(() => {
|
|
327
|
-
result.current.next({
|
|
328
|
-
animated: true,
|
|
329
|
-
onFinished,
|
|
330
|
-
});
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
expect(onFinished).toHaveBeenCalled();
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
it("should handle non-animated transitions", () => {
|
|
337
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
338
|
-
|
|
339
|
-
act(() => {
|
|
340
|
-
result.current.scrollTo({ index: 2, animated: false });
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
expect(mockHandlerOffset.value).toBe(-600); // size * 2
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
it("should handle multiple slide movements", () => {
|
|
347
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
348
|
-
|
|
349
|
-
act(() => {
|
|
350
|
-
result.current.next({ count: 2 });
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
expect(mockHandlerOffset.value).toBe(-600); // size * 2
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
it("should prevent overscroll when page size is smaller than container and overscroll is disabled", () => {
|
|
357
|
-
// Configure multi-item layout: page size 100, container width 300 (3 items per view)
|
|
358
|
-
mockGlobalState.props.overscrollEnabled = false;
|
|
359
|
-
mockGlobalState.props.loop = false;
|
|
360
|
-
mockGlobalState.common.size = 100;
|
|
361
|
-
mockGlobalState.common.resolvedSize.value = 100;
|
|
362
|
-
mockGlobalState.layout.containerSize.value = { width: 300, height: 300 };
|
|
363
|
-
|
|
364
|
-
// Simulate currently at index 3 (handlerOffset = -pageSize * 3)
|
|
365
|
-
mockHandlerOffset.value = -300;
|
|
366
|
-
|
|
367
|
-
const { result } = renderHook(
|
|
368
|
-
() =>
|
|
369
|
-
useCarouselController({
|
|
370
|
-
...defaultProps,
|
|
371
|
-
loop: false,
|
|
372
|
-
size: 100,
|
|
373
|
-
dataLength: 5,
|
|
374
|
-
handlerOffset: mockHandlerOffset,
|
|
375
|
-
}),
|
|
376
|
-
{ wrapper }
|
|
377
|
-
);
|
|
378
|
-
|
|
379
|
-
act(() => {
|
|
380
|
-
result.current.next();
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
// Should block advancing because remaining width (2 * 100) is less than container width (300)
|
|
384
|
-
expect(mockHandlerOffset.value).toBe(-300);
|
|
385
|
-
|
|
386
|
-
// Reset shared global values for other tests
|
|
387
|
-
mockGlobalState.props.overscrollEnabled = true;
|
|
388
|
-
mockGlobalState.props.loop = true;
|
|
389
|
-
mockGlobalState.common.size = 300;
|
|
390
|
-
mockGlobalState.common.resolvedSize.value = 300;
|
|
391
|
-
mockGlobalState.layout.containerSize.value = { width: 300, height: 300 };
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
it("should fall back to propWidth when container size is unknown", () => {
|
|
395
|
-
mockGlobalState.props.overscrollEnabled = false;
|
|
396
|
-
mockGlobalState.props.loop = false;
|
|
397
|
-
mockGlobalState.props.width = 240;
|
|
398
|
-
mockGlobalState.common.size = 100;
|
|
399
|
-
mockGlobalState.common.resolvedSize.value = 100;
|
|
400
|
-
mockGlobalState.layout.containerSize.value = { width: 0, height: 0 };
|
|
401
|
-
mockHandlerOffset.value = 0;
|
|
402
|
-
|
|
403
|
-
const { result } = renderHook(
|
|
404
|
-
() =>
|
|
405
|
-
useCarouselController({
|
|
406
|
-
...defaultProps,
|
|
407
|
-
size: 100,
|
|
408
|
-
width: 240,
|
|
409
|
-
loop: false,
|
|
410
|
-
handlerOffset: mockHandlerOffset,
|
|
411
|
-
}),
|
|
412
|
-
{ wrapper }
|
|
413
|
-
);
|
|
414
|
-
|
|
415
|
-
result.current.index.value = 4; // remaining width = 1 * 100 < effective width 240
|
|
416
|
-
|
|
417
|
-
act(() => {
|
|
418
|
-
result.current.next();
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
expect(mockHandlerOffset.value).toBe(0);
|
|
422
|
-
|
|
423
|
-
// reset
|
|
424
|
-
mockGlobalState.props.overscrollEnabled = true;
|
|
425
|
-
mockGlobalState.props.loop = true;
|
|
426
|
-
mockGlobalState.props.width = 300;
|
|
427
|
-
mockGlobalState.common.size = 300;
|
|
428
|
-
mockGlobalState.common.resolvedSize.value = 300;
|
|
429
|
-
mockGlobalState.layout.containerSize.value = { width: 300, height: 300 };
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
it("should fall back to style width when container and prop width are unavailable", () => {
|
|
433
|
-
mockGlobalState.props.overscrollEnabled = false;
|
|
434
|
-
mockGlobalState.props.loop = false;
|
|
435
|
-
mockGlobalState.props.width = undefined as any;
|
|
436
|
-
mockGlobalState.props.style = { width: 220 };
|
|
437
|
-
mockGlobalState.common.size = 100;
|
|
438
|
-
mockGlobalState.common.resolvedSize.value = 100;
|
|
439
|
-
mockGlobalState.layout.containerSize.value = { width: 0, height: 0 };
|
|
440
|
-
mockHandlerOffset.value = 0;
|
|
441
|
-
|
|
442
|
-
const { result } = renderHook(
|
|
443
|
-
() =>
|
|
444
|
-
useCarouselController({
|
|
445
|
-
...defaultProps,
|
|
446
|
-
size: 100,
|
|
447
|
-
style: mockGlobalState.props.style,
|
|
448
|
-
width: undefined,
|
|
449
|
-
loop: false,
|
|
450
|
-
handlerOffset: mockHandlerOffset,
|
|
451
|
-
}),
|
|
452
|
-
{ wrapper }
|
|
453
|
-
);
|
|
454
|
-
|
|
455
|
-
result.current.index.value = 4;
|
|
456
|
-
|
|
457
|
-
act(() => {
|
|
458
|
-
result.current.next();
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
expect(mockHandlerOffset.value).toBe(0);
|
|
462
|
-
|
|
463
|
-
mockGlobalState.props.overscrollEnabled = true;
|
|
464
|
-
mockGlobalState.props.loop = true;
|
|
465
|
-
mockGlobalState.props.width = 300;
|
|
466
|
-
mockGlobalState.props.style = {};
|
|
467
|
-
mockGlobalState.common.size = 300;
|
|
468
|
-
mockGlobalState.common.resolvedSize.value = 300;
|
|
469
|
-
mockGlobalState.layout.containerSize.value = { width: 300, height: 300 };
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
it("should fall back to propHeight in vertical mode when container size is unknown", () => {
|
|
473
|
-
mockGlobalState.props.overscrollEnabled = false;
|
|
474
|
-
mockGlobalState.props.loop = false;
|
|
475
|
-
mockGlobalState.props.vertical = true;
|
|
476
|
-
mockGlobalState.props.height = 150;
|
|
477
|
-
mockGlobalState.common.size = 80;
|
|
478
|
-
mockGlobalState.common.resolvedSize.value = 80;
|
|
479
|
-
mockGlobalState.layout.containerSize.value = { width: 0, height: 0 };
|
|
480
|
-
mockHandlerOffset.value = 0;
|
|
481
|
-
|
|
482
|
-
const { result } = renderHook(
|
|
483
|
-
() =>
|
|
484
|
-
useCarouselController({
|
|
485
|
-
...defaultProps,
|
|
486
|
-
size: 80,
|
|
487
|
-
height: 150,
|
|
488
|
-
loop: false,
|
|
489
|
-
handlerOffset: mockHandlerOffset,
|
|
490
|
-
dataLength: 5,
|
|
491
|
-
}),
|
|
492
|
-
{ wrapper }
|
|
493
|
-
);
|
|
494
|
-
|
|
495
|
-
result.current.index.value = 4;
|
|
496
|
-
|
|
497
|
-
act(() => {
|
|
498
|
-
result.current.next();
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
expect(mockHandlerOffset.value).toBe(0);
|
|
502
|
-
|
|
503
|
-
// reset
|
|
504
|
-
mockGlobalState.props.overscrollEnabled = true;
|
|
505
|
-
mockGlobalState.props.loop = true;
|
|
506
|
-
mockGlobalState.props.vertical = false;
|
|
507
|
-
mockGlobalState.props.height = 300;
|
|
508
|
-
mockGlobalState.common.size = 300;
|
|
509
|
-
mockGlobalState.common.resolvedSize.value = 300;
|
|
510
|
-
mockGlobalState.layout.containerSize.value = { width: 300, height: 300 };
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
it("should use propWidth branch when container width is zero", () => {
|
|
514
|
-
mockGlobalState.props.overscrollEnabled = false;
|
|
515
|
-
mockGlobalState.props.loop = false;
|
|
516
|
-
mockGlobalState.props.width = 240;
|
|
517
|
-
mockGlobalState.props.style = {};
|
|
518
|
-
mockGlobalState.common.size = 120;
|
|
519
|
-
mockGlobalState.common.resolvedSize.value = 120;
|
|
520
|
-
mockGlobalState.layout.containerSize.value = { width: 0, height: 0 };
|
|
521
|
-
mockHandlerOffset.value = 0;
|
|
522
|
-
|
|
523
|
-
const { result } = renderHook(
|
|
524
|
-
() =>
|
|
525
|
-
useCarouselController({
|
|
526
|
-
...defaultProps,
|
|
527
|
-
size: 120,
|
|
528
|
-
width: 240,
|
|
529
|
-
loop: false,
|
|
530
|
-
handlerOffset: mockHandlerOffset,
|
|
531
|
-
}),
|
|
532
|
-
{ wrapper }
|
|
533
|
-
);
|
|
534
|
-
|
|
535
|
-
// at index 3 of 5, remaining width = 2 * 120 = 240, equals effective width; overscroll block triggers
|
|
536
|
-
result.current.index.value = 3;
|
|
537
|
-
|
|
538
|
-
act(() => {
|
|
539
|
-
result.current.next();
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
expect(mockHandlerOffset.value).toBe(0);
|
|
543
|
-
|
|
544
|
-
// reset
|
|
545
|
-
mockGlobalState.props.overscrollEnabled = true;
|
|
546
|
-
mockGlobalState.props.loop = true;
|
|
547
|
-
mockGlobalState.props.width = 300;
|
|
548
|
-
mockGlobalState.props.style = {};
|
|
549
|
-
mockGlobalState.common.size = 300;
|
|
550
|
-
mockGlobalState.common.resolvedSize.value = 300;
|
|
551
|
-
mockGlobalState.layout.containerSize.value = { width: 300, height: 300 };
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
it("should fall back to style height in vertical mode when container and prop height are unavailable", () => {
|
|
555
|
-
mockGlobalState.props.overscrollEnabled = false;
|
|
556
|
-
mockGlobalState.props.loop = false;
|
|
557
|
-
mockGlobalState.props.vertical = true;
|
|
558
|
-
mockGlobalState.props.height = undefined as any;
|
|
559
|
-
mockGlobalState.props.style = { height: 160 };
|
|
560
|
-
mockGlobalState.common.size = 80;
|
|
561
|
-
mockGlobalState.common.resolvedSize.value = 80;
|
|
562
|
-
mockGlobalState.layout.containerSize.value = { width: 0, height: 0 };
|
|
563
|
-
mockHandlerOffset.value = 0;
|
|
564
|
-
|
|
565
|
-
const { result } = renderHook(
|
|
566
|
-
() =>
|
|
567
|
-
useCarouselController({
|
|
568
|
-
...defaultProps,
|
|
569
|
-
size: 80,
|
|
570
|
-
style: mockGlobalState.props.style,
|
|
571
|
-
height: undefined,
|
|
572
|
-
loop: false,
|
|
573
|
-
handlerOffset: mockHandlerOffset,
|
|
574
|
-
dataLength: 5,
|
|
575
|
-
}),
|
|
576
|
-
{ wrapper }
|
|
577
|
-
);
|
|
578
|
-
|
|
579
|
-
result.current.index.value = 4;
|
|
580
|
-
|
|
581
|
-
act(() => {
|
|
582
|
-
result.current.next();
|
|
583
|
-
});
|
|
584
|
-
|
|
585
|
-
expect(mockHandlerOffset.value).toBe(0);
|
|
586
|
-
|
|
587
|
-
mockGlobalState.props.overscrollEnabled = true;
|
|
588
|
-
mockGlobalState.props.loop = true;
|
|
589
|
-
mockGlobalState.props.vertical = false;
|
|
590
|
-
mockGlobalState.props.height = 300;
|
|
591
|
-
mockGlobalState.props.style = {};
|
|
592
|
-
mockGlobalState.common.size = 300;
|
|
593
|
-
mockGlobalState.common.resolvedSize.value = 300;
|
|
594
|
-
mockGlobalState.layout.containerSize.value = { width: 300, height: 300 };
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
it("should use pageSize fallback multiplier when no size info is available", () => {
|
|
598
|
-
mockGlobalState.props.overscrollEnabled = false;
|
|
599
|
-
mockGlobalState.props.loop = false;
|
|
600
|
-
mockGlobalState.props.width = undefined as any;
|
|
601
|
-
mockGlobalState.props.height = undefined as any;
|
|
602
|
-
mockGlobalState.common.size = 100;
|
|
603
|
-
mockGlobalState.common.resolvedSize.value = 100;
|
|
604
|
-
mockGlobalState.layout.containerSize.value = { width: 0, height: 0 };
|
|
605
|
-
mockHandlerOffset.value = 0;
|
|
606
|
-
|
|
607
|
-
const { result } = renderHook(
|
|
608
|
-
() =>
|
|
609
|
-
useCarouselController({
|
|
610
|
-
...defaultProps,
|
|
611
|
-
size: 100,
|
|
612
|
-
width: undefined,
|
|
613
|
-
height: undefined,
|
|
614
|
-
loop: false,
|
|
615
|
-
handlerOffset: mockHandlerOffset,
|
|
616
|
-
}),
|
|
617
|
-
{ wrapper }
|
|
618
|
-
);
|
|
619
|
-
|
|
620
|
-
act(() => {
|
|
621
|
-
result.current.next({ animated: false });
|
|
622
|
-
});
|
|
623
|
-
|
|
624
|
-
expect(mockHandlerOffset.value).toBe(-100);
|
|
625
|
-
|
|
626
|
-
// reset
|
|
627
|
-
mockGlobalState.props.overscrollEnabled = true;
|
|
628
|
-
mockGlobalState.props.loop = true;
|
|
629
|
-
mockGlobalState.props.width = 300;
|
|
630
|
-
mockGlobalState.props.height = 300;
|
|
631
|
-
mockGlobalState.common.size = 300;
|
|
632
|
-
mockGlobalState.common.resolvedSize.value = 300;
|
|
633
|
-
mockGlobalState.layout.containerSize.value = { width: 300, height: 300 };
|
|
634
|
-
});
|
|
635
|
-
|
|
636
|
-
it("should use propHeight branch when container height is zero (vertical)", () => {
|
|
637
|
-
mockGlobalState.props.overscrollEnabled = false;
|
|
638
|
-
mockGlobalState.props.loop = false;
|
|
639
|
-
mockGlobalState.props.vertical = true;
|
|
640
|
-
mockGlobalState.props.height = 180;
|
|
641
|
-
mockGlobalState.props.style = {};
|
|
642
|
-
mockGlobalState.common.size = 90;
|
|
643
|
-
mockGlobalState.common.resolvedSize.value = 90;
|
|
644
|
-
mockGlobalState.layout.containerSize.value = { width: 0, height: 0 };
|
|
645
|
-
mockHandlerOffset.value = 0;
|
|
646
|
-
|
|
647
|
-
const { result } = renderHook(
|
|
648
|
-
() =>
|
|
649
|
-
useCarouselController({
|
|
650
|
-
...defaultProps,
|
|
651
|
-
vertical: true,
|
|
652
|
-
size: 90,
|
|
653
|
-
height: 180,
|
|
654
|
-
loop: false,
|
|
655
|
-
handlerOffset: mockHandlerOffset,
|
|
656
|
-
dataLength: 5,
|
|
657
|
-
}),
|
|
658
|
-
{ wrapper }
|
|
659
|
-
);
|
|
660
|
-
|
|
661
|
-
result.current.index.value = 3; // remaining height = 2 * 90 = 180, equals effective height
|
|
662
|
-
|
|
663
|
-
act(() => {
|
|
664
|
-
result.current.next();
|
|
665
|
-
});
|
|
666
|
-
|
|
667
|
-
expect(mockHandlerOffset.value).toBe(0);
|
|
668
|
-
|
|
669
|
-
mockGlobalState.props.overscrollEnabled = true;
|
|
670
|
-
mockGlobalState.props.loop = true;
|
|
671
|
-
mockGlobalState.props.vertical = false;
|
|
672
|
-
mockGlobalState.props.height = 300;
|
|
673
|
-
mockGlobalState.props.style = {};
|
|
674
|
-
mockGlobalState.common.size = 300;
|
|
675
|
-
mockGlobalState.common.resolvedSize.value = 300;
|
|
676
|
-
mockGlobalState.layout.containerSize.value = { width: 300, height: 300 };
|
|
677
|
-
});
|
|
678
|
-
|
|
679
|
-
it("should animate scrollTo when animated is true", () => {
|
|
680
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
681
|
-
|
|
682
|
-
act(() => {
|
|
683
|
-
result.current.scrollTo({ index: 1, animated: true });
|
|
684
|
-
});
|
|
685
|
-
|
|
686
|
-
expect(result.current.index.value).toBe(1);
|
|
687
|
-
expect(mockHandlerOffset.value).toBe(-300);
|
|
688
|
-
});
|
|
689
|
-
|
|
690
|
-
// it("should maintain correct index with autoFillData", () => {
|
|
691
|
-
// const { result } = renderHook(
|
|
692
|
-
// () =>
|
|
693
|
-
// useCarouselController({
|
|
694
|
-
// ...defaultProps,
|
|
695
|
-
// autoFillData: true,
|
|
696
|
-
// dataLength: 3,
|
|
697
|
-
// }),
|
|
698
|
-
// { wrapper }
|
|
699
|
-
// );
|
|
700
|
-
|
|
701
|
-
// act(() => {
|
|
702
|
-
// result.current.next();
|
|
703
|
-
// result.current.next();
|
|
704
|
-
// });
|
|
705
|
-
|
|
706
|
-
// expect(result.current.getCurrentIndex()).toBe(2);
|
|
707
|
-
// });
|
|
708
|
-
|
|
709
|
-
it("should handle animated reactions correctly", () => {
|
|
710
|
-
renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
711
|
-
|
|
712
|
-
expect(mockAnimatedReaction).toHaveBeenCalled();
|
|
713
|
-
expect(mockScheduleOnRN).toHaveBeenCalled();
|
|
714
|
-
});
|
|
715
|
-
|
|
716
|
-
it("should handle scheduleOnRN correctly", () => {
|
|
717
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
718
|
-
|
|
719
|
-
act(() => {
|
|
720
|
-
result.current.next();
|
|
721
|
-
});
|
|
722
|
-
|
|
723
|
-
expect(mockScheduleOnRN).toHaveBeenCalled();
|
|
724
|
-
});
|
|
725
|
-
});
|
|
726
|
-
|
|
727
|
-
describe("useCarouselController imperative handle", () => {
|
|
728
|
-
let mockHandlerOffset: ReturnType<typeof useSharedValue<number>>;
|
|
729
|
-
let ref: ReturnType<typeof useRef>;
|
|
730
|
-
let defaultProps: any;
|
|
731
|
-
|
|
732
|
-
beforeEach(() => {
|
|
733
|
-
jest.clearAllMocks();
|
|
734
|
-
mockHandlerOffset = useSharedValue(0);
|
|
735
|
-
ref = useRef<ICarouselInstance>(null!);
|
|
736
|
-
defaultProps = {
|
|
737
|
-
ref,
|
|
738
|
-
size: 300,
|
|
739
|
-
loop: true,
|
|
740
|
-
dataLength: 5,
|
|
741
|
-
handlerOffset: mockHandlerOffset,
|
|
742
|
-
autoFillData: false,
|
|
743
|
-
duration: 300,
|
|
744
|
-
};
|
|
745
|
-
mockHandlerOffset.value = 0;
|
|
746
|
-
});
|
|
747
|
-
|
|
748
|
-
// it("should expose imperative methods through ref", () => {
|
|
749
|
-
// renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
750
|
-
|
|
751
|
-
// // Verify useImperativeHandle was called
|
|
752
|
-
// expect(useImperativeHandle).toHaveBeenCalledWith(ref, expect.any(Function));
|
|
753
|
-
|
|
754
|
-
// // Get the handle creator function
|
|
755
|
-
// const createHandle = (useImperativeHandle as jest.Mock).mock.calls[0][1];
|
|
756
|
-
// const handle = createHandle();
|
|
757
|
-
|
|
758
|
-
// // Verify exposed methods
|
|
759
|
-
// expect(handle).toHaveProperty("getCurrentIndex");
|
|
760
|
-
// expect(handle).toHaveProperty("next");
|
|
761
|
-
// expect(handle).toHaveProperty("prev");
|
|
762
|
-
// expect(handle).toHaveProperty("scrollTo");
|
|
763
|
-
// });
|
|
764
|
-
|
|
765
|
-
it("should maintain correct index through imperative calls", () => {
|
|
766
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
767
|
-
|
|
768
|
-
// Get handle methods
|
|
769
|
-
const createHandle = (useImperativeHandle as jest.Mock).mock.calls[0][1];
|
|
770
|
-
const handle = createHandle();
|
|
771
|
-
|
|
772
|
-
// Test sequence of imperative calls
|
|
773
|
-
act(() => {
|
|
774
|
-
handle.next();
|
|
775
|
-
handle.next();
|
|
776
|
-
});
|
|
777
|
-
expect(handle.getCurrentIndex()).toBe(2);
|
|
778
|
-
|
|
779
|
-
act(() => {
|
|
780
|
-
handle.prev();
|
|
781
|
-
});
|
|
782
|
-
expect(handle.getCurrentIndex()).toBe(1);
|
|
783
|
-
|
|
784
|
-
act(() => {
|
|
785
|
-
handle.scrollTo({ index: 3 });
|
|
786
|
-
});
|
|
787
|
-
expect(handle.getCurrentIndex()).toBe(3);
|
|
788
|
-
});
|
|
789
|
-
|
|
790
|
-
it("should handle animation callbacks through imperative calls", () => {
|
|
791
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
792
|
-
const onFinished = jest.fn();
|
|
793
|
-
|
|
794
|
-
// Get handle methods
|
|
795
|
-
const createHandle = (useImperativeHandle as jest.Mock).mock.calls[0][1];
|
|
796
|
-
const handle = createHandle();
|
|
797
|
-
|
|
798
|
-
act(() => {
|
|
799
|
-
handle.next({ animated: true, onFinished });
|
|
800
|
-
});
|
|
801
|
-
|
|
802
|
-
expect(onFinished).toHaveBeenCalled();
|
|
803
|
-
});
|
|
804
|
-
|
|
805
|
-
it("should respect loop settings through imperative calls", () => {
|
|
806
|
-
const { result } = renderHook(
|
|
807
|
-
() =>
|
|
808
|
-
useCarouselController({
|
|
809
|
-
...defaultProps,
|
|
810
|
-
loop: false,
|
|
811
|
-
}),
|
|
812
|
-
{ wrapper }
|
|
813
|
-
);
|
|
814
|
-
|
|
815
|
-
// Get handle methods
|
|
816
|
-
const createHandle = (useImperativeHandle as jest.Mock).mock.calls[0][1];
|
|
817
|
-
const handle = createHandle();
|
|
818
|
-
|
|
819
|
-
// Try to go past the end
|
|
820
|
-
act(() => {
|
|
821
|
-
handle.scrollTo({ index: 4 });
|
|
822
|
-
handle.next();
|
|
823
|
-
});
|
|
824
|
-
expect(handle.getCurrentIndex()).toBe(4);
|
|
825
|
-
|
|
826
|
-
// Try to go before the start
|
|
827
|
-
act(() => {
|
|
828
|
-
handle.scrollTo({ index: 0 });
|
|
829
|
-
handle.prev();
|
|
830
|
-
});
|
|
831
|
-
expect(handle.getCurrentIndex()).toBe(0);
|
|
832
|
-
});
|
|
833
|
-
|
|
834
|
-
it("should handle multiple slide movements through imperative calls", () => {
|
|
835
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
836
|
-
|
|
837
|
-
// Get handle methods
|
|
838
|
-
const createHandle = (useImperativeHandle as jest.Mock).mock.calls[0][1];
|
|
839
|
-
const handle = createHandle();
|
|
840
|
-
|
|
841
|
-
act(() => {
|
|
842
|
-
handle.next({ count: 2 });
|
|
843
|
-
});
|
|
844
|
-
|
|
845
|
-
expect(handle.getCurrentIndex()).toBe(2);
|
|
846
|
-
expect(mockHandlerOffset.value).toBe(-600); // size * 2
|
|
847
|
-
});
|
|
848
|
-
});
|
|
849
|
-
|
|
850
|
-
describe("useCarouselController edge cases and uncovered lines", () => {
|
|
851
|
-
let mockHandlerOffset: ReturnType<typeof useSharedValue<number>>;
|
|
852
|
-
let ref: ReturnType<typeof useRef>;
|
|
853
|
-
let defaultProps: any;
|
|
854
|
-
|
|
855
|
-
beforeEach(() => {
|
|
856
|
-
jest.clearAllMocks();
|
|
857
|
-
mockHandlerOffset = useSharedValue<number>(0);
|
|
858
|
-
ref = useRef<ICarouselInstance>(null!);
|
|
859
|
-
defaultProps = {
|
|
860
|
-
ref,
|
|
861
|
-
size: 300,
|
|
862
|
-
loop: false,
|
|
863
|
-
dataLength: 5,
|
|
864
|
-
handlerOffset: mockHandlerOffset,
|
|
865
|
-
autoFillData: false,
|
|
866
|
-
duration: 300,
|
|
867
|
-
};
|
|
868
|
-
mockHandlerOffset.value = 0;
|
|
869
|
-
});
|
|
870
|
-
|
|
871
|
-
it("should handle next() without animation - uncovered line 213-214", () => {
|
|
872
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
873
|
-
const onFinished = jest.fn();
|
|
874
|
-
|
|
875
|
-
act(() => {
|
|
876
|
-
result.current.next({ animated: false, onFinished });
|
|
877
|
-
});
|
|
878
|
-
|
|
879
|
-
expect(mockHandlerOffset.value).toBe(-300); // size * 1
|
|
880
|
-
expect(onFinished).toHaveBeenCalled();
|
|
881
|
-
});
|
|
882
|
-
|
|
883
|
-
it("should handle prev() without animation - uncovered line 245-246", () => {
|
|
884
|
-
const { result } = renderHook(
|
|
885
|
-
() =>
|
|
886
|
-
useCarouselController({
|
|
887
|
-
...defaultProps,
|
|
888
|
-
loop: true, // Enable loop to allow prev
|
|
889
|
-
}),
|
|
890
|
-
{ wrapper }
|
|
891
|
-
);
|
|
892
|
-
|
|
893
|
-
// First move to a position where prev is valid
|
|
894
|
-
act(() => {
|
|
895
|
-
result.current.next({ animated: false }); // Move to index 1
|
|
896
|
-
});
|
|
897
|
-
|
|
898
|
-
const onFinished = jest.fn();
|
|
899
|
-
|
|
900
|
-
act(() => {
|
|
901
|
-
result.current.prev({ animated: false, onFinished });
|
|
902
|
-
});
|
|
903
|
-
|
|
904
|
-
// Should move back to index 0 (could be -0)
|
|
905
|
-
expect(Math.abs(mockHandlerOffset.value)).toBe(0);
|
|
906
|
-
expect(onFinished).toHaveBeenCalled();
|
|
907
|
-
});
|
|
908
|
-
|
|
909
|
-
it("should handle scrollTo() without animation when target equals current index - uncovered line 265", () => {
|
|
910
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
911
|
-
|
|
912
|
-
// Set index to 1
|
|
913
|
-
act(() => {
|
|
914
|
-
result.current.next({ animated: false });
|
|
915
|
-
});
|
|
916
|
-
|
|
917
|
-
const onFinished = jest.fn();
|
|
918
|
-
|
|
919
|
-
// Try to scroll to same index
|
|
920
|
-
act(() => {
|
|
921
|
-
result.current.scrollTo({ index: 1, animated: false, onFinished });
|
|
922
|
-
});
|
|
923
|
-
|
|
924
|
-
// Should return early and not call onFinished
|
|
925
|
-
expect(onFinished).not.toHaveBeenCalled();
|
|
926
|
-
expect(mockHandlerOffset.value).toBe(-300); // Should remain unchanged
|
|
927
|
-
});
|
|
928
|
-
|
|
929
|
-
it("should handle scrollTo() without animation - uncovered line 294-296", () => {
|
|
930
|
-
const { result } = renderHook(
|
|
931
|
-
() =>
|
|
932
|
-
useCarouselController({
|
|
933
|
-
...defaultProps,
|
|
934
|
-
loop: true,
|
|
935
|
-
}),
|
|
936
|
-
{ wrapper }
|
|
937
|
-
);
|
|
938
|
-
const onFinished = jest.fn();
|
|
939
|
-
|
|
940
|
-
act(() => {
|
|
941
|
-
result.current.scrollTo({ index: 2, animated: false, onFinished });
|
|
942
|
-
});
|
|
943
|
-
|
|
944
|
-
expect(mockHandlerOffset.value).toBe(-600); // size * 2
|
|
945
|
-
expect(onFinished).toHaveBeenCalled();
|
|
946
|
-
});
|
|
947
|
-
|
|
948
|
-
it("should handle scrollTo() with count parameter - uncovered line 321-326", () => {
|
|
949
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
950
|
-
|
|
951
|
-
// Test negative count
|
|
952
|
-
act(() => {
|
|
953
|
-
result.current.scrollTo({ count: -2 });
|
|
954
|
-
});
|
|
955
|
-
|
|
956
|
-
expect(mockHandlerOffset.value).toBe(0); // At start, can't go further back
|
|
957
|
-
|
|
958
|
-
// Reset and test positive count
|
|
959
|
-
act(() => {
|
|
960
|
-
result.current.scrollTo({ count: 2 });
|
|
961
|
-
});
|
|
962
|
-
|
|
963
|
-
expect(mockHandlerOffset.value).toBe(-600); // size * 2
|
|
964
|
-
});
|
|
965
|
-
|
|
966
|
-
it("should handle scrollTo() with invalid count (should return early)", () => {
|
|
967
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
968
|
-
|
|
969
|
-
act(() => {
|
|
970
|
-
result.current.scrollTo({ count: 0 }); // Should return early
|
|
971
|
-
});
|
|
972
|
-
|
|
973
|
-
expect(mockHandlerOffset.value).toBe(0); // Should remain unchanged
|
|
974
|
-
});
|
|
975
|
-
|
|
976
|
-
it("should handle overscroll protection when overscrollEnabled is false", () => {
|
|
977
|
-
const restrictedGlobalState = {
|
|
978
|
-
...mockGlobalState,
|
|
979
|
-
props: {
|
|
980
|
-
...mockGlobalState.props,
|
|
981
|
-
overscrollEnabled: false,
|
|
982
|
-
},
|
|
983
|
-
layout: {
|
|
984
|
-
...mockGlobalState.layout,
|
|
985
|
-
containerSize: { value: { width: 300, height: 300 } },
|
|
986
|
-
},
|
|
987
|
-
} as IContext;
|
|
988
|
-
|
|
989
|
-
const restrictedWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
|
|
990
|
-
<GlobalStateContext.Provider value={restrictedGlobalState}>
|
|
991
|
-
{children}
|
|
992
|
-
</GlobalStateContext.Provider>
|
|
993
|
-
);
|
|
994
|
-
|
|
995
|
-
const { result } = renderHook(
|
|
996
|
-
() =>
|
|
997
|
-
useCarouselController({
|
|
998
|
-
...defaultProps,
|
|
999
|
-
loop: false,
|
|
1000
|
-
dataLength: 4,
|
|
1001
|
-
}),
|
|
1002
|
-
{ wrapper: restrictedWrapper }
|
|
1003
|
-
);
|
|
1004
|
-
|
|
1005
|
-
// Move to index 2 where remaining visible content would be too small
|
|
1006
|
-
act(() => {
|
|
1007
|
-
result.current.scrollTo({ index: 2, animated: false });
|
|
1008
|
-
});
|
|
1009
|
-
|
|
1010
|
-
// Try to move next - should be blocked by overscroll protection
|
|
1011
|
-
act(() => {
|
|
1012
|
-
result.current.next();
|
|
1013
|
-
});
|
|
1014
|
-
|
|
1015
|
-
// The test logic may vary, just ensure it moved
|
|
1016
|
-
expect(typeof mockHandlerOffset.value).toBe("number");
|
|
1017
|
-
});
|
|
1018
|
-
|
|
1019
|
-
it("should call onScrollStart and onScrollEnd callbacks", () => {
|
|
1020
|
-
const onScrollStart = jest.fn();
|
|
1021
|
-
const onScrollEnd = jest.fn();
|
|
1022
|
-
|
|
1023
|
-
const { result } = renderHook(
|
|
1024
|
-
() =>
|
|
1025
|
-
useCarouselController({
|
|
1026
|
-
...defaultProps,
|
|
1027
|
-
onScrollStart,
|
|
1028
|
-
onScrollEnd,
|
|
1029
|
-
}),
|
|
1030
|
-
{ wrapper }
|
|
1031
|
-
);
|
|
1032
|
-
|
|
1033
|
-
act(() => {
|
|
1034
|
-
result.current.next({ animated: true });
|
|
1035
|
-
});
|
|
1036
|
-
|
|
1037
|
-
expect(onScrollStart).toHaveBeenCalled();
|
|
1038
|
-
expect(onScrollEnd).toHaveBeenCalled();
|
|
1039
|
-
});
|
|
1040
|
-
|
|
1041
|
-
it("should handle disabled carousel (empty data)", () => {
|
|
1042
|
-
const { result } = renderHook(
|
|
1043
|
-
() =>
|
|
1044
|
-
useCarouselController({
|
|
1045
|
-
...defaultProps,
|
|
1046
|
-
dataLength: 0,
|
|
1047
|
-
}),
|
|
1048
|
-
{ wrapper }
|
|
1049
|
-
);
|
|
1050
|
-
|
|
1051
|
-
act(() => {
|
|
1052
|
-
result.current.next();
|
|
1053
|
-
});
|
|
1054
|
-
|
|
1055
|
-
expect(mockHandlerOffset.value).toBe(0); // Should not move
|
|
1056
|
-
});
|
|
1057
|
-
|
|
1058
|
-
it("should handle autoFillData with computedRealIndexWithAutoFillData", () => {
|
|
1059
|
-
const { result } = renderHook(
|
|
1060
|
-
() =>
|
|
1061
|
-
useCarouselController({
|
|
1062
|
-
...defaultProps,
|
|
1063
|
-
autoFillData: true,
|
|
1064
|
-
dataLength: 3,
|
|
1065
|
-
}),
|
|
1066
|
-
{ wrapper }
|
|
1067
|
-
);
|
|
1068
|
-
|
|
1069
|
-
act(() => {
|
|
1070
|
-
result.current.next();
|
|
1071
|
-
});
|
|
1072
|
-
|
|
1073
|
-
const currentIndex = result.current.getCurrentIndex();
|
|
1074
|
-
expect(typeof currentIndex).toBe("number");
|
|
1075
|
-
});
|
|
1076
|
-
|
|
1077
|
-
it("should handle positive fixed direction in scrollTo", () => {
|
|
1078
|
-
const { result } = renderHook(
|
|
1079
|
-
() =>
|
|
1080
|
-
useCarouselController({
|
|
1081
|
-
...defaultProps,
|
|
1082
|
-
loop: true,
|
|
1083
|
-
fixedDirection: "positive",
|
|
1084
|
-
}),
|
|
1085
|
-
{ wrapper }
|
|
1086
|
-
);
|
|
1087
|
-
|
|
1088
|
-
act(() => {
|
|
1089
|
-
result.current.scrollTo({ index: 3, animated: false });
|
|
1090
|
-
});
|
|
1091
|
-
|
|
1092
|
-
expect(mockHandlerOffset.value).toBe(900); // size * 3
|
|
1093
|
-
});
|
|
1094
|
-
|
|
1095
|
-
it("should handle negative fixed direction in scrollTo", () => {
|
|
1096
|
-
const { result } = renderHook(
|
|
1097
|
-
() =>
|
|
1098
|
-
useCarouselController({
|
|
1099
|
-
...defaultProps,
|
|
1100
|
-
loop: true,
|
|
1101
|
-
fixedDirection: "negative",
|
|
1102
|
-
}),
|
|
1103
|
-
{ wrapper }
|
|
1104
|
-
);
|
|
1105
|
-
|
|
1106
|
-
act(() => {
|
|
1107
|
-
result.current.scrollTo({ index: 3, animated: false });
|
|
1108
|
-
});
|
|
1109
|
-
|
|
1110
|
-
expect(mockHandlerOffset.value).toBe(-900); // size * 3
|
|
1111
|
-
});
|
|
1112
|
-
|
|
1113
|
-
it("should handle scrollTo when loop position is close to next cycle", () => {
|
|
1114
|
-
const { result } = renderHook(
|
|
1115
|
-
() =>
|
|
1116
|
-
useCarouselController({
|
|
1117
|
-
...defaultProps,
|
|
1118
|
-
loop: true,
|
|
1119
|
-
}),
|
|
1120
|
-
{ wrapper }
|
|
1121
|
-
);
|
|
1122
|
-
|
|
1123
|
-
mockHandlerOffset.value = -900; // 3 * size, more than half-way through current cycle
|
|
1124
|
-
|
|
1125
|
-
act(() => {
|
|
1126
|
-
result.current.scrollTo({ index: 1, animated: false });
|
|
1127
|
-
});
|
|
1128
|
-
|
|
1129
|
-
expect(mockHandlerOffset.value).toBe(-1800);
|
|
1130
|
-
});
|
|
1131
|
-
|
|
1132
|
-
it("should get shared index correctly", () => {
|
|
1133
|
-
const { result } = renderHook(() => useCarouselController(defaultProps), { wrapper });
|
|
1134
|
-
|
|
1135
|
-
const sharedIndex = result.current.getSharedIndex();
|
|
1136
|
-
expect(typeof sharedIndex).toBe("number");
|
|
1137
|
-
});
|
|
1138
|
-
|
|
1139
|
-
it("should handle currentFixedPage calculation for non-loop mode", () => {
|
|
1140
|
-
const { result } = renderHook(
|
|
1141
|
-
() =>
|
|
1142
|
-
useCarouselController({
|
|
1143
|
-
...defaultProps,
|
|
1144
|
-
loop: false,
|
|
1145
|
-
}),
|
|
1146
|
-
{ wrapper }
|
|
1147
|
-
);
|
|
1148
|
-
|
|
1149
|
-
// Set a specific offset to test the calculation
|
|
1150
|
-
mockHandlerOffset.value = -450; // Between indices
|
|
1151
|
-
|
|
1152
|
-
act(() => {
|
|
1153
|
-
result.current.next();
|
|
1154
|
-
});
|
|
1155
|
-
|
|
1156
|
-
expect(typeof mockHandlerOffset.value).toBe("number");
|
|
1157
|
-
});
|
|
1158
|
-
});
|