1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_
#define CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_
// A collection of functions designed for use with content_shell based browser
// tests internal to the content/ module.
// Note: If a function here also works with browser_tests, it should be in
// the content public API.
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "content/browser/bad_message.h"
#include "content/browser/renderer_host/back_forward_cache_metrics.h"
#include "content/browser/renderer_host/navigation_type.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/javascript_dialog_manager.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test_content_browser_client.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/test_support/test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "third_party/blink/public/mojom/choosers/file_chooser.mojom-forward.h"
#include "third_party/blink/public/mojom/choosers/popup_menu.mojom.h"
#include "third_party/blink/public/mojom/frame/frame.mojom-test-utils.h"
#include "third_party/blink/public/mojom/page/widget.mojom-test-utils.h"
#include "url/gurl.h"
namespace content {
class FrameTreeNode;
class RenderFrameHost;
class RenderFrameHostImpl;
class RenderWidgetHostImpl;
class Shell;
class SiteInstance;
class SiteInstanceGroup;
class ToRenderFrameHost;
// Navigates the frame represented by |node| to |url|, blocking until the
// navigation finishes. Returns true if the navigation succeedd and the final
// URL matches |url|.
bool NavigateFrameToURL(FrameTreeNode* node, const GURL& url);
// Sets the DialogManager to proceed by default or not when showing a
// BeforeUnload dialog, and if it proceeds, what value to return.
void SetShouldProceedOnBeforeUnload(Shell* shell, bool proceed, bool success);
// Extends the ToRenderFrameHost mechanism to FrameTreeNodes.
RenderFrameHost* ConvertToRenderFrameHost(FrameTreeNode* frame_tree_node);
// Helper function to navigate a window to a |url|, using a browser-initiated
// navigation that will stay in the same BrowsingInstance. Most
// browser-initiated navigations swap BrowsingInstances, but some tests need a
// navigation to swap processes for cross-site URLs (even outside of
// --site-per-process) while staying in the same BrowsingInstance.
[[nodiscard]] bool NavigateToURLInSameBrowsingInstance(Shell* window,
const GURL& url);
// Helper function to checks for a subframe navigation starting in
// `start_site_instance` and results in an error page correctly transitions to
// `end_site_instance` based on whether error page isolation is enabled or not.
[[nodiscard]] bool IsExpectedSubframeErrorTransition(
SiteInstance* start_site_instance,
SiteInstance* end_site_instance);
// Creates an iframe with id |frame_id| and src set to |url|, and appends it to
// the main frame's document, waiting until the RenderFrameHostCreated
// notification is received by the browser. If |wait_for_navigation| is true,
// will also wait for the first navigation in the iframe to finish. Returns the
// RenderFrameHost of the iframe. |extra_params| is a struct that allows
// for optional parameters to be specified for the subframe.
struct ExtraParams {
std::string sandbox_flags = "";
};
RenderFrameHost* CreateSubframe(WebContentsImpl* web_contents,
std::string frame_id,
const GURL& url,
bool wait_for_navigation);
RenderFrameHost* CreateSubframe(RenderFrameHost* parent,
std::string frame_id,
const GURL& url,
bool wait_for_navigation);
RenderFrameHost* CreateSubframe(RenderFrameHost* parent,
std::string frame_id,
const GURL& url,
bool wait_for_navigation,
ExtraParams extra_params);
// Returns the frames visited by |RenderFrameHostImpl::ForEachRenderFrameHost|
// in the same order.
std::vector<RenderFrameHostImpl*> CollectAllRenderFrameHosts(
RenderFrameHostImpl* starting_rfh);
std::vector<RenderFrameHostImpl*>
CollectAllRenderFrameHostsIncludingSpeculative(
RenderFrameHostImpl* starting_rfh);
// Returns the frames visited by |WebContentsImpl::ForEachRenderFrameHost|
// in the same order.
std::vector<RenderFrameHostImpl*> CollectAllRenderFrameHosts(
WebContentsImpl* web_contents);
std::vector<RenderFrameHostImpl*>
CollectAllRenderFrameHostsIncludingSpeculative(WebContentsImpl* web_contents);
// Open a new popup passing no URL to window.open, which results in a blank page
// and only the initial entry. Returns the newly created shell. Also saves the
// reference to the opened window in the "last_opened_window" variable in JS.
Shell* OpenBlankWindow(WebContentsImpl* web_contents);
// Pop open a new window that navigates to |url|. Returns the newly created
// shell. Also saves the reference to the opened window in the
// "last_opened_window" variable in JS.
Shell* OpenWindow(WebContentsImpl* web_contents, const GURL& url);
// Creates compact textual representations of the state of the frame tree that
// is appropriate for use in assertions.
//
// The diagrams show frame tree structure, the SiteInstance of current frames,
// presence of pending frames, and the SiteInstanceGroups of any and all
// proxies. They look like this:
//
// Site A (D pending) -- proxies for B {C,E}
// |--Site B --------- proxies for A {C,E}
// +--Site C --------- proxies for B A
// |--Site A ---- proxies for B {C,E}
// +--Site A ---- proxies for B {C,E}
// +--Site E -- proxies for A B
// Where A = http://127.0.0.1/
// B = http://foo.com/ (no process)
// C = http://bar.com/
// D = http://next.com/
// E = data:nonce_E
//
// SiteInstances are assigned single-letter names (A, B, C) which are remembered
// across invocations of the pretty-printer. Port numbers are excluded from the
// descriptions by default for DepictFrameTree. Isolated sandboxed SiteInstances
// are denoted with "(sandboxed)".
//
// SiteInstanceGroups with more than once SiteInstance are denoted as a set of
// the SiteInstances in the group. See comment for `GetGroupName`. In this case,
// E is in C's SiteInstanceGroup, denoted {C,E}. Note that SiteInstanceGroups
// may show SiteInstances that are no longer in the FrameTree. For example, if a
// subframe B does a same-SiteInstanceGroup navigation to data:nonce_C, B's
// SiteInstance is kept alive by a FrameNavigationEntry, and it retains its
// group and process because the active frame count is tracked on the
// SiteInstanceGroup (shared with data:nonce_C) and not the B SiteInstance
// itself. (This is not necessary but has no impact outside of DepictFrameTree
// output). That means it still exists from the perspective
// of DepictFrameTree.
class FrameTreeVisualizer {
public:
FrameTreeVisualizer();
FrameTreeVisualizer(const FrameTreeVisualizer&) = delete;
FrameTreeVisualizer& operator=(const FrameTreeVisualizer&) = delete;
~FrameTreeVisualizer();
// Formats and returns a diagram for the provided FrameTreeNode.
std::string DepictFrameTree(FrameTreeNode* root);
private:
// Assign or retrive the abbreviated short name (A, B, C) for a site instance.
std::string GetName(SiteInstance* site_instance);
// Assign the name for a SiteInstanceGroup. A group's name is denoted as a set
// containing all the SiteInstances in the group, using their abbreviated
// names. For example, if a group contains foo.com and bar.com, which are
// assigned A and B respectively, the group name will be {A,B}. If there is
// only one SiteInstance in the group, it is directly depicted as the short
// name without set notation to minimize changes to existing tests. E.g.
// SiteInstanceGroup that contains only SiteInstance A is depicted as A rather
// than {A}.
// TODO(crbug.com/40176090): Always use set notation, to indicate that proxies
// are associated with SiteInstanceGroups rather than SiteInstances.
std::string GetGroupName(SiteInstanceGroup* group);
// Returns an identical URL except the port, if any, has been removed.
GURL GetUrlWithoutPort(const GURL& url);
// Elements are site instance ids. The index of the SiteInstance in the vector
// determines the abbreviated name (0->A, 1->B) for that SiteInstance.
std::vector<SiteInstanceId> seen_site_instance_ids_;
};
// Uses FrameTreeVisualizer to draw a text representation of the FrameTree that
// is appropriate for use in assertions. If you are going to depict multiple
// trees in a single test, you might want to construct a longer-lived instance
// of FrameTreeVisualizer as this will ensure consistent naming of the site
// instances across all calls.
std::string DepictFrameTree(FrameTreeNode& root);
// Uses window.open to open a popup from the frame |opener| with the specified
// |url|, |name| and window |features|. |expect_return_from_window_open| is used
// to indicate if the caller expects window.open() to return a non-null value.
// Waits for the navigation to |url| to finish and then returns the new popup's
// Shell. Note that since this navigation to |url| is renderer-initiated, it
// won't cause a process swap unless used in --site-per-process mode.
Shell* OpenPopup(const ToRenderFrameHost& opener,
const GURL& url,
const std::string& name,
const std::string& features,
bool expect_return_from_window_open);
// Same as above, but with an empty |features| and
// |expect_return_from_window_open| assumed to be true..
Shell* OpenPopup(const ToRenderFrameHost& opener,
const GURL& url,
const std::string& name);
// Helper for mocking choosing a file via a file dialog.
class FileChooserDelegate : public WebContentsDelegate {
public:
// Constructs a WebContentsDelegate that mocks a file dialog.
// The mocked file dialog will always reply that the user selected |file| or
// |files|. |callback| is invoked when RunFileChooser() is called.
FileChooserDelegate(const base::FilePath& file, base::OnceClosure callback);
// |base_dir| must be set to the folder being uploaded in |kUploadFolder|
// mode, and must be empty in all other modes.
FileChooserDelegate(std::vector<base::FilePath> files,
const base::FilePath& base_dir,
base::OnceClosure callback);
~FileChooserDelegate() override;
// Implementation of WebContentsDelegate::RunFileChooser.
void RunFileChooser(RenderFrameHost* render_frame_host,
scoped_refptr<content::FileSelectListener> listener,
const blink::mojom::FileChooserParams& params) override;
// The params passed to RunFileChooser.
const blink::mojom::FileChooserParams& params() const { return *params_; }
private:
std::vector<base::FilePath> files_;
const base::FilePath base_dir_;
base::OnceClosure callback_;
blink::mojom::FileChooserParamsPtr params_;
};
// This class is a TestNavigationManager that only monitors notifications within
// the given frame tree node.
class FrameTestNavigationManager : public TestNavigationManager {
public:
FrameTestNavigationManager(FrameTreeNodeId frame_tree_node_id,
WebContents* web_contents,
const GURL& url);
FrameTestNavigationManager(const FrameTestNavigationManager&) = delete;
FrameTestNavigationManager& operator=(const FrameTestNavigationManager&) =
delete;
private:
// TestNavigationManager:
bool ShouldMonitorNavigation(NavigationHandle* handle) override;
// Notifications are filtered so only this frame is monitored.
FrameTreeNodeId filtering_frame_tree_node_id_;
};
// An observer that can wait for a specific URL to be committed in a specific
// frame.
// Note: it does not track the start of a navigation, unlike other observers.
class UrlCommitObserver : WebContentsObserver {
public:
explicit UrlCommitObserver(FrameTreeNode* frame_tree_node, const GURL& url);
UrlCommitObserver(const UrlCommitObserver&) = delete;
UrlCommitObserver& operator=(const UrlCommitObserver&) = delete;
~UrlCommitObserver() override;
void Wait();
private:
void DidFinishNavigation(NavigationHandle* navigation_handle) override;
// The id of the FrameTreeNode in which navigations are peformed.
FrameTreeNodeId frame_tree_node_id_;
// The URL this observer is expecting to be committed.
GURL url_;
// The RunLoop used to spin the message loop.
base::RunLoop run_loop_;
};
// Waits for a kill of the given RenderProcessHost and returns the
// BadMessageReason that caused a //content-triggerred kill.
//
// Example usage:
// RenderProcessHostBadIpcMessageWaiter kill_waiter(render_process_host);
// ... test code that triggers a renderer kill ...
// EXPECT_EQ(bad_message::RFH_INVALID_ORIGIN_ON_COMMIT, kill_waiter.Wait());
//
// Tests that don't expect kills (e.g. tests where a renderer process exits
// normally, like RenderFrameHostManagerTest.ProcessExitWithSwappedOutViews)
// should use RenderProcessHostWatcher instead of
// RenderProcessHostBadIpcMessageWaiter.
class RenderProcessHostBadIpcMessageWaiter {
public:
explicit RenderProcessHostBadIpcMessageWaiter(
RenderProcessHost* render_process_host);
RenderProcessHostBadIpcMessageWaiter(
const RenderProcessHostBadIpcMessageWaiter&) = delete;
RenderProcessHostBadIpcMessageWaiter& operator=(
const RenderProcessHostBadIpcMessageWaiter&) = delete;
// Waits until the renderer process exits. Returns the bad message that made
// //content kill the renderer. |std::nullopt| is returned if the renderer
// was killed outside of //content or exited normally.
[[nodiscard]] std::optional<bad_message::BadMessageReason> Wait();
private:
RenderProcessHostKillWaiter internal_waiter_;
};
// One-shot helper that listens for creation of a new popup widget.
class CreateNewPopupWidgetInterceptor
: public blink::mojom::LocalFrameHostInterceptorForTesting {
public:
explicit CreateNewPopupWidgetInterceptor(
RenderFrameHostImpl* rfh,
base::OnceCallback<void(RenderWidgetHostImpl*)> did_create_callback);
~CreateNewPopupWidgetInterceptor() override;
// LocalFrameHost overrides:
void CreateNewPopupWidget(
mojo::PendingAssociatedReceiver<blink::mojom::PopupWidgetHost>
blink_popup_widget_host,
mojo::PendingAssociatedReceiver<blink::mojom::WidgetHost>
blink_widget_host,
mojo::PendingAssociatedRemote<blink::mojom::Widget> blink_widget)
override;
// LocalFrameHostInterceptorForTesting overrides:
blink::mojom::LocalFrameHost* GetForwardingInterface() override;
private:
mojo::test::ScopedSwapImplForTesting<blink::mojom::LocalFrameHost>
swapped_impl_;
base::OnceCallback<void(RenderWidgetHostImpl*)> did_create_callback_;
};
class ShowPopupWidgetWaiter
: public blink::mojom::PopupWidgetHostInterceptorForTesting {
public:
ShowPopupWidgetWaiter(WebContentsImpl* web_contents,
RenderFrameHostImpl* frame_host);
ShowPopupWidgetWaiter(const ShowPopupWidgetWaiter&) = delete;
ShowPopupWidgetWaiter& operator=(const ShowPopupWidgetWaiter&) = delete;
~ShowPopupWidgetWaiter() override;
gfx::Rect last_initial_rect() const { return initial_rect_; }
int last_routing_id() const { return routing_id_; }
// Waits until a popup request is received.
void Wait();
private:
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
// Helper that waits for a `ShowPopupMenu()` call and then invokes the
// observer callback with the requested bounds. The actual call to show the
// popup menu is treated as if it were cancelled.
class ShowPopupMenuInterceptor
: public blink::mojom::LocalFrameHostInterceptorForTesting {
public:
explicit ShowPopupMenuInterceptor(RenderFrameHostImpl* rfh,
base::OnceCallback<void(const gfx::Rect&)>
did_show_popup_menu_callback);
~ShowPopupMenuInterceptor() override;
// LocalFrameHost overrides:
void ShowPopupMenu(
mojo::PendingRemote<blink::mojom::PopupMenuClient> popup_client,
const gfx::Rect& bounds,
double font_size,
int32_t selected_item,
std::vector<blink::mojom::MenuItemPtr> menu_items,
bool right_aligned,
bool allow_multiple_selection) override;
// LocalFrameHostInterceptorForTesting overrides:
blink::mojom::LocalFrameHost* GetForwardingInterface() override;
private:
mojo::test::ScopedSwapImplForTesting<blink::mojom::LocalFrameHost>
swapped_impl_;
base::OnceCallback<void(const gfx::Rect&)> did_show_popup_menu_callback_;
};
void DidShowPopupMenu(const gfx::Rect& bounds);
#endif
// Callback bound for creating a popup widget.
void DidCreatePopupWidget(RenderWidgetHostImpl* render_widget_host);
// blink::mojom::PopupWidgetHostInterceptorForTesting:
blink::mojom::PopupWidgetHost* GetForwardingInterface() override;
void ShowPopup(const gfx::Rect& initial_rect,
const gfx::Rect& initial_anchor_rect,
ShowPopupCallback callback) override;
CreateNewPopupWidgetInterceptor create_new_popup_widget_interceptor_;
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
ShowPopupMenuInterceptor show_popup_menu_interceptor_;
#endif
base::RunLoop run_loop_;
gfx::Rect initial_rect_;
int32_t routing_id_ = MSG_ROUTING_NONE;
int32_t process_id_ = 0;
const raw_ptr<RenderFrameHostImpl> frame_host_;
};
// This observer waits until WebContentsObserver::OnRendererUnresponsive
// notification.
class UnresponsiveRendererObserver : public WebContentsObserver {
public:
explicit UnresponsiveRendererObserver(WebContents* web_contents);
UnresponsiveRendererObserver(const UnresponsiveRendererObserver&) = delete;
UnresponsiveRendererObserver& operator=(const UnresponsiveRendererObserver&) =
delete;
~UnresponsiveRendererObserver() override;
RenderProcessHost* Wait(base::TimeDelta timeout = base::TimeDelta::Max());
private:
// WebContentsObserver:
void OnRendererUnresponsive(RenderProcessHost* render_process_host) override;
raw_ptr<RenderProcessHost> captured_render_process_host_ = nullptr;
base::RunLoop run_loop_;
};
// Helper class that overrides the JavaScriptDialogManager of a WebContents
// to endlessly block on beforeunload.
class BeforeUnloadBlockingDelegate : public JavaScriptDialogManager,
public WebContentsDelegate {
public:
explicit BeforeUnloadBlockingDelegate(WebContentsImpl* web_contents);
BeforeUnloadBlockingDelegate(const BeforeUnloadBlockingDelegate&) = delete;
BeforeUnloadBlockingDelegate& operator=(const BeforeUnloadBlockingDelegate&) =
delete;
~BeforeUnloadBlockingDelegate() override;
void Wait();
// WebContentsDelegate
JavaScriptDialogManager* GetJavaScriptDialogManager(
WebContents* source) override;
bool IsBackForwardCacheSupported(WebContents& web_contents) override;
// JavaScriptDialogManager
void RunJavaScriptDialog(WebContents* web_contents,
RenderFrameHost* render_frame_host,
JavaScriptDialogType dialog_type,
const std::u16string& message_text,
const std::u16string& default_prompt_text,
DialogClosedCallback callback,
bool* did_suppress_message) override;
void RunBeforeUnloadDialog(WebContents* web_contents,
RenderFrameHost* render_frame_host,
bool is_reload,
DialogClosedCallback callback) override;
bool HandleJavaScriptDialog(WebContents* web_contents,
bool accept,
const std::u16string* prompt_override) override;
void CancelDialogs(WebContents* web_contents, bool reset_state) override {}
private:
raw_ptr<WebContentsImpl> web_contents_;
DialogClosedCallback callback_;
std::unique_ptr<base::RunLoop> run_loop_ = std::make_unique<base::RunLoop>();
};
// Captures various properties of the NavigationHandle on DidFinishNavigation.
// By default, captures the next navigation (either for a specific frame or
// any frame in the WebContents) and waits until the navigation completely
// loads. Can be configured to not wait for load to finish, and also to capture
// properties for multiple navigations, as we save the values in arrays.
class FrameNavigateParamsCapturer : public WebContentsObserver {
public:
// Observes navigation for any node in `contents`.
explicit FrameNavigateParamsCapturer(WebContents* contents);
// Observes navigation for the specified |node|.
explicit FrameNavigateParamsCapturer(FrameTreeNode* node);
~FrameNavigateParamsCapturer() override;
// Start waiting for |navigations_remaining_| navigations to finish (and for
// load to finish if |wait_for_load_| is true).
void Wait();
// Sets the number of navigations to wait for.
void set_navigations_remaining(int count) {
DCHECK_GE(count, 0);
navigations_remaining_ = count;
}
// Sets |wait_for_load_| to determine whether to stop waiting when we receive
// DidFinishNavigation or DidStopLoading.
void set_wait_for_load(bool wait_for_load) { wait_for_load_ = wait_for_load; }
// Gets various captured parameters from the last navigation.
// Must only be called when we only capture a single navigation.
ui::PageTransition transition() const {
EXPECT_EQ(1U, transitions_.size());
return transitions_[0];
}
NavigationType navigation_type() const {
EXPECT_EQ(1U, navigation_types_.size());
return navigation_types_[0];
}
bool is_same_document() const {
EXPECT_EQ(1U, is_same_documents_.size());
return is_same_documents_[0];
}
bool is_renderer_initiated() const {
EXPECT_EQ(1U, is_renderer_initiateds_.size());
return is_renderer_initiateds_[0];
}
bool did_replace_entry() const {
EXPECT_EQ(1U, did_replace_entries_.size());
return did_replace_entries_[0];
}
bool has_user_gesture() const {
EXPECT_EQ(1U, has_user_gestures_.size());
return has_user_gestures_[0];
}
bool is_overriding_user_agent() const {
EXPECT_EQ(1U, is_overriding_user_agents_.size());
return is_overriding_user_agents_[0];
}
bool is_error_page() const {
EXPECT_EQ(1U, is_error_pages_.size());
return is_error_pages_[0];
}
// Gets various captured parameters from all observed navigations.
const std::vector<ui::PageTransition>& transitions() { return transitions_; }
const std::vector<GURL>& urls() { return urls_; }
const std::vector<NavigationType>& navigation_types() {
return navigation_types_;
}
const std::vector<bool>& is_same_documents() { return is_same_documents_; }
const std::vector<bool>& did_replace_entries() {
return did_replace_entries_;
}
const std::vector<bool>& has_user_gestures() { return has_user_gestures_; }
const std::vector<bool>& is_overriding_user_agents() {
return is_overriding_user_agents_;
}
const std::vector<bool>& is_error_pages() { return is_error_pages_; }
private:
void DidFinishNavigation(NavigationHandle* navigation_handle) override;
void DidStopLoading() override;
// The id of the FrameTreeNode whose navigations to observe. If this is not
// set, then this FrameNavigateParamsCapturer observes all navigations that
// happen in the observed WebContents.
std::optional<FrameTreeNodeId> frame_tree_node_id_;
// How many navigations remain to capture.
int navigations_remaining_ = 1;
// Whether to also wait for the load to complete.
bool wait_for_load_ = true;
// The saved properties of the NavigationHandle, captured on
// DidFinishNavigation. When Wait() finishes, these arrays should contain
// |navigations_remaining_|, as we always capture them for each navigations.
std::vector<ui::PageTransition> transitions_;
std::vector<GURL> urls_;
std::vector<NavigationType> navigation_types_;
std::vector<bool> is_same_documents_;
std::vector<bool> did_replace_entries_;
std::vector<bool> is_renderer_initiateds_;
std::vector<bool> has_user_gestures_;
std::vector<bool> is_overriding_user_agents_;
std::vector<bool> is_error_pages_;
base::RunLoop loop_;
};
// This observer keeps track of the number of created RenderFrameHosts. Tests
// can use this to ensure that a certain number of child frames has been
// created after navigating (defaults to 1), and can also supply a callback to
// run on every RenderFrameCreated call.
class RenderFrameHostCreatedObserver : public WebContentsObserver {
public:
using OnRenderFrameHostCreatedCallback =
base::RepeatingCallback<void(RenderFrameHost*)>;
explicit RenderFrameHostCreatedObserver(WebContents* web_contents);
RenderFrameHostCreatedObserver(WebContents* web_contents,
int expected_frame_count);
RenderFrameHostCreatedObserver(
WebContents* web_contents,
OnRenderFrameHostCreatedCallback on_rfh_created);
~RenderFrameHostCreatedObserver() override;
RenderFrameHost* Wait();
RenderFrameHost* last_rfh() { return last_rfh_; }
private:
void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
// The number of RenderFrameHosts to wait for.
int expected_frame_count_ = 1;
// The number of RenderFrameHosts that have been created.
int frames_created_ = 0;
// The RunLoop used to spin the message loop.
base::RunLoop run_loop_;
// The last RenderFrameHost created.
raw_ptr<RenderFrameHost, AcrossTasksDanglingUntriaged> last_rfh_ = nullptr;
// The callback to call when a RenderFrameCreated call is observed.
OnRenderFrameHostCreatedCallback on_rfh_created_;
};
// The standard DisabledReason used in testing. The functions below use this
// reason and tests will need to assert that it appears.
BackForwardCache::DisabledReason RenderFrameHostDisabledForTestingReason();
// Disable using the standard testing DisabledReason.
void DisableBFCacheForRFHForTesting(RenderFrameHost* render_frame_host);
void DisableBFCacheForRFHForTesting(GlobalRenderFrameHostId id);
// Changes the WebContents and active entry user agent override from
// DidStartNavigation().
class UserAgentInjector : public WebContentsObserver {
public:
UserAgentInjector(WebContents* web_contents, const std::string& user_agent)
: UserAgentInjector(web_contents,
blink::UserAgentOverride::UserAgentOnly(user_agent),
true) {}
UserAgentInjector(WebContents* web_contents,
const blink::UserAgentOverride& ua_override,
bool is_overriding_user_agent = true)
: WebContentsObserver(web_contents),
user_agent_override_(ua_override),
is_overriding_user_agent_(is_overriding_user_agent) {}
// WebContentsObserver:
void DidStartNavigation(NavigationHandle* navigation_handle) override;
void set_is_overriding_user_agent(bool is_overriding_user_agent) {
is_overriding_user_agent_ = is_overriding_user_agent;
}
void set_user_agent_override(const std::string& user_agent) {
user_agent_override_ = blink::UserAgentOverride::UserAgentOnly(user_agent);
}
private:
blink::UserAgentOverride user_agent_override_;
bool is_overriding_user_agent_ = true;
};
// Just like RenderFrameHostWrapper but holds and gives access to a
// RenderFrameHostImpl.
class RenderFrameHostImplWrapper : public RenderFrameHostWrapper {
public:
explicit RenderFrameHostImplWrapper(RenderFrameHost* rfh);
// Returns the pointer or nullptr if the RFH has already been deleted.
RenderFrameHostImpl* get() const;
// Pointerish operators. Feel free to add more if you need them.
RenderFrameHostImpl& operator*() const;
RenderFrameHostImpl* operator->() const;
};
// Use this class to wait for all RenderFrameHosts in a WebContents that are
// inactive (pending deletion, stored in BackForwardCache, prerendered, etc) to
// be deleted. This will triggerBackForwardCache flushing and prerender
// cancellations..
class InactiveRenderFrameHostDeletionObserver : public WebContentsObserver {
public:
explicit InactiveRenderFrameHostDeletionObserver(WebContents* content);
~InactiveRenderFrameHostDeletionObserver() override;
void Wait();
private:
void RenderFrameDeleted(RenderFrameHost*) override;
void CheckCondition();
std::unique_ptr<base::RunLoop> loop_;
std::set<raw_ptr<RenderFrameHost, SetExperimental>> inactive_rfhs_;
};
class TestNavigationObserverInternal : public TestNavigationObserver {
public:
using TestNavigationObserver::TestNavigationObserver;
~TestNavigationObserverInternal() override = default;
// TestNavigationObserver:
void OnDidFinishNavigation(NavigationHandle* navigation_handle) override;
// Return the NavigationType of the last navigation.
NavigationType last_navigation_type() const { return last_navigation_type_; }
private:
NavigationType last_navigation_type_ = NAVIGATION_TYPE_UNKNOWN;
};
// Return the descendant of `rfh` found by selecting children according to
// `descendant_indices`. E.g. `DescendantRenderFrameHostImplAt(rfh, {0, 1}) will
// return the child at index 1 of the child at index 0 of `rfh`.
RenderFrameHostImpl* DescendantRenderFrameHostImplAt(
const ToRenderFrameHost& adapter,
std::vector<size_t> descendant_indices);
class EffectiveURLContentBrowserTestContentBrowserClient
: public ContentBrowserTestContentBrowserClient {
public:
explicit EffectiveURLContentBrowserTestContentBrowserClient(
bool requires_dedicated_process);
EffectiveURLContentBrowserTestContentBrowserClient(
const GURL& url_to_modify,
const GURL& url_to_return,
bool requires_dedicated_process);
~EffectiveURLContentBrowserTestContentBrowserClient() override;
// Adds effective URL translation from |url_to_modify| to |url_to_return|.
void AddTranslation(const GURL& url_to_modify, const GURL& url_to_return);
private:
GURL GetEffectiveURL(BrowserContext* browser_context,
const GURL& url) override;
bool DoesSiteRequireDedicatedProcess(BrowserContext* browser_context,
const GURL& effective_site_url) override;
EffectiveURLContentBrowserClientHelper helper_;
};
// Class that requests that all pages belonging to the provided site get loaded
// in a non-default StoragePartition.
class CustomStoragePartitionBrowserClient
: public ContentBrowserTestContentBrowserClient {
public:
explicit CustomStoragePartitionBrowserClient(const GURL& site_to_isolate);
StoragePartitionConfig GetStoragePartitionConfigForSite(
BrowserContext* browser_context,
const GURL& site) override;
private:
GURL site_to_isolate_;
};
// Helper that waits for a request from the specified `RenderFrameHost` to send
// `CommitNavigation()` to the browser.
class CommitNavigationPauser
: public RenderFrameHostImpl::CommitCallbackInterceptor {
public:
explicit CommitNavigationPauser(RenderFrameHostImpl* rfh);
~CommitNavigationPauser() override;
void WaitForCommitAndPause();
// Once a `CommitNavigation()` call has been paused, these two methods may be
// used to resume or discard the commit as appropriate.
void ResumePausedCommit();
void DiscardPausedCommit();
private:
// CommitCallbackInterceptor overrides:
bool WillProcessDidCommitNavigation(
NavigationRequest* request,
mojom::DidCommitProvisionalLoadParamsPtr* params,
mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params)
override;
base::RunLoop loop_;
// The parameters to resume a previously paused `CommitNavigation()`.
base::WeakPtr<NavigationRequest> paused_request_;
mojom::DidCommitProvisionalLoadParamsPtr paused_params_;
mojom::DidCommitProvisionalLoadInterfaceParamsPtr paused_interface_params_;
};
// Sets up a /redirect-on-second-navigation?url endpoint on the provided
// `server`, which will return a 200 OK response for the first request, and
// redirect the second request to `url` provided in the query param. This should
// be called before starting `server`.
void AddRedirectOnSecondNavigationHandler(net::EmbeddedTestServer* server);
// Forwards DidStartLoading calls to the provided callback.
class LoadingStartObserver : public WebContentsObserver {
public:
using Callback = base::RepeatingCallback<void()>;
LoadingStartObserver(WebContents* web_contents, Callback callback);
~LoadingStartObserver() override;
private:
void DidStartLoading() override;
Callback callback_;
};
// Forwards DidStopLoading calls to the provided callback.
class LoadingStopObserver : public WebContentsObserver {
public:
using Callback = base::RepeatingCallback<void()>;
LoadingStopObserver(WebContents* web_contents, Callback callback);
~LoadingStopObserver() override;
private:
void DidStopLoading() override;
Callback callback_;
};
// Forwards DidFinishLoad calls to the provided callback.
class LoadFinishObserver : public WebContentsObserver {
public:
using Callback = base::RepeatingCallback<void(RenderFrameHost*, const GURL&)>;
LoadFinishObserver(WebContents* web_contents, Callback callback);
~LoadFinishObserver() override;
private:
void DidFinishLoad(RenderFrameHost* render_frame_host,
const GURL& validated_url) override;
Callback callback_;
};
} // namespace content
#endif // CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_
|