@assistant-ui/react-native 0.1.41 → 0.1.43
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.d.ts +5 -4
- package/dist/index.js +4 -3
- package/dist/primitives/actionBar/ActionBarCopy.d.ts +3 -3
- package/dist/primitives/actionBar/ActionBarCopy.d.ts.map +1 -1
- package/dist/primitives/actionBar/ActionBarCopy.js +23 -19
- package/dist/primitives/actionBar/ActionBarCopy.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarEdit.d.ts +7 -5
- package/dist/primitives/actionBar/ActionBarEdit.d.ts.map +1 -1
- package/dist/primitives/actionBar/ActionBarEdit.js +21 -11
- package/dist/primitives/actionBar/ActionBarEdit.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts +3 -3
- package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts.map +1 -1
- package/dist/primitives/actionBar/ActionBarFeedbackNegative.js +26 -16
- package/dist/primitives/actionBar/ActionBarFeedbackNegative.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts +3 -3
- package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts.map +1 -1
- package/dist/primitives/actionBar/ActionBarFeedbackPositive.js +26 -16
- package/dist/primitives/actionBar/ActionBarFeedbackPositive.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarReload.d.ts +7 -5
- package/dist/primitives/actionBar/ActionBarReload.d.ts.map +1 -1
- package/dist/primitives/actionBar/ActionBarReload.js +21 -11
- package/dist/primitives/actionBar/ActionBarReload.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarSpeak.d.ts +14 -0
- package/dist/primitives/actionBar/ActionBarSpeak.d.ts.map +1 -0
- package/dist/primitives/actionBar/ActionBarSpeak.js +61 -0
- package/dist/primitives/actionBar/ActionBarSpeak.js.map +1 -0
- package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts +14 -0
- package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts.map +1 -0
- package/dist/primitives/actionBar/ActionBarStopSpeaking.js +61 -0
- package/dist/primitives/actionBar/ActionBarStopSpeaking.js.map +1 -0
- package/dist/primitives/actionBar.d.ts +4 -2
- package/dist/primitives/actionBar.js +6 -2
- package/dist/primitives/actionBar.js.map +1 -1
- package/dist/primitives/attachment/AttachmentName.d.ts +2 -3
- package/dist/primitives/attachment/AttachmentName.d.ts.map +1 -1
- package/dist/primitives/attachment/AttachmentRemove.d.ts +2 -3
- package/dist/primitives/attachment/AttachmentRemove.d.ts.map +1 -1
- package/dist/primitives/attachment/AttachmentRoot.d.ts +2 -3
- package/dist/primitives/attachment/AttachmentRoot.d.ts.map +1 -1
- package/dist/primitives/attachment/AttachmentThumb.d.ts +2 -3
- package/dist/primitives/attachment/AttachmentThumb.d.ts.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerCount.d.ts +2 -3
- package/dist/primitives/branchPicker/BranchPickerCount.d.ts.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerNext.d.ts +7 -5
- package/dist/primitives/branchPicker/BranchPickerNext.d.ts.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerNext.js +21 -11
- package/dist/primitives/branchPicker/BranchPickerNext.js.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerNumber.d.ts +2 -3
- package/dist/primitives/branchPicker/BranchPickerNumber.d.ts.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts +7 -5
- package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerPrevious.js +21 -11
- package/dist/primitives/branchPicker/BranchPickerPrevious.js.map +1 -1
- package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts +2 -3
- package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts.map +1 -1
- package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts +2 -3
- package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerAddAttachment.d.ts +4 -7
- package/dist/primitives/composer/ComposerAddAttachment.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerAddAttachment.js +2 -4
- package/dist/primitives/composer/ComposerAddAttachment.js.map +1 -1
- package/dist/primitives/composer/ComposerAttachments.d.ts +4 -5
- package/dist/primitives/composer/ComposerAttachments.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerCancel.d.ts +2 -3
- package/dist/primitives/composer/ComposerCancel.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerInput.d.ts +2 -3
- package/dist/primitives/composer/ComposerInput.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerQuote.d.ts +2 -3
- package/dist/primitives/composer/ComposerQuote.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerQuoteDismiss.d.ts +2 -3
- package/dist/primitives/composer/ComposerQuoteDismiss.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerQuoteText.d.ts +2 -3
- package/dist/primitives/composer/ComposerQuoteText.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerRoot.d.ts +2 -3
- package/dist/primitives/composer/ComposerRoot.d.ts.map +1 -1
- package/dist/primitives/composer/ComposerSend.d.ts +2 -3
- package/dist/primitives/composer/ComposerSend.d.ts.map +1 -1
- package/dist/primitives/error/ErrorMessage.d.ts +2 -3
- package/dist/primitives/error/ErrorMessage.d.ts.map +1 -1
- package/dist/primitives/error/ErrorRoot.d.ts +2 -3
- package/dist/primitives/error/ErrorRoot.d.ts.map +1 -1
- package/dist/primitives/message/MessageAttachments.d.ts +4 -5
- package/dist/primitives/message/MessageAttachments.d.ts.map +1 -1
- package/dist/primitives/message/MessageContent.d.ts +2 -3
- package/dist/primitives/message/MessageContent.d.ts.map +1 -1
- package/dist/primitives/message/MessageIf.d.ts +2 -3
- package/dist/primitives/message/MessageIf.d.ts.map +1 -1
- package/dist/primitives/message/MessageParts.d.ts +3 -3
- package/dist/primitives/message/MessageParts.d.ts.map +1 -1
- package/dist/primitives/message/MessageRoot.d.ts +2 -3
- package/dist/primitives/message/MessageRoot.d.ts.map +1 -1
- package/dist/primitives/messagePart/MessagePartImage.d.ts +11 -0
- package/dist/primitives/messagePart/MessagePartImage.d.ts.map +1 -0
- package/dist/primitives/messagePart/MessagePartImage.js +39 -0
- package/dist/primitives/messagePart/MessagePartImage.js.map +1 -0
- package/dist/primitives/messagePart/MessagePartInProgress.d.ts +2 -0
- package/dist/primitives/messagePart/MessagePartInProgress.js +2 -0
- package/dist/primitives/messagePart/MessagePartText.d.ts +11 -0
- package/dist/primitives/messagePart/MessagePartText.d.ts.map +1 -0
- package/dist/primitives/messagePart/MessagePartText.js +32 -0
- package/dist/primitives/messagePart/MessagePartText.js.map +1 -0
- package/dist/primitives/messagePart.d.ts +10 -0
- package/dist/primitives/messagePart.d.ts.map +1 -0
- package/dist/primitives/messagePart.js +16 -0
- package/dist/primitives/messagePart.js.map +1 -0
- package/dist/primitives/queueItem/QueueItemRemove.d.ts +2 -3
- package/dist/primitives/queueItem/QueueItemRemove.d.ts.map +1 -1
- package/dist/primitives/queueItem/QueueItemSteer.d.ts +2 -3
- package/dist/primitives/queueItem/QueueItemSteer.d.ts.map +1 -1
- package/dist/primitives/queueItem/QueueItemText.d.ts +2 -3
- package/dist/primitives/queueItem/QueueItemText.d.ts.map +1 -1
- package/dist/primitives/suggestion/SuggestionDescription.d.ts +2 -3
- package/dist/primitives/suggestion/SuggestionDescription.d.ts.map +1 -1
- package/dist/primitives/suggestion/SuggestionTitle.d.ts +2 -3
- package/dist/primitives/suggestion/SuggestionTitle.d.ts.map +1 -1
- package/dist/primitives/suggestion/SuggestionTrigger.d.ts +2 -3
- package/dist/primitives/suggestion/SuggestionTrigger.d.ts.map +1 -1
- package/dist/primitives/thread/ThreadEmpty.d.ts +2 -3
- package/dist/primitives/thread/ThreadEmpty.d.ts.map +1 -1
- package/dist/primitives/thread/ThreadIf.d.ts +2 -3
- package/dist/primitives/thread/ThreadIf.d.ts.map +1 -1
- package/dist/primitives/thread/ThreadMessages.d.ts +9 -5
- package/dist/primitives/thread/ThreadMessages.d.ts.map +1 -1
- package/dist/primitives/thread/ThreadMessages.js +244 -171
- package/dist/primitives/thread/ThreadMessages.js.map +1 -1
- package/dist/primitives/thread/ThreadRoot.d.ts +2 -3
- package/dist/primitives/thread/ThreadRoot.d.ts.map +1 -1
- package/dist/primitives/thread/ThreadSuggestion.d.ts +2 -3
- package/dist/primitives/thread/ThreadSuggestion.d.ts.map +1 -1
- package/dist/primitives/threadList/ThreadListItems.d.ts +2 -3
- package/dist/primitives/threadList/ThreadListItems.d.ts.map +1 -1
- package/dist/primitives/threadList/ThreadListNew.d.ts +2 -3
- package/dist/primitives/threadList/ThreadListNew.d.ts.map +1 -1
- package/dist/primitives/threadList/ThreadListRoot.d.ts +2 -3
- package/dist/primitives/threadList/ThreadListRoot.d.ts.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts +2 -3
- package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts +2 -3
- package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts +2 -3
- package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts +2 -3
- package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts +2 -3
- package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts.map +1 -1
- package/package.json +13 -11
- package/src/index.ts +30 -0
- package/src/primitives/accessibilityRole.test.tsx +20 -0
- package/src/primitives/actionBar/ActionBar.test.tsx +299 -0
- package/src/primitives/actionBar/ActionBarCopy.tsx +8 -3
- package/src/primitives/actionBar/ActionBarEdit.tsx +16 -4
- package/src/primitives/actionBar/ActionBarFeedbackNegative.tsx +14 -3
- package/src/primitives/actionBar/ActionBarFeedbackPositive.tsx +14 -3
- package/src/primitives/actionBar/ActionBarReload.tsx +16 -4
- package/src/primitives/actionBar/ActionBarSpeak.tsx +42 -0
- package/src/primitives/actionBar/ActionBarStopSpeaking.tsx +42 -0
- package/src/primitives/actionBar.ts +8 -0
- package/src/primitives/branchPicker/BranchPickerNext.test.tsx +52 -3
- package/src/primitives/branchPicker/BranchPickerNext.tsx +16 -4
- package/src/primitives/branchPicker/BranchPickerPrevious.test.tsx +52 -6
- package/src/primitives/branchPicker/BranchPickerPrevious.tsx +16 -4
- package/src/primitives/composer/ComposerAddAttachment.tsx +3 -8
- package/src/primitives/messagePart/MessagePartImage.test.tsx +91 -0
- package/src/primitives/messagePart/MessagePartImage.tsx +33 -0
- package/src/primitives/messagePart/MessagePartInProgress.ts +1 -0
- package/src/primitives/messagePart/MessagePartText.test.tsx +80 -0
- package/src/primitives/messagePart/MessagePartText.tsx +36 -0
- package/src/primitives/messagePart.ts +10 -0
- package/src/primitives/thread/ThreadMessages.test.tsx +335 -54
- package/src/primitives/thread/ThreadMessages.tsx +104 -26
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { act, createRef } from "react";
|
|
2
2
|
import { createRoot, type Root } from "react-dom/client";
|
|
3
3
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
-
import type { FlatList } from "react-native";
|
|
4
|
+
import type { FlatList, FlatListProps } from "react-native";
|
|
5
5
|
import type { ThreadMessage } from "@assistant-ui/core";
|
|
6
6
|
import { ThreadMessages, ThreadMessagesFlatList } from "./ThreadMessages";
|
|
7
7
|
|
|
@@ -15,7 +15,7 @@ const h = vi.hoisted(() => ({
|
|
|
15
15
|
itemState: { role: "user" } as { role: string },
|
|
16
16
|
events: {} as Record<string, Set<() => void>>,
|
|
17
17
|
flatListProps: null as Record<string, unknown> | null,
|
|
18
|
-
|
|
18
|
+
scrollToOffset: vi.fn(),
|
|
19
19
|
}));
|
|
20
20
|
|
|
21
21
|
vi.mock("react-native", async (importOriginal) => {
|
|
@@ -29,7 +29,7 @@ vi.mock("react-native", async (importOriginal) => {
|
|
|
29
29
|
h.flatListProps = props;
|
|
30
30
|
|
|
31
31
|
React.useImperativeHandle(ref, () => ({
|
|
32
|
-
|
|
32
|
+
scrollToOffset: h.scrollToOffset,
|
|
33
33
|
}));
|
|
34
34
|
|
|
35
35
|
const data = (props.data as unknown[]) ?? [];
|
|
@@ -121,7 +121,7 @@ describe("ThreadMessages", () => {
|
|
|
121
121
|
h.itemState = { role: "user" };
|
|
122
122
|
h.events = {};
|
|
123
123
|
h.flatListProps = null;
|
|
124
|
-
h.
|
|
124
|
+
h.scrollToOffset.mockReset();
|
|
125
125
|
|
|
126
126
|
container = document.createElement("div");
|
|
127
127
|
document.body.appendChild(container);
|
|
@@ -154,6 +154,10 @@ describe("ThreadMessages", () => {
|
|
|
154
154
|
onContentSizeChange?: (width: number, height: number) => void;
|
|
155
155
|
onLayout?: (event: unknown) => void;
|
|
156
156
|
onScroll?: (event: unknown) => void;
|
|
157
|
+
onStartReached?: NonNullable<
|
|
158
|
+
FlatListProps<ThreadMessage>["onStartReached"]
|
|
159
|
+
>;
|
|
160
|
+
onStartReachedThreshold?: number;
|
|
157
161
|
scrollEventThrottle?: number;
|
|
158
162
|
} | null;
|
|
159
163
|
if (!props) throw new Error("FlatList was not rendered");
|
|
@@ -338,6 +342,25 @@ describe("ThreadMessages", () => {
|
|
|
338
342
|
expect(ref.current).not.toBeNull();
|
|
339
343
|
});
|
|
340
344
|
|
|
345
|
+
it("anchors the visible message while content is inserted above it", async () => {
|
|
346
|
+
await mountFlatList({ children: () => null });
|
|
347
|
+
|
|
348
|
+
expect(h.flatListProps?.maintainVisibleContentPosition).toEqual({
|
|
349
|
+
minIndexForVisible: 0,
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it("lets the app override the visible content anchor", async () => {
|
|
354
|
+
await mountFlatList({
|
|
355
|
+
children: () => null,
|
|
356
|
+
maintainVisibleContentPosition: { minIndexForVisible: 2 },
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
expect(h.flatListProps?.maintainVisibleContentPosition).toEqual({
|
|
360
|
+
minIndexForVisible: 2,
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
|
|
341
364
|
it("keeps deprecated Messages off the scroll-tracking path", async () => {
|
|
342
365
|
h.state.thread.messages = [{ id: "1", role: "user" }];
|
|
343
366
|
await mount({ components: messageComponents });
|
|
@@ -370,7 +393,81 @@ describe("ThreadMessages", () => {
|
|
|
370
393
|
await emit("thread.runStart");
|
|
371
394
|
await emit("threads.selectionChanged");
|
|
372
395
|
|
|
373
|
-
expect(h.
|
|
396
|
+
expect(h.scrollToOffset).not.toHaveBeenCalled();
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
describe("MessagesFlatList history", () => {
|
|
400
|
+
it("wires loadMore only while history can load more", async () => {
|
|
401
|
+
const loadMore = vi.fn();
|
|
402
|
+
|
|
403
|
+
await mountFlatList({
|
|
404
|
+
components: messageComponents,
|
|
405
|
+
history: { hasMore: true, isLoadingMore: false, loadMore },
|
|
406
|
+
});
|
|
407
|
+
getFlatListProps().onStartReached?.({ distanceFromStart: 0 });
|
|
408
|
+
expect(loadMore).toHaveBeenCalledOnce();
|
|
409
|
+
|
|
410
|
+
await mountFlatList({
|
|
411
|
+
components: messageComponents,
|
|
412
|
+
history: { hasMore: false, isLoadingMore: false, loadMore },
|
|
413
|
+
});
|
|
414
|
+
expect(getFlatListProps().onStartReached).toBeUndefined();
|
|
415
|
+
|
|
416
|
+
await mountFlatList({
|
|
417
|
+
components: messageComponents,
|
|
418
|
+
history: { hasMore: true, isLoadingMore: true, loadMore },
|
|
419
|
+
});
|
|
420
|
+
expect(getFlatListProps().onStartReached).toBeUndefined();
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it("defaults the history threshold and preserves a caller override", async () => {
|
|
424
|
+
const history = {
|
|
425
|
+
hasMore: true,
|
|
426
|
+
isLoadingMore: false,
|
|
427
|
+
loadMore: vi.fn(),
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
await mountFlatList({ components: messageComponents, history });
|
|
431
|
+
expect(getFlatListProps().onStartReachedThreshold).toBe(1);
|
|
432
|
+
|
|
433
|
+
await mountFlatList({
|
|
434
|
+
components: messageComponents,
|
|
435
|
+
history,
|
|
436
|
+
onStartReachedThreshold: 0.5,
|
|
437
|
+
});
|
|
438
|
+
expect(getFlatListProps().onStartReachedThreshold).toBe(0.5);
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
it("runs a caller onStartReached before loading more history", async () => {
|
|
442
|
+
const calls: string[] = [];
|
|
443
|
+
const info = { distanceFromStart: 42 };
|
|
444
|
+
const onStartReached = vi.fn(() => calls.push("onStartReached"));
|
|
445
|
+
|
|
446
|
+
await mountFlatList({
|
|
447
|
+
components: messageComponents,
|
|
448
|
+
history: {
|
|
449
|
+
hasMore: true,
|
|
450
|
+
isLoadingMore: false,
|
|
451
|
+
loadMore: () => calls.push("loadMore"),
|
|
452
|
+
},
|
|
453
|
+
onStartReached,
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
getFlatListProps().onStartReached?.(info);
|
|
457
|
+
|
|
458
|
+
expect(onStartReached).toHaveBeenCalledWith(info);
|
|
459
|
+
expect(calls).toEqual(["onStartReached", "loadMore"]);
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
it("leaves start-reached props untouched without history", async () => {
|
|
463
|
+
const onStartReached = vi.fn();
|
|
464
|
+
|
|
465
|
+
await mountFlatList({ components: messageComponents, onStartReached });
|
|
466
|
+
|
|
467
|
+
const props = getFlatListProps();
|
|
468
|
+
expect(props.onStartReached).toBe(onStartReached);
|
|
469
|
+
expect(props).not.toHaveProperty("onStartReachedThreshold");
|
|
470
|
+
});
|
|
374
471
|
});
|
|
375
472
|
|
|
376
473
|
describe("MessagesFlatList auto-scroll", () => {
|
|
@@ -379,24 +476,30 @@ describe("ThreadMessages", () => {
|
|
|
379
476
|
|
|
380
477
|
await mountFlatList({ components: messageComponents });
|
|
381
478
|
|
|
382
|
-
expect(h.
|
|
479
|
+
expect(h.scrollToOffset).toHaveBeenCalledWith({
|
|
480
|
+
animated: false,
|
|
481
|
+
offset: 0,
|
|
482
|
+
});
|
|
383
483
|
});
|
|
384
484
|
|
|
385
485
|
it("scrolls to the bottom when a run starts", async () => {
|
|
386
486
|
h.state.thread.messages = [{ id: "1", role: "user" }];
|
|
387
487
|
await mountFlatList({ components: messageComponents });
|
|
388
|
-
h.
|
|
488
|
+
h.scrollToOffset.mockClear();
|
|
389
489
|
|
|
390
490
|
await emit("thread.runStart");
|
|
391
491
|
|
|
392
|
-
expect(h.
|
|
492
|
+
expect(h.scrollToOffset).toHaveBeenCalledWith({
|
|
493
|
+
animated: true,
|
|
494
|
+
offset: 0,
|
|
495
|
+
});
|
|
393
496
|
});
|
|
394
497
|
|
|
395
498
|
it("scrolls when content grows while already at the bottom", async () => {
|
|
396
499
|
h.state.thread.messages = [{ id: "1", role: "user" }];
|
|
397
500
|
await mountFlatList({ components: messageComponents });
|
|
398
501
|
const props = getFlatListProps();
|
|
399
|
-
h.
|
|
502
|
+
h.scrollToOffset.mockClear();
|
|
400
503
|
|
|
401
504
|
await act(async () => {
|
|
402
505
|
props.onLayout?.({
|
|
@@ -412,7 +515,10 @@ describe("ThreadMessages", () => {
|
|
|
412
515
|
props.onContentSizeChange?.(0, 140);
|
|
413
516
|
});
|
|
414
517
|
|
|
415
|
-
expect(h.
|
|
518
|
+
expect(h.scrollToOffset).toHaveBeenCalledWith({
|
|
519
|
+
animated: false,
|
|
520
|
+
offset: 40,
|
|
521
|
+
});
|
|
416
522
|
});
|
|
417
523
|
|
|
418
524
|
it("does not treat the first content-size event as automatic content growth", async () => {
|
|
@@ -427,7 +533,7 @@ describe("ThreadMessages", () => {
|
|
|
427
533
|
props.onContentSizeChange?.(0, 140);
|
|
428
534
|
});
|
|
429
535
|
|
|
430
|
-
expect(h.
|
|
536
|
+
expect(h.scrollToOffset).not.toHaveBeenCalled();
|
|
431
537
|
});
|
|
432
538
|
|
|
433
539
|
it("lands the initialize scroll on the first content-size event", async () => {
|
|
@@ -435,35 +541,151 @@ describe("ThreadMessages", () => {
|
|
|
435
541
|
await mountFlatList({ components: messageComponents });
|
|
436
542
|
const props = getFlatListProps();
|
|
437
543
|
|
|
438
|
-
expect(h.
|
|
544
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(1);
|
|
439
545
|
|
|
440
546
|
await act(async () => {
|
|
547
|
+
props.onLayout?.({
|
|
548
|
+
nativeEvent: { layout: { height: 100 } },
|
|
549
|
+
});
|
|
441
550
|
props.onContentSizeChange?.(0, 140);
|
|
442
551
|
});
|
|
443
552
|
|
|
444
|
-
expect(h.
|
|
553
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(2);
|
|
554
|
+
expect(h.scrollToOffset).toHaveBeenLastCalledWith({
|
|
555
|
+
animated: false,
|
|
556
|
+
offset: 40,
|
|
557
|
+
});
|
|
445
558
|
|
|
446
559
|
await act(async () => {
|
|
447
560
|
props.onContentSizeChange?.(0, 140);
|
|
448
561
|
});
|
|
449
562
|
|
|
450
|
-
expect(h.
|
|
563
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(2);
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
it("waits for the first layout before consuming a measured initialize scroll", async () => {
|
|
567
|
+
h.state.thread.messages = [{ id: "1", role: "user" }];
|
|
568
|
+
await mountFlatList({ components: messageComponents });
|
|
569
|
+
const props = getFlatListProps();
|
|
570
|
+
|
|
571
|
+
await act(async () => {
|
|
572
|
+
props.onContentSizeChange?.(0, 140);
|
|
573
|
+
});
|
|
574
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(1);
|
|
575
|
+
|
|
576
|
+
await act(async () => {
|
|
577
|
+
props.onLayout?.({
|
|
578
|
+
nativeEvent: { layout: { height: 100 } },
|
|
579
|
+
});
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(2);
|
|
583
|
+
expect(h.scrollToOffset).toHaveBeenLastCalledWith({
|
|
584
|
+
animated: false,
|
|
585
|
+
offset: 40,
|
|
586
|
+
});
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
it("keeps the initialize scroll pending through a zero content measurement", async () => {
|
|
590
|
+
h.state.thread.messages = [{ id: "1", role: "user" }];
|
|
591
|
+
await mountFlatList({ components: messageComponents });
|
|
592
|
+
const props = getFlatListProps();
|
|
593
|
+
|
|
594
|
+
await act(async () => {
|
|
595
|
+
props.onLayout?.({
|
|
596
|
+
nativeEvent: { layout: { height: 100 } },
|
|
597
|
+
});
|
|
598
|
+
props.onContentSizeChange?.(0, 0);
|
|
599
|
+
});
|
|
600
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(1);
|
|
601
|
+
|
|
602
|
+
await act(async () => {
|
|
603
|
+
props.onContentSizeChange?.(0, 300);
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(2);
|
|
607
|
+
expect(h.scrollToOffset).toHaveBeenLastCalledWith({
|
|
608
|
+
animated: false,
|
|
609
|
+
offset: 200,
|
|
610
|
+
});
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
it("uses horizontal measurements for horizontal lists", async () => {
|
|
614
|
+
h.state.thread.messages = [{ id: "1", role: "user" }];
|
|
615
|
+
await mountFlatList({ components: messageComponents, horizontal: true });
|
|
616
|
+
const props = getFlatListProps();
|
|
617
|
+
|
|
618
|
+
await act(async () => {
|
|
619
|
+
props.onLayout?.({
|
|
620
|
+
nativeEvent: { layout: { width: 100 } },
|
|
621
|
+
});
|
|
622
|
+
props.onContentSizeChange?.(140, 0);
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
expect(h.scrollToOffset).toHaveBeenLastCalledWith({
|
|
626
|
+
animated: false,
|
|
627
|
+
offset: 40,
|
|
628
|
+
});
|
|
451
629
|
});
|
|
452
630
|
|
|
453
631
|
it("lands the thread-switch scroll on the next content-size event", async () => {
|
|
454
632
|
h.state.thread.messages = [{ id: "1", role: "user" }];
|
|
455
633
|
await mountFlatList({ components: messageComponents });
|
|
456
634
|
const props = getFlatListProps();
|
|
457
|
-
h.
|
|
635
|
+
h.scrollToOffset.mockClear();
|
|
458
636
|
|
|
459
637
|
await emit("threads.selectionChanged");
|
|
460
|
-
expect(h.
|
|
638
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(1);
|
|
639
|
+
|
|
640
|
+
await act(async () => {
|
|
641
|
+
props.onContentSizeChange?.(0, 300);
|
|
642
|
+
});
|
|
643
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(1);
|
|
644
|
+
|
|
645
|
+
await act(async () => {
|
|
646
|
+
props.onLayout?.({
|
|
647
|
+
nativeEvent: { layout: { height: 100 } },
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(2);
|
|
652
|
+
expect(h.scrollToOffset).toHaveBeenLastCalledWith({
|
|
653
|
+
animated: false,
|
|
654
|
+
offset: 200,
|
|
655
|
+
});
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
it("does not consume a thread-switch scroll with the previous thread metrics", async () => {
|
|
659
|
+
h.state.thread.messages = [{ id: "1", role: "user" }];
|
|
660
|
+
await mountFlatList({ components: messageComponents });
|
|
661
|
+
const props = getFlatListProps();
|
|
662
|
+
|
|
663
|
+
await act(async () => {
|
|
664
|
+
props.onLayout?.({
|
|
665
|
+
nativeEvent: { layout: { height: 100 } },
|
|
666
|
+
});
|
|
667
|
+
props.onScroll?.({
|
|
668
|
+
nativeEvent: {
|
|
669
|
+
contentOffset: { y: 200 },
|
|
670
|
+
contentSize: { height: 300, width: 0 },
|
|
671
|
+
layoutMeasurement: { height: 100, width: 0 },
|
|
672
|
+
},
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
h.scrollToOffset.mockClear();
|
|
461
676
|
|
|
677
|
+
await emit("threads.selectionChanged");
|
|
462
678
|
await act(async () => {
|
|
463
|
-
props.
|
|
679
|
+
props.onLayout?.({
|
|
680
|
+
nativeEvent: { layout: { height: 80 } },
|
|
681
|
+
});
|
|
682
|
+
props.onContentSizeChange?.(0, 260);
|
|
464
683
|
});
|
|
465
684
|
|
|
466
|
-
expect(h.
|
|
685
|
+
expect(h.scrollToOffset).toHaveBeenLastCalledWith({
|
|
686
|
+
animated: false,
|
|
687
|
+
offset: 180,
|
|
688
|
+
});
|
|
467
689
|
});
|
|
468
690
|
|
|
469
691
|
it("keeps following through consecutive growth events without scroll echoes", async () => {
|
|
@@ -483,7 +705,7 @@ describe("ThreadMessages", () => {
|
|
|
483
705
|
},
|
|
484
706
|
});
|
|
485
707
|
});
|
|
486
|
-
h.
|
|
708
|
+
h.scrollToOffset.mockClear();
|
|
487
709
|
|
|
488
710
|
await act(async () => {
|
|
489
711
|
props.onContentSizeChange?.(0, 140);
|
|
@@ -492,14 +714,14 @@ describe("ThreadMessages", () => {
|
|
|
492
714
|
props.onContentSizeChange?.(0, 180);
|
|
493
715
|
});
|
|
494
716
|
|
|
495
|
-
expect(h.
|
|
717
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(2);
|
|
496
718
|
});
|
|
497
719
|
|
|
498
720
|
it("does not scroll when content grows after the user scrolled away", async () => {
|
|
499
721
|
h.state.thread.messages = [{ id: "1", role: "user" }];
|
|
500
722
|
await mountFlatList({ components: messageComponents });
|
|
501
723
|
const props = getFlatListProps();
|
|
502
|
-
h.
|
|
724
|
+
h.scrollToOffset.mockClear();
|
|
503
725
|
|
|
504
726
|
await act(async () => {
|
|
505
727
|
props.onLayout?.({
|
|
@@ -522,7 +744,7 @@ describe("ThreadMessages", () => {
|
|
|
522
744
|
props.onContentSizeChange?.(0, 340);
|
|
523
745
|
});
|
|
524
746
|
|
|
525
|
-
expect(h.
|
|
747
|
+
expect(h.scrollToOffset).not.toHaveBeenCalled();
|
|
526
748
|
});
|
|
527
749
|
|
|
528
750
|
it("lands the run-start scroll once the appended message resizes content", async () => {
|
|
@@ -549,10 +771,10 @@ describe("ThreadMessages", () => {
|
|
|
549
771
|
},
|
|
550
772
|
});
|
|
551
773
|
});
|
|
552
|
-
h.
|
|
774
|
+
h.scrollToOffset.mockClear();
|
|
553
775
|
|
|
554
776
|
await emit("thread.runStart");
|
|
555
|
-
expect(h.
|
|
777
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(1);
|
|
556
778
|
|
|
557
779
|
await act(async () => {
|
|
558
780
|
props.onScroll?.({
|
|
@@ -565,18 +787,39 @@ describe("ThreadMessages", () => {
|
|
|
565
787
|
props.onContentSizeChange?.(0, 360);
|
|
566
788
|
});
|
|
567
789
|
|
|
568
|
-
expect(h.
|
|
569
|
-
expect(h.
|
|
790
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(2);
|
|
791
|
+
expect(h.scrollToOffset).toHaveBeenLastCalledWith({
|
|
792
|
+
animated: true,
|
|
793
|
+
offset: 260,
|
|
794
|
+
});
|
|
570
795
|
});
|
|
571
796
|
|
|
572
|
-
it("
|
|
797
|
+
it("uses the measured bottom when a thread switch does not resize content", async () => {
|
|
573
798
|
h.state.thread.messages = [{ id: "1", role: "user" }];
|
|
574
799
|
await mountFlatList({ components: messageComponents });
|
|
575
|
-
|
|
800
|
+
const props = getFlatListProps();
|
|
801
|
+
|
|
802
|
+
await act(async () => {
|
|
803
|
+
props.onLayout?.({
|
|
804
|
+
nativeEvent: { layout: { height: 100 } },
|
|
805
|
+
});
|
|
806
|
+
props.onScroll?.({
|
|
807
|
+
nativeEvent: {
|
|
808
|
+
contentOffset: { y: 120 },
|
|
809
|
+
contentSize: { height: 300, width: 0 },
|
|
810
|
+
layoutMeasurement: { height: 100, width: 0 },
|
|
811
|
+
},
|
|
812
|
+
});
|
|
813
|
+
});
|
|
814
|
+
h.scrollToOffset.mockClear();
|
|
576
815
|
|
|
577
816
|
await emit("threads.selectionChanged");
|
|
578
817
|
|
|
579
|
-
expect(h.
|
|
818
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(1);
|
|
819
|
+
expect(h.scrollToOffset).toHaveBeenCalledWith({
|
|
820
|
+
animated: false,
|
|
821
|
+
offset: 200,
|
|
822
|
+
});
|
|
580
823
|
});
|
|
581
824
|
|
|
582
825
|
it("does not rearm initialize scroll when thread-switch scroll is disabled", async () => {
|
|
@@ -585,7 +828,7 @@ describe("ThreadMessages", () => {
|
|
|
585
828
|
components: messageComponents,
|
|
586
829
|
scrollToBottomOnThreadSwitch: false,
|
|
587
830
|
});
|
|
588
|
-
h.
|
|
831
|
+
h.scrollToOffset.mockClear();
|
|
589
832
|
|
|
590
833
|
await emit("threads.selectionChanged");
|
|
591
834
|
|
|
@@ -598,7 +841,7 @@ describe("ThreadMessages", () => {
|
|
|
598
841
|
scrollToBottomOnThreadSwitch: false,
|
|
599
842
|
});
|
|
600
843
|
|
|
601
|
-
expect(h.
|
|
844
|
+
expect(h.scrollToOffset).not.toHaveBeenCalled();
|
|
602
845
|
});
|
|
603
846
|
|
|
604
847
|
it("honors opt-outs for automatic content growth and run-start scrolls", async () => {
|
|
@@ -610,7 +853,7 @@ describe("ThreadMessages", () => {
|
|
|
610
853
|
scrollToBottomOnRunStart: false,
|
|
611
854
|
});
|
|
612
855
|
const props = getFlatListProps();
|
|
613
|
-
h.
|
|
856
|
+
h.scrollToOffset.mockClear();
|
|
614
857
|
|
|
615
858
|
await act(async () => {
|
|
616
859
|
props.onLayout?.({
|
|
@@ -627,7 +870,7 @@ describe("ThreadMessages", () => {
|
|
|
627
870
|
});
|
|
628
871
|
await emit("thread.runStart");
|
|
629
872
|
|
|
630
|
-
expect(h.
|
|
873
|
+
expect(h.scrollToOffset).not.toHaveBeenCalled();
|
|
631
874
|
});
|
|
632
875
|
|
|
633
876
|
it("sets a useful default scroll throttle", async () => {
|
|
@@ -655,10 +898,32 @@ describe("ThreadMessages", () => {
|
|
|
655
898
|
});
|
|
656
899
|
props.onContentSizeChange?.(0, 300);
|
|
657
900
|
});
|
|
658
|
-
h.
|
|
901
|
+
h.scrollToOffset.mockClear();
|
|
659
902
|
return props;
|
|
660
903
|
};
|
|
661
904
|
|
|
905
|
+
it("stays pinned when an anchor adjustment moves the offset with the content above it", async () => {
|
|
906
|
+
const props = await mountPinned();
|
|
907
|
+
|
|
908
|
+
await act(async () => {
|
|
909
|
+
props.onScroll?.({
|
|
910
|
+
nativeEvent: {
|
|
911
|
+
contentOffset: { y: 180 },
|
|
912
|
+
contentSize: { height: 280, width: 0 },
|
|
913
|
+
layoutMeasurement: { height: 100, width: 0 },
|
|
914
|
+
},
|
|
915
|
+
});
|
|
916
|
+
});
|
|
917
|
+
await act(async () => {
|
|
918
|
+
props.onContentSizeChange?.(0, 320);
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
expect(h.scrollToOffset).toHaveBeenCalledWith({
|
|
922
|
+
animated: false,
|
|
923
|
+
offset: 220,
|
|
924
|
+
});
|
|
925
|
+
});
|
|
926
|
+
|
|
662
927
|
it("stays pinned when the viewport shrinks while at the bottom", async () => {
|
|
663
928
|
const props = await mountPinned();
|
|
664
929
|
|
|
@@ -667,12 +932,15 @@ describe("ThreadMessages", () => {
|
|
|
667
932
|
nativeEvent: { layout: { height: 60 } },
|
|
668
933
|
});
|
|
669
934
|
});
|
|
670
|
-
h.
|
|
935
|
+
h.scrollToOffset.mockClear();
|
|
671
936
|
await act(async () => {
|
|
672
937
|
props.onContentSizeChange?.(0, 340);
|
|
673
938
|
});
|
|
674
939
|
|
|
675
|
-
expect(h.
|
|
940
|
+
expect(h.scrollToOffset).toHaveBeenCalledWith({
|
|
941
|
+
animated: false,
|
|
942
|
+
offset: 280,
|
|
943
|
+
});
|
|
676
944
|
});
|
|
677
945
|
|
|
678
946
|
it("commands a bottom scroll when the viewport shrinks while pinned", async () => {
|
|
@@ -684,22 +952,29 @@ describe("ThreadMessages", () => {
|
|
|
684
952
|
});
|
|
685
953
|
});
|
|
686
954
|
|
|
687
|
-
expect(h.
|
|
955
|
+
expect(h.scrollToOffset).toHaveBeenCalledWith({
|
|
956
|
+
animated: false,
|
|
957
|
+
offset: 240,
|
|
958
|
+
});
|
|
688
959
|
});
|
|
689
960
|
|
|
690
961
|
it("preserves a pending animated scroll on a pinned viewport change", async () => {
|
|
691
962
|
const props = await mountPinned();
|
|
692
963
|
|
|
693
964
|
await emit("thread.runStart");
|
|
694
|
-
h.
|
|
965
|
+
h.scrollToOffset.mockClear();
|
|
695
966
|
await act(async () => {
|
|
696
967
|
props.onLayout?.({
|
|
697
968
|
nativeEvent: { layout: { height: 60 } },
|
|
698
969
|
});
|
|
970
|
+
props.onContentSizeChange?.(0, 360);
|
|
699
971
|
});
|
|
700
972
|
|
|
701
|
-
expect(h.
|
|
702
|
-
expect(h.
|
|
973
|
+
expect(h.scrollToOffset).toHaveBeenCalledTimes(2);
|
|
974
|
+
expect(h.scrollToOffset).toHaveBeenLastCalledWith({
|
|
975
|
+
animated: true,
|
|
976
|
+
offset: 300,
|
|
977
|
+
});
|
|
703
978
|
});
|
|
704
979
|
|
|
705
980
|
it("ignores a layout event with an unchanged viewport height", async () => {
|
|
@@ -711,13 +986,13 @@ describe("ThreadMessages", () => {
|
|
|
711
986
|
});
|
|
712
987
|
});
|
|
713
988
|
|
|
714
|
-
expect(h.
|
|
989
|
+
expect(h.scrollToOffset).not.toHaveBeenCalled();
|
|
715
990
|
});
|
|
716
991
|
|
|
717
992
|
it("does not command a scroll on the first layout measurement", async () => {
|
|
718
993
|
await mountFlatList({ components: messageComponents });
|
|
719
994
|
getFlatListProps();
|
|
720
|
-
h.
|
|
995
|
+
h.scrollToOffset.mockClear();
|
|
721
996
|
|
|
722
997
|
await act(async () => {
|
|
723
998
|
getFlatListProps().onLayout?.({
|
|
@@ -725,7 +1000,7 @@ describe("ThreadMessages", () => {
|
|
|
725
1000
|
});
|
|
726
1001
|
});
|
|
727
1002
|
|
|
728
|
-
expect(h.
|
|
1003
|
+
expect(h.scrollToOffset).not.toHaveBeenCalled();
|
|
729
1004
|
});
|
|
730
1005
|
|
|
731
1006
|
it("does not command a scroll on viewport change when autoScroll is off", async () => {
|
|
@@ -744,7 +1019,7 @@ describe("ThreadMessages", () => {
|
|
|
744
1019
|
});
|
|
745
1020
|
props.onContentSizeChange?.(0, 300);
|
|
746
1021
|
});
|
|
747
|
-
h.
|
|
1022
|
+
h.scrollToOffset.mockClear();
|
|
748
1023
|
|
|
749
1024
|
await act(async () => {
|
|
750
1025
|
props.onLayout?.({
|
|
@@ -752,7 +1027,7 @@ describe("ThreadMessages", () => {
|
|
|
752
1027
|
});
|
|
753
1028
|
});
|
|
754
1029
|
|
|
755
|
-
expect(h.
|
|
1030
|
+
expect(h.scrollToOffset).not.toHaveBeenCalled();
|
|
756
1031
|
});
|
|
757
1032
|
|
|
758
1033
|
it("stays unpinned when the viewport shrinks after scrolling away", async () => {
|
|
@@ -776,7 +1051,7 @@ describe("ThreadMessages", () => {
|
|
|
776
1051
|
props.onContentSizeChange?.(0, 340);
|
|
777
1052
|
});
|
|
778
1053
|
|
|
779
|
-
expect(h.
|
|
1054
|
+
expect(h.scrollToOffset).not.toHaveBeenCalled();
|
|
780
1055
|
});
|
|
781
1056
|
|
|
782
1057
|
it("keeps the pin through a downward scroll echo after a commanded scroll", async () => {
|
|
@@ -795,7 +1070,7 @@ describe("ThreadMessages", () => {
|
|
|
795
1070
|
await act(async () => {
|
|
796
1071
|
props.onContentSizeChange?.(0, 320);
|
|
797
1072
|
});
|
|
798
|
-
h.
|
|
1073
|
+
h.scrollToOffset.mockClear();
|
|
799
1074
|
await act(async () => {
|
|
800
1075
|
props.onScroll?.({
|
|
801
1076
|
nativeEvent: {
|
|
@@ -809,14 +1084,17 @@ describe("ThreadMessages", () => {
|
|
|
809
1084
|
props.onContentSizeChange?.(0, 360);
|
|
810
1085
|
});
|
|
811
1086
|
|
|
812
|
-
expect(h.
|
|
1087
|
+
expect(h.scrollToOffset).toHaveBeenCalledWith({
|
|
1088
|
+
animated: false,
|
|
1089
|
+
offset: 260,
|
|
1090
|
+
});
|
|
813
1091
|
});
|
|
814
1092
|
|
|
815
1093
|
it("unpins and cancels a pending scroll on an upward gesture echo", async () => {
|
|
816
1094
|
const props = await mountPinned();
|
|
817
1095
|
|
|
818
1096
|
await emit("thread.runStart");
|
|
819
|
-
h.
|
|
1097
|
+
h.scrollToOffset.mockClear();
|
|
820
1098
|
await act(async () => {
|
|
821
1099
|
props.onScroll?.({
|
|
822
1100
|
nativeEvent: {
|
|
@@ -830,17 +1108,20 @@ describe("ThreadMessages", () => {
|
|
|
830
1108
|
props.onContentSizeChange?.(0, 360);
|
|
831
1109
|
});
|
|
832
1110
|
|
|
833
|
-
expect(h.
|
|
1111
|
+
expect(h.scrollToOffset).not.toHaveBeenCalled();
|
|
834
1112
|
});
|
|
835
1113
|
|
|
836
1114
|
it("scrolls on content growth while pinned and stays put while unpinned", async () => {
|
|
837
1115
|
const props = await mountPinned();
|
|
838
|
-
h.
|
|
1116
|
+
h.scrollToOffset.mockClear();
|
|
839
1117
|
|
|
840
1118
|
await act(async () => {
|
|
841
1119
|
props.onContentSizeChange?.(0, 340);
|
|
842
1120
|
});
|
|
843
|
-
expect(h.
|
|
1121
|
+
expect(h.scrollToOffset).toHaveBeenCalledWith({
|
|
1122
|
+
animated: false,
|
|
1123
|
+
offset: 240,
|
|
1124
|
+
});
|
|
844
1125
|
|
|
845
1126
|
await act(async () => {
|
|
846
1127
|
props.onScroll?.({
|
|
@@ -851,12 +1132,12 @@ describe("ThreadMessages", () => {
|
|
|
851
1132
|
},
|
|
852
1133
|
});
|
|
853
1134
|
});
|
|
854
|
-
h.
|
|
1135
|
+
h.scrollToOffset.mockClear();
|
|
855
1136
|
await act(async () => {
|
|
856
1137
|
props.onContentSizeChange?.(0, 380);
|
|
857
1138
|
});
|
|
858
1139
|
|
|
859
|
-
expect(h.
|
|
1140
|
+
expect(h.scrollToOffset).not.toHaveBeenCalled();
|
|
860
1141
|
});
|
|
861
1142
|
});
|
|
862
1143
|
});
|