1 /*
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "list_test_ng.h"
17
18 #include "test/mock/base/mock_task_executor.h"
19 #include "test/mock/core/common/mock_theme_manager.h"
20 #include "test/mock/core/pipeline/mock_pipeline_context.h"
21
22 #include "core/components/button/button_theme.h"
23 #include "core/components/list/list_theme.h"
24 #include "core/components_ng/pattern/linear_layout/column_model_ng.h"
25 #include "core/components_ng/pattern/linear_layout/row_model_ng.h"
26 #include "core/components_ng/syntax/repeat_virtual_scroll_model_ng.h"
27
28 namespace OHOS::Ace::NG {
SetUpTestSuite()29 void ListTestNg::SetUpTestSuite()
30 {
31 TestNG::SetUpTestSuite();
32 auto themeManager = AceType::MakeRefPtr<MockThemeManager>();
33 MockPipelineContext::GetCurrent()->SetThemeManager(themeManager);
34 auto buttonTheme = AceType::MakeRefPtr<ButtonTheme>();
35 EXPECT_CALL(*themeManager, GetTheme(_)).WillRepeatedly(Return(buttonTheme));
36 auto listThemeConstants = CreateThemeConstants(THEME_PATTERN_LIST);
37 auto listTheme = ListTheme::Builder().Build(listThemeConstants);
38 EXPECT_CALL(*themeManager, GetTheme(ListTheme::TypeId())).WillRepeatedly(Return(listTheme));
39 auto listItemThemeConstants = CreateThemeConstants(THEME_PATTERN_LIST_ITEM);
40 auto listItemTheme = ListItemTheme::Builder().Build(listItemThemeConstants);
41 EXPECT_CALL(*themeManager, GetTheme(ListItemTheme::TypeId())).WillRepeatedly(Return(listItemTheme));
42 listItemTheme->itemDefaultColor_ = ITEMDEFAULT_COLOR;
43 listItemTheme->hoverColor_ = HOVER_COLOR;
44 listItemTheme->pressColor_ = PRESS_COLOR;
45 int32_t hoverAnimationDuration = 250;
46 int32_t hoverToPressAnimationDuration = 100;
47 listItemTheme->hoverAnimationDuration_ = hoverAnimationDuration;
48 listItemTheme->hoverToPressAnimationDuration_ = hoverToPressAnimationDuration;
49 listItemTheme->disabledAlpha_ = DISABLED_ALPHA;
50 listItemTheme->defaultColor_ = Color::WHITE;
51 listItemTheme->defaultLeftMargin_ = GROUP_MARGIN;
52 listItemTheme->defaultRightMargin_ = GROUP_MARGIN;
53 listItemTheme->defaultPadding_ = Edge(0.0_vp);
54 MockPipelineContext::GetCurrentContext()->taskExecutor_ = AceType::MakeRefPtr<MockTaskExecutor>();
55 MockAnimationManager::Enable(true);
56 }
57
TearDownTestSuite()58 void ListTestNg::TearDownTestSuite()
59 {
60 TestNG::TearDownTestSuite();
61 }
62
SetUp()63 void ListTestNg::SetUp()
64 {
65 MockAnimationManager::GetInstance().Reset();
66 }
67
TearDown()68 void ListTestNg::TearDown()
69 {
70 frameNode_ = nullptr;
71 pattern_ = nullptr;
72 eventHub_ = nullptr;
73 layoutProperty_ = nullptr;
74 paintProperty_ = nullptr;
75 accessibilityProperty_ = nullptr;
76 ClearOldNodes(); // Each testcase will create new list at begin
77 AceApplicationInfo::GetInstance().isRightToLeft_ = false;
78 }
79
GetList()80 void ListTestNg::GetList()
81 {
82 RefPtr<UINode> element = ViewStackProcessor::GetInstance()->GetMainElementNode();
83 frameNode_ = AceType::DynamicCast<FrameNode>(element);
84 pattern_ = frameNode_->GetPattern<ListPattern>();
85 eventHub_ = frameNode_->GetEventHub<ListEventHub>();
86 layoutProperty_ = frameNode_->GetLayoutProperty<ListLayoutProperty>();
87 paintProperty_ = frameNode_->GetPaintProperty<ScrollablePaintProperty>();
88 accessibilityProperty_ = frameNode_->GetAccessibilityProperty<ListAccessibilityProperty>();
89 }
90
CreateList()91 ListModelNG ListTestNg::CreateList()
92 {
93 ResetElmtId();
94 ViewStackProcessor::GetInstance()->StartGetAccessRecordingFor(GetElmtId());
95 ListModelNG model;
96 model.Create();
97 ViewAbstract::SetWidth(CalcLength(LIST_WIDTH));
98 ViewAbstract::SetHeight(CalcLength(LIST_HEIGHT));
99 RefPtr<ScrollControllerBase> scrollController = model.CreateScrollController();
100 RefPtr<ScrollProxy> proxy = AceType::MakeRefPtr<NG::ScrollBarProxy>();
101 model.SetScroller(scrollController, proxy);
102 GetList();
103 return model;
104 }
105
CreateListItems(int32_t itemNumber,V2::ListItemStyle listItemStyle)106 void ListTestNg::CreateListItems(int32_t itemNumber, V2::ListItemStyle listItemStyle)
107 {
108 for (int32_t index = 0; index < itemNumber; index++) {
109 CreateListItem(listItemStyle);
110 ViewStackProcessor::GetInstance()->Pop();
111 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
112 }
113 }
114
CreateListItem(V2::ListItemStyle listItemStyle)115 ListItemModelNG ListTestNg::CreateListItem(V2::ListItemStyle listItemStyle)
116 {
117 ViewStackProcessor::GetInstance()->StartGetAccessRecordingFor(GetElmtId());
118 ListItemModelNG itemModel;
119 itemModel.Create([](int32_t) {}, listItemStyle);
120 if (layoutProperty_->GetListDirection().value_or(Axis::VERTICAL) == Axis::VERTICAL) {
121 ViewAbstract::SetWidth(CalcLength(FILL_LENGTH));
122 ViewAbstract::SetHeight(CalcLength(ITEM_HEIGHT));
123 } else {
124 ViewAbstract::SetWidth(CalcLength(ITEM_WIDTH));
125 ViewAbstract::SetHeight(CalcLength(FILL_LENGTH));
126 }
127 return itemModel;
128 }
129
CreateListItemGroups(int32_t groupNumber,V2::ListItemGroupStyle listItemGroupStyle)130 void ListTestNg::CreateListItemGroups(int32_t groupNumber, V2::ListItemGroupStyle listItemGroupStyle)
131 {
132 for (int32_t index = 0; index < groupNumber; index++) {
133 CreateListItemGroup(listItemGroupStyle);
134 CreateListItems(GROUP_ITEM_NUMBER, static_cast<V2::ListItemStyle>(listItemGroupStyle));
135 ViewStackProcessor::GetInstance()->Pop();
136 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
137 }
138 }
139
CreateListItemGroup(V2::ListItemGroupStyle listItemGroupStyle)140 ListItemGroupModelNG ListTestNg::CreateListItemGroup(V2::ListItemGroupStyle listItemGroupStyle)
141 {
142 ViewStackProcessor::GetInstance()->StartGetAccessRecordingFor(GetElmtId());
143 ListItemGroupModelNG groupModel;
144 groupModel.Create(listItemGroupStyle);
145 return groupModel;
146 }
147
CreateItemWithSize(int32_t itemNumber,SizeT<Dimension> itemSize)148 void ListTestNg::CreateItemWithSize(int32_t itemNumber, SizeT<Dimension> itemSize)
149 {
150 for (int32_t index = 0; index < itemNumber; ++index) {
151 ListItemModelNG itemModel = CreateListItem();
152 ViewAbstract::SetWidth(CalcLength(itemSize.Width()));
153 ViewAbstract::SetHeight(CalcLength(itemSize.Height()));
154 ViewStackProcessor::GetInstance()->Pop();
155 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
156 }
157 }
158
CreateGroupWithSetting(int32_t groupNumber,V2::ListItemGroupStyle listItemGroupStyle,int32_t itemNumber)159 void ListTestNg::CreateGroupWithSetting(
160 int32_t groupNumber, V2::ListItemGroupStyle listItemGroupStyle, int32_t itemNumber)
161 {
162 for (int32_t index = 0; index < groupNumber; index++) {
163 auto header = GetRowOrColBuilder(FILL_LENGTH, Dimension(GROUP_HEADER_LEN));
164 auto footer = GetRowOrColBuilder(FILL_LENGTH, Dimension(GROUP_HEADER_LEN));
165 ListItemGroupModelNG groupModel = CreateListItemGroup(listItemGroupStyle);
166 groupModel.SetSpace(Dimension(SPACE));
167 groupModel.SetDivider(ITEM_DIVIDER);
168 groupModel.SetHeader(std::move(header));
169 groupModel.SetFooter(std::move(footer));
170 CreateListItems(itemNumber, static_cast<V2::ListItemStyle>(listItemGroupStyle));
171 ViewStackProcessor::GetInstance()->Pop();
172 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
173 }
174 }
175
CreateGroupWithSettingChildrenMainSize(int32_t groupNumber)176 void ListTestNg::CreateGroupWithSettingChildrenMainSize(int32_t groupNumber)
177 {
178 for (int32_t index = 0; index < groupNumber; ++index) {
179 auto header = GetRowOrColBuilder(FILL_LENGTH, Dimension(GROUP_HEADER_LEN));
180 auto footer = GetRowOrColBuilder(FILL_LENGTH, Dimension(GROUP_HEADER_LEN));
181 ListItemGroupModelNG groupModel = CreateListItemGroup();
182 groupModel.SetSpace(Dimension(SPACE));
183 groupModel.SetDivider(ITEM_DIVIDER);
184 groupModel.SetHeader(std::move(header));
185 groupModel.SetFooter(std::move(footer));
186
187 auto childrenSize = groupModel.GetOrCreateListChildrenMainSize();
188 childrenSize->UpdateDefaultSize(ITEM_HEIGHT);
189 const int32_t itemNumber = 2;
190 childrenSize->ChangeData(1, itemNumber, { 50.f, 200.f });
191 CreateListItems(1);
192 CreateItemWithSize(1, SizeT<Dimension>(FILL_LENGTH, Dimension(50.f)));
193 CreateItemWithSize(1, SizeT<Dimension>(FILL_LENGTH, Dimension(200.f)));
194 CreateListItems(1);
195 ViewStackProcessor::GetInstance()->Pop();
196 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
197 }
198 }
199
CreateGroupChildrenMainSize(int32_t groupNumber)200 void ListTestNg::CreateGroupChildrenMainSize(int32_t groupNumber)
201 {
202 for (int32_t index = 0; index < groupNumber; index++) {
203 ListItemGroupModelNG groupModel = CreateListItemGroup();
204 auto childrenSize = groupModel.GetOrCreateListChildrenMainSize();
205 childrenSize->UpdateDefaultSize(ITEM_HEIGHT);
206 const int32_t itemNumber = 2;
207 childrenSize->ChangeData(1, itemNumber, { 50.f, 200.f });
208 CreateListItems(1);
209 CreateItemWithSize(1, SizeT<Dimension>(FILL_LENGTH, Dimension(50.f)));
210 CreateItemWithSize(1, SizeT<Dimension>(FILL_LENGTH, Dimension(200.f)));
211 CreateListItems(1);
212 ViewStackProcessor::GetInstance()->Pop();
213 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
214 }
215 }
216
CreateGroupWithItem(int32_t groupNumber,Axis axis)217 void ListTestNg::CreateGroupWithItem(int32_t groupNumber, Axis axis)
218 {
219 for (int32_t index = 0; index < groupNumber; index++) {
220 if (index & 1) {
221 CreateListItems(1);
222 } else {
223 CreateListItemGroups(1);
224 }
225 }
226 }
227
CreateSwipeItems(std::function<void ()> startAction,std::function<void ()> endAction,V2::SwipeEdgeEffect effect,int32_t itemNumber)228 void ListTestNg::CreateSwipeItems(
229 std::function<void()> startAction, std::function<void()> endAction,
230 V2::SwipeEdgeEffect effect, int32_t itemNumber)
231 {
232 for (int32_t index = 0; index < itemNumber; index++) {
233 ListItemModelNG itemModel = CreateListItem();
234 itemModel.SetSwiperAction(nullptr, nullptr, nullptr, effect);
235 if (startAction) {
236 itemModel.SetDeleteArea(
237 std::move(startAction), nullptr, nullptr, nullptr, nullptr, Dimension(DELETE_AREA_DISTANCE), true);
238 }
239 if (endAction) {
240 itemModel.SetDeleteArea(
241 std::move(endAction), nullptr, nullptr, nullptr, nullptr, Dimension(DELETE_AREA_DISTANCE), false);
242 }
243 {
244 Axis axis = layoutProperty_->GetListDirection().value_or(Axis::VERTICAL);
245 float mainSize = axis == Axis::VERTICAL ? ITEM_HEIGHT : ITEM_WIDTH;
246 GetRowOrColBuilder(FILL_LENGTH, Dimension(mainSize))();
247 ViewStackProcessor::GetInstance()->Pop();
248 }
249 ViewStackProcessor::GetInstance()->Pop();
250 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
251 }
252 }
253
GetRowOrColBuilder(float crossSize,float mainSize)254 std::function<void()> ListTestNg::GetRowOrColBuilder(float crossSize, float mainSize)
255 {
256 return GetRowOrColBuilder(Dimension(crossSize), Dimension(mainSize));
257 }
258
GetRowOrColBuilder(Dimension crossSize,Dimension mainSize)259 std::function<void()> ListTestNg::GetRowOrColBuilder(Dimension crossSize, Dimension mainSize)
260 {
261 Axis axis = layoutProperty_->GetListDirection().value_or(Axis::VERTICAL);
262 return [axis, mainSize, crossSize]() {
263 if (axis == Axis::VERTICAL) {
264 RowModelNG rowModel;
265 rowModel.Create(std::nullopt, nullptr, "");
266 ViewAbstract::SetWidth(CalcLength(crossSize));
267 ViewAbstract::SetHeight(CalcLength(mainSize));
268 } else {
269 ColumnModelNG colModel;
270 colModel.Create(Dimension(0), nullptr, "");
271 ViewAbstract::SetWidth(CalcLength(mainSize));
272 ViewAbstract::SetHeight(CalcLength(crossSize));
273 }
274 };
275 }
276
UpdateCurrentOffset(float offset,int32_t source)277 void ListTestNg::UpdateCurrentOffset(float offset, int32_t source)
278 {
279 pattern_->UpdateCurrentOffset(offset, source);
280 FlushLayoutTask(frameNode_);
281 }
282
ScrollToEdge(ScrollEdgeType scrollEdgeType)283 void ListTestNg::ScrollToEdge(ScrollEdgeType scrollEdgeType)
284 {
285 pattern_->ScrollToEdge(scrollEdgeType, false);
286 FlushLayoutTask(frameNode_);
287 }
288
ScrollToIndex(int32_t index,bool smooth,ScrollAlign align,std::optional<float> extraOffset)289 void ListTestNg::ScrollToIndex(int32_t index, bool smooth, ScrollAlign align, std::optional<float> extraOffset)
290 {
291 pattern_->ScrollToIndex(index, smooth, align, extraOffset);
292 FlushLayoutTask(frameNode_);
293 if (smooth) {
294 auto iter = pattern_->itemPosition_.find(index);
295 float targetPos = 0.0f;
296 if (iter->second.isGroup) {
297 if (!pattern_->GetListItemGroupAnimatePosWithoutIndexInGroup(index, iter->second.startPos,
298 iter->second.endPos, align, targetPos)) {
299 return;
300 }
301 } else {
302 pattern_->GetListItemAnimatePos(iter->second.startPos, iter->second.endPos, align, targetPos);
303 }
304 if (extraOffset.has_value()) {
305 targetPos += extraOffset.value();
306 }
307 if (!NearZero(targetPos)) {
308 float endValue = pattern_->GetFinalPosition();
309 pattern_->ScrollTo(endValue);
310 FlushLayoutTask(frameNode_);
311 }
312 }
313 }
314
ScrollToItemInGroup(int32_t index,int32_t indexInGroup,bool smooth,ScrollAlign align)315 void ListTestNg::ScrollToItemInGroup(int32_t index, int32_t indexInGroup, bool smooth, ScrollAlign align)
316 {
317 pattern_->ScrollToItemInGroup(index, indexInGroup, smooth, align);
318 FlushLayoutTask(frameNode_);
319 if (smooth) {
320 float endValue = pattern_->GetFinalPosition();
321 pattern_->ScrollTo(endValue);
322 FlushLayoutTask(frameNode_);
323 }
324 }
325
DragSwiperItem(int32_t index,float mainDelta,float mainVelocity)326 void ListTestNg::DragSwiperItem(int32_t index, float mainDelta, float mainVelocity)
327 {
328 HandleDragStart(index);
329 HandleDragUpdate(index, mainDelta);
330 HandleDragEnd(index, mainVelocity);
331 }
332
HandleDragStart(int32_t index)333 void ListTestNg::HandleDragStart(int32_t index)
334 {
335 GestureEvent info;
336 auto itemPattern = GetChildPattern<ListItemPattern>(frameNode_, index);
337 auto handleDragStart = itemPattern->panEvent_->GetActionStartEventFunc();
338 handleDragStart(info);
339 }
340
HandleDragUpdate(int32_t index,float mainDelta)341 void ListTestNg::HandleDragUpdate(int32_t index, float mainDelta)
342 {
343 GestureEvent info;
344 info.SetMainDelta(mainDelta);
345 auto itemPattern = GetChildPattern<ListItemPattern>(frameNode_, index);
346 auto handleDragUpdate = itemPattern->panEvent_->GetActionUpdateEventFunc();
347 handleDragUpdate(info);
348 frameNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
349 FlushLayoutTask(frameNode_);
350 }
351
HandleDragEnd(int32_t index,float mainVelocity)352 void ListTestNg::HandleDragEnd(int32_t index, float mainVelocity)
353 {
354 GestureEvent info;
355 info.SetMainVelocity(mainVelocity);
356 auto itemPattern = GetChildPattern<ListItemPattern>(frameNode_, index);
357 auto handleDragEnd = itemPattern->panEvent_->GetActionEndEventFunc();
358 handleDragEnd(info);
359 // curOffset_ would be NodeSize or Zero
360 EXPECT_NE(itemPattern->springMotion_, nullptr);
361 double position = itemPattern->springMotion_->GetEndValue();
362 itemPattern->UpdatePostion(position - itemPattern->curOffset_);
363 frameNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
364 FlushLayoutTask(frameNode_);
365 }
366
ScrollSnap(double offset,double endVelocity)367 void ListTestNg::ScrollSnap(double offset, double endVelocity)
368 {
369 double velocity = offset > 0.f ? 1200.f : -1200.f;
370 // Define (150.0, 500.0) as finger press position.
371 double touchPosX = 150.0;
372 double touchPosY = 500.0;
373 // Generate pan gesture from finger for List sliding.
374 GestureEvent info;
375 info.SetMainVelocity(velocity);
376 info.SetGlobalPoint(Point(touchPosX, touchPosY));
377 info.SetGlobalLocation(Offset(touchPosX, touchPosY));
378 info.SetSourceTool(SourceTool::FINGER);
379 info.SetInputEventType(InputEventType::TOUCH_SCREEN);
380 // Call HandleTouchDown and HandleDragStart.
381 auto scrollable = pattern_->scrollableEvent_->GetScrollable();
382 scrollable->HandleTouchDown();
383 scrollable->isDragging_ = true;
384 scrollable->HandleDragStart(info);
385
386 // Update finger position.
387 info.SetGlobalLocation(Offset(touchPosX, touchPosY + offset));
388 info.SetGlobalPoint(Point(touchPosX, touchPosY + offset));
389 info.SetMainVelocity(velocity);
390 info.SetMainDelta(offset);
391 scrollable->HandleDragUpdate(info);
392 FlushLayoutTask(frameNode_);
393
394 // Lift finger and end List sliding.
395 info.SetMainVelocity(endVelocity);
396 info.SetMainDelta(0.0);
397 scrollable->HandleTouchUp();
398 scrollable->HandleDragEnd(info);
399 scrollable->isDragging_ = false;
400 FlushLayoutTask(frameNode_);
401
402 if (scrollable->IsSpringMotionRunning()) {
403 // If current position is out of boundary, trig spring motion.
404 float endValue = scrollable->GetFinalPosition();
405 scrollable->ProcessSpringMotion(endValue);
406 scrollable->StopSpringAnimation();
407 FlushLayoutTask(frameNode_);
408 } else if (!(scrollable->isSnapScrollAnimationStop_)) {
409 // StartScrollSnapMotion, for condition that equal item height.
410 float endValue = scrollable->GetSnapFinalPosition();
411 scrollable->ProcessScrollSnapMotion(endValue);
412 scrollable->ProcessScrollSnapStop();
413 FlushLayoutTask(frameNode_);
414 }
415 scrollable->StopScrollable();
416 }
417
ScrollToIndex(int32_t index,bool smooth,ScrollAlign align,float expectOffset)418 AssertionResult ListTestNg::ScrollToIndex(int32_t index, bool smooth, ScrollAlign align, float expectOffset)
419 {
420 // After every call to ScrollToIndex(), reset currentDelta_
421 float startOffset = pattern_->GetTotalOffset();
422 pattern_->ScrollToIndex(index, smooth, align);
423 FlushLayoutTask(frameNode_);
424 if (smooth) {
425 // Because can not get targetPos, use source code
426 auto iter = pattern_->itemPosition_.find(index);
427 float targetPos = 0.0f;
428 if (iter->second.isGroup) {
429 pattern_->GetListItemGroupAnimatePosWithoutIndexInGroup(index, iter->second.startPos,
430 iter->second.endPos, align, targetPos);
431 } else {
432 pattern_->GetListItemAnimatePos(iter->second.startPos, iter->second.endPos, align, targetPos);
433 }
434 if (!NearZero(targetPos)) {
435 // Straight to the end of the anmiation, use ScrollTo replace AnimateTo
436 float finalPosition = pattern_->GetFinalPosition();
437 float totalHeight = pattern_->GetTotalHeight();
438 finalPosition = std::clamp(finalPosition, 0.f, totalHeight); // limit scrollDistance
439 pattern_->ScrollTo(finalPosition);
440 FlushLayoutTask(frameNode_);
441 }
442 }
443 float currentOffset = pattern_->GetTotalOffset();
444 pattern_->ScrollTo(startOffset); // reset offset before return
445 FlushLayoutTask(frameNode_);
446 return IsEqual(currentOffset, expectOffset);
447 }
448
JumpToItemInGroup(int32_t index,int32_t indexInGroup,bool smooth,ScrollAlign align,float expectOffset)449 AssertionResult ListTestNg::JumpToItemInGroup(
450 int32_t index, int32_t indexInGroup, bool smooth, ScrollAlign align, float expectOffset)
451 {
452 auto controller = pattern_->positionController_;
453 float startOffset = pattern_->GetTotalOffset();
454 controller->JumpToItemInGroup(index, indexInGroup, smooth, align);
455 FlushLayoutTask(frameNode_);
456 if (smooth) {
457 // Because can not get targetPos, use source code
458 auto iter = pattern_->itemPosition_.find(index);
459 float targetPos = 0.0f;
460 if (iter->second.isGroup) {
461 pattern_->GetListItemGroupAnimatePosWithIndexInGroup(index, indexInGroup,
462 iter->second.startPos, align, targetPos);
463 } else {
464 pattern_->GetListItemAnimatePos(iter->second.startPos, iter->second.endPos, align, targetPos);
465 }
466 if (!NearZero(targetPos)) {
467 // Straight to the end of the anmiation, use ScrollTo replace AnimateTo
468 float finalPosition = pattern_->GetFinalPosition();
469 float totalHeight = pattern_->GetTotalHeight();
470 finalPosition = std::clamp(finalPosition, 0.f, totalHeight); // limit scrollDistance
471 pattern_->ScrollTo(finalPosition);
472 FlushLayoutTask(frameNode_);
473 }
474 }
475 float currentOffset = pattern_->GetTotalOffset();
476 pattern_->ScrollTo(startOffset); // reset offset before return
477 FlushLayoutTask(frameNode_);
478 return IsEqual(currentOffset, expectOffset);
479 }
480
481 // Get all listItem that in or not in listItemGroup
GetALLItem()482 std::vector<RefPtr<FrameNode>> ListTestNg::GetALLItem()
483 {
484 std::vector<RefPtr<FrameNode>> listItems;
485 auto children = frameNode_->GetChildren();
486 for (auto child : children) {
487 auto childFrameNode = AceType::DynamicCast<FrameNode>(child);
488 if (childFrameNode->GetTag() == V2::LIST_ITEM_GROUP_ETS_TAG) {
489 auto group = child->GetChildren();
490 for (auto item : group) {
491 auto itemFrameNode = AceType::DynamicCast<FrameNode>(item);
492 if (itemFrameNode->GetTag() == V2::LIST_ITEM_ETS_TAG) {
493 listItems.emplace_back(itemFrameNode);
494 }
495 }
496 } else if (childFrameNode->GetTag() == V2::LIST_ITEM_ETS_TAG) {
497 listItems.emplace_back(childFrameNode);
498 }
499 }
500 return listItems;
501 }
502
findFocusNodeIndex(RefPtr<FocusHub> & focusNode)503 int32_t ListTestNg::findFocusNodeIndex(RefPtr<FocusHub>& focusNode)
504 {
505 std::vector<RefPtr<FrameNode>> listItems = GetALLItem();
506 int32_t size = static_cast<int32_t>(listItems.size());
507 for (int32_t index = 0; index < size; index++) {
508 if (focusNode == listItems[index]->GetOrCreateFocusHub()) {
509 return index;
510 }
511 }
512 return NULL_VALUE;
513 }
514
ScrollTo(float position)515 void ListTestNg::ScrollTo(float position)
516 {
517 pattern_->ScrollTo(position);
518 FlushLayoutTask(frameNode_);
519 }
520
CreateRepeatVirtualScrollNode(int32_t itemNumber,const std::function<void (uint32_t)> & createFunc)521 void ListTestNg::CreateRepeatVirtualScrollNode(int32_t itemNumber, const std::function<void(uint32_t)>& createFunc)
522 {
523 RepeatVirtualScrollModelNG repeatModel;
524 std::function<void(const std::string&, uint32_t)> updateFunc = [](const std::string& value, uint32_t idx) {};
525 std::function<std::list<std::string>(uint32_t, uint32_t)> getKeys = [](uint32_t start, uint32_t end) {
526 std::list<std::string> keys;
527 for (uint32_t i = start; i <= end; ++i) {
528 keys.emplace_back(std::to_string(i));
529 }
530 return keys;
531 };
532 std::function<std::list<std::string>(uint32_t, uint32_t)> getTypes = [](uint32_t start, uint32_t end) {
533 std::list<std::string> keys;
534 for (uint32_t i = start; i <= end; ++i) {
535 keys.emplace_back("0");
536 }
537 return keys;
538 };
539 std::function<void(uint32_t, uint32_t)> setActiveRange = [](uint32_t start, uint32_t end) {};
540 repeatModel.Create(itemNumber, {}, createFunc, updateFunc, getKeys, getTypes, setActiveRange);
541 }
542
FlushIdleTask(const RefPtr<ListPattern> & listPattern)543 void ListTestNg::FlushIdleTask(const RefPtr<ListPattern>& listPattern)
544 {
545 int32_t tryCount = 10;
546 auto predictParam = listPattern->GetPredictLayoutParamV2();
547 while (predictParam && tryCount > 0) {
548 const int64_t time = GetSysTimestamp();
549 PipelineContext::GetCurrentContext()->OnIdle(time + 16 * 1000000); // 16 * 1000000: 16ms
550 FlushLayoutTask(frameNode_);
551 predictParam = listPattern->GetPredictLayoutParamV2();
552 tryCount--;
553 }
554 }
555
CreateGroupWithSettingWithComponentContent(int32_t groupNumber,V2::ListItemGroupStyle listItemGroupStyle,int32_t itemNumber)556 void ListTestNg::CreateGroupWithSettingWithComponentContent(
557 int32_t groupNumber, V2::ListItemGroupStyle listItemGroupStyle, int32_t itemNumber)
558 {
559 for (int32_t index = 0; index < groupNumber; index++) {
560 ListItemGroupModelNG groupModel = CreateListItemGroup(listItemGroupStyle);
561 groupModel.SetSpace(Dimension(SPACE));
562 groupModel.SetDivider(ITEM_DIVIDER);
563 groupModel.SetHeaderComponent(CreateCustomNode("Header"));
564 groupModel.SetFooterComponent(CreateCustomNode("Footer"));
565 CreateListItems(itemNumber, static_cast<V2::ListItemStyle>(listItemGroupStyle));
566 ViewStackProcessor::GetInstance()->Pop();
567 ViewStackProcessor::GetInstance()->StopGetAccessRecording();
568 }
569 }
570
CreateCustomNode(const std::string & tag)571 RefPtr<FrameNode> ListTestNg::CreateCustomNode(const std::string& tag)
572 {
573 auto frameNode = AceType::MakeRefPtr<FrameNode>(
574 tag, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<Pattern>());
575 auto layoutProperty = frameNode->GetLayoutProperty();
576 layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(LIST_WIDTH), CalcLength(LIST_HEIGHT)));
577 return frameNode;
578 }
579 } // namespace OHOS::Ace::NG
580