Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 <stddef.h> | 5 #include <stddef.h> |
| 6 #include <utility> | 6 #include <utility> |
| 7 | 7 |
| 8 #include "base/base64.h" | 8 #include "base/base64.h" |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
| 11 #include "base/json/json_writer.h" | 11 #include "base/json/json_writer.h" |
| 12 #include "base/memory/ptr_util.h" | |
| 12 #include "base/run_loop.h" | 13 #include "base/run_loop.h" |
| 13 #include "base/values.h" | 14 #include "base/values.h" |
| 14 #include "build/build_config.h" | 15 #include "build/build_config.h" |
| 15 #include "content/public/browser/devtools_agent_host.h" | 16 #include "content/public/browser/devtools_agent_host.h" |
| 16 #include "content/public/browser/javascript_dialog_manager.h" | 17 #include "content/public/browser/javascript_dialog_manager.h" |
| 17 #include "content/public/browser/render_view_host.h" | 18 #include "content/public/browser/render_view_host.h" |
| 18 #include "content/public/browser/web_contents.h" | 19 #include "content/public/browser/web_contents.h" |
| 19 #include "content/public/common/url_constants.h" | 20 #include "content/public/common/url_constants.h" |
| 20 #include "content/public/test/browser_test_utils.h" | 21 #include "content/public/test/browser_test_utils.h" |
| 21 #include "content/public/test/content_browser_test.h" | 22 #include "content/public/test/content_browser_test.h" |
| 22 #include "content/public/test/content_browser_test_utils.h" | 23 #include "content/public/test/content_browser_test_utils.h" |
| 23 #include "content/public/test/test_navigation_observer.h" | 24 #include "content/public/test/test_navigation_observer.h" |
| 24 #include "content/shell/browser/shell.h" | 25 #include "content/shell/browser/shell.h" |
| 25 #include "net/dns/mock_host_resolver.h" | 26 #include "net/dns/mock_host_resolver.h" |
| 26 #include "net/test/embedded_test_server/embedded_test_server.h" | 27 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 28 #include "testing/gmock/include/gmock/gmock.h" | |
| 29 #include "third_party/re2/src/re2/re2.h" | |
| 27 #include "third_party/skia/include/core/SkBitmap.h" | 30 #include "third_party/skia/include/core/SkBitmap.h" |
| 28 #include "ui/compositor/compositor_switches.h" | 31 #include "ui/compositor/compositor_switches.h" |
| 29 #include "ui/gfx/codec/png_codec.h" | 32 #include "ui/gfx/codec/png_codec.h" |
| 30 | 33 |
| 34 using testing::MatchesRegex; | |
| 35 | |
| 31 namespace content { | 36 namespace content { |
| 32 | 37 |
| 33 namespace { | 38 namespace { |
| 34 | 39 |
| 35 const char kIdParam[] = "id"; | 40 const char kIdParam[] = "id"; |
| 36 const char kMethodParam[] = "method"; | 41 const char kMethodParam[] = "method"; |
| 37 const char kParamsParam[] = "params"; | 42 const char kParamsParam[] = "params"; |
| 38 | 43 |
| 39 class TestJavaScriptDialogManager : public JavaScriptDialogManager, | 44 class TestJavaScriptDialogManager : public JavaScriptDialogManager, |
| 40 public WebContentsDelegate { | 45 public WebContentsDelegate { |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 163 agent_host_->AttachClient(this); | 168 agent_host_->AttachClient(this); |
| 164 } | 169 } |
| 165 | 170 |
| 166 void TearDownOnMainThread() override { | 171 void TearDownOnMainThread() override { |
| 167 if (agent_host_) { | 172 if (agent_host_) { |
| 168 agent_host_->DetachClient(this); | 173 agent_host_->DetachClient(this); |
| 169 agent_host_ = nullptr; | 174 agent_host_ = nullptr; |
| 170 } | 175 } |
| 171 } | 176 } |
| 172 | 177 |
| 173 void WaitForNotification(const std::string& notification) { | 178 // Waits for an event of type |notification_name| to be sent. |
| 174 waiting_for_notification_ = notification; | 179 void WaitForNotification(const std::string& notification_name) { |
| 180 waiting_for_notification_ = notification_name; | |
| 181 waiting_for_notification_count_ = | |
| 182 notification_count_[notification_name] + 1; | |
| 175 RunMessageLoop(); | 183 RunMessageLoop(); |
| 176 } | 184 } |
| 177 | 185 |
| 186 // Waits until the count of events of type |notification_name| is >= count. | |
| 187 void WaitForNotificationCount(const std::string& notification_name, | |
| 188 int count) { | |
| 189 if (notification_count_[notification_name] < count) { | |
| 190 waiting_for_notification_ = notification_name; | |
| 191 waiting_for_notification_count_ = count; | |
| 192 RunMessageLoop(); | |
| 193 } | |
| 194 } | |
| 195 | |
| 196 struct ExpectedNavigation { | |
| 197 std::string url_regex; | |
| 198 bool renderer_initiated; | |
| 199 bool is_in_main_frame; | |
| 200 bool is_redirect; | |
| 201 std::string navigation_response; | |
| 202 }; | |
| 203 | |
| 204 // Waits for the expected navigations to occur in any order. If an expected | |
| 205 // navigation occurs, Page.processNavigation is called with the specified | |
| 206 // navigation_response to either allow it to proceed or to cancel it. | |
| 207 void WaitForNavigationsInAnyOrder( | |
| 208 std::vector<ExpectedNavigation> expected_navigations) { | |
| 209 while (!expected_navigations.empty()) { | |
| 210 WaitForNotification("Page.navigationRequested"); | |
| 211 ASSERT_TRUE(requested_notification_params_.get()); | |
| 212 | |
| 213 std::string url; | |
| 214 ASSERT_TRUE(requested_notification_params_->GetString("url", &url)); | |
| 215 int navigation_id; | |
| 216 ASSERT_TRUE(requested_notification_params_->GetInteger("navigationId", | |
| 217 &navigation_id)); | |
| 218 bool renderer_initiated; | |
| 219 ASSERT_TRUE(requested_notification_params_->GetBoolean( | |
| 220 "rendererInitiated", &renderer_initiated)); | |
| 221 bool is_in_main_frame; | |
| 222 ASSERT_TRUE(requested_notification_params_->GetBoolean( | |
| 223 "isInMainFrame", &is_in_main_frame)); | |
| 224 bool is_redirect; | |
| 225 ASSERT_TRUE(requested_notification_params_->GetBoolean("isRedirect", | |
| 226 &is_redirect)); | |
| 227 | |
| 228 bool navigation_was_expected; | |
| 229 for (auto it = expected_navigations.begin(); | |
| 230 it != expected_navigations.end(); it++) { | |
| 231 if (!RE2::FullMatch(url, it->url_regex) || | |
| 232 renderer_initiated != it->renderer_initiated || | |
| 233 is_in_main_frame != it->is_in_main_frame || | |
| 234 is_redirect != it->is_redirect) { | |
| 235 continue; | |
| 236 } | |
| 237 | |
| 238 std::unique_ptr<base::DictionaryValue> params( | |
| 239 new base::DictionaryValue()); | |
| 240 params->SetString("response", it->navigation_response); | |
| 241 params->SetInteger("navigationId", navigation_id); | |
| 242 SendCommand("Page.processNavigation", std::move(params), false); | |
| 243 | |
| 244 navigation_was_expected = true; | |
| 245 expected_navigations.erase(it); | |
| 246 break; | |
| 247 } | |
| 248 EXPECT_TRUE(navigation_was_expected) | |
| 249 << "url = " << url << "renderer_initiated = " << renderer_initiated | |
| 250 << "is_in_main_frame = " << is_in_main_frame | |
| 251 << "is_redirect = " << is_redirect; | |
| 252 } | |
| 253 } | |
| 254 | |
| 178 std::unique_ptr<base::DictionaryValue> result_; | 255 std::unique_ptr<base::DictionaryValue> result_; |
| 179 scoped_refptr<DevToolsAgentHost> agent_host_; | 256 scoped_refptr<DevToolsAgentHost> agent_host_; |
| 180 int last_sent_id_; | 257 int last_sent_id_; |
| 181 std::vector<int> result_ids_; | 258 std::vector<int> result_ids_; |
| 182 std::vector<std::string> notifications_; | 259 std::unique_ptr<base::DictionaryValue> requested_notification_params_; |
| 260 | |
| 261 bool NoEventsReceived() const { return notification_count_.empty(); } | |
| 183 | 262 |
| 184 private: | 263 private: |
| 185 void DispatchProtocolMessage(DevToolsAgentHost* agent_host, | 264 void DispatchProtocolMessage(DevToolsAgentHost* agent_host, |
| 186 const std::string& message) override { | 265 const std::string& message) override { |
| 187 std::unique_ptr<base::DictionaryValue> root( | 266 std::unique_ptr<base::DictionaryValue> root( |
| 188 static_cast<base::DictionaryValue*>( | 267 static_cast<base::DictionaryValue*>( |
| 189 base::JSONReader::Read(message).release())); | 268 base::JSONReader::Read(message).release())); |
| 190 int id; | 269 int id; |
| 191 if (root->GetInteger("id", &id)) { | 270 if (root->GetInteger("id", &id)) { |
| 192 result_ids_.push_back(id); | 271 result_ids_.push_back(id); |
| 193 base::DictionaryValue* result; | 272 base::DictionaryValue* result; |
| 194 ASSERT_TRUE(root->GetDictionary("result", &result)); | 273 ASSERT_TRUE(root->GetDictionary("result", &result)); |
| 195 result_.reset(result->DeepCopy()); | 274 result_.reset(result->DeepCopy()); |
| 196 in_dispatch_ = false; | 275 in_dispatch_ = false; |
| 197 if (id && id == waiting_for_command_result_id_) { | 276 if (id && id == waiting_for_command_result_id_) { |
| 198 waiting_for_command_result_id_ = 0; | 277 waiting_for_command_result_id_ = 0; |
| 199 base::MessageLoop::current()->QuitNow(); | 278 base::MessageLoop::current()->QuitNow(); |
| 200 } | 279 } |
| 201 } else { | 280 } else { |
| 202 std::string notification; | 281 std::string notification; |
| 203 EXPECT_TRUE(root->GetString("method", ¬ification)); | 282 EXPECT_TRUE(root->GetString("method", ¬ification)); |
| 204 notifications_.push_back(notification); | 283 int count = ++notification_count_[notification]; |
| 205 if (waiting_for_notification_ == notification) { | 284 if (waiting_for_notification_ == notification && |
| 285 count >= waiting_for_notification_count_) { | |
| 286 base::DictionaryValue* params; | |
| 287 if (root->GetDictionary("params", ¶ms)) { | |
| 288 requested_notification_params_ = params->CreateDeepCopy(); | |
| 289 } else { | |
| 290 requested_notification_params_.reset(); | |
| 291 } | |
| 206 waiting_for_notification_ = std::string(); | 292 waiting_for_notification_ = std::string(); |
| 207 base::MessageLoop::current()->QuitNow(); | 293 base::MessageLoop::current()->QuitNow(); |
| 208 } | 294 } |
| 209 } | 295 } |
| 210 } | 296 } |
| 211 | 297 |
| 212 void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override { | 298 void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override { |
| 213 EXPECT_TRUE(false); | 299 EXPECT_TRUE(false); |
| 214 } | 300 } |
| 215 | 301 |
| 302 std::map<std::string, int> notification_count_; | |
| 216 std::string waiting_for_notification_; | 303 std::string waiting_for_notification_; |
| 304 int waiting_for_notification_count_; | |
| 217 int waiting_for_command_result_id_; | 305 int waiting_for_command_result_id_; |
| 218 bool in_dispatch_; | 306 bool in_dispatch_; |
| 219 }; | 307 }; |
| 220 | 308 |
| 221 class SyntheticKeyEventTest : public DevToolsProtocolTest { | 309 class SyntheticKeyEventTest : public DevToolsProtocolTest { |
| 222 protected: | 310 protected: |
| 223 void SendKeyEvent(const std::string& type, | 311 void SendKeyEvent(const std::string& type, |
| 224 int modifier, | 312 int modifier, |
| 225 int windowsKeyCode, | 313 int windowsKeyCode, |
| 226 int nativeKeyCode, | 314 int nativeKeyCode, |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 409 SendCommand("Page.navigate", std::move(params), true); | 497 SendCommand("Page.navigate", std::move(params), true); |
| 410 navigation_observer.Wait(); | 498 navigation_observer.Wait(); |
| 411 | 499 |
| 412 bool enough_results = result_ids_.size() >= 2u; | 500 bool enough_results = result_ids_.size() >= 2u; |
| 413 EXPECT_TRUE(enough_results); | 501 EXPECT_TRUE(enough_results); |
| 414 if (enough_results) { | 502 if (enough_results) { |
| 415 EXPECT_EQ(1, result_ids_[0]); // Page.enable | 503 EXPECT_EQ(1, result_ids_[0]); // Page.enable |
| 416 EXPECT_EQ(2, result_ids_[1]); // Page.navigate | 504 EXPECT_EQ(2, result_ids_[1]); // Page.navigate |
| 417 } | 505 } |
| 418 | 506 |
| 419 enough_results = notifications_.size() >= 1u; | 507 WaitForNotificationCount("Page.frameStartedLoading", 1); |
| 420 EXPECT_TRUE(enough_results); | |
| 421 bool found_frame_notification = false; | |
| 422 for (const std::string& notification : notifications_) { | |
| 423 if (notification == "Page.frameStartedLoading") | |
| 424 found_frame_notification = true; | |
| 425 } | |
| 426 EXPECT_TRUE(found_frame_notification); | |
| 427 } | 508 } |
| 428 | 509 |
| 429 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, CrossSiteNoDetach) { | 510 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, CrossSiteNoDetach) { |
| 430 host_resolver()->AddRule("*", "127.0.0.1"); | 511 host_resolver()->AddRule("*", "127.0.0.1"); |
| 431 ASSERT_TRUE(embedded_test_server()->Start()); | 512 ASSERT_TRUE(embedded_test_server()->Start()); |
| 432 content::SetupCrossSiteRedirector(embedded_test_server()); | 513 content::SetupCrossSiteRedirector(embedded_test_server()); |
| 433 | 514 |
| 434 GURL test_url1 = embedded_test_server()->GetURL( | 515 GURL test_url1 = embedded_test_server()->GetURL( |
| 435 "A.com", "/devtools/navigation.html"); | 516 "A.com", "/devtools/navigation.html"); |
| 436 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url1, 1); | 517 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url1, 1); |
| 437 Attach(); | 518 Attach(); |
| 438 | 519 |
| 439 GURL test_url2 = embedded_test_server()->GetURL( | 520 GURL test_url2 = embedded_test_server()->GetURL( |
| 440 "B.com", "/devtools/navigation.html"); | 521 "B.com", "/devtools/navigation.html"); |
| 441 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url2, 1); | 522 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url2, 1); |
| 442 | 523 |
| 443 EXPECT_EQ(0u, notifications_.size()); | 524 EXPECT_TRUE(NoEventsReceived()); |
| 444 } | 525 } |
| 445 | 526 |
| 446 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ReconnectPreservesState) { | 527 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ReconnectPreservesState) { |
| 447 ASSERT_TRUE(embedded_test_server()->Start()); | 528 ASSERT_TRUE(embedded_test_server()->Start()); |
| 448 GURL test_url = embedded_test_server()->GetURL("/devtools/navigation.html"); | 529 GURL test_url = embedded_test_server()->GetURL("/devtools/navigation.html"); |
| 449 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1); | 530 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1); |
| 450 | 531 |
| 451 Shell* second = CreateBrowser(); | 532 Shell* second = CreateBrowser(); |
| 452 NavigateToURLBlockUntilNavigationsComplete(second, test_url, 1); | 533 NavigateToURLBlockUntilNavigationsComplete(second, test_url, 1); |
| 453 | 534 |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 590 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, BrowserNewPage) { | 671 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, BrowserNewPage) { |
| 591 NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1); | 672 NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1); |
| 592 Attach(); | 673 Attach(); |
| 593 EXPECT_EQ(1u, shell()->windows().size()); | 674 EXPECT_EQ(1u, shell()->windows().size()); |
| 594 std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue()); | 675 std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue()); |
| 595 params->SetString("initialUrl", "about:blank"); | 676 params->SetString("initialUrl", "about:blank"); |
| 596 SendCommand("Browser.newPage", std::move(params), true); | 677 SendCommand("Browser.newPage", std::move(params), true); |
| 597 EXPECT_EQ(2u, shell()->windows().size()); | 678 EXPECT_EQ(2u, shell()->windows().size()); |
| 598 } | 679 } |
| 599 | 680 |
| 681 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ControlNavigations_MainFrame) { | |
|
nasko
2016/07/14 16:47:19
No underscores, just CamelCase.
alex clarke (OOO till 29th)
2016/07/14 17:38:34
Done.
| |
| 682 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 683 | |
| 684 NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1); | |
| 685 Attach(); | |
| 686 SendCommand("Page.enable", nullptr); | |
| 687 | |
| 688 std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue()); | |
| 689 params->SetBoolean("enabled", true); | |
| 690 SendCommand("Page.setControlNavigations", std::move(params), true); | |
| 691 | |
| 692 GURL test_url = embedded_test_server()->GetURL( | |
| 693 "/devtools/control_navigations/meta_tag.html"); | |
| 694 shell()->LoadURL(test_url); | |
| 695 | |
| 696 std::vector<ExpectedNavigation> expected_navigations = { | |
| 697 {"http://127.0.0.1:\\d+/devtools/control_navigations/meta_tag.html", | |
| 698 false /* expected_renderer_initiated */, | |
| 699 true /* expected_is_in_main_frame */, false /* expected_is_redirect */, | |
| 700 "Proceed"}, | |
| 701 {"http://127.0.0.1:\\d+/devtools/navigation.html", | |
| 702 true /* expected_renderer_initiated */, | |
| 703 true /* expected_is_in_main_frame */, false /* expected_is_redirect */, | |
| 704 "Cancel"}}; | |
| 705 | |
| 706 WaitForNavigationsInAnyOrder(std::move(expected_navigations)); | |
| 707 | |
| 708 WaitForNotificationCount("Page.frameStoppedLoading", 2); | |
| 709 | |
| 710 // Check main frame has the expected url. | |
| 711 SendCommand("Page.getResourceTree", nullptr); | |
| 712 | |
| 713 const base::DictionaryValue* frame_tree; | |
| 714 ASSERT_TRUE(result_->GetDictionary("frameTree", &frame_tree)); | |
| 715 const base::DictionaryValue* frame; | |
| 716 ASSERT_TRUE(frame_tree->GetDictionary("frame", &frame)); | |
| 717 | |
| 718 std::string frame_url; | |
| 719 ASSERT_TRUE(frame->GetString("url", &frame_url)); | |
| 720 EXPECT_THAT( | |
| 721 frame_url, | |
| 722 MatchesRegex( | |
| 723 "http://127.0.0.1:\\d+/devtools/control_navigations/meta_tag.html")); | |
|
nasko
2016/07/14 16:47:19
very minor nit: You could just strip the port numb
alex clarke (OOO till 29th)
2016/07/14 17:38:34
Seems like a good idea, are there any utilities fo
nasko
2016/07/14 17:55:51
You can use a GURL::Replacements. There are some e
alex clarke (OOO till 29th)
2016/07/15 13:21:21
Done.
| |
| 724 } | |
| 725 | |
| 726 // TODO(alexclarke): Make this work with IsolateAllSitesForTesting. | |
| 727 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ControlNavigations_ChildFrames) { | |
|
nasko
2016/07/14 16:47:20
Thanks for adding this test!
| |
| 728 host_resolver()->AddRule("*", "127.0.0.1"); | |
| 729 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 730 content::SetupCrossSiteRedirector(embedded_test_server()); | |
| 731 | |
| 732 NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1); | |
|
nasko
2016/07/14 16:47:19
Why do you need to navigate to about:blank first?
alex clarke (OOO till 29th)
2016/07/14 17:38:34
For two reasons:
1. To make sure there's a page we
nasko
2016/07/14 17:55:51
In general, each frame starts with an initial blan
| |
| 733 Attach(); | |
| 734 SendCommand("Page.enable", nullptr); | |
| 735 | |
| 736 std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue()); | |
| 737 params->SetBoolean("enabled", true); | |
| 738 SendCommand("Page.setControlNavigations", std::move(params), true); | |
| 739 | |
| 740 GURL test_url = embedded_test_server()->GetURL( | |
| 741 "/devtools/control_navigations/iframe_navigation.html"); | |
| 742 shell()->LoadURL(test_url); | |
| 743 | |
| 744 // Allow main frame navigation, and all iframe navigations to http://a.com | |
| 745 // Allow initial iframe navigation to http://b.com but dissallow it to | |
| 746 // navigate to /devtools/navigation.html. | |
| 747 std::vector<ExpectedNavigation> expected_navigations = { | |
| 748 {"http://127.0.0.1:\\d+/devtools/control_navigations/" | |
| 749 "iframe_navigation.html", | |
| 750 /* expected_renderer_initiated */ false, | |
| 751 /* expected_is_in_main_frame */ true, | |
| 752 /* expected_is_redirect */ false, "Proceed"}, | |
| 753 {"http://127.0.0.1:\\d+/cross-site/a.com/devtools/control_navigations/" | |
| 754 "meta_tag.html", | |
| 755 /* expected_renderer_initiated */ true, | |
| 756 /* expected_is_in_main_frame */ false, | |
| 757 /* expected_is_redirect */ false, "Proceed"}, | |
| 758 {"http://127.0.0.1:\\d+/cross-site/b.com/devtools/control_navigations/" | |
| 759 "meta_tag.html", | |
| 760 /* expected_renderer_initiated */ true, | |
| 761 /* expected_is_in_main_frame */ false, | |
| 762 /* expected_is_redirect */ false, "Proceed"}, | |
| 763 {"http://a.com:\\d+/devtools/control_navigations/meta_tag.html", | |
| 764 /* expected_renderer_initiated */ true, | |
| 765 /* expected_is_in_main_frame */ false, | |
| 766 /* expected_is_redirect */ true, "Proceed"}, | |
| 767 {"http://b.com:\\d+/devtools/control_navigations/meta_tag.html", | |
| 768 /* expected_renderer_initiated */ true, | |
| 769 /* expected_is_in_main_frame */ false, | |
| 770 /* expected_is_redirect */ true, "Proceed"}, | |
| 771 {"http://a.com:\\d+/devtools/navigation.html", | |
| 772 /* expected_renderer_initiated */ true, | |
| 773 /* expected_is_in_main_frame */ false, | |
| 774 /* expected_is_redirect */ false, "Proceed"}, | |
| 775 {"http://b.com:\\d+/devtools/navigation.html", | |
| 776 /* expected_renderer_initiated */ true, | |
| 777 /* expected_is_in_main_frame */ false, | |
| 778 /* expected_is_redirect */ false, "Cancel"}}; | |
| 779 | |
| 780 WaitForNavigationsInAnyOrder(std::move(expected_navigations)); | |
| 781 | |
| 782 WaitForNotificationCount("Page.frameStoppedLoading", 5); | |
| 783 | |
| 784 // Check that the a.com iframe navigated to /devtools/navigation.html and that | |
| 785 // the b.com iframe was stuck at /devtools/control_navigations/meta_tag.html. | |
| 786 SendCommand("Page.getResourceTree", nullptr); | |
| 787 | |
| 788 const base::DictionaryValue* frame_tree; | |
| 789 ASSERT_TRUE(result_->GetDictionary("frameTree", &frame_tree)); | |
| 790 | |
| 791 const base::ListValue* child_frames; | |
| 792 ASSERT_TRUE(frame_tree->GetList("childFrames", &child_frames)); | |
| 793 EXPECT_EQ(2u, child_frames->GetSize()); | |
| 794 | |
| 795 const base::DictionaryValue* child_frame0; | |
| 796 ASSERT_TRUE(child_frames->GetDictionary(0, &child_frame0)); | |
| 797 ASSERT_TRUE(child_frame0->GetDictionary("frame", &child_frame0)); | |
| 798 | |
| 799 std::string frame0_url; | |
| 800 ASSERT_TRUE(child_frame0->GetString("url", &frame0_url)); | |
| 801 EXPECT_THAT(frame0_url, | |
| 802 MatchesRegex("http://a.com:\\d+/devtools/navigation.html")); | |
| 803 | |
| 804 const base::DictionaryValue* child_frame1; | |
| 805 ASSERT_TRUE(child_frames->GetDictionary(1, &child_frame1)); | |
| 806 ASSERT_TRUE(child_frame1->GetDictionary("frame", &child_frame1)); | |
| 807 std::string frame1_url; | |
| 808 ASSERT_TRUE(child_frame1->GetString("url", &frame1_url)); | |
| 809 EXPECT_THAT( | |
| 810 frame1_url, | |
| 811 MatchesRegex( | |
| 812 "http://b.com:\\d+/devtools/control_navigations/meta_tag.html")); | |
| 813 } | |
| 814 | |
| 600 } // namespace content | 815 } // namespace content |
| OLD | NEW |