Skip to content

Commit 6351050

Browse files
committed
update: unit test
1 parent 52fa3b8 commit 6351050

File tree

1 file changed

+144
-18
lines changed

1 file changed

+144
-18
lines changed

test/chat_scroll_observer_test.dart

Lines changed: 144 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ void main() {
2727
},
2828
);
2929
await tester.pumpWidget(widget);
30-
await tester.tap(find.byType(FloatingActionButton));
30+
await tester.tap(find.byIcon(Icons.add));
3131
await tester.pumpAndSettle();
3232

3333
final result = await observerController.dispatchOnceObserve(
@@ -164,6 +164,118 @@ void main() {
164164

165165
scrollController.dispose();
166166
});
167+
168+
testWidgets('Keeping position with customAdjustPositionDelta',
169+
(tester) async {
170+
final scrollController = ScrollController();
171+
final observerController = ListObserverController(
172+
controller: scrollController,
173+
);
174+
final chatScrollObserver = ChatScrollObserver(observerController)
175+
..fixedPositionOffset = -1;
176+
Map<int, double> itemHeightMap = {};
177+
const double expandedItemHeight = 200;
178+
const double normalItemHeight = 100;
179+
180+
Widget widget = ChatListView(
181+
scrollController: scrollController,
182+
observerController: observerController,
183+
chatScrollObserver: chatScrollObserver,
184+
itemBuilder: (context, index) {
185+
if (itemHeightMap[index] == null) {
186+
itemHeightMap[index] = normalItemHeight;
187+
}
188+
double itemHeight = itemHeightMap[index] ?? normalItemHeight;
189+
return SizedBox(
190+
height: itemHeight,
191+
child: Center(child: Text(index.toString())),
192+
);
193+
},
194+
);
195+
await tester.pumpWidget(widget);
196+
197+
Future<void> setState() async {
198+
await tester.tap(find.byIcon(Icons.refresh));
199+
await tester.pumpAndSettle();
200+
}
201+
202+
var result = await observerController.dispatchOnceObserve(
203+
isForce: true,
204+
isDependObserveCallback: false,
205+
);
206+
var observeResult = result.observeResult;
207+
final displayingChildModelList =
208+
observeResult?.displayingChildModelList ?? [];
209+
expect(displayingChildModelList, isNotEmpty);
210+
211+
final targetIndex = displayingChildModelList.last.index + 1;
212+
// Jump to targetIndex and align its bottom with the viewport bottom.
213+
observerController.jumpTo(
214+
index: targetIndex,
215+
offset: (targetOffset) {
216+
final viewportMainAxisExtent =
217+
observeResult?.firstChild?.viewportMainAxisExtent ?? 0;
218+
return viewportMainAxisExtent - normalItemHeight;
219+
},
220+
);
221+
await tester.pumpAndSettle();
222+
await tester.pump(observerController.observeIntervalForScrolling);
223+
224+
// Check if the last item is aligned with the viewport bottom.
225+
result = await observerController.dispatchOnceObserve(
226+
isForce: true,
227+
isDependObserveCallback: false,
228+
);
229+
observeResult = result.observeResult;
230+
var lastDisplayingChildModel = observeResult?.displayingChildModelList.last;
231+
expect(lastDisplayingChildModel?.index, targetIndex);
232+
expect(lastDisplayingChildModel?.trailingMarginToViewport, 0);
233+
234+
// Expand the last item.
235+
itemHeightMap[targetIndex] = expandedItemHeight;
236+
final refItemIndex = targetIndex;
237+
await chatScrollObserver.standby(
238+
mode: ChatScrollObserverHandleMode.specified,
239+
refIndexType: ChatScrollObserverRefIndexType.itemIndex,
240+
refItemIndex: refItemIndex,
241+
refItemIndexAfterUpdate: refItemIndex,
242+
customAdjustPositionDelta: (model) {
243+
return expandedItemHeight - normalItemHeight;
244+
},
245+
);
246+
await setState();
247+
result = await observerController.dispatchOnceObserve(
248+
isForce: true,
249+
isDependObserveCallback: false,
250+
);
251+
observeResult = result.observeResult;
252+
lastDisplayingChildModel = observeResult?.displayingChildModelList.last;
253+
expect(lastDisplayingChildModel?.index, targetIndex);
254+
expect(lastDisplayingChildModel?.trailingMarginToViewport, 0);
255+
256+
// Restore the last item to normal height.
257+
itemHeightMap[targetIndex] = normalItemHeight;
258+
await chatScrollObserver.standby(
259+
mode: ChatScrollObserverHandleMode.specified,
260+
refIndexType: ChatScrollObserverRefIndexType.itemIndex,
261+
refItemIndex: refItemIndex,
262+
refItemIndexAfterUpdate: refItemIndex,
263+
customAdjustPositionDelta: (model) {
264+
return normalItemHeight - expandedItemHeight;
265+
},
266+
);
267+
await setState();
268+
result = await observerController.dispatchOnceObserve(
269+
isForce: true,
270+
isDependObserveCallback: false,
271+
);
272+
observeResult = result.observeResult;
273+
lastDisplayingChildModel = observeResult?.displayingChildModelList.last;
274+
expect(lastDisplayingChildModel?.index, targetIndex);
275+
expect(lastDisplayingChildModel?.trailingMarginToViewport, 0);
276+
277+
scrollController.dispose();
278+
});
167279
}
168280

169281
class ChatListView extends StatefulWidget {
@@ -173,12 +285,14 @@ class ChatListView extends StatefulWidget {
173285
required this.observerController,
174286
required this.chatScrollObserver,
175287
this.onReceiveScrollNotification,
288+
this.itemBuilder,
176289
}) : super(key: key);
177290

178291
final ScrollController scrollController;
179292
final ListObserverController observerController;
180293
final ChatScrollObserver chatScrollObserver;
181294
final Function()? onReceiveScrollNotification;
295+
final NullableIndexedWidgetBuilder? itemBuilder;
182296

183297
@override
184298
State<ChatListView> createState() => ChatListViewState();
@@ -194,17 +308,28 @@ class ChatListViewState extends State<ChatListView> {
194308
home: Scaffold(
195309
appBar: AppBar(),
196310
body: _buildListView(),
197-
floatingActionButton: FloatingActionButton(
198-
onPressed: () {
199-
widget.chatScrollObserver.standby(changeCount: 4);
200-
setState(() {
201-
dataList.insert(0, '-1');
202-
dataList.insert(0, '-2');
203-
dataList.insert(0, '-3');
204-
dataList.insert(0, '-4');
205-
});
206-
},
207-
child: const Icon(Icons.add),
311+
floatingActionButton: Column(
312+
verticalDirection: VerticalDirection.up,
313+
children: [
314+
FloatingActionButton(
315+
onPressed: () {
316+
widget.chatScrollObserver.standby(changeCount: 4);
317+
setState(() {
318+
dataList.insert(0, '-1');
319+
dataList.insert(0, '-2');
320+
dataList.insert(0, '-3');
321+
dataList.insert(0, '-4');
322+
});
323+
},
324+
child: const Icon(Icons.add),
325+
),
326+
FloatingActionButton(
327+
onPressed: () {
328+
setState(() {});
329+
},
330+
child: const Icon(Icons.refresh),
331+
),
332+
],
208333
),
209334
),
210335
);
@@ -219,12 +344,13 @@ class ChatListViewState extends State<ChatListView> {
219344
observer: widget.chatScrollObserver,
220345
),
221346
controller: widget.scrollController,
222-
itemBuilder: (context, index) {
223-
return SizedBox(
224-
height: 100,
225-
child: Center(child: Text(dataList[index])),
226-
);
227-
},
347+
itemBuilder: widget.itemBuilder ??
348+
(context, index) {
349+
return SizedBox(
350+
height: 100,
351+
child: Center(child: Text(dataList[index])),
352+
);
353+
},
228354
),
229355
);
230356
resultWidget = NotificationListener<ScrollNotification>(

0 commit comments

Comments
 (0)