1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/test/media_router/media_router_integration_browsertest.h"
8 #include "base/files/file_util.h"
9 #include "base/json/json_file_value_serializer.h"
10 #include "base/json/json_reader.h"
11 #include "base/json/json_writer.h"
12 #include "base/path_service.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser_finder.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/browser/ui/views/frame/browser_view.h"
19 #include "chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.h"
20 #include "chrome/common/url_constants.h"
21 #include "chrome/test/base/ui_test_utils.h"
22 #include "content/public/test/browser_test_utils.h"
23 #include "content/public/test/test_navigation_observer.h"
24 #include "content/public/test/test_utils.h"
25 #include "net/base/filename_util.h"
26 #include "testing/gtest/include/gtest/gtest.h"
29 namespace media_router
{
32 // The path relative to <chromium src>/out/<build config> for media router
33 // browser test resources.
34 const base::FilePath::StringPieceType kResourcePath
= FILE_PATH_LITERAL(
35 "media_router/browser_test_resources/");
36 // The javascript snippets.
37 const std::string kCheckSessionScript
= "checkSession();";
38 const std::string kCheckSessionFailedScript
= "checkSessionFailedToStart();";
39 const std::string kStartSessionScript
= "startSession();";
40 const std::string kStopSessionScript
= "stopSession()";
41 const std::string kWaitDeviceScript
= "waitUntilDeviceAvailable();";
43 std::string
GetStartedSessionId(content::WebContents
* web_contents
) {
44 std::string session_id
;
45 CHECK(content::ExecuteScriptAndExtractString(
46 web_contents
, "window.domAutomationController.send(startedSession.id)",
51 std::string
GetDefaultRequestSessionId(content::WebContents
* web_contents
) {
52 std::string session_id
;
53 CHECK(content::ExecuteScriptAndExtractString(
55 "window.domAutomationController.send(defaultRequestSessionId)",
62 MediaRouterIntegrationBrowserTest::MediaRouterIntegrationBrowserTest() {
65 MediaRouterIntegrationBrowserTest::~MediaRouterIntegrationBrowserTest() {
68 void MediaRouterIntegrationBrowserTest::TearDownOnMainThread() {
69 MediaRouterBaseBrowserTest::TearDownOnMainThread();
70 test_navigation_observer_
.reset();
73 void MediaRouterIntegrationBrowserTest::ExecuteJavaScriptAPI(
74 content::WebContents
* web_contents
,
75 const std::string
& script
) {
76 std::string
result(ExecuteScriptAndExtractString(web_contents
, script
));
78 // Read the test result, the test result set by javascript is a
79 // JSON string with the following format:
80 // {"passed": "<true/false>", "errorMessage": "<error_message>"}
81 scoped_ptr
<base::Value
> value
=
82 base::JSONReader::Read(result
, base::JSON_ALLOW_TRAILING_COMMAS
);
84 // Convert to dictionary.
85 base::DictionaryValue
* dict_value
= nullptr;
86 ASSERT_TRUE(value
->GetAsDictionary(&dict_value
));
88 // Extract the fields.
90 ASSERT_TRUE(dict_value
->GetBoolean("passed", &passed
));
91 std::string error_message
;
92 ASSERT_TRUE(dict_value
->GetString("errorMessage", &error_message
));
94 ASSERT_TRUE(passed
) << error_message
;
97 void MediaRouterIntegrationBrowserTest::OpenTestPage(
98 base::FilePath::StringPieceType file_name
) {
99 base::FilePath full_path
= GetResourceFile(file_name
);
100 ui_test_utils::NavigateToURL(browser(), net::FilePathToFileURL(full_path
));
103 void MediaRouterIntegrationBrowserTest::OpenTestPageInNewTab(
104 base::FilePath::StringPieceType file_name
) {
105 base::FilePath full_path
= GetResourceFile(file_name
);
106 ui_test_utils::NavigateToURLWithDisposition(
107 browser(), net::FilePathToFileURL(full_path
), NEW_FOREGROUND_TAB
,
108 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION
);
111 void MediaRouterIntegrationBrowserTest::StartSession(
112 content::WebContents
* web_contents
) {
113 test_navigation_observer_
.reset(
114 new content::TestNavigationObserver(web_contents
, 1));
115 test_navigation_observer_
->StartWatchingNewWebContents();
116 ExecuteJavaScriptAPI(web_contents
, kStartSessionScript
);
117 test_navigation_observer_
->Wait();
118 test_navigation_observer_
->StopWatchingNewWebContents();
121 void MediaRouterIntegrationBrowserTest::ChooseSink(
122 content::WebContents
* web_contents
,
123 const std::string
& sink_id
,
124 const std::string
& current_route
) {
125 content::WebContents
* dialog_contents
= GetMRDialog(web_contents
);
127 if (current_route
.empty()) {
130 route
= current_route
;
131 std::string script
= base::StringPrintf(
132 "window.document.getElementById('media-router-container')."
133 "currentRoute_ = %s", route
.c_str());
134 ASSERT_TRUE(content::ExecuteScript(dialog_contents
, script
));
136 std::string script
= base::StringPrintf(
137 "window.document.getElementById('media-router-container')."
138 "showOrCreateRoute_({'id': '%s', 'name': ''}, %s)",
139 sink_id
.c_str(), route
.c_str());
140 ASSERT_TRUE(content::ExecuteScript(dialog_contents
, script
));
143 content::WebContents
* MediaRouterIntegrationBrowserTest::GetMRDialog(
144 content::WebContents
* web_contents
) {
145 MediaRouterDialogControllerImpl
* controller
=
146 MediaRouterDialogControllerImpl::GetOrCreateForWebContents(web_contents
);
147 content::WebContents
* dialog_contents
= controller
->GetMediaRouterDialog();
148 CHECK(dialog_contents
);
149 return dialog_contents
;
152 void MediaRouterIntegrationBrowserTest::SetTestData(
153 base::FilePath::StringPieceType test_data_file
) {
154 base::FilePath full_path
= GetResourceFile(test_data_file
);
155 JSONFileValueDeserializer
deserializer(full_path
);
157 std::string error_message
;
158 scoped_ptr
<base::Value
> value(
159 deserializer
.Deserialize(&error_code
, &error_message
));
160 CHECK(value
.get()) << "Deserialize failed: " << error_message
;
161 std::string test_data_str
;
162 ASSERT_TRUE(base::JSONWriter::Write(*value
, &test_data_str
));
163 ExecuteScriptInBackgroundPageNoWait(
165 base::StringPrintf("localStorage['testdata'] = '%s'",
166 test_data_str
.c_str()));
169 content::WebContents
* MediaRouterIntegrationBrowserTest::OpenMRDialog(
170 content::WebContents
* web_contents
) {
171 MediaRouterDialogControllerImpl
* controller
=
172 MediaRouterDialogControllerImpl::GetOrCreateForWebContents(web_contents
);
173 test_navigation_observer_
.reset(
174 new content::TestNavigationObserver(web_contents
, 1));
175 test_navigation_observer_
->StartWatchingNewWebContents();
176 CHECK(controller
->ShowMediaRouterDialog());
177 test_navigation_observer_
->Wait();
178 test_navigation_observer_
->StopWatchingNewWebContents();
179 content::WebContents
* dialog_contents
= controller
->GetMediaRouterDialog();
180 CHECK(dialog_contents
);
181 return dialog_contents
;
184 base::FilePath
MediaRouterIntegrationBrowserTest::GetResourceFile(
185 base::FilePath::StringPieceType relative_path
) const {
186 base::FilePath base_dir
;
187 // ASSERT_TRUE can only be used in void returning functions.
188 // Use CHECK instead in non-void returning functions.
189 CHECK(PathService::Get(base::DIR_MODULE
, &base_dir
));
190 base::FilePath full_path
=
191 base_dir
.Append(kResourcePath
).Append(relative_path
);
192 CHECK(PathExists(full_path
));
196 int MediaRouterIntegrationBrowserTest::ExecuteScriptAndExtractInt(
197 const content::ToRenderFrameHost
& adapter
, const std::string
& script
) {
199 CHECK(content::ExecuteScriptAndExtractInt(adapter
, script
, &result
));
203 std::string
MediaRouterIntegrationBrowserTest::ExecuteScriptAndExtractString(
204 const content::ToRenderFrameHost
& adapter
, const std::string
& script
) {
206 CHECK(content::ExecuteScriptAndExtractString(adapter
, script
, &result
));
210 bool MediaRouterIntegrationBrowserTest::IsRouteCreatedOnUI() {
211 content::WebContents
* web_contents
=
212 browser()->tab_strip_model()->GetActiveWebContents();
213 content::WebContents
* dialog_contents
= GetMRDialog(web_contents
);
215 script
= base::StringPrintf(
216 "domAutomationController.send(window.document.getElementById("
217 "'media-router-container').routeList.length)");
218 return ExecuteScriptAndExtractInt(dialog_contents
, script
) == 1;
221 void MediaRouterIntegrationBrowserTest::WaitUntilRouteCreated() {
222 ASSERT_TRUE(ConditionalWait(
223 base::TimeDelta::FromSeconds(10), base::TimeDelta::FromSeconds(1),
224 base::Bind(&MediaRouterIntegrationBrowserTest::IsRouteCreatedOnUI
,
225 base::Unretained(this))));
228 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest
, MANUAL_Basic
) {
229 OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
230 content::WebContents
* web_contents
=
231 browser()->tab_strip_model()->GetActiveWebContents();
232 ASSERT_TRUE(web_contents
);
233 ExecuteJavaScriptAPI(web_contents
, kWaitDeviceScript
);
234 StartSession(web_contents
);
235 ChooseSink(web_contents
, "id1", "");
236 ExecuteJavaScriptAPI(web_contents
, kCheckSessionScript
);
237 Wait(base::TimeDelta::FromSeconds(5));
239 std::string
session_id(GetStartedSessionId(web_contents
));
240 EXPECT_FALSE(session_id
.empty());
242 std::string
default_request_session_id(
243 GetDefaultRequestSessionId(web_contents
));
244 EXPECT_EQ(session_id
, default_request_session_id
);
246 ExecuteJavaScriptAPI(web_contents
, kStopSessionScript
);
249 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest
,
250 MANUAL_Fail_No_Provider
) {
251 SetTestData(FILE_PATH_LITERAL("no_provider.json"));
252 OpenTestPage(FILE_PATH_LITERAL("no_provider.html"));
253 content::WebContents
* web_contents
=
254 browser()->tab_strip_model()->GetActiveWebContents();
255 ASSERT_TRUE(web_contents
);
256 ExecuteJavaScriptAPI(web_contents
, kWaitDeviceScript
);
257 StartSession(web_contents
);
258 ChooseSink(web_contents
, "id1", "");
259 ExecuteJavaScriptAPI(web_contents
, kCheckSessionFailedScript
);
262 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest
,
263 MANUAL_Fail_Create_Route
) {
264 SetTestData(FILE_PATH_LITERAL("fail_create_route.json"));
265 OpenTestPage(FILE_PATH_LITERAL("fail_create_route.html"));
266 content::WebContents
* web_contents
=
267 browser()->tab_strip_model()->GetActiveWebContents();
268 ASSERT_TRUE(web_contents
);
269 ExecuteJavaScriptAPI(web_contents
, kWaitDeviceScript
);
270 StartSession(web_contents
);
271 ChooseSink(web_contents
, "id1", "");
272 ExecuteJavaScriptAPI(web_contents
, kCheckSessionFailedScript
);
275 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest
,
276 MANUAL_ReconnectSession
) {
277 OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
278 content::WebContents
* web_contents
=
279 browser()->tab_strip_model()->GetActiveWebContents();
280 ASSERT_TRUE(web_contents
);
281 ExecuteJavaScriptAPI(web_contents
, kWaitDeviceScript
);
282 StartSession(web_contents
);
283 ChooseSink(web_contents
, "id1", "");
284 ExecuteJavaScriptAPI(web_contents
, kCheckSessionScript
);
285 std::string
session_id(GetStartedSessionId(web_contents
));
287 OpenTestPageInNewTab(FILE_PATH_LITERAL("basic_test.html"));
288 content::WebContents
* new_web_contents
=
289 browser()->tab_strip_model()->GetActiveWebContents();
290 ASSERT_TRUE(new_web_contents
);
291 ASSERT_NE(web_contents
, new_web_contents
);
292 ExecuteJavaScriptAPI(
294 base::StringPrintf("reconnectSession('%s');", session_id
.c_str()));
295 std::string reconnected_session_id
;
296 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
298 "window.domAutomationController.send(reconnectedSession.id)",
299 &reconnected_session_id
));
300 ASSERT_EQ(session_id
, reconnected_session_id
);
303 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest
,
304 MANUAL_Fail_ReconnectSession
) {
305 OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
306 content::WebContents
* web_contents
=
307 browser()->tab_strip_model()->GetActiveWebContents();
308 ASSERT_TRUE(web_contents
);
309 ExecuteJavaScriptAPI(web_contents
, kWaitDeviceScript
);
310 content::TestNavigationObserver
test_navigation_observer(web_contents
, 1);
311 StartSession(web_contents
);
312 ChooseSink(web_contents
, "id1", "");
313 ExecuteJavaScriptAPI(web_contents
, kCheckSessionScript
);
314 std::string
session_id(GetStartedSessionId(web_contents
));
316 SetTestData(FILE_PATH_LITERAL("fail_reconnect_session.json"));
317 OpenTestPage(FILE_PATH_LITERAL("fail_reconnect_session.html"));
318 content::WebContents
* new_web_contents
=
319 browser()->tab_strip_model()->GetActiveWebContents();
320 ASSERT_TRUE(new_web_contents
);
321 ExecuteJavaScriptAPI(
323 base::StringPrintf("checkReconnectSessionFails('%s');",
324 session_id
.c_str()));
327 } // namespace media_router