Commit 00f4bfdf authored by Takumi Fujimoto's avatar Takumi Fujimoto Committed by Commit Bot

[Media Router] Update integration and E2E tests to use the test API

Update the tests to use the test UI API, which is implemented using the
Views Cast dialog, replacing the use of the WebUI dialog. Some changes
are made to the test UI API to better suit the needs of the tests.

This re-enables many tests that were previously disabled for being flaky.

Local file casting tests (5 test cases) are disabled in this CL, and
will be implemented in a later CL:
DISABLED_OpenLocalMediaFileInCurrentTab
DISABLED_OpenLocalMediaFileInNewTab
DISABLED_OpenLocalMediaFileFailsAndShowsIssue
DISABLED_OpenLocalMediaFileFullscreen
DISABLED_OpenLocalMediaFileCastFailNoFullscreen

The following tests are still flaky, so they are marked MANUAL and will
be run only on the private waterfall until they are fixed:
MediaRouterIntegrationBrowserTest.MANUAL_Fail_NoProvider
MediaRouterIntegrationBrowserTest.MANUAL_Dialog_Basic
MediaRouterIntegrationBrowserTest.MANUAL_Dialog_RouteCreationTimedOut
MediaRouterIntegrationOneUABrowserTest.MANUAL_SendAndOnMessage
MediaRouterIntegrationOneUABrowserTest.MANUAL_ReceiverCloseConnection

Bug: 900248
Change-Id: Ie328fd1c4b606a7f8291d8d22b7d83a89f1ee666
Reviewed-on: https://chromium-review.googlesource.com/c/1338226
Commit-Queue: Takumi Fujimoto <takumif@chromium.org>
Reviewed-by: default avatarmark a. foltz <mfoltz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611479}
parent 80bfd587
......@@ -253,7 +253,7 @@ bool MediaRouterUIBase::CreateRoute(const MediaSink::Id& sink_id,
params = GetRouteParameters(sink_id, cast_mode);
}
if (!params) {
SendIssueForUnableToCast(cast_mode);
SendIssueForUnableToCast(cast_mode, sink_id);
return false;
}
......@@ -406,6 +406,10 @@ void MediaRouterUIBase::OnRouteResponseReceived(
}
current_route_request_.reset();
if (result.result_code() == RouteRequestResult::TIMED_OUT) {
SendIssueForRouteTimeout(cast_mode, sink_id,
presentation_request_source_name);
}
}
void MediaRouterUIBase::HandleCreateSessionRequestRouteResponse(
......@@ -582,6 +586,7 @@ GURL MediaRouterUIBase::GetFrameURL() const {
void MediaRouterUIBase::SendIssueForRouteTimeout(
MediaCastMode cast_mode,
const MediaSink::Id& sink_id,
const base::string16& presentation_request_source_name) {
std::string issue_title;
switch (cast_mode) {
......@@ -606,11 +611,14 @@ void MediaRouterUIBase::SendIssueForRouteTimeout(
break;
}
AddIssue(IssueInfo(issue_title, IssueInfo::Action::DISMISS,
IssueInfo::Severity::NOTIFICATION));
IssueInfo issue_info(issue_title, IssueInfo::Action::DISMISS,
IssueInfo::Severity::NOTIFICATION);
issue_info.sink_id = sink_id;
AddIssue(issue_info);
}
void MediaRouterUIBase::SendIssueForUnableToCast(MediaCastMode cast_mode) {
void MediaRouterUIBase::SendIssueForUnableToCast(MediaCastMode cast_mode,
const MediaSink::Id& sink_id) {
// For a generic error, claim a tab error unless it was specifically desktop
// mirroring.
std::string issue_title =
......@@ -619,8 +627,10 @@ void MediaRouterUIBase::SendIssueForUnableToCast(MediaCastMode cast_mode) {
IDS_MEDIA_ROUTER_ISSUE_UNABLE_TO_CAST_DESKTOP)
: l10n_util::GetStringUTF8(
IDS_MEDIA_ROUTER_ISSUE_CREATE_ROUTE_TIMEOUT_FOR_TAB);
AddIssue(IssueInfo(issue_title, IssueInfo::Action::DISMISS,
IssueInfo::Severity::WARNING));
IssueInfo issue_info(issue_title, IssueInfo::Action::DISMISS,
IssueInfo::Severity::WARNING);
issue_info.sink_id = sink_id;
AddIssue(issue_info);
}
IssueManager* MediaRouterUIBase::GetIssueManager() {
......
......@@ -197,10 +197,13 @@ class MediaRouterUIBase
// Creates and sends an issue if route creation timed out.
void SendIssueForRouteTimeout(
MediaCastMode cast_mode,
const MediaSink::Id& sink_id,
const base::string16& presentation_request_source_name);
// Creates and sends an issue if casting fails for any other reason.
void SendIssueForUnableToCast(MediaCastMode cast_mode);
// Creates and sends an issue if casting fails for any reason other than
// timeout.
void SendIssueForUnableToCast(MediaCastMode cast_mode,
const MediaSink::Id& sink_id);
// Returns the IssueManager associated with |router_|.
IssueManager* GetIssueManager();
......
......@@ -225,6 +225,11 @@ void CastDialogView::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void CastDialogView::KeepShownForTesting() {
keep_shown_for_testing_ = true;
set_close_on_deactivate(false);
}
// static
void CastDialogView::ShowDialog(views::View* anchor_view,
views::BubbleBorder::Arrow anchor_position,
......@@ -382,21 +387,22 @@ void CastDialogView::SinkPressed(size_t index) {
selected_sink_index_ = index;
const UIMediaSink& sink = sink_buttons_.at(index)->sink();
if (sink.route) {
controller_->StopCasting(sink.route->media_route_id());
metrics_.OnStopCasting(sink.route->is_local());
// StopCasting() may trigger a model update and invalidate |sink|.
controller_->StopCasting(sink.route->media_route_id());
} else {
base::Optional<MediaCastMode> cast_mode = GetCastModeToUse(sink);
if (cast_mode) {
// Starting local file casting may open a new tab synchronously on the UI
// thread, which deactivates the dialog. So we must prevent it from
// closing and getting destroyed.
if (cast_mode == LOCAL_FILE)
if (cast_mode.value() == LOCAL_FILE)
set_close_on_deactivate(false);
controller_->StartCasting(sink.id, cast_mode.value());
// Re-enable close on deactivate so the user can click elsewhere to close
// the dialog.
if (cast_mode == LOCAL_FILE)
set_close_on_deactivate(true);
if (cast_mode.value() == LOCAL_FILE)
set_close_on_deactivate(!keep_shown_for_testing_);
metrics_.OnStartCasting(base::Time::Now(), index);
}
}
......@@ -454,7 +460,7 @@ void CastDialogView::RecordSinkCount() {
void CastDialogView::OnFilePickerClosed(const ui::SelectedFileInfo* file_info) {
// Re-enable the setting to close the dialog when it loses focus.
set_close_on_deactivate(true);
set_close_on_deactivate(!keep_shown_for_testing_);
if (file_info) {
#if defined(OS_WIN)
local_file_name_ = file_info->display_name;
......
......@@ -100,6 +100,11 @@ class CastDialogView : public views::BubbleDialogDelegateView,
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// If the dialog loses focus during a test and closes, the test can
// fail unexpectedly. This method prevents that by keeping the dialog from
// closing on blur.
void KeepShownForTesting();
// Called by tests.
const std::vector<CastDialogSinkButton*>& sink_buttons_for_test() const {
return sink_buttons_;
......@@ -226,6 +231,9 @@ class CastDialogView : public views::BubbleDialogDelegateView,
base::ObserverList<Observer> observers_;
// When this is set to true, the dialog does not close on blur.
bool keep_shown_for_testing_ = false;
base::WeakPtrFactory<CastDialogView> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(CastDialogView);
......
......@@ -70,25 +70,15 @@ CastToolbarButton::CastToolbarButton(
ToolbarButton::Init();
IssuesObserver::Init();
MediaRouterActionController* controller =
MediaRouterUIService::Get(profile_)->action_controller();
controller->AddObserver(this);
SetVisible(controller->ShouldEnableAction());
}
CastToolbarButton::~CastToolbarButton() {
MediaRouterUIService::Get(profile_)->action_controller()->RemoveObserver(
this);
DCHECK(GetActionController());
GetActionController()->AddObserver(this);
SetVisible(GetActionController()->ShouldEnableAction());
}
void CastToolbarButton::UpdateIcon() {
const gfx::VectorIcon& icon = GetCurrentIcon();
SetImage(views::Button::STATE_NORMAL,
gfx::CreateVectorIcon(icon, GetIconColor(&icon)));
// This icon is smaller than the touchable-UI expected 24dp, so we need to pad
// the insets to match.
SetLayoutInsetDelta(
gfx::Insets(ui::MaterialDesignController::touch_ui() ? 4 : 0));
CastToolbarButton::~CastToolbarButton() {
if (GetActionController())
GetActionController()->RemoveObserver(this);
}
const gfx::VectorIcon& CastToolbarButton::GetCurrentIcon() const {
......@@ -150,21 +140,15 @@ void CastToolbarButton::OnRoutesUpdated(
}
bool CastToolbarButton::OnMousePressed(const ui::MouseEvent& event) {
if (event.IsRightMouseButton()) {
MediaRouterUIService::Get(profile_)
->action_controller()
->KeepIconOnRightMousePressed();
}
if (event.IsRightMouseButton() && GetActionController())
GetActionController()->KeepIconOnRightMousePressed();
return ToolbarButton::OnMousePressed(event);
}
void CastToolbarButton::OnMouseReleased(const ui::MouseEvent& event) {
ToolbarButton::OnMouseReleased(event);
if (event.IsRightMouseButton()) {
MediaRouterUIService::Get(profile_)
->action_controller()
->MaybeHideIconOnRightMouseReleased();
}
if (event.IsRightMouseButton() && GetActionController())
GetActionController()->MaybeHideIconOnRightMouseReleased();
}
void CastToolbarButton::ButtonPressed(views::Button* sender,
......@@ -181,4 +165,18 @@ void CastToolbarButton::ButtonPressed(views::Button* sender,
}
}
void CastToolbarButton::UpdateIcon() {
const gfx::VectorIcon& icon = GetCurrentIcon();
SetImage(views::Button::STATE_NORMAL,
gfx::CreateVectorIcon(icon, GetIconColor(&icon)));
// This icon is smaller than the touchable-UI expected 24dp, so we need to pad
// the insets to match.
SetLayoutInsetDelta(
gfx::Insets(ui::MaterialDesignController::touch_ui() ? 4 : 0));
}
MediaRouterActionController* CastToolbarButton::GetActionController() const {
return MediaRouterUIService::Get(profile_)->action_controller();
}
} // namespace media_router
......@@ -70,6 +70,8 @@ class CastToolbarButton : public ToolbarButton,
private:
const gfx::VectorIcon& GetCurrentIcon() const;
MediaRouterActionController* GetActionController() const;
Browser* const browser_;
Profile* const profile_;
......
......@@ -65,6 +65,8 @@ void MediaRouterDialogControllerViews::CreateMediaRouterDialog() {
dialog_creation_time);
}
CastDialogView::GetCurrentDialogWidget()->AddObserver(this);
if (dialog_creation_callback_)
dialog_creation_callback_.Run();
}
void MediaRouterDialogControllerViews::CloseMediaRouterDialog() {
......@@ -76,8 +78,11 @@ bool MediaRouterDialogControllerViews::IsShowingMediaRouterDialog() const {
}
void MediaRouterDialogControllerViews::Reset() {
MediaRouterDialogControllerImplBase::Reset();
ui_.reset();
// If |ui_| is null, Reset() has already been called.
if (ui_) {
MediaRouterDialogControllerImplBase::Reset();
ui_.reset();
}
}
void MediaRouterDialogControllerViews::OnWidgetClosing(views::Widget* widget) {
......@@ -90,6 +95,11 @@ void MediaRouterDialogControllerViews::OnWidgetDestroying(
widget->RemoveObserver(this);
}
void MediaRouterDialogControllerViews::SetDialogCreationCallbackForTesting(
base::RepeatingClosure callback) {
dialog_creation_callback_ = std::move(callback);
}
MediaRouterDialogControllerViews::MediaRouterDialogControllerViews(
content::WebContents* web_contents)
: MediaRouterDialogControllerImplBase(web_contents) {}
......
......@@ -8,6 +8,7 @@
#include <memory>
#include "base/macros.h"
#include "base/observer_list.h"
#include "chrome/browser/ui/media_router/media_router_dialog_controller_impl_base.h"
#include "chrome/browser/ui/views/media_router/media_router_views_ui.h"
#include "ui/views/widget/widget_observer.h"
......@@ -35,6 +36,9 @@ class MediaRouterDialogControllerViews
void OnWidgetClosing(views::Widget* widget) override;
void OnWidgetDestroying(views::Widget* widget) override;
// Sets a callback to be called whenever a dialog is created.
void SetDialogCreationCallbackForTesting(base::RepeatingClosure callback);
private:
friend class content::WebContentsUserData<MediaRouterDialogControllerViews>;
......@@ -47,6 +51,8 @@ class MediaRouterDialogControllerViews
// closed.
std::unique_ptr<MediaRouterViewsUI> ui_;
base::RepeatingClosure dialog_creation_callback_;
DISALLOW_COPY_AND_ASSIGN(MediaRouterDialogControllerViews);
};
......
......@@ -102,7 +102,7 @@ bool MediaRouterUI::ConnectRoute(const MediaSink::Id& sink_id,
base::Optional<RouteParameters> params =
GetRouteParameters(sink_id, MediaCastMode::PRESENTATION);
if (!params) {
SendIssueForUnableToCast(MediaCastMode::PRESENTATION);
SendIssueForUnableToCast(MediaCastMode::PRESENTATION, sink_id);
return false;
}
GetIssueManager()->ClearNonBlockingIssues();
......@@ -315,8 +315,6 @@ void MediaRouterUI::OnRouteResponseReceived(
route_request_id, sink_id, cast_mode, presentation_request_source_name,
result);
handler_->OnCreateRouteResponseReceived(sink_id, result.route());
if (result.result_code() == RouteRequestResult::TIMED_OUT)
SendIssueForRouteTimeout(cast_mode, presentation_request_source_name);
}
void MediaRouterUI::HandleCreateSessionRequestRouteResponse(
......
......@@ -42,7 +42,7 @@ void MediaRouterBaseBrowserTest::SetUp() {
ParseCommandLine();
// The integration and E2E tests depend on the WebUI Cast dialog, so the Views
// dialog must be disabled.
feature_list_.InitAndDisableFeature(features::kViewsCastDialog);
feature_list_.InitAndEnableFeature(features::kViewsCastDialog);
ExtensionBrowserTest::SetUp();
}
......
......@@ -81,7 +81,7 @@ void MediaRouterE2EBrowserTest::CreateMediaRoute(
observer_.reset(new TestMediaSinksObserver(media_router_, source, origin));
observer_->Init();
DVLOG(1) << "Receiver name: " << receiver();
DVLOG(1) << "Receiver name: " << receiver_;
// Wait for MediaSinks compatible with |source| to be discovered.
ASSERT_TRUE(ConditionalWait(
base::TimeDelta::FromSeconds(30), base::TimeDelta::FromSeconds(1),
......@@ -89,7 +89,7 @@ void MediaRouterE2EBrowserTest::CreateMediaRoute(
base::Unretained(this))));
const auto& sink_map = observer_->sink_map;
const auto it = sink_map.find(receiver());
const auto it = sink_map.find(receiver_);
const MediaSink& sink = it->second;
// The callback will set route_id_ when invoked.
......@@ -112,7 +112,7 @@ void MediaRouterE2EBrowserTest::StopMediaRoute() {
}
bool MediaRouterE2EBrowserTest::IsSinkDiscovered() const {
return base::ContainsKey(observer_->sink_map, receiver());
return base::ContainsKey(observer_->sink_map, receiver_);
}
bool MediaRouterE2EBrowserTest::IsRouteCreated() const {
......
......@@ -29,22 +29,15 @@ IN_PROC_BROWSER_TEST_F(MediaRouterE2EBrowserTest,
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WebContents* dialog_contents = OpenMRDialog(web_contents);
ASSERT_TRUE(dialog_contents);
// Wait util the dialog finishes rendering.
WaitUntilDialogFullyLoaded(dialog_contents);
// Get the media router UI
MediaRouterUI* media_router_ui = GetMediaRouterUI(dialog_contents);
test_ui_->ShowDialog();
test_ui_->WaitForSinkAvailable(receiver_);
// Mock out file dialog operations, as those can't be simulated.
FileDialogSelectsFile(media_router_ui, file_url);
// Open the Cast mode list.
ClickHeader(dialog_contents);
FileDialogSelectsFile(file_url);
// Click on the desired mode.
ClickCastMode(dialog_contents, MediaCastMode::LOCAL_FILE);
WaitUntilSinkDiscoveredOnUI();
ChooseSink(web_contents, receiver());
test_ui_->ChooseSourceType(CastDialogView::kLocalFile);
test_ui_->WaitForSinkAvailable(receiver_);
test_ui_->StartCasting(receiver_);
// Play the file for 10 seconds.
Wait(base::TimeDelta::FromSeconds(10));
......@@ -61,9 +54,8 @@ IN_PROC_BROWSER_TEST_F(MediaRouterE2EBrowserTest,
&is_fullscreen));
ASSERT_TRUE(is_fullscreen);
if (IsDialogClosed(web_contents))
OpenMRDialog(web_contents);
CloseRouteOnUI();
test_ui_->WaitForSink(receiver_);
test_ui_->StopCasting(receiver_);
// Wait 15s for Chromecast to back to home screen and ready to use status.
Wait(base::TimeDelta::FromSeconds(15));
}
......@@ -71,23 +63,18 @@ IN_PROC_BROWSER_TEST_F(MediaRouterE2EBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaRouterE2EBrowserTest, MANUAL_MirrorHTML5Video) {
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WebContents* dialog_contents = OpenMRDialog(web_contents);
ASSERT_TRUE(dialog_contents);
test_ui_ = MediaRouterUiForTest::GetOrCreateForWebContents(web_contents);
test_ui_->ShowDialog();
// Wait until the dialog finishes rendering.
WaitUntilDialogFullyLoaded(dialog_contents);
WaitUntilSinkDiscoveredOnUI();
ChooseSink(web_contents, receiver());
test_ui_->WaitForSinkAvailable(receiver_);
test_ui_->StartCasting(receiver_);
// Mirror tab for 10s.
Wait(base::TimeDelta::FromSeconds(10));
if (IsDialogClosed(web_contents))
dialog_contents = OpenMRDialog(web_contents);
WaitUntilDialogFullyLoaded(dialog_contents);
// Check the mirroring session has started successfully.
ASSERT_TRUE(!GetRouteId(receiver()).empty());
ASSERT_FALSE(test_ui_->GetRouteIdForSink(receiver_).empty());
OpenMediaPage();
// Play the video on loop and wait 5s for it to play smoothly.
......@@ -101,16 +88,18 @@ IN_PROC_BROWSER_TEST_F(MediaRouterE2EBrowserTest, MANUAL_MirrorHTML5Video) {
"webkitRequestFullScreen();";
ExecuteScript(web_contents, script);
Wait(base::TimeDelta::FromSeconds(5));
if (IsDialogClosed(web_contents))
dialog_contents = OpenMRDialog(web_contents);
WaitUntilDialogFullyLoaded(dialog_contents);
if (!test_ui_->IsDialogShown())
test_ui_->ShowDialog();
// Check the mirroring session is still live.
ASSERT_TRUE(!GetRouteId(receiver()).empty());
ASSERT_FALSE(test_ui_->GetRouteIdForSink(receiver_).empty());
Wait(base::TimeDelta::FromSeconds(20));
if (IsDialogClosed(web_contents))
OpenMRDialog(web_contents);
CloseRouteOnUI();
if (!test_ui_->IsDialogShown())
test_ui_->ShowDialog();
test_ui_->WaitForSink(receiver_);
test_ui_->StopCasting(receiver_);
test_ui_->WaitUntilNoRoutes();
test_ui_->HideDialog();
}
} // namespace media_router
......@@ -16,14 +16,11 @@
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/media_router/media_cast_mode.h"
#include "chrome/browser/ui/media_router/media_router_file_dialog.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/webui/media_router/media_router_dialog_controller_webui_impl.h"
#include "chrome/browser/ui/webui/media_router/media_router_ui.h"
#include "chrome/common/media_router/issue.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
......@@ -63,66 +60,6 @@ const char kSendMessageAndExpectResponseScript[] =
"sendMessageAndExpectResponse('%s');";
const char kSendMessageAndExpectConnectionCloseOnErrorScript[] =
"sendMessageAndExpectConnectionCloseOnError()";
const char kChooseSinkScript[] =
"var sinks = Array.from(document.getElementById('media-router-container')."
" shadowRoot.getElementById('sink-list').getElementsByTagName('span'));"
"var sink = sinks.find(sink => sink.textContent.trim() == '%s');"
"if (sink) {"
" sink.click();"
"}";
const char kClickCastModeScript[] =
"var mediaRouterContainer ="
" document.getElementById('media-router-container');"
"var modes = Array.from(mediaRouterContainer"
" .shadowRoot"
" .getElementById('cast-mode-list')"
" .getElementsByTagName('span'));"
"var mode = modes.find(mode => {"
" return mode.textContent.trim() == mediaRouterContainer"
" .castModeList.find(mode => mode.type == %d).description;"
" });"
"if (mode) {"
" mode.click();"
"}";
const char kCloseRouteScript[] =
"window.document.getElementById('media-router-container').shadowRoot."
" getElementById('route-details').shadowRoot.getElementById("
" 'close-route-button').click()";
const char kClickDialog[] =
"window.document.getElementById('media-router-container').click();";
const char kClickHeader[] =
"window.document.getElementById('media-router-container').shadowRoot"
".getElementById('container-header').shadowRoot"
".getElementById('header-text').click();";
const char kGetSinkIdScript[] =
"var sinks = window.document.getElementById('media-router-container')."
" allSinks;"
"var sink = sinks.find(sink => sink.name == '%s');"
"window.domAutomationController.send(sink ? sink.id : '');";
const char kGetRouteIdScript[] =
"var routes = window.document.getElementById('media-router-container')."
" routeList;"
"var route = routes.find(route => route.sinkId == '%s');"
"window.domAutomationController.send(route ? route.id : '');";
const char kFindSinkScript[] =
"var sinkList = document.getElementById('media-router-container')."
" shadowRoot.getElementById('sink-list');"
"if (!sinkList) {"
" window.domAutomationController.send(false);"
"} else {"
" var sinks = Array.from(sinkList.getElementsByTagName('span'));"
" var result = sinks.some(sink => sink.textContent.trim() == '%s');"
" window.domAutomationController.send(result);"
"}";
const char kCheckDialogLoadedScript[] =
"var container = document.getElementById('media-router-container');"
"/** Wait until media router container is not undefined and "
"* deviceMissingUrl is not undefined, "
"* once deviceMissingUrl is not undefined, which means "
"* the dialog is fully loaded."
"*/"
"window.domAutomationController.send(!!container && "
" !!container.deviceMissingUrl);";
std::string GetStartedConnectionId(WebContents* web_contents) {
std::string session_id;
......@@ -141,7 +78,7 @@ std::string GetDefaultRequestSessionId(WebContents* web_contents) {
return session_id;
}
// File Dialog which fails on open
// File Dialog which fails on open.
class TestFailMediaRouterFileDialog : public MediaRouterFileDialog {
public:
TestFailMediaRouterFileDialog(MediaRouterFileDialogDelegate* delegate,
......@@ -193,6 +130,13 @@ void MediaRouterIntegrationBrowserTest::SetUpInProcessBrowserTestFixture() {
policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
}
void MediaRouterIntegrationBrowserTest::SetUpOnMainThread() {
MediaRouterBaseBrowserTest::SetUpOnMainThread();
// Dialogs created while MediaRouterUiForTest exists will not close on blur.
test_ui_ =
MediaRouterUiForTest::GetOrCreateForWebContents(GetActiveWebContents());
}
void MediaRouterIntegrationBrowserTest::ExecuteJavaScriptAPI(
WebContents* web_contents,
const std::string& script) {
......@@ -221,11 +165,11 @@ void MediaRouterIntegrationBrowserTest::StartSessionAndAssertNotFoundError() {
OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
WebContents* web_contents = GetActiveWebContents();
CHECK(web_contents);
StartSession(web_contents);
ExecuteJavaScriptAPI(web_contents, kStartSessionScript);
// Wait for any sinks to be displayed.
// Wait to simulate the user waiting for any sinks to be displayed.
Wait(base::TimeDelta::FromSeconds(1));
GetControllerForShownDialog(web_contents)->HideMediaRouterDialog();
test_ui_->HideDialog();
CheckStartFailed(web_contents, "NotFoundError", "No screens found.");
}
......@@ -235,19 +179,20 @@ MediaRouterIntegrationBrowserTest::StartSessionWithTestPageAndSink() {
WebContents* web_contents = GetActiveWebContents();
CHECK(web_contents);
ExecuteJavaScriptAPI(web_contents, kWaitSinkScript);
StartSession(web_contents);
ExecuteJavaScriptAPI(web_contents, kStartSessionScript);
test_ui_->WaitForDialogShown();
return web_contents;
}
WebContents*
MediaRouterIntegrationBrowserTest::StartSessionWithTestPageAndChooseSink() {
WebContents* web_contents = StartSessionWithTestPageAndSink();
WaitUntilSinkDiscoveredOnUI();
ChooseSink(web_contents, receiver_);
test_ui_->WaitForSinkAvailable(receiver_);
test_ui_->StartCasting(receiver_);
// TODO(takumif): Remove the HideDialog() call once the dialog can close
// itself automatically after casting.
test_ui_->HideDialog();
// Wait a few seconds for MediaRouter to receive updates containing the
// created route.
Wait(base::TimeDelta::FromSeconds(3));
return web_contents;
}
......@@ -258,22 +203,15 @@ void MediaRouterIntegrationBrowserTest::OpenDialogAndCastFile(
: SetTestData(FILE_PATH_LITERAL("local_media_sink_route_fail.json"));
GURL file_url = net::FilePathToFileURL(
media::GetTestDataFilePath("butterfly-853x480.webm"));
// Open the dialog, waits for it to load
WebContents* dialog_contents = OpenMRDialog(GetActiveWebContents());
// Get the media router UI
MediaRouterUI* media_router_ui = GetMediaRouterUI(dialog_contents);
test_ui_->ShowDialog();
// Mock out file dialog operations, as those can't be simulated.
FileDialogSelectsFile(media_router_ui, file_url);
// Open the Cast mode list.
ClickHeader(dialog_contents);
FileDialogSelectsFile(file_url);
// Click on the desired mode.
ClickCastMode(dialog_contents, MediaCastMode::LOCAL_FILE);
test_ui_->ChooseSourceType(CastDialogView::kLocalFile);
// Wait for the sinks to load.
WaitUntilSinkDiscoveredOnUI();
test_ui_->WaitForSinkAvailable(receiver_);
// Click on sink.
ChooseSink(GetActiveWebContents(), receiver_);
// Give casting a few seconds to go through.
Wait(base::TimeDelta::FromSeconds(3));
test_ui_->StartCasting(receiver_);
// Expect that the current tab has the file open in it.
ASSERT_EQ(file_url, GetActiveWebContents()->GetURL());
}
......@@ -282,18 +220,13 @@ void MediaRouterIntegrationBrowserTest::OpenDialogAndCastFileFails() {
SetTestData(FILE_PATH_LITERAL("local_media_sink.json"));
GURL file_url = net::FilePathToFileURL(
media::GetTestDataFilePath("butterfly-853x480.webm"));
// Open the dialog, waits for it to load
WebContents* dialog_contents = OpenMRDialog(GetActiveWebContents());
// Get the media router UI
MediaRouterUI* media_router_ui = GetMediaRouterUI(dialog_contents);
test_ui_->ShowDialog();
// Mock out file dialog opperations, as those can't be simulated.
FileDialogSelectFails(media_router_ui, IssueInfo());
// Open the Cast mode list.
ClickHeader(dialog_contents);
FileDialogSelectFails(IssueInfo());
// Click on the desired mode.
ClickCastMode(dialog_contents, MediaCastMode::LOCAL_FILE);
test_ui_->ChooseSourceType(CastDialogView::kLocalFile);
// Wait for the issue to appear.
WaitUntilIssue();
test_ui_->WaitForAnyIssue();
}
void MediaRouterIntegrationBrowserTest::OpenTestPage(
......@@ -309,6 +242,10 @@ void MediaRouterIntegrationBrowserTest::OpenTestPageInNewTab(
browser(), GetTestPageUrl(full_path),
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
// Opening a new tab creates new WebContents, so we must re-configure the
// test UI for it.
test_ui_ =
MediaRouterUiForTest::GetOrCreateForWebContents(GetActiveWebContents());
}
GURL MediaRouterIntegrationBrowserTest::GetTestPageUrl(
......@@ -316,34 +253,6 @@ GURL MediaRouterIntegrationBrowserTest::GetTestPageUrl(
return net::FilePathToFileURL(full_path);
}
void MediaRouterIntegrationBrowserTest::StartSession(
WebContents* web_contents) {
test_navigation_observer_.reset(
new content::TestNavigationObserver(web_contents, 1));
test_navigation_observer_->StartWatchingNewWebContents();
ExecuteJavaScriptAPI(web_contents, kStartSessionScript);
test_navigation_observer_->Wait();
test_navigation_observer_->StopWatchingNewWebContents();
}
void MediaRouterIntegrationBrowserTest::ChooseSink(
WebContents* web_contents,
const std::string& sink_name) {
WebContents* dialog_contents = GetMRDialog(web_contents);
std::string script = base::StringPrintf(
kChooseSinkScript, sink_name.c_str());
// Execute javascript to choose sink, but don't wait until it finishes.
dialog_contents->GetMainFrame()->ExecuteJavaScriptWithUserGestureForTests(
base::UTF8ToUTF16(script));
}
void MediaRouterIntegrationBrowserTest::ClickCastMode(
WebContents* dialog_contents,
MediaCastMode mode) {
std::string script = base::StringPrintf(kClickCastModeScript, mode);
ASSERT_TRUE(content::ExecuteScript(dialog_contents, script));
}
void MediaRouterIntegrationBrowserTest::CheckStartFailed(
WebContents* web_contents,
const std::string& error_name,
......@@ -354,52 +263,6 @@ void MediaRouterIntegrationBrowserTest::CheckStartFailed(
ExecuteJavaScriptAPI(web_contents, script);
}
void MediaRouterIntegrationBrowserTest::ClickDialog() {
WebContents* web_contents = GetActiveWebContents();
WebContents* dialog_contents = GetMRDialog(web_contents);
ASSERT_TRUE(content::ExecuteScript(dialog_contents, kClickDialog));
}
void MediaRouterIntegrationBrowserTest::ClickHeader(
WebContents* dialog_contents) {
ASSERT_TRUE(content::ExecuteScript(dialog_contents, kClickHeader));
}
WebContents* MediaRouterIntegrationBrowserTest::GetMRDialog(
WebContents* web_contents) {
MediaRouterDialogControllerWebUIImpl* controller =
MediaRouterDialogControllerWebUIImpl::GetOrCreateForWebContents(
web_contents);
WebContents* dialog_contents = controller->GetMediaRouterDialog();
CHECK(dialog_contents);
WaitUntilDialogFullyLoaded(dialog_contents);
return dialog_contents;
}
bool MediaRouterIntegrationBrowserTest::IsDialogClosed(
WebContents* web_contents) {
MediaRouterDialogControllerWebUIImpl* controller =
MediaRouterDialogControllerWebUIImpl::GetOrCreateForWebContents(
web_contents);
return !controller->GetMediaRouterDialog();
}
void MediaRouterIntegrationBrowserTest::WaitUntilDialogClosed(
WebContents* web_contents) {
ASSERT_TRUE(ConditionalWait(
base::TimeDelta::FromSeconds(5), base::TimeDelta::FromSeconds(1),
base::Bind(&MediaRouterIntegrationBrowserTest::IsDialogClosed,
base::Unretained(this), web_contents)));
}
void MediaRouterIntegrationBrowserTest::CheckDialogRemainsOpen(
WebContents* web_contents) {
ASSERT_FALSE(ConditionalWait(
base::TimeDelta::FromSeconds(5), base::TimeDelta::FromSeconds(1),
base::Bind(&MediaRouterIntegrationBrowserTest::IsDialogClosed,
base::Unretained(this), web_contents)));
}
void MediaRouterIntegrationBrowserTest::SetTestData(
base::FilePath::StringPieceType test_data_file) {
base::FilePath full_path = GetResourceFile(test_data_file);
......@@ -421,23 +284,6 @@ void MediaRouterIntegrationBrowserTest::SetTestData(
test_data_str.c_str()));
}
WebContents* MediaRouterIntegrationBrowserTest::OpenMRDialog(
WebContents* web_contents) {
MediaRouterDialogControllerWebUIImpl* controller =
MediaRouterDialogControllerWebUIImpl::GetOrCreateForWebContents(
web_contents);
test_navigation_observer_.reset(
new content::TestNavigationObserver(web_contents, 1));
test_navigation_observer_->StartWatchingNewWebContents();
CHECK(controller->ShowMediaRouterDialog());
test_navigation_observer_->Wait();
test_navigation_observer_->StopWatchingNewWebContents();
WebContents* dialog_contents = controller->GetMediaRouterDialog();
CHECK(dialog_contents);
WaitUntilDialogFullyLoaded(dialog_contents);
return dialog_contents;
}
base::FilePath MediaRouterIntegrationBrowserTest::GetResourceFile(
base::FilePath::StringPieceType relative_path) const {
base::FilePath base_dir;
......@@ -481,110 +327,22 @@ void MediaRouterIntegrationBrowserTest::ExecuteScript(
}
bool MediaRouterIntegrationBrowserTest::IsRouteCreatedOnUI() {
return !GetRouteId(receiver()).empty();
}
std::string MediaRouterIntegrationBrowserTest::GetRouteId(
const std::string& sink_name) {
WebContents* web_contents = GetActiveWebContents();
WebContents* dialog_contents = GetMRDialog(web_contents);
std::string script = base::StringPrintf(kGetSinkIdScript, sink_name.c_str());
std::string sink_id = ExecuteScriptAndExtractString(dialog_contents, script);
DVLOG(0) << "sink id: " << sink_id;
script = base::StringPrintf(kGetRouteIdScript, sink_id.c_str());
std::string route_id = ExecuteScriptAndExtractString(dialog_contents, script);
DVLOG(0) << "route id: " << route_id;
return route_id;
}
void MediaRouterIntegrationBrowserTest::WaitUntilRouteCreated() {
ASSERT_TRUE(ConditionalWait(
base::TimeDelta::FromSeconds(10), base::TimeDelta::FromSeconds(1),
base::Bind(&MediaRouterIntegrationBrowserTest::IsRouteCreatedOnUI,
base::Unretained(this))));
return !test_ui_->GetRouteIdForSink(receiver_).empty();
}
bool MediaRouterIntegrationBrowserTest::IsUIShowingIssue() {
WebContents* web_contents = GetActiveWebContents();
WebContents* dialog_contents = GetMRDialog(web_contents);
std::string script = base::StringPrintf(
"domAutomationController.send(window.document.getElementById("
"'media-router-container').issue != undefined)");
bool has_issue = false;
CHECK(content::ExecuteScriptAndExtractBool(dialog_contents, script,
&has_issue));
return has_issue;
}
void MediaRouterIntegrationBrowserTest::WaitUntilIssue() {
ASSERT_TRUE(ConditionalWait(
base::TimeDelta::FromSeconds(30), base::TimeDelta::FromSeconds(1),
base::Bind(&MediaRouterIntegrationBrowserTest::IsUIShowingIssue,
base::Unretained(this))));
}
std::string MediaRouterIntegrationBrowserTest::GetIssueTitle() {
WebContents* web_contents = GetActiveWebContents();
WebContents* dialog_contents = GetMRDialog(web_contents);
std::string script = base::StringPrintf(
"domAutomationController.send(window.document.getElementById("
"'media-router-container').issue.title)");
return ExecuteScriptAndExtractString(dialog_contents, script);
std::string issue_text = test_ui_->GetIssueTextForSink(receiver_);
return !issue_text.empty();
}
bool MediaRouterIntegrationBrowserTest::IsRouteClosedOnUI() {
// After execute js script to close route on UI, the dialog will dispear
// after 3s. But sometimes it takes more than 3s to close the route, so
// we need to re-open the dialog if it is closed.
WebContents* web_contents = GetActiveWebContents();
MediaRouterDialogControllerWebUIImpl* controller =
MediaRouterDialogControllerWebUIImpl::GetOrCreateForWebContents(
web_contents);
WebContents* dialog_contents = controller->GetMediaRouterDialog();
if (!dialog_contents) {
VLOG(0) << "Media router dialog was closed, reopen it again.";
OpenMRDialog(web_contents);
}
return GetRouteId(receiver()).empty();
}
void MediaRouterIntegrationBrowserTest::CloseRouteOnUI() {
WebContents* web_contents = GetActiveWebContents();
WebContents* dialog_contents = GetMRDialog(web_contents);
ASSERT_TRUE(content::ExecuteScript(dialog_contents, kCloseRouteScript));
ASSERT_TRUE(ConditionalWait(
base::TimeDelta::FromSeconds(10), base::TimeDelta::FromSeconds(1),
base::Bind(&MediaRouterIntegrationBrowserTest::IsRouteClosedOnUI,
base::Unretained(this))));
}
bool MediaRouterIntegrationBrowserTest::IsSinkDiscoveredOnUI() {
WebContents* web_contents = GetActiveWebContents();
WebContents* dialog_contents = GetMRDialog(web_contents);
std::string script = base::StringPrintf(kFindSinkScript, receiver().c_str());
return ExecuteScriptAndExtractBool(dialog_contents, script);
}
void MediaRouterIntegrationBrowserTest::WaitUntilSinkDiscoveredOnUI() {
DVLOG(0) << "Receiver name: " << receiver_;
// Wait for sink to show up in UI.
ASSERT_TRUE(ConditionalWait(
base::TimeDelta::FromSeconds(30), base::TimeDelta::FromSeconds(1),
base::Bind(&MediaRouterIntegrationBrowserTest::IsSinkDiscoveredOnUI,
base::Unretained(this))));
}
bool MediaRouterIntegrationBrowserTest::IsDialogLoaded(
WebContents* dialog_contents) {
return ExecuteScriptAndExtractBool(dialog_contents, kCheckDialogLoadedScript);
}
void MediaRouterIntegrationBrowserTest::WaitUntilDialogFullyLoaded(
WebContents* dialog_contents) {
ASSERT_TRUE(ConditionalWait(
base::TimeDelta::FromSeconds(30), base::TimeDelta::FromSeconds(1),
base::Bind(&MediaRouterIntegrationBrowserTest::IsDialogLoaded,
base::Unretained(this), dialog_contents)));
if (!test_ui_->IsDialogShown())
test_ui_->ShowDialog();
test_ui_->WaitForSink(receiver_);
return test_ui_->GetRouteIdForSink(receiver_).empty();
}
void MediaRouterIntegrationBrowserTest::ParseCommandLine() {
......@@ -606,49 +364,26 @@ void MediaRouterIntegrationBrowserTest::CheckSessionValidity(
EXPECT_EQ(session_id, default_request_session_id);
}
MediaRouterDialogControllerWebUIImpl*
MediaRouterIntegrationBrowserTest::GetControllerForShownDialog(
WebContents* web_contents) {
MediaRouterDialogControllerWebUIImpl* controller =
MediaRouterDialogControllerWebUIImpl::GetOrCreateForWebContents(
web_contents);
EXPECT_TRUE(controller->IsShowingMediaRouterDialog());
return controller;
}
WebContents* MediaRouterIntegrationBrowserTest::GetActiveWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
MediaRouterUI* MediaRouterIntegrationBrowserTest::GetMediaRouterUI(
content::WebContents* dialog_contents) {
content::WebUI* web_ui = dialog_contents->GetWebUI();
CHECK(web_ui) << "Error getting MediaRouterUI, no WebUI at all";
return static_cast<MediaRouterUI*>(web_ui->GetController());
}
void MediaRouterIntegrationBrowserTest::FileDialogSelectsFile(
MediaRouterUI* media_router_ui,
GURL file_url) {
// Ensure that the media_router_ui is set
DCHECK(media_router_ui);
media_router_ui->InitForTest(
std::make_unique<TestMediaRouterFileDialog>(media_router_ui, file_url));
void MediaRouterIntegrationBrowserTest::FileDialogSelectsFile(GURL file_url) {
// TODO(https://crbug.com/900248): Implement this.
NOTIMPLEMENTED();
}
void MediaRouterIntegrationBrowserTest::FileDialogSelectFails(
MediaRouterUI* media_router_ui,
const IssueInfo& issue) {
// Ensure that the media_router_ui is set
DCHECK(media_router_ui);
media_router_ui->InitForTest(
std::make_unique<TestFailMediaRouterFileDialog>(media_router_ui, issue));
// TODO(https://crbug.com/900248): Implement this.
NOTIMPLEMENTED();
}
void MediaRouterIntegrationBrowserTest::RunBasicTest() {
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
CheckSessionValidity(web_contents);
ExecuteJavaScriptAPI(web_contents, kTerminateSessionScript);
test_ui_->WaitUntilNoRoutes();
}
void MediaRouterIntegrationBrowserTest::RunSendMessageTest(
......@@ -690,6 +425,7 @@ void MediaRouterIntegrationBrowserTest::RunReconnectSessionTest() {
ASSERT_EQ(session_id, reconnected_session_id);
ExecuteJavaScriptAPI(web_contents, kTerminateSessionScript);
test_ui_->WaitUntilNoRoutes();
}
void MediaRouterIntegrationBrowserTest::SetEnableMediaRouter(bool enable) {
......@@ -698,8 +434,7 @@ void MediaRouterIntegrationBrowserTest::SetEnableMediaRouter(bool enable) {
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
std::make_unique<base::Value>(enable), nullptr);
provider_.UpdateChromePolicy(policy);
base::RunLoop loop;
loop.RunUntilIdle();
base::RunLoop().RunUntilIdle();
}
void MediaRouterIntegrationBrowserTest::RunReconnectSessionSameTabTest() {
......@@ -718,15 +453,14 @@ void MediaRouterIntegrationBrowserTest::RunReconnectSessionSameTabTest() {
ASSERT_EQ(session_id, reconnected_session_id);
}
// TODO(crbug.com/822337): Flaky on Linux_CFI bot.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, MANUAL_Basic) {
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, Basic) {
RunBasicTest();
}
// Tests that creating a route with a local file opens the file in a new tab.
// TODO(crbug.com/818767): Fails when run with Chromium component.
// TODO(https://crbug.com/900248): Make this test pass with the Views dialog.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
MANUAL_OpenLocalMediaFileInCurrentTab) {
DISABLED_OpenLocalMediaFileInCurrentTab) {
// Start at a new tab, the file should open in the same tab.
ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
// Make sure there is 1 tab.
......@@ -737,20 +471,18 @@ IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
// Expect that no new tab has been opened.
ASSERT_EQ(1, browser()->tab_strip_model()->count());
// Open the dialog again to check for a route.
OpenMRDialog(GetActiveWebContents());
test_ui_->ShowDialog();
// Wait for a route to be created.
WaitUntilRouteCreated();
test_ui_->WaitForAnyRoute();
}
// TODO(crbug.com/849216): Disabled due to crashes and timeouts.
//
// Tests that creating a route with a local file opens the file in a new tab.
// TODO(https://crbug.com/900248): Make this test pass with the Views dialog.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
DISABLED_OpenLocalMediaFileInNewTab) {
// Start at a tab with content in it, the file will open in a new tab.
ui_test_utils::NavigateToURL(browser(), GURL("http://google.com"));
ui_test_utils::NavigateToURL(browser(), GURL("https://google.com"));
// Make sure there is 1 tab.
ASSERT_EQ(1, browser()->tab_strip_model()->count());
......@@ -759,25 +491,25 @@ IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
// Expect that a new tab has been opened.
ASSERT_EQ(2, browser()->tab_strip_model()->count());
// Open the dialog again to check for a route.
OpenMRDialog(GetActiveWebContents());
test_ui_->ShowDialog();
// Wait for a route to be created.
WaitUntilRouteCreated();
test_ui_->WaitForAnyRoute();
}
// Tests that failing to create a route with a local file shows an issue.
// TODO(https://crbug.com/900248): Make this test pass with the Views dialog.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
OpenLocalMediaFileFailsAndShowsIssue) {
DISABLED_OpenLocalMediaFileFailsAndShowsIssue) {
OpenDialogAndCastFileFails();
// Expect that the issue is showing.
ASSERT_TRUE(IsUIShowingIssue());
}
// Tests that creating a route with a local file opens in fullscreen.
// TODO(crbug.com/822029): Fails on msan; fix and re-enable.
// TODO(https://crbug.com/900248): Make this test pass with the Views dialog.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
MANUAL_OpenLocalMediaFileFullscreen) {
DISABLED_OpenLocalMediaFileFullscreen) {
// Start at a new tab, the file should open in the same tab.
ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
// Make sure there is 1 tab.
......@@ -799,8 +531,9 @@ IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
}
// Tests that failed route creation of local file does not enter fullscreen.
// TODO(https://crbug.com/900248): Make this test pass with the Views dialog.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
OpenLocalMediaFileCastFailNoFullscreen) {
DISABLED_OpenLocalMediaFileCastFailNoFullscreen) {
// Start at a new tab, the file should open in the same tab.
ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
// Make sure there is 1 tab.
......@@ -836,8 +569,9 @@ IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, Fail_SendMessage) {
RunFailToSendMessageTest();
}
// TODO(https://crbug.com/822231): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
DISABLED_Fail_NoProvider) {
MANUAL_Fail_NoProvider) {
SetTestData(FILE_PATH_LITERAL("no_provider.json"));
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
CheckStartFailed(web_contents, "UnknownError",
......@@ -850,20 +584,12 @@ IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, Fail_CreateRoute) {
CheckStartFailed(web_contents, "UnknownError", "Unknown sink");
}
// TODO(crbug.com/822231): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
MANUAL_ReconnectSession) {
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, ReconnectSession) {
RunReconnectSessionTest();
}
// Flaky on Linux MSAN. https://crbug.com/840165
#if defined(OS_LINUX) && defined(MEMORY_SANITIZER)
#define MAYBE_Fail_ReconnectSession DISABLED_Fail_ReconnectSession
#else
#define MAYBE_Fail_ReconnectSession Fail_ReconnectSession
#endif
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
MAYBE_Fail_ReconnectSession) {
Fail_ReconnectSession) {
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
CheckSessionValidity(web_contents);
std::string session_id(GetStartedConnectionId(web_contents));
......@@ -880,7 +606,7 @@ IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, Fail_StartCancelled) {
WebContents* web_contents = StartSessionWithTestPageAndSink();
GetControllerForShownDialog(web_contents)->HideMediaRouterDialog();
test_ui_->HideDialog();
CheckStartFailed(web_contents, "NotAllowedError", "Dialog closed.");
}
......@@ -914,21 +640,21 @@ Browser* MediaRouterIntegrationIncognitoBrowserTest::browser() {
return incognito_browser_;
}
// Test is flaky on Linux. (https://crbug.com/853167)
#if defined(OS_LINUX)
#define MAYBE_Basic DISABLED_Basic
#else
#define MAYBE_Basic Basic
#endif
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationIncognitoBrowserTest,
MAYBE_Basic) {
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationIncognitoBrowserTest, Basic) {
RunBasicTest();
// If we tear down before route observers are notified of route termination,
// MediaRouter will create another TerminateRoute() request which will have a
// dangling Mojo callback at shutdown. So we must wait for the update.
test_ui_->WaitUntilNoRoutes();
}
// TODO(crbug.com/822300): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationIncognitoBrowserTest,
MANUAL_ReconnectSession) {
ReconnectSession) {
RunReconnectSessionTest();
// If we tear down before route observers are notified of route termination,
// MediaRouter will create another TerminateRoute() request which will have a
// dangling Mojo callback at shutdown. So we must wait for the update.
test_ui_->WaitUntilNoRoutes();
}
} // namespace media_router
......@@ -14,14 +14,13 @@
#include "chrome/browser/ui/media_router/media_cast_mode.h"
#include "chrome/browser/ui/toolbar/media_router_action.h"
#include "chrome/test/media_router/media_router_base_browsertest.h"
#include "chrome/test/media_router/media_router_ui_for_test.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
namespace media_router {
class MediaRouterDialogControllerWebUIImpl;
class MediaRouterUI;
struct IssueInfo;
class MediaRouterIntegrationBrowserTest : public MediaRouterBaseBrowserTest {
......@@ -33,23 +32,11 @@ class MediaRouterIntegrationBrowserTest : public MediaRouterBaseBrowserTest {
// InProcessBrowserTest Overrides
void TearDownOnMainThread() override;
void SetUpInProcessBrowserTestFixture() override;
void SetUpOnMainThread() override;
// MediaRouterBaseBrowserTest Overrides
void ParseCommandLine() override;
// Simulate user action to choose one sink in the popup dialog.
// |web_contents|: The web contents of the test page which invokes the popup
// dialog.
// |sink_name|: The sink's human readable name.
void ChooseSink(content::WebContents* web_contents,
const std::string& sink_name);
// Simulate user action to choose the local media cast mode in the popup
// dialog. This will not work unless the dialog is in the choose cast mode
// view. |dialog_contents|: The web contents of the popup dialog.
// |cast_mode_text|: The cast mode's dialog name.
void ClickCastMode(content::WebContents* dialog_contents, MediaCastMode mode);
// Checks that the request initiated from |web_contents| to start presentation
// failed with expected |error_name| and |error_message_substring|.
void CheckStartFailed(content::WebContents* web_contents,
......@@ -67,12 +54,6 @@ class MediaRouterIntegrationBrowserTest : public MediaRouterBaseBrowserTest {
static std::string ExecuteScriptAndExtractString(
const content::ToRenderFrameHost& adapter, const std::string& script);
void ClickDialog();
// Clicks on the header of the dialog. If in sinks view, will change to cast
// mode view, if in cast mode view, will change to sinks view.
void ClickHeader(content::WebContents* dialog_contents);
static bool ExecuteScriptAndExtractBool(
const content::ToRenderFrameHost& adapter,
const std::string& script);
......@@ -80,17 +61,6 @@ class MediaRouterIntegrationBrowserTest : public MediaRouterBaseBrowserTest {
static void ExecuteScript(const content::ToRenderFrameHost& adapter,
const std::string& script);
// Get the chrome modal dialog.
// |web_contents|: The web contents of the test page which invokes the popup
// dialog.
content::WebContents* GetMRDialog(content::WebContents* web_contents);
// Checks that the chrome modal dialog does not exist.
bool IsDialogClosed(content::WebContents* web_contents);
void WaitUntilDialogClosed(content::WebContents* web_contents);
void CheckDialogRemainsOpen(content::WebContents* web_contents);
// Opens "basic_test.html" and asserts that attempting to start a presentation
// fails with NotFoundError due to no sinks available.
void StartSessionAndAssertNotFoundError();
......@@ -121,76 +91,30 @@ class MediaRouterIntegrationBrowserTest : public MediaRouterBaseBrowserTest {
void SetTestData(base::FilePath::StringPieceType test_data_file);
// Start presentation and wait until the pop dialog shows up.
// |web_contents|: The web contents of the test page which invokes the popup
// dialog.
void StartSession(content::WebContents* web_contents);
// Open the chrome modal dialog.
// |web_contents|: The web contents of the test page which invokes the popup
// dialog.
content::WebContents* OpenMRDialog(content::WebContents* web_contents);
bool IsRouteCreatedOnUI();
bool IsRouteClosedOnUI();
bool IsSinkDiscoveredOnUI();
// Close route through clicking 'Stop casting' button in route details dialog.
void CloseRouteOnUI();
// Wait for the route to show up in the UI with a timeout. Fails if the
// route did not show up before the timeout.
void WaitUntilRouteCreated();
// Wait until there is an issue showing in the UI.
void WaitUntilIssue();
// Returns true if there is an issue showing in the UI.
bool IsUIShowingIssue();
// Returns the title of issue showing in UI. It is an error to call this if
// there are no issues showing in UI.
std::string GetIssueTitle();
// Returns the route ID for the specific sink.
std::string GetRouteId(const std::string& sink_id);
// Wait for the specific sink shows up in UI with a timeout. Fails if the sink
// doesn't show up before the timeout.
void WaitUntilSinkDiscoveredOnUI();
// Checks if media router dialog is fully loaded.
bool IsDialogLoaded(content::WebContents* dialog_contents);
// Wait until media router dialog is fully loaded.
void WaitUntilDialogFullyLoaded(content::WebContents* dialog_contents);
// Checks that the presentation started for |web_contents| has connected and
// is the default presentation.
void CheckSessionValidity(content::WebContents* web_contents);
// Checks that a Media Router dialog is shown for |web_contents|, and returns
// its controller.
MediaRouterDialogControllerWebUIImpl* GetControllerForShownDialog(
content::WebContents* web_contents);
// Returns the active WebContents for the current window.
content::WebContents* GetActiveWebContents();
// Gets the MediaRouterUI that is associated with the open dialog.
// This is needed to bypass potential issues that may arise when trying to
// test code that uses the native file dialog.
MediaRouterUI* GetMediaRouterUI(content::WebContents* media_router_dialog);
// Sets the MediaRouterFileDialog to act like a valid file was selected on
// opening the dialog.
void FileDialogSelectsFile(MediaRouterUI* media_router_ui, GURL file_url);
void FileDialogSelectsFile(GURL file_url);
// Sets the MediaRouterFileDialog to act like a bad file was selected on
// opening the dialog.
void FileDialogSelectFails(MediaRouterUI* media_router_ui,
const IssueInfo& issue);
void FileDialogSelectFails(const IssueInfo& issue);
// Runs a basic test in which a presentation is created through the
// MediaRouter dialog, then terminated.
......@@ -213,11 +137,15 @@ class MediaRouterIntegrationBrowserTest : public MediaRouterBaseBrowserTest {
// Sets whether media router is enabled.
void SetEnableMediaRouter(bool enable);
std::string receiver() const { return receiver_; }
// Test API for manipulating the UI.
MediaRouterUiForTest* test_ui_ = nullptr;
// Enabled features
// Enabled features.
base::test::ScopedFeatureList scoped_feature_list_;
// Name of the test receiver to use.
std::string receiver_;
private:
// Get the full path of the resource file.
// |relative_path|: The relative path to
......@@ -228,14 +156,11 @@ class MediaRouterIntegrationBrowserTest : public MediaRouterBaseBrowserTest {
std::unique_ptr<content::TestNavigationObserver> test_navigation_observer_;
policy::MockConfigurationPolicyProvider provider_;
// Fields
std::string receiver_;
};
class MediaRouterIntegrationIncognitoBrowserTest
: public MediaRouterIntegrationBrowserTest {
public:
protected:
void InstallAndEnableMRExtension() override;
void UninstallMRExtension() override;
Browser* browser() override;
......
......@@ -17,150 +17,37 @@
namespace media_router {
namespace {
const char kTestSinkName[] = "test-sink-1";
}
// Disabled due to flakiness: https://crbug.com/873912.
#if defined(OS_CHROMEOS) && defined(MEMORY_SANITIZER)
#define MAYBE_Dialog_Basic DISABLED_Dialog_Basic
#else
#define MAYBE_Dialog_Basic Dialog_Basic
#endif
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, MAYBE_Dialog_Basic) {
// TODO(https://crbug.com/822231): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, MANUAL_Dialog_Basic) {
OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WebContents* dialog_contents = OpenMRDialog(web_contents);
WaitUntilSinkDiscoveredOnUI();
// Verify the sink list.
std::string sink_length_script = base::StringPrintf(
"domAutomationController.send("
"window.document.getElementById('media-router-container')."
"sinksToShow_.length)");
ASSERT_GT(ExecuteScriptAndExtractInt(dialog_contents, sink_length_script), 0);
LOG(INFO) << "Choose Sink";
ChooseSink(web_contents, kTestSinkName);
// Linux and Windows bots run browser tests without a physical display, which
// is causing flaky event dispatching of mouseenter and mouseleave events. This
// causes the dialog to sometimes close prematurely even though a mouseenter
// event is explicitly dispatched in the test.
// Here, we still dispatch the mouseenter event for OSX, but close
// the dialog and reopen it on Linux and Windows.
// The test succeeds fine when run with a physical display.
// http://crbug.com/577943 http://crbug.com/591779
#if defined(OS_MACOSX)
// Simulate keeping the mouse on the dialog to prevent it from automatically
// closing after the route has been created. Then, check that the dialog
// remains open.
std::string mouse_enter_script = base::StringPrintf(
"window.document.getElementById('media-router-container')"
" .dispatchEvent(new Event('mouseenter'));");
ASSERT_TRUE(content::ExecuteScript(dialog_contents, mouse_enter_script));
#endif
WaitUntilRouteCreated();
#if defined(OS_MACOSX)
CheckDialogRemainsOpen(web_contents);
#elif defined(OS_LINUX) || defined(OS_WIN)
Wait(base::TimeDelta::FromSeconds(5));
LOG(INFO) << "Waiting for dialog to be closed";
WaitUntilDialogClosed(web_contents);
LOG(INFO) << "Reopen MR dialog";
dialog_contents = OpenMRDialog(web_contents);
#endif
LOG(INFO) << "Check route details dialog";
std::string route_script;
// Verify the route details is not undefined.
route_script = base::StringPrintf(
"domAutomationController.send("
"window.document.getElementById('media-router-container').shadowRoot."
"getElementById('route-details') != undefined)");
ASSERT_TRUE(ConditionalWait(
base::TimeDelta::FromSeconds(30), base::TimeDelta::FromSeconds(1),
base::Bind(
&MediaRouterIntegrationBrowserTest::ExecuteScriptAndExtractBool,
dialog_contents, route_script)));
route_script = base::StringPrintf(
"domAutomationController.send("
"window.document.getElementById('media-router-container').currentView_ "
"== media_router.MediaRouterView.ROUTE_DETAILS)");
ASSERT_TRUE(ExecuteScriptAndExtractBool(dialog_contents, route_script));
// Verify the route details page.
route_script = base::StringPrintf(
"domAutomationController.send("
"window.document.getElementById('media-router-container').shadowRoot."
"getElementById('route-details').shadowRoot.getElementById("
"'route-description').innerText)");
std::string route_information = ExecuteScriptAndExtractString(
dialog_contents, route_script);
ASSERT_EQ("Test Route", route_information);
std::string sink_script;
// Verify the container header is not undefined.
sink_script = base::StringPrintf(
"domAutomationController.send("
"window.document.getElementById('media-router-container').shadowRoot."
"getElementById('container-header') != undefined)");
LOG(INFO) << "Checking container-header";
ASSERT_TRUE(ConditionalWait(
base::TimeDelta::FromSeconds(30), base::TimeDelta::FromSeconds(1),
base::Bind(
&MediaRouterIntegrationBrowserTest::ExecuteScriptAndExtractBool,
dialog_contents, sink_script)));
sink_script = base::StringPrintf(
"domAutomationController.send("
"window.document.getElementById('media-router-container').shadowRoot."
"getElementById('container-header').shadowRoot.getElementById("
"'header-text').innerText)");
std::string sink_name = ExecuteScriptAndExtractString(
dialog_contents, sink_script);
ASSERT_EQ(kTestSinkName, sink_name);
LOG(INFO) << "Finish verification";
#if defined(OS_MACOSX)
// Simulate moving the mouse off the dialog. Confirm that the dialog closes
// automatically after the route is closed.
// In tests, it sometimes takes too long to CloseRouteOnUI() to finish so
// the timer started when the route is initially closed times out before the
// mouseleave event is dispatched. In that case, the dialog remains open.
std::string mouse_leave_script = base::StringPrintf(
"window.document.getElementById('media-router-container')"
" .dispatchEvent(new Event('mouseleave'));");
ASSERT_TRUE(content::ExecuteScript(dialog_contents, mouse_leave_script));
#endif
LOG(INFO) << "Closing route on UI";
CloseRouteOnUI();
#if defined(OS_MACOSX)
LOG(INFO) << "Waiting for dialog to be closed";
WaitUntilDialogClosed(web_contents);
#endif
LOG(INFO) << "Closed dialog, end of test";
test_ui_->ShowDialog();
test_ui_->WaitForSinkAvailable(receiver_);
test_ui_->StartCasting(receiver_);
test_ui_->WaitForAnyRoute();
if (!test_ui_->IsDialogShown())
test_ui_->ShowDialog();
ASSERT_EQ("Test Route", test_ui_->GetStatusTextForSink(receiver_));
test_ui_->StopCasting(receiver_);
test_ui_->WaitUntilNoRoutes();
// TODO(takumif): Remove the HideDialog() call once the dialog can close on
// its own.
test_ui_->HideDialog();
}
// TODO(crbug.com/822301): Flaky in Chromium waterfall.
// TODO(https://crbug.com/822231): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
MANUAL_Dialog_RouteCreationTimedOut) {
SetTestData(FILE_PATH_LITERAL("route_creation_timed_out.json"));
OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WebContents* dialog_contents = OpenMRDialog(web_contents);
// Verify the sink list.
std::string sink_length_script = base::StringPrintf(
"domAutomationController.send("
"window.document.getElementById('media-router-container')."
"sinksToShow_.length)");
ASSERT_GT(ExecuteScriptAndExtractInt(dialog_contents, sink_length_script), 0);
test_ui_->ShowDialog();
test_ui_->WaitForSinkAvailable(receiver_);
base::TimeTicks start_time(base::TimeTicks::Now());
ChooseSink(web_contents, kTestSinkName);
WaitUntilIssue();
test_ui_->StartCasting(receiver_);
test_ui_->WaitForAnyIssue();
base::TimeDelta elapsed(base::TimeTicks::Now() - start_time);
// The hardcoded timeout route creation timeout for the UI.
......@@ -170,7 +57,7 @@ IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
EXPECT_GE(elapsed, expected_timeout);
EXPECT_LE(elapsed - expected_timeout, base::TimeDelta::FromSeconds(5));
std::string issue_title = GetIssueTitle();
std::string issue_title = test_ui_->GetIssueTextForSink(receiver_);
// TODO(imcheng): Fix host name for file schemes (crbug.com/560576).
ASSERT_EQ(
l10n_util::GetStringFUTF8(IDS_MEDIA_ROUTER_ISSUE_CREATE_ROUTE_TIMEOUT,
......@@ -178,7 +65,8 @@ IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
issue_title);
// Route will still get created, it just takes longer than usual.
WaitUntilRouteCreated();
test_ui_->WaitForAnyRoute();
test_ui_->HideDialog();
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
......@@ -191,33 +79,22 @@ IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
// Enable media routing and open media router dialog.
SetEnableMediaRouter(true);
OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
OpenMRDialog(web_contents);
MediaRouterDialogControllerWebUIImpl* controller =
MediaRouterDialogControllerWebUIImpl::GetOrCreateForWebContents(
web_contents);
ASSERT_TRUE(controller->IsShowingMediaRouterDialog());
test_ui_->ShowDialog();
ASSERT_TRUE(test_ui_->IsDialogShown());
test_ui_->HideDialog();
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
DisableMediaRoutingWhenDialogIsOpened) {
// Open media router dialog.
OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
OpenMRDialog(web_contents);
MediaRouterDialogControllerWebUIImpl* controller =
MediaRouterDialogControllerWebUIImpl::GetOrCreateForWebContents(
web_contents);
ASSERT_TRUE(controller->IsShowingMediaRouterDialog());
test_ui_->ShowDialog();
ASSERT_TRUE(test_ui_->IsDialogShown());
// Disable media routing.
SetEnableMediaRouter(false);
ASSERT_FALSE(controller->IsShowingMediaRouterDialog());
ASSERT_FALSE(test_ui_->IsDialogShown());
}
} // namespace media_router
......@@ -41,18 +41,17 @@ class MediaRouterIntegrationOneUABrowserTest
}
};
// TODO(crbug.com/822231): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest, MANUAL_Basic) {
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest, Basic) {
RunBasicTest();
}
// TODO(crbug.com/822216): Flaky in Chromium waterfall.
// TODO(https://crbug.com/822231): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest,
MANUAL_SendAndOnMessage) {
RunSendMessageTest("foo");
}
// TODO(crbug.com/821717): Flaky in Chromium waterfall.
// TODO(https://crbug.com/822231): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest,
MANUAL_ReceiverCloseConnection) {
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
......@@ -60,21 +59,18 @@ IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest,
ExecuteJavaScriptAPI(web_contents, kInitiateCloseFromReceiverPageScript);
}
// TODO(crbug.com/824889): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest,
MANUAL_Fail_SendMessage) {
Fail_SendMessage) {
RunFailToSendMessageTest();
}
// TODO(crbug.com/821717): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest,
MANUAL_ReconnectSession) {
ReconnectSession) {
RunReconnectSessionTest();
}
// TODO(crbug.com/821717): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest,
MANUAL_ReconnectSessionSameTab) {
ReconnectSessionSameTab) {
RunReconnectSessionSameTabTest();
}
......@@ -87,28 +83,23 @@ class MediaRouterIntegrationOneUANoReceiverBrowserTest
}
};
// TODO(crbug.com/822179,822337): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUANoReceiverBrowserTest,
MANUAL_Basic) {
Basic) {
RunBasicTest();
}
// TODO(crbug.com/821717): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUANoReceiverBrowserTest,
MANUAL_Fail_SendMessage) {
Fail_SendMessage) {
RunFailToSendMessageTest();
}
// TODO(crbug.com/822231): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUANoReceiverBrowserTest,
MANUAL_ReconnectSession) {
ReconnectSession) {
RunReconnectSessionTest();
}
// TODO(crbug.com/826016): Crashes on ASAN.
// TODO(crbug.com/834681): Crashes elsewhere too, flakily.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUANoReceiverBrowserTest,
MANUAL_ReconnectSessionSameTab) {
ReconnectSessionSameTab) {
RunReconnectSessionSameTabTest();
}
......
......@@ -5,6 +5,8 @@
#include "chrome/test/media_router/media_router_ui_for_test.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/media/router/media_router_factory.h"
#include "chrome/browser/media/router/media_routes_observer.h"
#include "chrome/browser/ui/views/media_router/cast_dialog_sink_button.h"
#include "chrome/browser/ui/views/media_router/cast_dialog_view.h"
#include "chrome/browser/ui/views/media_router/media_router_dialog_controller_views.h"
......@@ -30,6 +32,24 @@ ui::MouseEvent CreateMouseReleasedEvent() {
ui::EF_LEFT_MOUSE_BUTTON, 0);
}
// Routes observer that calls a callback once there are no routes.
class NoRoutesObserver : public MediaRoutesObserver {
public:
NoRoutesObserver(MediaRouter* router, base::OnceClosure callback)
: MediaRoutesObserver(router), callback_(std::move(callback)) {}
~NoRoutesObserver() override = default;
void OnRoutesUpdated(
const std::vector<MediaRoute>& routes,
const std::vector<MediaRoute::Id>& joinable_route_ids) override {
if (callback_ && routes.empty())
std::move(callback_).Run();
}
private:
base::OnceClosure callback_;
};
} // namespace
// static
......@@ -80,15 +100,15 @@ void MediaRouterUiForTest::ChooseSourceType(
dialog_view->sources_menu_model_for_test()->ActivatedAt(source_index);
}
void MediaRouterUiForTest::StartCasting(const MediaSink::Id& sink_id) {
CastDialogSinkButton* sink_button = GetSinkButton(sink_id);
void MediaRouterUiForTest::StartCasting(const std::string& sink_name) {
CastDialogSinkButton* sink_button = GetSinkButton(sink_name);
sink_button->OnMousePressed(CreateMousePressedEvent());
sink_button->OnMouseReleased(CreateMouseReleasedEvent());
base::RunLoop().RunUntilIdle();
}
void MediaRouterUiForTest::StopCasting(const MediaSink::Id& sink_id) {
CastDialogSinkButton* sink_button = GetSinkButton(sink_id);
void MediaRouterUiForTest::StopCasting(const std::string& sink_name) {
CastDialogSinkButton* sink_button = GetSinkButton(sink_name);
sink_button->icon_view()->OnMousePressed(CreateMousePressedEvent());
sink_button->icon_view()->OnMouseReleased(CreateMouseReleasedEvent());
base::RunLoop().RunUntilIdle();
......@@ -109,8 +129,12 @@ void MediaRouterUiForTest::StopCasting() {
NOTREACHED() << "Sink was not found";
}
void MediaRouterUiForTest::WaitForSink(const MediaSink::Id& sink_id) {
ObserveDialog(WatchType::kSink, sink_id);
void MediaRouterUiForTest::WaitForSink(const std::string& sink_name) {
ObserveDialog(WatchType::kSink, sink_name);
}
void MediaRouterUiForTest::WaitForSinkAvailable(const std::string& sink_name) {
ObserveDialog(WatchType::kSinkAvailable, sink_name);
}
void MediaRouterUiForTest::WaitForAnyIssue() {
......@@ -121,37 +145,53 @@ void MediaRouterUiForTest::WaitForAnyRoute() {
ObserveDialog(WatchType::kAnyRoute);
}
void MediaRouterUiForTest::WaitForDialogClosed() {
ObserveDialog(WatchType::kDialogClosed);
void MediaRouterUiForTest::WaitForDialogShown() {
CHECK(!watch_sink_name_);
CHECK(!watch_callback_);
CHECK_EQ(watch_type_, WatchType::kNone);
if (IsDialogShown())
return;
base::RunLoop run_loop;
watch_callback_ = run_loop.QuitClosure();
watch_type_ = WatchType::kDialogShown;
run_loop.Run();
}
void MediaRouterUiForTest::WaitForDialogHidden() {
ObserveDialog(WatchType::kDialogHidden);
}
std::string MediaRouterUiForTest::GetSinkName(
const MediaSink::Id& sink_id) const {
CastDialogSinkButton* sink_button = GetSinkButton(sink_id);
return base::UTF16ToUTF8(sink_button->sink().friendly_name);
void MediaRouterUiForTest::WaitUntilNoRoutes() {
base::RunLoop run_loop;
NoRoutesObserver no_routes_observer(
MediaRouterFactory::GetApiForBrowserContext(
web_contents_->GetBrowserContext()),
run_loop.QuitClosure());
run_loop.Run();
}
MediaRoute::Id MediaRouterUiForTest::GetRouteIdForSink(
const MediaSink::Id& sink_id) const {
CastDialogSinkButton* sink_button = GetSinkButton(sink_id);
const std::string& sink_name) const {
CastDialogSinkButton* sink_button = GetSinkButton(sink_name);
if (!sink_button->sink().route) {
NOTREACHED() << "Route not found for sink " << sink_id;
NOTREACHED() << "Route not found for sink " << sink_name;
return "";
}
return sink_button->sink().route->media_route_id();
}
std::string MediaRouterUiForTest::GetStatusTextForSink(
const MediaSink::Id& sink_id) const {
CastDialogSinkButton* sink_button = GetSinkButton(sink_id);
const std::string& sink_name) const {
CastDialogSinkButton* sink_button = GetSinkButton(sink_name);
return base::UTF16ToUTF8(sink_button->sink().status_text);
}
std::string MediaRouterUiForTest::GetIssueTextForSink(
const MediaSink::Id& sink_id) const {
CastDialogSinkButton* sink_button = GetSinkButton(sink_id);
const std::string& sink_name) const {
CastDialogSinkButton* sink_button = GetSinkButton(sink_name);
if (!sink_button->sink().issue) {
NOTREACHED() << "Issue not found for sink " << sink_id;
NOTREACHED() << "Issue not found for sink " << sink_name;
return "";
}
return sink_button->sink().issue->info().title;
......@@ -161,11 +201,17 @@ MediaRouterUiForTest::MediaRouterUiForTest(content::WebContents* web_contents)
: web_contents_(web_contents),
dialog_controller_(
MediaRouterDialogControllerViews::GetOrCreateForWebContents(
web_contents)) {}
web_contents)),
weak_factory_(this) {
dialog_controller_->SetDialogCreationCallbackForTesting(base::BindRepeating(
&MediaRouterUiForTest::OnDialogCreated, weak_factory_.GetWeakPtr()));
}
void MediaRouterUiForTest::OnDialogModelUpdated(CastDialogView* dialog_view) {
if (!watch_callback_ || watch_type_ == WatchType::kDialogClosed)
if (!watch_callback_ || watch_type_ == WatchType::kDialogShown ||
watch_type_ == WatchType::kDialogHidden) {
return;
}
const std::vector<CastDialogSinkButton*>& sink_buttons =
dialog_view->sink_buttons_for_test();
......@@ -173,27 +219,34 @@ void MediaRouterUiForTest::OnDialogModelUpdated(CastDialogView* dialog_view) {
[&, this](CastDialogSinkButton* sink_button) {
switch (watch_type_) {
case WatchType::kSink:
return sink_button->sink().id == *watch_sink_id_;
return sink_button->sink().friendly_name ==
base::UTF8ToUTF16(*watch_sink_name_);
case WatchType::kSinkAvailable:
return sink_button->sink().friendly_name ==
base::UTF8ToUTF16(*watch_sink_name_) &&
sink_button->sink().state ==
UIMediaSinkState::AVAILABLE;
case WatchType::kAnyIssue:
return sink_button->sink().issue.has_value();
case WatchType::kAnyRoute:
return sink_button->sink().route.has_value();
case WatchType::kNone:
case WatchType::kDialogClosed:
case WatchType::kDialogShown:
case WatchType::kDialogHidden:
NOTREACHED() << "Invalid WatchType";
return false;
}
}) != sink_buttons.end()) {
std::move(*watch_callback_).Run();
watch_callback_.reset();
watch_sink_id_.reset();
watch_sink_name_.reset();
watch_type_ = WatchType::kNone;
dialog_view->RemoveObserver(this);
}
}
void MediaRouterUiForTest::OnDialogWillClose(CastDialogView* dialog_view) {
if (watch_type_ == WatchType::kDialogClosed) {
if (watch_type_ == WatchType::kDialogHidden) {
std::move(*watch_callback_).Run();
watch_callback_.reset();
watch_type_ = WatchType::kNone;
......@@ -203,18 +256,28 @@ void MediaRouterUiForTest::OnDialogWillClose(CastDialogView* dialog_view) {
dialog_view->RemoveObserver(this);
}
void MediaRouterUiForTest::OnDialogCreated() {
if (watch_type_ == WatchType::kDialogShown) {
std::move(*watch_callback_).Run();
watch_callback_.reset();
watch_type_ = WatchType::kNone;
}
CastDialogView::GetInstance()->KeepShownForTesting();
}
CastDialogSinkButton* MediaRouterUiForTest::GetSinkButton(
const MediaSink::Id& sink_id) const {
const std::string& sink_name) const {
CastDialogView* dialog_view = CastDialogView::GetInstance();
CHECK(dialog_view);
const std::vector<CastDialogSinkButton*>& sink_buttons =
dialog_view->sink_buttons_for_test();
auto it = std::find_if(sink_buttons.begin(), sink_buttons.end(),
[sink_id](CastDialogSinkButton* sink_button) {
return sink_button->sink().id == sink_id;
[sink_name](CastDialogSinkButton* sink_button) {
return sink_button->sink().friendly_name ==
base::UTF8ToUTF16(sink_name);
});
if (it == sink_buttons.end()) {
NOTREACHED() << "Sink button not found for sink ID: " << sink_id;
NOTREACHED() << "Sink button not found for sink: " << sink_name;
return nullptr;
} else {
return *it;
......@@ -223,12 +286,12 @@ CastDialogSinkButton* MediaRouterUiForTest::GetSinkButton(
void MediaRouterUiForTest::ObserveDialog(
WatchType watch_type,
base::Optional<MediaSink::Id> sink_id) {
CHECK(!watch_sink_id_);
base::Optional<std::string> sink_name) {
CHECK(!watch_sink_name_);
CHECK(!watch_callback_);
CHECK_EQ(watch_type_, WatchType::kNone);
base::RunLoop run_loop;
watch_sink_id_ = std::move(sink_id);
watch_sink_name_ = std::move(sink_name);
watch_callback_ = run_loop.QuitClosure();
watch_type_ = watch_type;
......
......@@ -7,8 +7,10 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "chrome/browser/ui/views/media_router/cast_dialog_view.h"
#include "chrome/browser/ui/views/media_router/media_router_dialog_controller_views.h"
#include "chrome/common/media_router/media_sink.h"
#include "chrome/common/media_router/media_source.h"
#include "content/public/browser/web_contents_user_data.h"
......@@ -19,8 +21,6 @@ class WebContents;
namespace media_router {
class MediaRouterDialogControllerViews;
class MediaRouterUiForTest
: public content::WebContentsUserData<MediaRouterUiForTest>,
public CastDialogView::Observer {
......@@ -39,31 +39,41 @@ class MediaRouterUiForTest
// These methods require that the dialog is shown and the specified sink is
// shown in the dialog.
void StartCasting(const MediaSink::Id& sink_id);
void StopCasting(const MediaSink::Id& sink_id);
void StartCasting(const std::string& sink_name);
void StopCasting(const std::string& sink_name);
// Stops casting to the first active sink found on the sink list. Requires
// that such a sink exists.
void StopCasting();
// Waits until . Requires that the dialog is shown.
void WaitForSink(const MediaSink::Id& sink_id);
// Waits until a condition is met. Requires that the dialog is shown.
void WaitForSink(const std::string& sink_name);
void WaitForSinkAvailable(const std::string& sink_name);
void WaitForAnyIssue();
void WaitForAnyRoute();
void WaitForDialogClosed();
void WaitForDialogShown();
void WaitForDialogHidden();
void WaitUntilNoRoutes();
// These methods require that the dialog is shown, and the sink specified by
// |sink_id| is in the dialog.
std::string GetSinkName(const MediaSink::Id& sink_id) const;
MediaRoute::Id GetRouteIdForSink(const MediaSink::Id& sink_id) const;
std::string GetStatusTextForSink(const MediaSink::Id& sink_id) const;
std::string GetIssueTextForSink(const MediaSink::Id& sink_id) const;
// |sink_name| is in the dialog.
MediaRoute::Id GetRouteIdForSink(const std::string& sink_name) const;
std::string GetStatusTextForSink(const std::string& sink_name) const;
std::string GetIssueTextForSink(const std::string& sink_name) const;
content::WebContents* web_contents() const { return web_contents_; }
private:
friend class content::WebContentsUserData<MediaRouterUiForTest>;
enum class WatchType { kNone, kSink, kAnyIssue, kAnyRoute, kDialogClosed };
enum class WatchType {
kNone,
kSink, // Sink is found in any state.
kSinkAvailable, // Sink is found in the "Available" state.
kAnyIssue,
kAnyRoute,
kDialogShown,
kDialogHidden
};
explicit MediaRouterUiForTest(content::WebContents* web_contents);
......@@ -71,21 +81,26 @@ class MediaRouterUiForTest
void OnDialogModelUpdated(CastDialogView* dialog_view) override;
void OnDialogWillClose(CastDialogView* dialog_view) override;
CastDialogSinkButton* GetSinkButton(const MediaSink::Id& sink_id) const;
// Called by MediaRouterDialogControllerViews.
void OnDialogCreated();
CastDialogSinkButton* GetSinkButton(const std::string& sink_name) const;
// Registers itself as an observer to the dialog, and waits until an event
// of |watch_type| is observed. |sink_id| should be set only if observing for
// a sink.
// of |watch_type| is observed. |sink_name| should be set only if observing
// for a sink.
void ObserveDialog(WatchType watch_type,
base::Optional<MediaSink::Id> sink_id = base::nullopt);
base::Optional<std::string> sink_name = base::nullopt);
content::WebContents* web_contents_;
MediaRouterDialogControllerViews* dialog_controller_;
base::Optional<MediaSink::Id> watch_sink_id_;
base::Optional<std::string> watch_sink_name_;
base::Optional<base::OnceClosure> watch_callback_;
WatchType watch_type_ = WatchType::kNone;
base::WeakPtrFactory<MediaRouterUiForTest> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MediaRouterUiForTest);
};
......
......@@ -120,7 +120,7 @@ function checkStartFailed(expectedErrorName, expectedErrorMessageSubstring) {
sendResult(false, 'start() unexpectedly succeeded.');
}).catch(function(e) {
if (expectedErrorName != e.name) {
sendResult(false, 'Got unexpected error: ' + e.name);
sendResult(false, 'Got unexpected error. ' + e.name + ': ' + e.message);
} else if (e.message.indexOf(expectedErrorMessageSubstring) == -1) {
sendResult(false,
'Error message is not correct, it should contain "' +
......@@ -219,6 +219,12 @@ function sendMessageAndExpectResponse(message) {
sendResult(false, 'startedConnection does not exist.');
return;
}
if (startedConnection.state != 'connected') {
sendResult(false,
`Expected the connection state to be connected but it was \
${startedConnection.state}`);
return;
}
startedConnection.onmessage = function(receivedMessage) {
var expectedResponse = 'Pong: ' + message;
var actualResponse = receivedMessage.data;
......@@ -241,6 +247,12 @@ function initiateCloseFromReceiverPage() {
sendResult(false, 'startedConnection does not exist.');
return;
}
if (startedConnection.state != 'connected') {
sendResult(false,
`Expected the connection state to be connected but it was \
${startedConnection.state}`);
return;
}
startedConnection.onclose = (event) => {
const reason = event.reason;
if (reason != 'closed') {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment