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 |