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

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

Issue 11639019: [chromedriver] Implement SwitchToFrame command. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 11 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/test/chromedriver/chrome_impl.h" 5 #include "chrome/test/chromedriver/chrome_impl.h"
6 6
7 #include "base/json/json_reader.h" 7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h" 8 #include "base/json/json_writer.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/process_util.h" 10 #include "base/process_util.h"
11 #include "base/stringprintf.h" 11 #include "base/stringprintf.h"
12 #include "base/threading/platform_thread.h" 12 #include "base/threading/platform_thread.h"
13 #include "base/time.h" 13 #include "base/time.h"
14 #include "base/values.h" 14 #include "base/values.h"
15 #include "chrome/test/chromedriver/devtools_client_impl.h" 15 #include "chrome/test/chromedriver/devtools_client_impl.h"
16 #include "chrome/test/chromedriver/dom_tracker.h"
16 #include "chrome/test/chromedriver/js.h" 17 #include "chrome/test/chromedriver/js.h"
17 #include "chrome/test/chromedriver/net/net_util.h" 18 #include "chrome/test/chromedriver/net/net_util.h"
18 #include "chrome/test/chromedriver/net/sync_websocket_impl.h" 19 #include "chrome/test/chromedriver/net/sync_websocket_impl.h"
19 #include "chrome/test/chromedriver/net/url_request_context_getter.h" 20 #include "chrome/test/chromedriver/net/url_request_context_getter.h"
20 #include "chrome/test/chromedriver/status.h" 21 #include "chrome/test/chromedriver/status.h"
21 #include "googleurl/src/gurl.h" 22 #include "googleurl/src/gurl.h"
22 23
23 namespace { 24 namespace {
24 25
25 Status FetchPagesInfo(URLRequestContextGetter* context_getter, 26 Status FetchPagesInfo(URLRequestContextGetter* context_getter,
26 int port, 27 int port,
27 std::list<std::string>* debugger_urls) { 28 std::list<std::string>* debugger_urls) {
28 std::string url = base::StringPrintf( 29 std::string url = base::StringPrintf(
29 "http://127.0.0.1:%d/json", port); 30 "http://127.0.0.1:%d/json", port);
30 std::string data; 31 std::string data;
31 if (!FetchUrl(GURL(url), context_getter, &data)) 32 if (!FetchUrl(GURL(url), context_getter, &data))
32 return Status(kChromeNotReachable); 33 return Status(kChromeNotReachable);
33 return internal::ParsePagesInfo(data, debugger_urls); 34 return internal::ParsePagesInfo(data, debugger_urls);
34 } 35 }
35 36
37 Status GetContextIdForFrame(DomTracker* tracker,
38 const std::string& frame,
39 int* context_id) {
40 if (frame.empty()) {
41 *context_id = 0;
42 return Status(kOk);
43 }
44 Status status = tracker->GetContextIdForFrame(frame, context_id);
45 if (status.IsError())
46 return status;
47 return Status(kOk);
48 }
49
36 } // namespace 50 } // namespace
37 51
38 ChromeImpl::ChromeImpl(base::ProcessHandle process, 52 ChromeImpl::ChromeImpl(base::ProcessHandle process,
39 URLRequestContextGetter* context_getter, 53 URLRequestContextGetter* context_getter,
40 base::ScopedTempDir* user_data_dir, 54 base::ScopedTempDir* user_data_dir,
41 int port, 55 int port,
42 const SyncWebSocketFactory& socket_factory) 56 const SyncWebSocketFactory& socket_factory)
43 : process_(process), 57 : process_(process),
44 context_getter_(context_getter), 58 context_getter_(context_getter),
45 port_(port), 59 port_(port),
46 socket_factory_(socket_factory) { 60 socket_factory_(socket_factory),
61 dom_tracker_(new DomTracker()) {
47 if (user_data_dir->IsValid()) { 62 if (user_data_dir->IsValid()) {
48 CHECK(user_data_dir_.Set(user_data_dir->Take())); 63 CHECK(user_data_dir_.Set(user_data_dir->Take()));
49 } 64 }
50 } 65 }
51 66
52 ChromeImpl::~ChromeImpl() { 67 ChromeImpl::~ChromeImpl() {
53 base::CloseProcessHandle(process_); 68 base::CloseProcessHandle(process_);
54 } 69 }
55 70
56 Status ChromeImpl::Init() { 71 Status ChromeImpl::Init() {
57 base::Time deadline = base::Time::Now() + base::TimeDelta::FromSeconds(20); 72 base::Time deadline = base::Time::Now() + base::TimeDelta::FromSeconds(20);
58 std::list<std::string> debugger_urls; 73 std::list<std::string> debugger_urls;
59 while (base::Time::Now() < deadline) { 74 while (base::Time::Now() < deadline) {
60 FetchPagesInfo(context_getter_, port_, &debugger_urls); 75 FetchPagesInfo(context_getter_, port_, &debugger_urls);
61 if (debugger_urls.empty()) 76 if (debugger_urls.empty())
62 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); 77 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
63 else 78 else
64 break; 79 break;
65 } 80 }
66 if (debugger_urls.empty()) 81 if (debugger_urls.empty())
67 return Status(kUnknownError, "unable to discover open pages"); 82 return Status(kUnknownError, "unable to discover open pages");
68 client_.reset(new DevToolsClientImpl( 83 client_.reset(new DevToolsClientImpl(
69 socket_factory_, debugger_urls.front(), NULL)); 84 socket_factory_, debugger_urls.front(), dom_tracker_.get()));
70 return Status(kOk); 85
86 // Perform necessary configuration of the DevTools client.
87 // Fetch the root document node so that Inspector will push DOM node
88 // information to the client.
89 base::DictionaryValue params;
90 Status status = client_->SendCommand("DOM.getDocument", params);
91 if (status.IsError())
92 return status;
93 // Enable runtime events to allow tracking execution context creation.
94 return client_->SendCommand("Runtime.enable", params);
71 } 95 }
72 96
73 Status ChromeImpl::Load(const std::string& url) { 97 Status ChromeImpl::Load(const std::string& url) {
74 base::DictionaryValue params; 98 base::DictionaryValue params;
75 params.SetString("url", url); 99 params.SetString("url", url);
76 return client_->SendCommand("Page.navigate", params); 100 return client_->SendCommand("Page.navigate", params);
77 } 101 }
78 102
79 Status ChromeImpl::EvaluateScript(const std::string& expression, 103 Status ChromeImpl::EvaluateScript(const std::string& frame,
104 const std::string& expression,
80 scoped_ptr<base::Value>* result) { 105 scoped_ptr<base::Value>* result) {
81 return internal::EvaluateScript(client_.get(), expression, result); 106 int context_id;
107 Status status = GetContextIdForFrame(dom_tracker_.get(), frame, &context_id);
108 if (status.IsError())
109 return status;
110 return internal::EvaluateScriptAndGetValue(
111 client_.get(), context_id, expression, result);
82 } 112 }
83 113
84 Status ChromeImpl::CallFunction(const std::string& function, 114 Status ChromeImpl::CallFunction(const std::string& frame,
115 const std::string& function,
85 const base::ListValue& args, 116 const base::ListValue& args,
86 scoped_ptr<base::Value>* result) { 117 scoped_ptr<base::Value>* result) {
87 std::string json; 118 std::string json;
88 base::JSONWriter::Write(&args, &json); 119 base::JSONWriter::Write(&args, &json);
89 std::string expression = base::StringPrintf( 120 std::string expression = base::StringPrintf(
90 "(%s).apply(null, [%s, %s])", 121 "(%s).apply(null, [%s, %s])",
91 kCallFunctionScript, 122 kCallFunctionScript,
92 function.c_str(), 123 function.c_str(),
93 json.c_str()); 124 json.c_str());
94 return EvaluateScript(expression, result); 125 return EvaluateScript(frame, expression, result);
126 }
127
128 Status ChromeImpl::GetFrameByFunction(const std::string& frame,
129 const std::string& function,
130 const base::ListValue& args,
131 std::string* out_frame) {
132 int context_id;
133 Status status = GetContextIdForFrame(dom_tracker_.get(), frame, &context_id);
134 if (status.IsError())
135 return status;
136 int node_id;
137 status = internal::GetNodeIdFromFunction(
138 client_.get(), context_id, function, args, &node_id);
139 if (status.IsError())
140 return status;
141 return dom_tracker_->GetFrameIdForNode(node_id, out_frame);
95 } 142 }
96 143
97 Status ChromeImpl::Quit() { 144 Status ChromeImpl::Quit() {
98 if (!base::KillProcess(process_, 0, true)) 145 if (!base::KillProcess(process_, 0, true))
99 return Status(kUnknownError, "cannot kill Chrome"); 146 return Status(kUnknownError, "cannot kill Chrome");
100 return Status(kOk); 147 return Status(kOk);
101 } 148 }
102 149
103 namespace internal { 150 namespace internal {
104 151
(...skipping 14 matching lines...) Expand all
119 std::string debugger_url; 166 std::string debugger_url;
120 if (!info->GetString("webSocketDebuggerUrl", &debugger_url)) 167 if (!info->GetString("webSocketDebuggerUrl", &debugger_url))
121 return Status(kUnknownError, "DevTools did not include debugger URL"); 168 return Status(kUnknownError, "DevTools did not include debugger URL");
122 internal_urls.push_back(debugger_url); 169 internal_urls.push_back(debugger_url);
123 } 170 }
124 debugger_urls->swap(internal_urls); 171 debugger_urls->swap(internal_urls);
125 return Status(kOk); 172 return Status(kOk);
126 } 173 }
127 174
128 Status EvaluateScript(DevToolsClient* client, 175 Status EvaluateScript(DevToolsClient* client,
176 int context_id,
129 const std::string& expression, 177 const std::string& expression,
130 scoped_ptr<base::Value>* result) { 178 EvaluateScriptReturnType return_type,
179 scoped_ptr<base::DictionaryValue>* result) {
131 base::DictionaryValue params; 180 base::DictionaryValue params;
132 params.SetString("expression", expression); 181 params.SetString("expression", expression);
133 params.SetBoolean("returnByValue", true); 182 if (context_id)
183 params.SetInteger("contextId", context_id);
184 params.SetBoolean("returnByValue", return_type == ReturnByValue);
134 scoped_ptr<base::DictionaryValue> cmd_result; 185 scoped_ptr<base::DictionaryValue> cmd_result;
135 Status status = client->SendCommandAndGetResult( 186 Status status = client->SendCommandAndGetResult(
136 "Runtime.evaluate", params, &cmd_result); 187 "Runtime.evaluate", params, &cmd_result);
137 if (status.IsError()) 188 if (status.IsError())
138 return status; 189 return status;
139 190
140 bool was_thrown; 191 bool was_thrown;
141 if (!cmd_result->GetBoolean("wasThrown", &was_thrown)) 192 if (!cmd_result->GetBoolean("wasThrown", &was_thrown))
142 return Status(kUnknownError, "Runtime.evaluate missing 'wasThrown'"); 193 return Status(kUnknownError, "Runtime.evaluate missing 'wasThrown'");
143 if (was_thrown) { 194 if (was_thrown) {
144 std::string description = "unknown"; 195 std::string description = "unknown";
145 cmd_result->GetString("result.description", &description); 196 cmd_result->GetString("result.description", &description);
146 return Status(kUnknownError, 197 return Status(kUnknownError,
147 "Runtime.evaluate threw exception: " + description); 198 "Runtime.evaluate threw exception: " + description);
148 } 199 }
149 200
201 base::DictionaryValue* unscoped_result;
202 if (!cmd_result->GetDictionary("result", &unscoped_result))
203 return Status(kUnknownError, "evaluate missing dictionary 'result'");
204 result->reset(unscoped_result->DeepCopy());
205 return Status(kOk);
206 }
207
208 Status EvaluateScriptAndGetObject(DevToolsClient* client,
209 int context_id,
210 const std::string& expression,
211 std::string* object_id) {
212 scoped_ptr<base::DictionaryValue> result;
213 Status status = EvaluateScript(client, context_id, expression, ReturnByObject,
214 &result);
215 if (status.IsError())
216 return status;
217 if (!result->GetString("objectId", object_id))
218 return Status(kUnknownError, "evaluate missing string 'objectId'");
219 return Status(kOk);
220 }
221
222 Status EvaluateScriptAndGetValue(DevToolsClient* client,
223 int context_id,
224 const std::string& expression,
225 scoped_ptr<base::Value>* result) {
226 scoped_ptr<base::DictionaryValue> temp_result;
227 Status status = EvaluateScript(client, context_id, expression, ReturnByValue,
228 &temp_result);
229 if (status.IsError())
230 return status;
231
150 std::string type; 232 std::string type;
151 if (!cmd_result->GetString("result.type", &type)) 233 if (!temp_result->GetString("type", &type))
152 return Status(kUnknownError, "Runtime.evaluate missing result.type"); 234 return Status(kUnknownError, "Runtime.evaluate missing string 'type'");
153 235
154 if (type == "undefined") { 236 if (type == "undefined") {
155 result->reset(base::Value::CreateNullValue()); 237 result->reset(base::Value::CreateNullValue());
156 } else { 238 } else {
157 int status_code; 239 int status_code;
158 if (!cmd_result->GetInteger("result.value.status", &status_code)) { 240 if (!temp_result->GetInteger("value.status", &status_code)) {
159 return Status(kUnknownError, 241 return Status(kUnknownError,
160 "Runtime.evaluate missing result.value.status"); 242 "Runtime.evaluate missing int 'value.status'");
161 } 243 }
162 if (status_code != kOk) 244 if (status_code != kOk)
163 return Status(static_cast<StatusCode>(status_code)); 245 return Status(static_cast<StatusCode>(status_code));
164 base::Value* unscoped_value; 246 base::Value* unscoped_value;
165 if (!cmd_result->Get("result.value.value", &unscoped_value)) { 247 if (!temp_result->Get("value.value", &unscoped_value)) {
166 return Status(kUnknownError, 248 return Status(kUnknownError,
167 "Runtime.evaluate missing result.value.value"); 249 "Runtime.evaluate missing 'value.value'");
168 } 250 }
169 result->reset(unscoped_value->DeepCopy()); 251 result->reset(unscoped_value->DeepCopy());
170 } 252 }
171 return Status(kOk); 253 return Status(kOk);
172 } 254 }
173 255
256 Status GetNodeIdFromFunction(DevToolsClient* client,
257 int context_id,
258 const std::string& function,
259 const base::ListValue& args,
260 int* node_id) {
261 std::string json;
262 base::JSONWriter::Write(&args, &json);
263 std::string expression = base::StringPrintf(
264 "(%s).apply(null, [%s, %s, true])",
265 kCallFunctionScript,
266 function.c_str(),
267 json.c_str());
268
269 std::string element_id;
270 Status status = internal::EvaluateScriptAndGetObject(
271 client, context_id, expression, &element_id);
272 if (status.IsError())
273 return status;
274
275 scoped_ptr<base::DictionaryValue> cmd_result;
276 {
277 base::DictionaryValue params;
278 params.SetString("objectId", element_id);
279 status = client->SendCommandAndGetResult(
280 "DOM.requestNode", params, &cmd_result);
281 }
282 {
283 // Release the remote object before doing anything else.
284 base::DictionaryValue params;
285 params.SetString("objectId", element_id);
286 Status release_status =
287 client->SendCommand("Runtime.releaseObject", params);
288 if (release_status.IsError()) {
289 LOG(ERROR) << "Failed to release remote object: "
290 << release_status.message();
291 }
292 }
293 if (status.IsError())
294 return status;
295
296 if (!cmd_result->GetInteger("nodeId", node_id))
297 return Status(kUnknownError, "DOM.requestNode missing int 'nodeId'");
298 return Status(kOk);
299 }
300
174 } // namespace internal 301 } // namespace internal
OLDNEW
« no previous file with comments | « chrome/test/chromedriver/chrome_impl.h ('k') | chrome/test/chromedriver/chrome_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698