Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(311)

Side by Side Diff: chrome/test/chromedriver/web_view_impl.cc

Issue 12848005: [chromedriver] Separate stuff of chrome from chromedriver. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments and fix compile error on mac. Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/test/chromedriver/web_view_impl.h"
6
7 #include "base/bind.h"
8 #include "base/json/json_writer.h"
9 #include "base/logging.h"
10 #include "base/stringprintf.h"
11 #include "base/values.h"
12 #include "chrome/test/chromedriver/devtools_client_impl.h"
13 #include "chrome/test/chromedriver/dom_tracker.h"
14 #include "chrome/test/chromedriver/frame_tracker.h"
15 #include "chrome/test/chromedriver/javascript_dialog_manager.h"
16 #include "chrome/test/chromedriver/js.h"
17 #include "chrome/test/chromedriver/navigation_tracker.h"
18 #include "chrome/test/chromedriver/status.h"
19 #include "chrome/test/chromedriver/ui_events.h"
20 #include "chrome/test/chromedriver/web_view_delegate.h"
21
22 namespace {
23
24 Status GetContextIdForFrame(FrameTracker* tracker,
25 const std::string& frame,
26 int* context_id) {
27 if (frame.empty()) {
28 *context_id = 0;
29 return Status(kOk);
30 }
31 Status status = tracker->GetContextIdForFrame(frame, context_id);
32 if (status.IsError())
33 return status;
34 return Status(kOk);
35 }
36
37 const char* GetAsString(MouseEventType type) {
38 switch (type) {
39 case kPressedMouseEventType:
40 return "mousePressed";
41 case kReleasedMouseEventType:
42 return "mouseReleased";
43 case kMovedMouseEventType:
44 return "mouseMoved";
45 default:
46 return "";
47 }
48 }
49
50 const char* GetAsString(MouseButton button) {
51 switch (button) {
52 case kLeftMouseButton:
53 return "left";
54 case kMiddleMouseButton:
55 return "middle";
56 case kRightMouseButton:
57 return "right";
58 case kNoneMouseButton:
59 return "none";
60 default:
61 return "";
62 }
63 }
64
65 Status IsNotPendingNavigation(NavigationTracker* tracker,
66 const std::string& frame_id,
67 bool* is_not_pending) {
68 bool is_pending;
69 Status status = tracker->IsPendingNavigation(frame_id, &is_pending);
70 if (status.IsError())
71 return status;
72 *is_not_pending = !is_pending;
73 return Status(kOk);
74 }
75
76 const char* GetAsString(KeyEventType type) {
77 switch (type) {
78 case kKeyDownEventType:
79 return "keyDown";
80 case kKeyUpEventType:
81 return "keyUp";
82 case kRawKeyDownEventType:
83 return "rawKeyDown";
84 case kCharEventType:
85 return "char";
86 default:
87 return "";
88 }
89 }
90
91 } // namespace
92
93 WebViewImpl::WebViewImpl(const std::string& id,
94 DevToolsClient* client,
95 WebViewDelegate* delegate,
96 const CloserFunc& closer_func)
97 : id_(id),
98 dom_tracker_(new DomTracker(client)),
99 frame_tracker_(new FrameTracker(client)),
100 navigation_tracker_(new NavigationTracker(client)),
101 dialog_manager_(new JavaScriptDialogManager(client)),
102 client_(client),
103 delegate_(delegate),
104 closer_func_(closer_func) {}
105
106 WebViewImpl::~WebViewImpl() {}
107
108 std::string WebViewImpl::GetId() {
109 return id_;
110 }
111
112 Status WebViewImpl::ConnectIfNecessary() {
113 return client_->ConnectIfNecessary();
114 }
115
116 Status WebViewImpl::Close() {
117 Status status = closer_func_.Run();
118 if (status.IsOk())
119 delegate_->OnWebViewClose(this);
120 return status;
121 }
122
123 Status WebViewImpl::Load(const std::string& url) {
124 base::DictionaryValue params;
125 params.SetString("url", url);
126 return client_->SendCommand("Page.navigate", params);
127 }
128
129 Status WebViewImpl::Reload() {
130 base::DictionaryValue params;
131 params.SetBoolean("ignoreCache", false);
132 return client_->SendCommand("Page.reload", params);
133 }
134
135 Status WebViewImpl::EvaluateScript(const std::string& frame,
136 const std::string& expression,
137 scoped_ptr<base::Value>* result) {
138 int context_id;
139 Status status = GetContextIdForFrame(frame_tracker_.get(), frame,
140 &context_id);
141 if (status.IsError())
142 return status;
143 return internal::EvaluateScriptAndGetValue(
144 client_.get(), context_id, expression, result);
145 }
146
147 Status WebViewImpl::CallFunction(const std::string& frame,
148 const std::string& function,
149 const base::ListValue& args,
150 scoped_ptr<base::Value>* result) {
151 std::string json;
152 base::JSONWriter::Write(&args, &json);
153 std::string expression = base::StringPrintf(
154 "(%s).apply(null, [%s, %s])",
155 kCallFunctionScript,
156 function.c_str(),
157 json.c_str());
158 scoped_ptr<base::Value> temp_result;
159 Status status = EvaluateScript(frame, expression, &temp_result);
160 if (status.IsError())
161 return status;
162
163 return internal::ParseCallFunctionResult(*temp_result, result);
164 }
165
166 Status WebViewImpl::GetFrameByFunction(const std::string& frame,
167 const std::string& function,
168 const base::ListValue& args,
169 std::string* out_frame) {
170 int context_id;
171 Status status = GetContextIdForFrame(frame_tracker_.get(), frame,
172 &context_id);
173 if (status.IsError())
174 return status;
175 int node_id;
176 status = internal::GetNodeIdFromFunction(
177 client_.get(), context_id, function, args, &node_id);
178 if (status.IsError())
179 return status;
180 return dom_tracker_->GetFrameIdForNode(node_id, out_frame);
181 }
182
183 Status WebViewImpl::DispatchMouseEvents(const std::list<MouseEvent>& events) {
184 for (std::list<MouseEvent>::const_iterator it = events.begin();
185 it != events.end(); ++it) {
186 base::DictionaryValue params;
187 params.SetString("type", GetAsString(it->type));
188 params.SetInteger("x", it->x);
189 params.SetInteger("y", it->y);
190 params.SetString("button", GetAsString(it->button));
191 params.SetInteger("clickCount", it->click_count);
192 Status status = client_->SendCommand("Input.dispatchMouseEvent", params);
193 if (status.IsError())
194 return status;
195 }
196 return Status(kOk);
197 }
198
199 Status WebViewImpl::DispatchKeyEvents(const std::list<KeyEvent>& events) {
200 for (std::list<KeyEvent>::const_iterator it = events.begin();
201 it != events.end(); ++it) {
202 base::DictionaryValue params;
203 params.SetString("type", GetAsString(it->type));
204 if (it->modifiers & kNumLockKeyModifierMask) {
205 params.SetBoolean("isKeypad", true);
206 params.SetInteger("modifiers",
207 it->modifiers & ~kNumLockKeyModifierMask);
208 } else {
209 params.SetInteger("modifiers", it->modifiers);
210 }
211 params.SetString("text", it->modified_text);
212 params.SetString("unmodifiedText", it->unmodified_text);
213 params.SetInteger("nativeVirtualKeyCode", it->key_code);
214 params.SetInteger("windowsVirtualKeyCode", it->key_code);
215 Status status = client_->SendCommand("Input.dispatchKeyEvent", params);
216 if (status.IsError())
217 return status;
218 }
219 return Status(kOk);
220 }
221
222 Status WebViewImpl::GetCookies(scoped_ptr<base::ListValue>* cookies) {
223 base::DictionaryValue params;
224 scoped_ptr<base::DictionaryValue> result;
225 Status status = client_->SendCommandAndGetResult(
226 "Page.getCookies", params, &result);
227 if (status.IsError())
228 return status;
229 base::ListValue* cookies_tmp;
230 if (!result->GetList("cookies", &cookies_tmp))
231 return Status(kUnknownError, "DevTools didn't return cookies");
232 cookies->reset(cookies_tmp->DeepCopy());
233 return Status(kOk);
234 }
235
236 Status WebViewImpl::DeleteCookie(const std::string& name,
237 const std::string& url) {
238 base::DictionaryValue params;
239 params.SetString("cookieName", name);
240 params.SetString("url", url);
241 return client_->SendCommand("Page.deleteCookie", params);
242 }
243
244 Status WebViewImpl::WaitForPendingNavigations(const std::string& frame_id) {
245 std::string full_frame_id(frame_id);
246 if (full_frame_id.empty()) {
247 Status status = GetMainFrame(&full_frame_id);
248 if (status.IsError())
249 return status;
250 }
251 return client_->HandleEventsUntil(
252 base::Bind(IsNotPendingNavigation, navigation_tracker_.get(),
253 full_frame_id));
254 }
255
256 Status WebViewImpl::IsPendingNavigation(const std::string& frame_id,
257 bool* is_pending) {
258 std::string full_frame_id(frame_id);
259 if (full_frame_id.empty()) {
260 Status status = GetMainFrame(&full_frame_id);
261 if (status.IsError())
262 return status;
263 }
264 return navigation_tracker_->IsPendingNavigation(frame_id, is_pending);
265 }
266
267 Status WebViewImpl::GetMainFrame(std::string* out_frame) {
268 base::DictionaryValue params;
269 scoped_ptr<base::DictionaryValue> result;
270 Status status = client_->SendCommandAndGetResult(
271 "Page.getResourceTree", params, &result);
272 if (status.IsError())
273 return status;
274 if (!result->GetString("frameTree.frame.id", out_frame))
275 return Status(kUnknownError, "missing 'frameTree.frame.id' in response");
276 return Status(kOk);
277 }
278
279 JavaScriptDialogManager* WebViewImpl::GetJavaScriptDialogManager() {
280 return dialog_manager_.get();
281 }
282
283 Status WebViewImpl::CaptureScreenshot(std::string* screenshot) {
284 base::DictionaryValue params;
285 scoped_ptr<base::DictionaryValue> result;
286 Status status = client_->SendCommandAndGetResult(
287 "Page.captureScreenshot", params, &result);
288 if (status.IsError())
289 return status;
290 if (!result->GetString("data", screenshot))
291 return Status(kUnknownError, "expected string 'data' in response");
292 return Status(kOk);
293 }
294
295 namespace internal {
296
297 Status EvaluateScript(DevToolsClient* client,
298 int context_id,
299 const std::string& expression,
300 EvaluateScriptReturnType return_type,
301 scoped_ptr<base::DictionaryValue>* result) {
302 base::DictionaryValue params;
303 params.SetString("expression", expression);
304 if (context_id)
305 params.SetInteger("contextId", context_id);
306 params.SetBoolean("returnByValue", return_type == ReturnByValue);
307 scoped_ptr<base::DictionaryValue> cmd_result;
308 Status status = client->SendCommandAndGetResult(
309 "Runtime.evaluate", params, &cmd_result);
310 if (status.IsError())
311 return status;
312
313 bool was_thrown;
314 if (!cmd_result->GetBoolean("wasThrown", &was_thrown))
315 return Status(kUnknownError, "Runtime.evaluate missing 'wasThrown'");
316 if (was_thrown) {
317 std::string description = "unknown";
318 cmd_result->GetString("result.description", &description);
319 return Status(kUnknownError,
320 "Runtime.evaluate threw exception: " + description);
321 }
322
323 base::DictionaryValue* unscoped_result;
324 if (!cmd_result->GetDictionary("result", &unscoped_result))
325 return Status(kUnknownError, "evaluate missing dictionary 'result'");
326 result->reset(unscoped_result->DeepCopy());
327 return Status(kOk);
328 }
329
330 Status EvaluateScriptAndGetObject(DevToolsClient* client,
331 int context_id,
332 const std::string& expression,
333 std::string* object_id) {
334 scoped_ptr<base::DictionaryValue> result;
335 Status status = EvaluateScript(client, context_id, expression, ReturnByObject,
336 &result);
337 if (status.IsError())
338 return status;
339 if (!result->GetString("objectId", object_id))
340 return Status(kUnknownError, "evaluate missing string 'objectId'");
341 return Status(kOk);
342 }
343
344 Status EvaluateScriptAndGetValue(DevToolsClient* client,
345 int context_id,
346 const std::string& expression,
347 scoped_ptr<base::Value>* result) {
348 scoped_ptr<base::DictionaryValue> temp_result;
349 Status status = EvaluateScript(client, context_id, expression, ReturnByValue,
350 &temp_result);
351 if (status.IsError())
352 return status;
353
354 std::string type;
355 if (!temp_result->GetString("type", &type))
356 return Status(kUnknownError, "Runtime.evaluate missing string 'type'");
357
358 if (type == "undefined") {
359 result->reset(base::Value::CreateNullValue());
360 } else {
361 base::Value* value;
362 if (!temp_result->Get("value", &value))
363 return Status(kUnknownError, "Runtime.evaluate missing 'value'");
364 result->reset(value->DeepCopy());
365 }
366 return Status(kOk);
367 }
368
369 Status ParseCallFunctionResult(const base::Value& temp_result,
370 scoped_ptr<base::Value>* result) {
371 const base::DictionaryValue* dict;
372 if (!temp_result.GetAsDictionary(&dict))
373 return Status(kUnknownError, "call function result must be a dictionary");
374 int status_code;
375 if (!dict->GetInteger("status", &status_code)) {
376 return Status(kUnknownError,
377 "call function result missing int 'status'");
378 }
379 if (status_code != kOk) {
380 std::string message;
381 dict->GetString("value", &message);
382 return Status(static_cast<StatusCode>(status_code), message);
383 }
384 const base::Value* unscoped_value;
385 if (!dict->Get("value", &unscoped_value)) {
386 return Status(kUnknownError,
387 "call function result missing 'value'");
388 }
389 result->reset(unscoped_value->DeepCopy());
390 return Status(kOk);
391 }
392
393 Status GetNodeIdFromFunction(DevToolsClient* client,
394 int context_id,
395 const std::string& function,
396 const base::ListValue& args,
397 int* node_id) {
398 std::string json;
399 base::JSONWriter::Write(&args, &json);
400 std::string expression = base::StringPrintf(
401 "(%s).apply(null, [%s, %s, true])",
402 kCallFunctionScript,
403 function.c_str(),
404 json.c_str());
405
406 std::string element_id;
407 Status status = internal::EvaluateScriptAndGetObject(
408 client, context_id, expression, &element_id);
409 if (status.IsError())
410 return status;
411
412 scoped_ptr<base::DictionaryValue> cmd_result;
413 {
414 base::DictionaryValue params;
415 params.SetString("objectId", element_id);
416 status = client->SendCommandAndGetResult(
417 "DOM.requestNode", params, &cmd_result);
418 }
419 {
420 // Release the remote object before doing anything else.
421 base::DictionaryValue params;
422 params.SetString("objectId", element_id);
423 Status release_status =
424 client->SendCommand("Runtime.releaseObject", params);
425 if (release_status.IsError()) {
426 LOG(ERROR) << "Failed to release remote object: "
427 << release_status.message();
428 }
429 }
430 if (status.IsError())
431 return status;
432
433 if (!cmd_result->GetInteger("nodeId", node_id))
434 return Status(kUnknownError, "DOM.requestNode missing int 'nodeId'");
435 return Status(kOk);
436 }
437
438 } // namespace internal
OLDNEW
« no previous file with comments | « chrome/test/chromedriver/web_view_impl.h ('k') | chrome/test/chromedriver/web_view_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698