Clear webapp storage when site data is cleared
[chromium-blink-merge.git] / content / browser / devtools / protocol / devtools_protocol_browsertest.cc
blob79f76279464bfd14e36cb3ec3f388ac2c37de0de
1 // Copyright 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.
5 #include "base/base64.h"
6 #include "base/command_line.h"
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/values.h"
10 #include "content/public/browser/devtools_agent_host.h"
11 #include "content/public/browser/render_view_host.h"
12 #include "content/public/browser/web_contents.h"
13 #include "content/public/common/url_constants.h"
14 #include "content/public/test/browser_test_utils.h"
15 #include "content/public/test/content_browser_test.h"
16 #include "content/public/test/content_browser_test_utils.h"
17 #include "content/public/test/test_navigation_observer.h"
18 #include "content/shell/browser/shell.h"
19 #include "net/dns/mock_host_resolver.h"
20 #include "net/test/embedded_test_server/embedded_test_server.h"
21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "ui/compositor/compositor_switches.h"
23 #include "ui/gfx/codec/png_codec.h"
25 namespace content {
27 namespace {
29 const char kIdParam[] = "id";
30 const char kMethodParam[] = "method";
31 const char kParamsParam[] = "params";
35 class DevToolsProtocolTest : public ContentBrowserTest,
36 public DevToolsAgentHostClient {
37 public:
38 DevToolsProtocolTest()
39 : last_sent_id_(0),
40 in_dispatch_(false) {
43 protected:
44 void SendCommand(const std::string& method,
45 scoped_ptr<base::DictionaryValue> params) {
46 SendCommand(method, params.Pass(), true);
49 void SendCommand(const std::string& method,
50 scoped_ptr<base::DictionaryValue> params,
51 bool wait) {
52 in_dispatch_ = true;
53 base::DictionaryValue command;
54 command.SetInteger(kIdParam, ++last_sent_id_);
55 command.SetString(kMethodParam, method);
56 if (params)
57 command.Set(kParamsParam, params.release());
59 std::string json_command;
60 base::JSONWriter::Write(command, &json_command);
61 agent_host_->DispatchProtocolMessage(json_command);
62 // Some messages are dispatched synchronously.
63 // Only run loop if we are not finished yet.
64 if (in_dispatch_ && wait)
65 base::MessageLoop::current()->Run();
66 in_dispatch_ = false;
69 bool HasValue(const std::string& path) {
70 base::Value* value = 0;
71 return result_->Get(path, &value);
74 bool HasListItem(const std::string& path_to_list,
75 const std::string& name,
76 const std::string& value) {
77 base::ListValue* list;
78 if (!result_->GetList(path_to_list, &list))
79 return false;
81 for (size_t i = 0; i != list->GetSize(); i++) {
82 base::DictionaryValue* item;
83 if (!list->GetDictionary(i, &item))
84 return false;
85 std::string id;
86 if (!item->GetString(name, &id))
87 return false;
88 if (id == value)
89 return true;
91 return false;
94 void Attach() {
95 agent_host_ = DevToolsAgentHost::GetOrCreateFor(shell()->web_contents());
96 agent_host_->AttachClient(this);
99 void TearDownOnMainThread() override {
100 if (agent_host_) {
101 agent_host_->DetachClient();
102 agent_host_ = nullptr;
106 scoped_ptr<base::DictionaryValue> result_;
107 scoped_refptr<DevToolsAgentHost> agent_host_;
108 int last_sent_id_;
109 std::vector<int> result_ids_;
110 std::vector<std::string> notifications_;
112 private:
113 void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
114 const std::string& message) override {
115 scoped_ptr<base::DictionaryValue> root(static_cast<base::DictionaryValue*>(
116 base::JSONReader::Read(message).release()));
117 int id;
118 if (root->GetInteger("id", &id)) {
119 result_ids_.push_back(id);
120 base::DictionaryValue* result;
121 EXPECT_TRUE(root->GetDictionary("result", &result));
122 result_.reset(result->DeepCopy());
123 in_dispatch_ = false;
124 if (base::MessageLoop::current()->is_running())
125 base::MessageLoop::current()->QuitNow();
126 } else {
127 std::string notification;
128 EXPECT_TRUE(root->GetString("method", &notification));
129 notifications_.push_back(notification);
133 void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override {
134 EXPECT_TRUE(false);
137 bool in_dispatch_;
140 class SyntheticKeyEventTest : public DevToolsProtocolTest {
141 protected:
142 void SendKeyEvent(const std::string& type,
143 int modifier,
144 int windowsKeyCode,
145 int nativeKeyCode) {
146 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
147 params->SetString("type", type);
148 params->SetInteger("modifiers", modifier);
149 params->SetInteger("windowsVirtualKeyCode", windowsKeyCode);
150 params->SetInteger("nativeVirtualKeyCode", nativeKeyCode);
151 SendCommand("Input.dispatchKeyEvent", params.Pass());
155 IN_PROC_BROWSER_TEST_F(SyntheticKeyEventTest, KeyEventSynthesizeKeyIdentifier) {
156 NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
157 Attach();
158 ASSERT_TRUE(content::ExecuteScript(
159 shell()->web_contents()->GetRenderViewHost(),
160 "function handleKeyEvent(event) {"
161 "domAutomationController.setAutomationId(0);"
162 "domAutomationController.send(event.keyIdentifier);"
164 "document.body.addEventListener('keydown', handleKeyEvent);"
165 "document.body.addEventListener('keyup', handleKeyEvent);"));
167 DOMMessageQueue dom_message_queue;
169 // Send enter (keycode 13).
170 SendKeyEvent("rawKeyDown", 0, 13, 13);
171 SendKeyEvent("keyUp", 0, 13, 13);
173 std::string key_identifier;
174 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key_identifier));
175 EXPECT_EQ("\"Enter\"", key_identifier);
176 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key_identifier));
177 EXPECT_EQ("\"Enter\"", key_identifier);
179 // Send escape (keycode 27).
180 SendKeyEvent("rawKeyDown", 0, 27, 27);
181 SendKeyEvent("keyUp", 0, 27, 27);
183 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key_identifier));
184 EXPECT_EQ("\"U+001B\"", key_identifier);
185 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key_identifier));
186 EXPECT_EQ("\"U+001B\"", key_identifier);
189 class CaptureScreenshotTest : public DevToolsProtocolTest {
190 private:
191 #if !defined(OS_ANDROID)
192 void SetUpCommandLine(base::CommandLine* command_line) override {
193 command_line->AppendSwitch(switches::kEnablePixelOutputInTests);
195 #endif
198 // Does not link on Android
199 #if defined(OS_ANDROID)
200 #define MAYBE_CaptureScreenshot DISABLED_CaptureScreenshot
201 #elif defined(OS_MACOSX) // Fails on 10.9. http://crbug.com/430620
202 #define MAYBE_CaptureScreenshot DISABLED_CaptureScreenshot
203 #elif defined(MEMORY_SANITIZER)
204 // Also fails under MSAN. http://crbug.com/423583
205 #define MAYBE_CaptureScreenshot DISABLED_CaptureScreenshot
206 #else
207 #define MAYBE_CaptureScreenshot CaptureScreenshot
208 #endif
209 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, MAYBE_CaptureScreenshot) {
210 shell()->LoadURL(GURL("about:blank"));
211 Attach();
212 EXPECT_TRUE(content::ExecuteScript(
213 shell()->web_contents()->GetRenderViewHost(),
214 "document.body.style.background = '#123456'"));
215 SendCommand("Page.captureScreenshot", nullptr);
216 std::string base64;
217 EXPECT_TRUE(result_->GetString("data", &base64));
218 std::string png;
219 EXPECT_TRUE(base::Base64Decode(base64, &png));
220 SkBitmap bitmap;
221 gfx::PNGCodec::Decode(reinterpret_cast<const unsigned char*>(png.data()),
222 png.size(), &bitmap);
223 SkColor color(bitmap.getColor(0, 0));
224 EXPECT_TRUE(std::abs(0x12-(int)SkColorGetR(color)) <= 1);
225 EXPECT_TRUE(std::abs(0x34-(int)SkColorGetG(color)) <= 1);
226 EXPECT_TRUE(std::abs(0x56-(int)SkColorGetB(color)) <= 1);
229 #if defined(OS_ANDROID)
230 // Disabled, see http://crbug.com/469947.
231 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, DISABLED_SynthesizePinchGesture) {
232 GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
233 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
234 Attach();
236 int old_width;
237 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
238 shell()->web_contents(),
239 "domAutomationController.send(window.innerWidth)", &old_width));
241 int old_height;
242 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
243 shell()->web_contents(),
244 "domAutomationController.send(window.innerHeight)", &old_height));
246 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
247 params->SetInteger("x", old_width / 2);
248 params->SetInteger("y", old_height / 2);
249 params->SetDouble("scaleFactor", 2.0);
250 SendCommand("Input.synthesizePinchGesture", params.Pass());
252 int new_width;
253 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
254 shell()->web_contents(),
255 "domAutomationController.send(window.innerWidth)", &new_width));
256 ASSERT_DOUBLE_EQ(2.0, static_cast<double>(old_width) / new_width);
258 int new_height;
259 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
260 shell()->web_contents(),
261 "domAutomationController.send(window.innerHeight)", &new_height));
262 ASSERT_DOUBLE_EQ(2.0, static_cast<double>(old_height) / new_height);
265 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SynthesizeScrollGesture) {
266 GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
267 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
268 Attach();
270 int scroll_top;
271 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
272 shell()->web_contents(),
273 "domAutomationController.send(document.body.scrollTop)", &scroll_top));
274 ASSERT_EQ(0, scroll_top);
276 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
277 params->SetInteger("x", 0);
278 params->SetInteger("y", 0);
279 params->SetInteger("xDistance", 0);
280 params->SetInteger("yDistance", -100);
281 SendCommand("Input.synthesizeScrollGesture", params.Pass());
283 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
284 shell()->web_contents(),
285 "domAutomationController.send(document.body.scrollTop)", &scroll_top));
286 ASSERT_EQ(100, scroll_top);
289 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SynthesizeTapGesture) {
290 GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html");
291 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
292 Attach();
294 int scroll_top;
295 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
296 shell()->web_contents(),
297 "domAutomationController.send(document.body.scrollTop)", &scroll_top));
298 ASSERT_EQ(0, scroll_top);
300 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
301 params->SetInteger("x", 16);
302 params->SetInteger("y", 16);
303 params->SetString("gestureSourceType", "touch");
304 SendCommand("Input.synthesizeTapGesture", params.Pass());
306 // The link that we just tapped should take us to the bottom of the page. The
307 // new value of |document.body.scrollTop| will depend on the screen dimensions
308 // of the device that we're testing on, but in any case it should be greater
309 // than 0.
310 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
311 shell()->web_contents(),
312 "domAutomationController.send(document.body.scrollTop)", &scroll_top));
313 ASSERT_GT(scroll_top, 0);
315 #endif // defined(OS_ANDROID)
317 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, NavigationPreservesMessages) {
318 ASSERT_TRUE(test_server()->Start());
319 GURL test_url = test_server()->GetURL("files/devtools/navigation.html");
320 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
321 Attach();
322 SendCommand("Page.enable", nullptr, false);
324 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
325 test_url = GetTestUrl("devtools", "navigation.html");
326 params->SetString("url", test_url.spec());
327 SendCommand("Page.navigate", params.Pass(), true);
329 bool enough_results = result_ids_.size() >= 2u;
330 EXPECT_TRUE(enough_results);
331 if (enough_results) {
332 EXPECT_EQ(1, result_ids_[0]); // Page.enable
333 EXPECT_EQ(2, result_ids_[1]); // Page.navigate
336 enough_results = notifications_.size() >= 1u;
337 EXPECT_TRUE(enough_results);
338 bool found_frame_notification = false;
339 for (const std::string& notification : notifications_) {
340 if (notification == "Page.frameStartedLoading")
341 found_frame_notification = true;
343 EXPECT_TRUE(found_frame_notification);
346 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, CrossSiteNoDetach) {
347 host_resolver()->AddRule("*", "127.0.0.1");
348 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
349 content::SetupCrossSiteRedirector(embedded_test_server());
351 GURL test_url1 = embedded_test_server()->GetURL(
352 "A.com", "/devtools/navigation.html");
353 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url1, 1);
354 Attach();
356 GURL test_url2 = embedded_test_server()->GetURL(
357 "B.com", "/devtools/navigation.html");
358 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url2, 1);
360 EXPECT_EQ(0u, notifications_.size());
363 } // namespace content