blob: ba16fd1e35dc3a2da60822c25ee4ad60a826f224 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/test/media_router/media_router_integration_browsertest.h"
#include <memory>
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/json/json_file_value_serializer.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/path_service.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.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/common/media_router/issue.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/policy_constants.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "media/base/test_data_util.h"
#include "net/base/filename_util.h"
#include "testing/gtest/include/gtest/gtest.h"
using content::WebContents;
namespace media_router {
namespace {
// Command line argument to specify receiver,
const char kReceiver[] = "receiver";
// The path relative to <chromium src>/out/<build config> for media router
// browser test resources.
const base::FilePath::StringPieceType kResourcePath = FILE_PATH_LITERAL(
"media_router/browser_test_resources/");
const char kTestSinkName[] = "test-sink-1";
const char kButterflyVideoFileName[] = "butterfly-853x480.webm";
// The javascript snippets.
const char kCheckSessionScript[] = "checkSession();";
const char kCheckStartFailedScript[] = "checkStartFailed('%s', '%s');";
const char kStartSessionScript[] = "startSession();";
const char kTerminateSessionScript[] =
"terminateSessionAndWaitForStateChange();";
const char kCloseSessionScript[] = "closeConnectionAndWaitForStateChange();";
const char kReconnectSessionScript[] = "reconnectSession('%s');";
const char kCheckSendMessageFailedScript[] = "checkSendMessageFailed('%s');";
const char kWaitSinkScript[] = "waitUntilDeviceAvailable();";
const char kSendMessageAndExpectResponseScript[] =
"sendMessageAndExpectResponse('%s');";
const char kSendMessageAndExpectConnectionCloseOnErrorScript[] =
"sendMessageAndExpectConnectionCloseOnError()";
std::string GetStartedConnectionId(WebContents* web_contents) {
std::string session_id;
CHECK(content::ExecuteScriptAndExtractString(
web_contents, "window.domAutomationController.send(startedConnection.id)",
&session_id));
return session_id;
}
std::string GetDefaultRequestSessionId(WebContents* web_contents) {
std::string session_id;
CHECK(content::ExecuteScriptAndExtractString(
web_contents,
"window.domAutomationController.send(defaultRequestSessionId)",
&session_id));
return session_id;
}
} // namespace
MediaRouterIntegrationBrowserTest::MediaRouterIntegrationBrowserTest() {
}
MediaRouterIntegrationBrowserTest::~MediaRouterIntegrationBrowserTest() {
}
void MediaRouterIntegrationBrowserTest::TearDownOnMainThread() {
test_ui_->TearDown();
MediaRouterBaseBrowserTest::TearDownOnMainThread();
test_navigation_observer_.reset();
}
void MediaRouterIntegrationBrowserTest::SetUpInProcessBrowserTestFixture() {
MediaRouterBaseBrowserTest::SetUpInProcessBrowserTestFixture();
EXPECT_CALL(provider_, IsInitializationComplete(testing::_))
.WillRepeatedly(testing::Return(true));
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) {
std::string result(ExecuteScriptAndExtractString(web_contents, script));
// Read the test result, the test result set by javascript is a
// JSON string with the following format:
// {"passed": "<true/false>", "errorMessage": "<error_message>"}
std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
result, base::JSON_ALLOW_TRAILING_COMMAS);
// Convert to dictionary.
base::DictionaryValue* dict_value = nullptr;
ASSERT_TRUE(value->GetAsDictionary(&dict_value));
// Extract the fields.
bool passed = false;
ASSERT_TRUE(dict_value->GetBoolean("passed", &passed));
std::string error_message;
ASSERT_TRUE(dict_value->GetString("errorMessage", &error_message));
ASSERT_TRUE(passed) << error_message;
}
void MediaRouterIntegrationBrowserTest::StartSessionAndAssertNotFoundError() {
OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
WebContents* web_contents = GetActiveWebContents();
CHECK(web_contents);
ExecuteJavaScriptAPI(web_contents, kStartSessionScript);
// Wait to simulate the user waiting for any sinks to be displayed.
Wait(base::TimeDelta::FromSeconds(1));
test_ui_->HideDialog();
CheckStartFailed(web_contents, "NotFoundError", "No screens found.");
}
WebContents*
MediaRouterIntegrationBrowserTest::StartSessionWithTestPageAndSink() {
OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
WebContents* web_contents = GetActiveWebContents();
CHECK(web_contents);
ExecuteJavaScriptAPI(web_contents, kWaitSinkScript);
ExecuteJavaScriptAPI(web_contents, kStartSessionScript);
test_ui_->WaitForDialogShown();
return web_contents;
}
WebContents*
MediaRouterIntegrationBrowserTest::StartSessionWithTestPageAndChooseSink() {
WebContents* web_contents = StartSessionWithTestPageAndSink();
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();
return web_contents;
}
void MediaRouterIntegrationBrowserTest::OpenDialogAndCastFile(
bool route_success) {
route_success
? SetTestData(FILE_PATH_LITERAL("local_media_sink.json"))
: SetTestData(FILE_PATH_LITERAL("local_media_sink_route_fail.json"));
GURL file_url = net::FilePathToFileURL(
media::GetTestDataFilePath(kButterflyVideoFileName));
test_ui_->ShowDialog();
// Mock out file dialog operations, as those can't be simulated.
test_ui_->SetLocalFile(file_url);
test_ui_->WaitForSink(receiver_);
test_ui_->ChooseSourceType(CastDialogView::kLocalFile);
ASSERT_EQ(CastDialogView::kLocalFile, test_ui_->GetChosenSourceType());
test_ui_->WaitForSinkAvailable(receiver_);
test_ui_->StartCasting(receiver_);
ASSERT_EQ(file_url, GetActiveWebContents()->GetURL());
}
void MediaRouterIntegrationBrowserTest::OpenDialogAndCastFileFails() {
SetTestData(FILE_PATH_LITERAL("local_media_sink.json"));
GURL file_url = net::FilePathToFileURL(
media::GetTestDataFilePath(kButterflyVideoFileName));
test_ui_->ShowDialog();
// Mock out file dialog opperations, as those can't be simulated.
test_ui_->SetLocalFileSelectionIssue(IssueInfo());
test_ui_->WaitForSink(receiver_);
test_ui_->ChooseSourceType(CastDialogView::kLocalFile);
test_ui_->WaitForAnyIssue();
}
void MediaRouterIntegrationBrowserTest::OpenTestPage(
base::FilePath::StringPieceType file_name) {
base::FilePath full_path = GetResourceFile(file_name);
ui_test_utils::NavigateToURL(browser(), GetTestPageUrl(full_path));
}
void MediaRouterIntegrationBrowserTest::OpenTestPageInNewTab(
base::FilePath::StringPieceType file_name) {
base::FilePath full_path = GetResourceFile(file_name);
ui_test_utils::NavigateToURLWithDisposition(
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(
const base::FilePath& full_path) {
return net::FilePathToFileURL(full_path);
}
void MediaRouterIntegrationBrowserTest::CheckStartFailed(
WebContents* web_contents,
const std::string& error_name,
const std::string& error_message_substring) {
std::string script(base::StringPrintf(kCheckStartFailedScript,
error_name.c_str(),
error_message_substring.c_str()));
ExecuteJavaScriptAPI(web_contents, script);
}
void MediaRouterIntegrationBrowserTest::SetTestData(
base::FilePath::StringPieceType test_data_file) {
base::FilePath full_path = GetResourceFile(test_data_file);
JSONFileValueDeserializer deserializer(full_path);
int error_code = 0;
std::string error_message;
std::unique_ptr<base::Value> value;
{
// crbug.com/724573
base::ScopedAllowBlockingForTesting allow_blocking;
value = deserializer.Deserialize(&error_code, &error_message);
}
CHECK(value.get()) << "Deserialize failed: " << error_message;
std::string test_data_str;
ASSERT_TRUE(base::JSONWriter::Write(*value, &test_data_str));
ExecuteScriptInBackgroundPageNoWait(
extension_id_,
base::StringPrintf("localStorage['testdata'] = '%s'",
test_data_str.c_str()));
}
base::FilePath MediaRouterIntegrationBrowserTest::GetResourceFile(
base::FilePath::StringPieceType relative_path) const {
base::FilePath base_dir;
// ASSERT_TRUE can only be used in void returning functions.
// Use CHECK instead in non-void returning functions.
CHECK(base::PathService::Get(base::DIR_MODULE, &base_dir));
base::FilePath full_path =
base_dir.Append(kResourcePath).Append(relative_path);
{
// crbug.com/724573
base::ScopedAllowBlockingForTesting allow_blocking;
CHECK(PathExists(full_path));
}
return full_path;
}
int MediaRouterIntegrationBrowserTest::ExecuteScriptAndExtractInt(
const content::ToRenderFrameHost& adapter, const std::string& script) {
int result;
CHECK(content::ExecuteScriptAndExtractInt(adapter, script, &result));
return result;
}
std::string MediaRouterIntegrationBrowserTest::ExecuteScriptAndExtractString(
const content::ToRenderFrameHost& adapter, const std::string& script) {
std::string result;
CHECK(content::ExecuteScriptAndExtractString(adapter, script, &result));
return result;
}
bool MediaRouterIntegrationBrowserTest::ExecuteScriptAndExtractBool(
const content::ToRenderFrameHost& adapter, const std::string& script) {
bool result;
CHECK(content::ExecuteScriptAndExtractBool(adapter, script, &result));
return result;
}
void MediaRouterIntegrationBrowserTest::ExecuteScript(
const content::ToRenderFrameHost& adapter, const std::string& script) {
ASSERT_TRUE(content::ExecuteScript(adapter, script));
}
bool MediaRouterIntegrationBrowserTest::IsRouteCreatedOnUI() {
return !test_ui_->GetRouteIdForSink(receiver_).empty();
}
bool MediaRouterIntegrationBrowserTest::IsUIShowingIssue() {
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.
if (!test_ui_->IsDialogShown())
test_ui_->ShowDialog();
test_ui_->WaitForSink(receiver_);
return test_ui_->GetRouteIdForSink(receiver_).empty();
}
void MediaRouterIntegrationBrowserTest::ParseCommandLine() {
MediaRouterBaseBrowserTest::ParseCommandLine();
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
receiver_ = command_line->GetSwitchValueASCII(kReceiver);
if (receiver_.empty())
receiver_ = kTestSinkName;
}
void MediaRouterIntegrationBrowserTest::CheckSessionValidity(
WebContents* web_contents) {
ExecuteJavaScriptAPI(web_contents, kCheckSessionScript);
std::string session_id(GetStartedConnectionId(web_contents));
EXPECT_FALSE(session_id.empty());
std::string default_request_session_id(
GetDefaultRequestSessionId(web_contents));
EXPECT_EQ(session_id, default_request_session_id);
}
WebContents* MediaRouterIntegrationBrowserTest::GetActiveWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
void MediaRouterIntegrationBrowserTest::RunBasicTest() {
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
CheckSessionValidity(web_contents);
ExecuteJavaScriptAPI(web_contents, kTerminateSessionScript);
test_ui_->WaitUntilNoRoutes();
}
void MediaRouterIntegrationBrowserTest::RunSendMessageTest(
const std::string& message) {
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
CheckSessionValidity(web_contents);
ExecuteJavaScriptAPI(
web_contents,
base::StringPrintf(kSendMessageAndExpectResponseScript, message.c_str()));
}
void MediaRouterIntegrationBrowserTest::RunFailToSendMessageTest() {
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
CheckSessionValidity(web_contents);
ExecuteJavaScriptAPI(web_contents, kCloseSessionScript);
ExecuteJavaScriptAPI(
web_contents,
base::StringPrintf(kCheckSendMessageFailedScript, "closed"));
}
void MediaRouterIntegrationBrowserTest::RunReconnectSessionTest() {
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
CheckSessionValidity(web_contents);
std::string session_id(GetStartedConnectionId(web_contents));
OpenTestPageInNewTab(FILE_PATH_LITERAL("basic_test.html"));
WebContents* new_web_contents = GetActiveWebContents();
ASSERT_TRUE(new_web_contents);
ASSERT_NE(web_contents, new_web_contents);
ExecuteJavaScriptAPI(
new_web_contents,
base::StringPrintf(kReconnectSessionScript, session_id.c_str()));
std::string reconnected_session_id;
ASSERT_TRUE(content::ExecuteScriptAndExtractString(
new_web_contents,
"window.domAutomationController.send(reconnectedSession.id)",
&reconnected_session_id));
ASSERT_EQ(session_id, reconnected_session_id);
ExecuteJavaScriptAPI(web_contents, kTerminateSessionScript);
test_ui_->WaitUntilNoRoutes();
}
void MediaRouterIntegrationBrowserTest::SetEnableMediaRouter(bool enable) {
policy::PolicyMap policy;
policy.Set(policy::key::kEnableMediaRouter, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
std::make_unique<base::Value>(enable), nullptr);
provider_.UpdateChromePolicy(policy);
base::RunLoop().RunUntilIdle();
}
void MediaRouterIntegrationBrowserTest::RunReconnectSessionSameTabTest() {
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
CheckSessionValidity(web_contents);
std::string session_id(GetStartedConnectionId(web_contents));
ExecuteJavaScriptAPI(web_contents, kCloseSessionScript);
ExecuteJavaScriptAPI(web_contents, base::StringPrintf(kReconnectSessionScript,
session_id.c_str()));
std::string reconnected_session_id;
ASSERT_TRUE(content::ExecuteScriptAndExtractString(
web_contents,
"window.domAutomationController.send(reconnectedSession.id)",
&reconnected_session_id));
ASSERT_EQ(session_id, reconnected_session_id);
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, Basic) {
RunBasicTest();
}
// Tests that creating a route with a local file opens the file in a new tab.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
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.
ASSERT_EQ(1, browser()->tab_strip_model()->count());
OpenDialogAndCastFile();
// Expect that no new tab has been opened.
ASSERT_EQ(1, browser()->tab_strip_model()->count());
// The dialog will close from navigating to the local file within the tab, so
// open it again after it closes.
test_ui_->WaitForDialogHidden();
test_ui_->ShowDialog();
// Wait for a route to be created.
test_ui_->WaitForAnyRoute();
}
// Tests that creating a route with a local file opens the file in a new tab.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
OpenLocalMediaFileInNewTab) {
// Start at a tab with content in it, the file will open in a new tab.
ui_test_utils::NavigateToURL(browser(), GURL("https://google.com"));
// Make sure there is 1 tab.
ASSERT_EQ(1, browser()->tab_strip_model()->count());
OpenDialogAndCastFile();
// Expect that a new tab has been opened.
ASSERT_EQ(2, browser()->tab_strip_model()->count());
test_ui_->ShowDialog();
// Wait for a route to be created.
test_ui_->WaitForAnyRoute();
}
// Tests that failing to create a route with a local file shows an issue.
// TODO(https://crbug.com/907539): Make the Views dialog show the issue.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
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(https://crbug.com/903016) Disabled due to flakiness in entering
// fullscreen.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
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.
ASSERT_EQ(1, browser()->tab_strip_model()->count());
OpenDialogAndCastFile();
// Increment web contents capturer count so it thinks capture has started.
// This will allow the file tab to go fullscreen.
content::WebContents* web_contents = GetActiveWebContents();
web_contents->IncrementCapturerCount(gfx::Size());
// Wait for capture poll timer to pick up change.
Wait(base::TimeDelta::FromSeconds(3));
// Expect that fullscreen was entered.
ASSERT_TRUE(
web_contents->GetDelegate()->IsFullscreenForTabOrPending(web_contents));
}
// Tests that failed route creation of local file does not enter fullscreen.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
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.
ASSERT_EQ(1, browser()->tab_strip_model()->count());
OpenDialogAndCastFile(false);
// Wait for file to start playing (but not being captured).
Wait(base::TimeDelta::FromSeconds(3));
// Expect no capture is ongoing.
content::WebContents* web_contents = GetActiveWebContents();
ASSERT_FALSE(web_contents->IsBeingCaptured());
// Expect that fullscreen is not entered.
ASSERT_FALSE(
web_contents->GetDelegate()->IsFullscreenForTabOrPending(web_contents));
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, SendAndOnMessage) {
RunSendMessageTest("foo");
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, CloseOnError) {
SetTestData(FILE_PATH_LITERAL("close_route_with_error_on_send.json"));
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
CheckSessionValidity(web_contents);
ExecuteJavaScriptAPI(web_contents,
kSendMessageAndExpectConnectionCloseOnErrorScript);
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, Fail_SendMessage) {
RunFailToSendMessageTest();
}
// TODO(https://crbug.com/822231): Flaky in Chromium waterfall.
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
MANUAL_Fail_NoProvider) {
SetTestData(FILE_PATH_LITERAL("no_provider.json"));
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
CheckStartFailed(web_contents, "UnknownError",
"No provider supports createRoute with source");
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, Fail_CreateRoute) {
SetTestData(FILE_PATH_LITERAL("fail_create_route.json"));
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
CheckStartFailed(web_contents, "UnknownError", "Unknown sink");
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, ReconnectSession) {
RunReconnectSessionTest();
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
Fail_ReconnectSession) {
WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
CheckSessionValidity(web_contents);
std::string session_id(GetStartedConnectionId(web_contents));
SetTestData(FILE_PATH_LITERAL("fail_reconnect_session.json"));
OpenTestPageInNewTab(FILE_PATH_LITERAL("fail_reconnect_session.html"));
WebContents* new_web_contents = GetActiveWebContents();
ASSERT_TRUE(new_web_contents);
ExecuteJavaScriptAPI(
new_web_contents,
base::StringPrintf("checkReconnectSessionFails('%s');",
session_id.c_str()));
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, Fail_StartCancelled) {
WebContents* web_contents = StartSessionWithTestPageAndSink();
test_ui_->HideDialog();
CheckStartFailed(web_contents, "NotAllowedError", "Dialog closed.");
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
Fail_StartCancelledNoSinks) {
SetTestData(FILE_PATH_LITERAL("no_sinks.json"));
StartSessionAndAssertNotFoundError();
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
Fail_StartCancelledNoSupportedSinks) {
SetTestData(FILE_PATH_LITERAL("no_supported_sinks.json"));
StartSessionAndAssertNotFoundError();
}
void MediaRouterIntegrationIncognitoBrowserTest::InstallAndEnableMRExtension() {
const extensions::Extension* extension =
LoadExtensionIncognito(extension_unpacked_);
incognito_extension_id_ = extension->id();
}
void MediaRouterIntegrationIncognitoBrowserTest::UninstallMRExtension() {
if (!incognito_extension_id_.empty()) {
UninstallExtension(incognito_extension_id_);
}
}
Browser* MediaRouterIntegrationIncognitoBrowserTest::browser() {
if (!incognito_browser_)
incognito_browser_ = CreateIncognitoBrowser();
return incognito_browser_;
}
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();
}
IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationIncognitoBrowserTest,
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