1 /*
2 * Copyright (c) 2021-2022 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 #include "gtest/gtest.h"
16 #include "ui_driver.h"
17 #include "ui_model.h"
18
19 using namespace OHOS::uitest;
20 using namespace std;
21
22 static constexpr auto ATTR_TEXT = "text";
23 // record the triggered touch events.
24 static vector<TouchEvent> touch_event_records;
25
26 class MockController : public UiController {
27 public:
MockController()28 explicit MockController() : UiController("mock_controller") {}
29
30 ~MockController() = default;
31
SetDomFrame(string_view domFrame)32 void SetDomFrame(string_view domFrame)
33 {
34 mockDomFrame_ = domFrame;
35 }
36
GetUiHierarchy(vector<pair<Window,nlohmann::json>> & out)37 void GetUiHierarchy(vector<pair<Window, nlohmann::json>>& out) override
38 {
39 auto winInfo = Window(0);
40 auto dom = nlohmann::json::parse(mockDomFrame_);
41 out.push_back(make_pair(move(winInfo), move(dom)));
42 }
43
IsWorkable() const44 bool IsWorkable() const override
45 {
46 return true;
47 }
48
49 private:
50 string mockDomFrame_;
51 };
52
53 // test fixture
54 class UiDriverTest : public testing::Test {
55 protected:
SetUp()56 void SetUp() override
57 {
58 touch_event_records.clear();
59 auto mockController = make_unique<MockController>();
60 controller_ = mockController.get();
61 UiController::RegisterController(move(mockController), Priority::MEDIUM);
62 driver_ = make_unique<UiDriver>();
63 }
64
TearDown()65 void TearDown() override
66 {
67 controller_ = nullptr;
68 UiController::RemoveAllControllers();
69 }
70
71 MockController *controller_ = nullptr;
72 unique_ptr<UiDriver> driver_ = nullptr;
73 UiOpArgs opt_;
74
75 ~UiDriverTest() override = default;
76 };
77
TEST_F(UiDriverTest,internalError)78 TEST_F(UiDriverTest, internalError)
79 {
80 // give no UiController, should cause internal error
81 UiController::RemoveAllControllers();
82 auto error = ApiCallErr(NO_ERROR);
83 auto key = Back();
84 driver_->TriggerKey(key, opt_, error);
85 ASSERT_EQ(ERR_INTERNAL, error.code_);
86 }
87
TEST_F(UiDriverTest,normalInteraction)88 TEST_F(UiDriverTest, normalInteraction)
89 {
90 constexpr auto mockDom0 = R"({
91 "attributes": {
92 "index": "0",
93 "resource-id": "id1",
94 "bounds": "[0,0][100,100]",
95 "text": ""
96 },
97 "children": [
98 {
99 "attributes": {
100 "index": "0",
101 "resource-id": "id4",
102 "bounds": "[0,0][50,50]",
103 "text": "USB",
104 "type": "Text"
105 },
106 "children": []
107 }
108 ]
109 }
110 )";
111 controller_->SetDomFrame(mockDom0);
112
113 auto error = ApiCallErr(NO_ERROR);
114 auto selector = WidgetSelector();
115 auto matcher = WidgetAttrMatcher(ATTR_TEXT, "USB", EQ);
116 selector.AddMatcher(matcher);
117 vector<unique_ptr<Widget>> widgets;
118 driver_->FindWidgets(selector, widgets, error);
119
120 ASSERT_EQ(1, widgets.size());
121 ASSERT_EQ("NONE", widgets.at(0)->GetHostTreeId()); // should return dettached widget
122 // perform interactions
123 auto key = Back();
124 driver_->TriggerKey(key, opt_, error);
125 ASSERT_EQ(NO_ERROR, error.code_);
126 }
127
TEST_F(UiDriverTest,retrieveWidgetFailure)128 TEST_F(UiDriverTest, retrieveWidgetFailure)
129 {
130 constexpr auto mockDom0 = R"({
131 "attributes": {
132 "text": "",
133 "bounds": "[0,0][100,100]"
134 },
135 "children": [
136 {
137 "attributes": {
138 "text": "USB",
139 "bounds": "[0,0][50,50]"
140 },
141 "children": []
142 }
143 ]
144 }
145 )";
146 constexpr auto mockDom1 = R"({
147 "attributes": {
148 "text": "",
149 "bounds": "[0,0][100,100]"
150 },
151 "children": [
152 {
153 "attributes": {
154 "text": "WYZ",
155 "bounds": "[0,0][50,50]"
156 },
157 "children": []
158 }
159 ]
160 }
161 )";
162 controller_->SetDomFrame(mockDom0);
163
164 auto error = ApiCallErr(NO_ERROR);
165 auto selector = WidgetSelector();
166 auto matcher = WidgetAttrMatcher(ATTR_TEXT, "USB", EQ);
167 selector.AddMatcher(matcher);
168 vector<unique_ptr<Widget>> widgets;
169 driver_->FindWidgets(selector, widgets, error);
170
171 ASSERT_EQ(1, widgets.size());
172
173 // mock another dom on which the target widget is missing, and perform click
174 controller_->SetDomFrame(mockDom1);
175 error = ApiCallErr(NO_ERROR);
176 driver_->RetrieveWidget(*widgets.at(0), error, true);
177
178 // retrieve widget failed should be marked as exception
179 ASSERT_EQ(ERR_COMPONENT_LOST, error.code_);
180 ASSERT_TRUE(error.message_.find(selector.Describe()) != string::npos)
181 << "Error message should contains the widget selection description";
182 }
183
TEST_F(UiDriverTest,retrieveWidget)184 TEST_F(UiDriverTest, retrieveWidget)
185 {
186 constexpr auto mockDom0 = R"({
187 "attributes": {"bounds": "[0,0][100,100]", "text": ""},
188 "children": [
189 {
190 "attributes": {
191 "bounds": "[0,0][50,50]",
192 "hashcode": "12345",
193 "text": "USB","type": "Text"},
194 "children": []}]})";
195 controller_->SetDomFrame(mockDom0);
196
197 auto error = ApiCallErr(NO_ERROR);
198 auto selector = WidgetSelector();
199 auto matcher = WidgetAttrMatcher(ATTR_NAMES[UiAttr::HASHCODE], "12345", EQ);
200 selector.AddMatcher(matcher);
201 vector<unique_ptr<Widget>> widgets;
202 driver_->FindWidgets(selector, widgets, error);
203 ASSERT_EQ(1, widgets.size());
204 ASSERT_EQ("USB", widgets.at(0)->GetAttr(ATTR_TEXT, ""));
205
206 // mock new UI
207 constexpr auto mockDom1 = R"({
208 "attributes": {"bounds": "[0,0][100,100]", "text": ""},
209 "children": [
210 {
211 "attributes": {
212 "bounds": "[0,0][50,50]",
213 "hashcode": "12345",
214 "text": "WYZ","type": "Text"},
215 "children": []}]})";
216 controller_->SetDomFrame(mockDom1);
217 // we should be able to refresh WidgetImage on the new UI
218 auto snapshot = driver_->RetrieveWidget(*widgets.at(0), error);
219 ASSERT_EQ(NO_ERROR, error.code_);
220 ASSERT_NE(nullptr, snapshot);
221 ASSERT_EQ("WYZ", snapshot->GetAttr(ATTR_TEXT, "")); // attribute should be updated to new value
222 // mock new UI
223 constexpr auto mockDom2 = R"({
224 "attributes": {"bounds": "[0,0][100,100]", "text": ""},
225 "children": [
226 {
227 "attributes": {
228 "bounds": "[0,0][50,50]",
229 "hashcode": "23456",
230 "text": "ZL", "type":"Button"},
231 "children": []}]})";
232 controller_->SetDomFrame(mockDom2);
233 // we should not be able to refresh WidgetImage on the new UI since its gone (hashcode and attributes changed)
234 snapshot = driver_->RetrieveWidget(*widgets.at(0), error);
235 ASSERT_EQ(ERR_COMPONENT_LOST, error.code_);
236 ASSERT_EQ(nullptr, snapshot);
237 }