1 // Copyright (c) 2012 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.
6 #include "base/cancelable_callback.h"
7 #include "base/command_line.h"
8 #include "base/compiler_specific.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/path_service.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/test/test_timeouts.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/devtools/browser_list_tabcontents_provider.h"
17 #include "chrome/browser/devtools/devtools_window.h"
18 #include "chrome/browser/extensions/extension_apitest.h"
19 #include "chrome/browser/extensions/extension_browsertest.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/unpacked_installer.h"
22 #include "chrome/browser/lifetime/application_lifetime.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
25 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
26 #include "chrome/browser/ui/browser.h"
27 #include "chrome/browser/ui/browser_commands.h"
28 #include "chrome/browser/ui/browser_iterator.h"
29 #include "chrome/browser/ui/tabs/tab_strip_model.h"
30 #include "chrome/common/chrome_paths.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/common/url_constants.h"
34 #include "chrome/test/base/in_process_browser_test.h"
35 #include "chrome/test/base/test_switches.h"
36 #include "chrome/test/base/ui_test_utils.h"
37 #include "content/public/browser/child_process_data.h"
38 #include "content/public/browser/content_browser_client.h"
39 #include "content/public/browser/devtools_agent_host.h"
40 #include "content/public/browser/devtools_client_host.h"
41 #include "content/public/browser/devtools_http_handler.h"
42 #include "content/public/browser/devtools_manager.h"
43 #include "content/public/browser/notification_registrar.h"
44 #include "content/public/browser/notification_service.h"
45 #include "content/public/browser/render_view_host.h"
46 #include "content/public/browser/web_contents.h"
47 #include "content/public/browser/worker_service.h"
48 #include "content/public/browser/worker_service_observer.h"
49 #include "content/public/common/content_switches.h"
50 #include "content/public/test/browser_test_utils.h"
51 #include "extensions/browser/extension_system.h"
52 #include "extensions/common/switches.h"
53 #include "net/socket/tcp_listen_socket.h"
54 #include "net/test/spawned_test_server/spawned_test_server.h"
56 using content::BrowserThread;
57 using content::DevToolsManager;
58 using content::DevToolsAgentHost;
59 using content::NavigationController;
60 using content::RenderViewHost;
61 using content::WebContents;
62 using content::WorkerService;
63 using content::WorkerServiceObserver;
67 const char kDebuggerTestPage[] = "files/devtools/debugger_test_page.html";
68 const char kPauseWhenLoadingDevTools[] =
69 "files/devtools/pause_when_loading_devtools.html";
70 const char kPauseWhenScriptIsRunning[] =
71 "files/devtools/pause_when_script_is_running.html";
72 const char kPageWithContentScript[] =
73 "files/devtools/page_with_content_script.html";
74 const char kNavigateBackTestPage[] =
75 "files/devtools/navigate_back.html";
76 const char kChunkedTestPage[] = "chunked";
77 const char kSlowTestPage[] =
78 "chunked?waitBeforeHeaders=100&waitBetweenChunks=100&chunksNumber=2";
79 const char kSharedWorkerTestPage[] =
80 "files/workers/workers_ui_shared_worker.html";
81 const char kReloadSharedWorkerTestPage[] =
82 "files/workers/debug_shared_worker_initialization.html";
84 void RunTestFunction(DevToolsWindow* window, const char* test_name) {
87 // At first check that JavaScript part of the front-end is loaded by
88 // checking that global variable uiTests exists(it's created after all js
89 // files have been loaded) and has runTest method.
91 content::ExecuteScriptAndExtractString(
92 window->web_contents()->GetRenderViewHost(),
93 "window.domAutomationController.send("
94 " '' + (window.uiTests && (typeof uiTests.runTest)));",
97 ASSERT_EQ("function", result) << "DevTools front-end is broken.";
98 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
99 window->web_contents()->GetRenderViewHost(),
100 base::StringPrintf("uiTests.runTest('%s')", test_name),
102 EXPECT_EQ("[OK]", result);
107 class DevToolsSanityTest : public InProcessBrowserTest {
111 inspected_rvh_(NULL) {}
114 void RunTest(const std::string& test_name, const std::string& test_page) {
115 OpenDevToolsWindow(test_page, false);
116 RunTestFunction(window_, test_name.c_str());
117 CloseDevToolsWindow();
120 void LoadTestPage(const std::string& test_page) {
121 GURL url = test_server()->GetURL(test_page);
122 ui_test_utils::NavigateToURL(browser(), url);
125 void OpenDevToolsWindow(const std::string& test_page, bool is_docked) {
126 ASSERT_TRUE(test_server()->Start());
127 LoadTestPage(test_page);
129 inspected_rvh_ = GetInspectedTab()->GetRenderViewHost();
131 DevToolsWindow::OpenDevToolsWindowForTest(inspected_rvh_, is_docked);
132 ui_test_utils::WaitUntilDevToolsWindowLoaded(window_);
135 WebContents* GetInspectedTab() {
136 return browser()->tab_strip_model()->GetWebContentsAt(0);
139 void ToggleDevToolsWindow() {
140 content::WindowedNotificationObserver close_observer(
141 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
142 content::Source<content::WebContents>(window_->web_contents()));
143 DevToolsWindow::ToggleDevToolsWindow(inspected_rvh_, false,
144 DevToolsToggleAction::Toggle());
145 close_observer.Wait();
148 void ToggleDevToolsWindowDontWait() {
149 DevToolsWindow::ToggleDevToolsWindow(inspected_rvh_, false,
150 DevToolsToggleAction::Toggle());
153 void CloseDevToolsWindow() {
154 DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
155 content::WindowedNotificationObserver close_observer(
156 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
157 content::Source<content::WebContents>(window_->web_contents()));
158 devtools_manager->CloseAllClientHosts();
159 close_observer.Wait();
162 DevToolsWindow* window_;
163 RenderViewHost* inspected_rvh_;
166 // Used to block until a dev tools window gets beforeunload event.
167 class DevToolsWindowBeforeUnloadObserver
168 : public content::WebContentsObserver {
170 explicit DevToolsWindowBeforeUnloadObserver(DevToolsWindow*);
173 // Invoked when the beforeunload handler fires.
174 virtual void BeforeUnloadFired(const base::TimeTicks& proceed_time) OVERRIDE;
177 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
178 DISALLOW_COPY_AND_ASSIGN(DevToolsWindowBeforeUnloadObserver);
181 DevToolsWindowBeforeUnloadObserver::DevToolsWindowBeforeUnloadObserver(
182 DevToolsWindow* devtools_window)
183 : WebContentsObserver(devtools_window->web_contents()),
187 void DevToolsWindowBeforeUnloadObserver::Wait() {
190 message_loop_runner_ = new content::MessageLoopRunner;
191 message_loop_runner_->Run();
194 void DevToolsWindowBeforeUnloadObserver::BeforeUnloadFired(
195 const base::TimeTicks& proceed_time) {
197 if (message_loop_runner_.get())
198 message_loop_runner_->Quit();
201 class DevToolsBeforeUnloadTest: public DevToolsSanityTest {
203 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
204 command_line->AppendSwitch(
205 switches::kDisableHangMonitor);
208 void CloseInspectedTab() {
209 browser()->tab_strip_model()->CloseWebContentsAt(0,
210 TabStripModel::CLOSE_NONE);
213 void CloseDockedDevTools() {
214 ToggleDevToolsWindowDontWait();
217 void CloseUndockedDevTools() {
218 chrome::CloseWindow(window_->browser());
221 void CloseInspectedBrowser() {
222 chrome::CloseWindow(browser());
225 void InjectBeforeUnloadListener(content::WebContents* web_contents) {
226 ASSERT_TRUE(content::ExecuteScript(web_contents->GetRenderViewHost(),
227 "window.addEventListener('beforeunload',"
228 "function(event) { event.returnValue = 'Foo'; });"));
231 void RunBeforeUnloadSanityTest(bool is_docked,
232 base::Callback<void(void)> close_method,
233 bool wait_for_browser_close = true) {
234 OpenDevToolsWindow(kDebuggerTestPage, is_docked);
235 content::WindowedNotificationObserver devtools_close_observer(
236 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
237 content::Source<content::WebContents>(window_->web_contents()));
238 InjectBeforeUnloadListener(window_->web_contents());
240 DevToolsWindowBeforeUnloadObserver before_unload_observer(window_);
243 before_unload_observer.Wait();
246 content::WindowedNotificationObserver close_observer(
247 chrome::NOTIFICATION_BROWSER_CLOSED,
248 content::Source<Browser>(browser()));
251 if (wait_for_browser_close)
252 close_observer.Wait();
254 devtools_close_observer.Wait();
257 DevToolsWindow* OpenDevToolWindowOnWebContents(
258 content::WebContents* contents, bool is_docked) {
259 DevToolsWindow* window = DevToolsWindow::OpenDevToolsWindowForTest(
260 contents->GetRenderViewHost(), is_docked);
261 ui_test_utils::WaitUntilDevToolsWindowLoaded(window);
265 void OpenDevToolsPopupWindow(DevToolsWindow* devtools_window) {
266 content::WindowedNotificationObserver observer(
267 content::NOTIFICATION_LOAD_STOP,
268 content::NotificationService::AllSources());
269 ASSERT_TRUE(content::ExecuteScript(
270 devtools_window->web_contents()->GetRenderViewHost(),
271 "window.open(\"\", \"\", \"location=0\");"));
275 void CloseDevToolsPopupWindow(DevToolsWindow* devtools_window) {
276 Browser* popup_browser = NULL;
277 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
278 if (it->is_devtools()) {
279 content::WebContents* contents =
280 it->tab_strip_model()->GetWebContentsAt(0);
281 if (devtools_window->web_contents() != contents) {
287 ASSERT_FALSE(popup_browser == NULL);
288 content::WindowedNotificationObserver close_observer(
289 chrome::NOTIFICATION_BROWSER_CLOSED,
290 content::Source<Browser>(popup_browser));
291 chrome::CloseWindow(popup_browser);
292 close_observer.Wait();
295 void AcceptModalDialog() {
296 NativeAppModalDialog* native_dialog = GetDialog();
297 native_dialog->AcceptAppModalDialog();
300 void CancelModalDialog() {
301 NativeAppModalDialog* native_dialog = GetDialog();
302 native_dialog->CancelAppModalDialog();
305 NativeAppModalDialog* GetDialog() {
306 AppModalDialog* dialog = ui_test_utils::WaitForAppModalDialog();
307 EXPECT_TRUE(dialog->IsJavaScriptModalDialog());
308 JavaScriptAppModalDialog* js_dialog =
309 static_cast<JavaScriptAppModalDialog*>(dialog);
310 NativeAppModalDialog* native_dialog = js_dialog->native_dialog();
311 EXPECT_TRUE(native_dialog);
312 return native_dialog;
316 class DevToolsUnresponsiveBeforeUnloadTest: public DevToolsBeforeUnloadTest {
318 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {}
321 void TimeoutCallback(const std::string& timeout_message) {
322 ADD_FAILURE() << timeout_message;
323 base::MessageLoop::current()->Quit();
326 // Base class for DevTools tests that test devtools functionality for
327 // extensions and content scripts.
328 class DevToolsExtensionTest : public DevToolsSanityTest,
329 public content::NotificationObserver {
331 DevToolsExtensionTest() : DevToolsSanityTest() {
332 PathService::Get(chrome::DIR_TEST_DATA, &test_extensions_dir_);
333 test_extensions_dir_ = test_extensions_dir_.AppendASCII("devtools");
334 test_extensions_dir_ = test_extensions_dir_.AppendASCII("extensions");
338 // Load an extension from test\data\devtools\extensions\<extension_name>
339 void LoadExtension(const char* extension_name) {
340 base::FilePath path = test_extensions_dir_.AppendASCII(extension_name);
341 ASSERT_TRUE(LoadExtensionFromPath(path)) << "Failed to load extension.";
345 bool LoadExtensionFromPath(const base::FilePath& path) {
346 ExtensionService* service = extensions::ExtensionSystem::Get(
347 browser()->profile())->extension_service();
348 size_t num_before = service->extensions()->size();
350 content::NotificationRegistrar registrar;
352 chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
353 content::NotificationService::AllSources());
354 base::CancelableClosure timeout(
355 base::Bind(&TimeoutCallback, "Extension load timed out."));
356 base::MessageLoop::current()->PostDelayedTask(
357 FROM_HERE, timeout.callback(), TestTimeouts::action_timeout());
358 extensions::UnpackedInstaller::Create(service)->Load(path);
359 content::RunMessageLoop();
362 size_t num_after = service->extensions()->size();
363 if (num_after != (num_before + 1))
366 return WaitForExtensionViewsToLoad();
369 bool WaitForExtensionViewsToLoad() {
370 // Wait for all the extension render views that exist to finish loading.
371 // NOTE: This assumes that the extension views list is not changing while
372 // this method is running.
374 content::NotificationRegistrar registrar;
375 registrar.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
376 content::NotificationService::AllSources());
377 base::CancelableClosure timeout(
378 base::Bind(&TimeoutCallback, "Extension host load timed out."));
379 base::MessageLoop::current()->PostDelayedTask(
380 FROM_HERE, timeout.callback(), TestTimeouts::action_timeout());
382 extensions::ProcessManager* manager =
383 extensions::ExtensionSystem::Get(browser()->profile())->
385 extensions::ProcessManager::ViewSet all_views = manager->GetAllViews();
386 for (extensions::ProcessManager::ViewSet::const_iterator iter =
388 iter != all_views.end();) {
389 if (!(*iter)->IsLoading())
392 content::RunMessageLoop();
399 virtual void Observe(int type,
400 const content::NotificationSource& source,
401 const content::NotificationDetails& details) OVERRIDE {
403 case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED:
404 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING:
405 base::MessageLoopForUI::current()->Quit();
413 base::FilePath test_extensions_dir_;
416 class DevToolsExperimentalExtensionTest : public DevToolsExtensionTest {
418 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
419 command_line->AppendSwitch(
420 extensions::switches::kEnableExperimentalExtensionApis);
424 class WorkerDevToolsSanityTest : public InProcessBrowserTest {
426 WorkerDevToolsSanityTest() : window_(NULL) {}
429 class WorkerData : public base::RefCountedThreadSafe<WorkerData> {
431 WorkerData() : worker_process_id(0), worker_route_id(0) {}
432 int worker_process_id;
436 friend class base::RefCountedThreadSafe<WorkerData>;
440 class WorkerCreationObserver : public WorkerServiceObserver {
442 explicit WorkerCreationObserver(WorkerData* worker_data)
443 : worker_data_(worker_data) {
447 virtual ~WorkerCreationObserver() {}
449 virtual void WorkerCreated (
451 const base::string16& name,
453 int route_id) OVERRIDE {
454 worker_data_->worker_process_id = process_id;
455 worker_data_->worker_route_id = route_id;
456 WorkerService::GetInstance()->RemoveObserver(this);
457 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
458 base::MessageLoop::QuitClosure());
461 scoped_refptr<WorkerData> worker_data_;
464 class WorkerTerminationObserver : public WorkerServiceObserver {
466 explicit WorkerTerminationObserver(WorkerData* worker_data)
467 : worker_data_(worker_data) {
471 virtual ~WorkerTerminationObserver() {}
473 virtual void WorkerDestroyed(int process_id, int route_id) OVERRIDE {
474 ASSERT_EQ(worker_data_->worker_process_id, process_id);
475 ASSERT_EQ(worker_data_->worker_route_id, route_id);
476 WorkerService::GetInstance()->RemoveObserver(this);
477 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
478 base::MessageLoop::QuitClosure());
481 scoped_refptr<WorkerData> worker_data_;
484 void RunTest(const char* test_name, const char* test_page) {
485 ASSERT_TRUE(test_server()->Start());
486 GURL url = test_server()->GetURL(test_page);
487 ui_test_utils::NavigateToURL(browser(), url);
489 scoped_refptr<WorkerData> worker_data = WaitForFirstSharedWorker();
490 OpenDevToolsWindowForSharedWorker(worker_data.get());
491 RunTestFunction(window_, test_name);
492 CloseDevToolsWindow();
495 static void TerminateWorkerOnIOThread(scoped_refptr<WorkerData> worker_data) {
496 if (!WorkerService::GetInstance()->TerminateWorker(
497 worker_data->worker_process_id, worker_data->worker_route_id))
498 FAIL() << "Failed to terminate worker.\n";
499 WorkerService::GetInstance()->AddObserver(
500 new WorkerTerminationObserver(worker_data.get()));
503 static void TerminateWorker(scoped_refptr<WorkerData> worker_data) {
504 BrowserThread::PostTask(
505 BrowserThread::IO, FROM_HERE,
506 base::Bind(&TerminateWorkerOnIOThread, worker_data));
507 content::RunMessageLoop();
510 static void WaitForFirstSharedWorkerOnIOThread(
511 scoped_refptr<WorkerData> worker_data) {
512 std::vector<WorkerService::WorkerInfo> worker_info =
513 WorkerService::GetInstance()->GetWorkers();
514 if (!worker_info.empty()) {
515 worker_data->worker_process_id = worker_info[0].process_id;
516 worker_data->worker_route_id = worker_info[0].route_id;
517 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
518 base::MessageLoop::QuitClosure());
522 WorkerService::GetInstance()->AddObserver(
523 new WorkerCreationObserver(worker_data.get()));
526 static scoped_refptr<WorkerData> WaitForFirstSharedWorker() {
527 scoped_refptr<WorkerData> worker_data(new WorkerData());
528 BrowserThread::PostTask(
529 BrowserThread::IO, FROM_HERE,
530 base::Bind(&WaitForFirstSharedWorkerOnIOThread, worker_data));
531 content::RunMessageLoop();
535 void OpenDevToolsWindowForSharedWorker(WorkerData* worker_data) {
536 Profile* profile = browser()->profile();
537 scoped_refptr<DevToolsAgentHost> agent_host(
538 DevToolsAgentHost::GetForWorker(
539 worker_data->worker_process_id,
540 worker_data->worker_route_id));
541 window_ = DevToolsWindow::OpenDevToolsWindowForWorker(profile, agent_host);
542 RenderViewHost* client_rvh = window_->web_contents()->GetRenderViewHost();
543 WebContents* client_contents = WebContents::FromRenderViewHost(client_rvh);
544 content::WaitForLoadStop(client_contents);
547 void CloseDevToolsWindow() {
548 Browser* browser = window_->browser();
549 content::WindowedNotificationObserver close_observer(
550 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
551 content::Source<content::WebContents>(window_->web_contents()));
552 browser->tab_strip_model()->CloseAllTabs();
553 close_observer.Wait();
556 DevToolsWindow* window_;
559 // Tests that BeforeUnload event gets called on docked devtools if
560 // we try to close them.
561 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest, TestDockedDevToolsClose) {
562 RunBeforeUnloadSanityTest(true, base::Bind(
563 &DevToolsBeforeUnloadTest::CloseDockedDevTools, this), false);
566 // Tests that BeforeUnload event gets called on docked devtools if
567 // we try to close the inspected page.
568 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
569 TestDockedDevToolsInspectedTabClose) {
570 RunBeforeUnloadSanityTest(true, base::Bind(
571 &DevToolsBeforeUnloadTest::CloseInspectedTab, this));
574 // Tests that BeforeUnload event gets called on docked devtools if
575 // we try to close the inspected browser.
576 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
577 TestDockedDevToolsInspectedBrowserClose) {
578 RunBeforeUnloadSanityTest(true, base::Bind(
579 &DevToolsBeforeUnloadTest::CloseInspectedBrowser, this));
582 // Tests that BeforeUnload event gets called on undocked devtools if
583 // we try to close them.
584 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest, TestUndockedDevToolsClose) {
585 RunBeforeUnloadSanityTest(false, base::Bind(
586 &DevToolsBeforeUnloadTest::CloseUndockedDevTools, this), false);
589 // Tests that BeforeUnload event gets called on undocked devtools if
590 // we try to close the inspected page.
591 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
592 TestUndockedDevToolsInspectedTabClose) {
593 RunBeforeUnloadSanityTest(false, base::Bind(
594 &DevToolsBeforeUnloadTest::CloseInspectedTab, this));
597 // Tests that BeforeUnload event gets called on undocked devtools if
598 // we try to close the inspected browser.
599 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
600 TestUndockedDevToolsInspectedBrowserClose) {
601 RunBeforeUnloadSanityTest(false, base::Bind(
602 &DevToolsBeforeUnloadTest::CloseInspectedBrowser, this));
605 // Tests that BeforeUnload event gets called on undocked devtools if
606 // we try to exit application.
607 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
608 TestUndockedDevToolsApplicationClose) {
609 RunBeforeUnloadSanityTest(false, base::Bind(
610 &chrome::CloseAllBrowsers));
613 // Tests that inspected tab gets closed if devtools renderer
614 // becomes unresponsive during beforeunload event interception.
615 // @see http://crbug.com/322380
616 IN_PROC_BROWSER_TEST_F(DevToolsUnresponsiveBeforeUnloadTest,
617 TestUndockedDevToolsUnresponsive) {
618 ASSERT_TRUE(test_server()->Start());
619 LoadTestPage(kDebuggerTestPage);
620 DevToolsWindow* devtools_window = OpenDevToolWindowOnWebContents(
621 GetInspectedTab(), false);
622 content::WindowedNotificationObserver devtools_close_observer(
623 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
624 content::Source<content::WebContents>(
625 devtools_window->web_contents()));
627 ASSERT_TRUE(content::ExecuteScript(
628 devtools_window->web_contents()->GetRenderViewHost(),
629 "window.addEventListener('beforeunload',"
630 "function(event) { while (true); });"));
632 devtools_close_observer.Wait();
635 // Tests that closing worker inspector window does not cause browser crash
636 // @see http://crbug.com/323031
637 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
638 TestWorkerWindowClosing) {
639 ASSERT_TRUE(test_server()->Start());
640 LoadTestPage(kDebuggerTestPage);
641 DevToolsWindow* devtools_window = OpenDevToolWindowOnWebContents(
642 GetInspectedTab(), false);
643 content::WindowedNotificationObserver devtools_close_observer(
644 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
645 content::Source<content::WebContents>(
646 devtools_window->web_contents()));
648 OpenDevToolsPopupWindow(devtools_window);
649 CloseDevToolsPopupWindow(devtools_window);
652 // Tests that BeforeUnload event gets called on devtools that are opened
653 // on another devtools.
654 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
655 TestDevToolsOnDevTools) {
656 ASSERT_TRUE(test_server()->Start());
657 LoadTestPage(kDebuggerTestPage);
659 std::vector<DevToolsWindow*> windows;
660 std::vector<content::WindowedNotificationObserver*> close_observers;
661 content::WebContents* inspected_web_contents = GetInspectedTab();
662 for (int i = 0; i < 3; ++i) {
663 DevToolsWindow* devtools_window = OpenDevToolWindowOnWebContents(
664 inspected_web_contents, i == 0);
665 windows.push_back(devtools_window);
666 content::WindowedNotificationObserver* close_observer =
667 new content::WindowedNotificationObserver(
668 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
669 content::Source<content::WebContents>(
670 devtools_window->web_contents()));
671 close_observers.push_back(close_observer);
672 inspected_web_contents = devtools_window->web_contents();
675 InjectBeforeUnloadListener(windows[0]->web_contents());
676 InjectBeforeUnloadListener(windows[2]->web_contents());
677 // Try to close second devtools.
679 content::WindowedNotificationObserver cancel_browser(
680 chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
681 content::NotificationService::AllSources());
682 chrome::CloseWindow(windows[1]->browser());
684 cancel_browser.Wait();
686 // Try to close browser window.
688 content::WindowedNotificationObserver cancel_browser(
689 chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
690 content::NotificationService::AllSources());
691 chrome::CloseWindow(browser());
694 cancel_browser.Wait();
696 // Try to exit application.
698 content::WindowedNotificationObserver close_observer(
699 chrome::NOTIFICATION_BROWSER_CLOSED,
700 content::Source<Browser>(browser()));
701 chrome::IncrementKeepAliveCount();
702 chrome::CloseAllBrowsers();
705 close_observer.Wait();
707 for (size_t i = 0; i < close_observers.size(); ++i) {
708 close_observers[i]->Wait();
709 delete close_observers[i];
713 // Tests scripts panel showing.
714 // TODO(pfeldman): figure out flake.
715 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestShowScriptsTab) {
716 RunTest("testShowScriptsTab", kDebuggerTestPage);
719 // Tests that scripts tab is populated with inspected scripts even if it
720 // hadn't been shown by the moment inspected paged refreshed.
721 // @see http://crbug.com/26312
722 IN_PROC_BROWSER_TEST_F(
724 TestScriptsTabIsPopulatedOnInspectedPageRefresh) {
725 // Clear inspector settings to ensure that Elements will be
726 // current panel when DevTools window is open.
727 content::BrowserContext* browser_context =
728 GetInspectedTab()->GetBrowserContext();
729 Profile::FromBrowserContext(browser_context)->GetPrefs()->
730 ClearPref(prefs::kWebKitInspectorSettings);
732 RunTest("testScriptsTabIsPopulatedOnInspectedPageRefresh",
736 // Tests that chrome.devtools extension is correctly exposed.
737 IN_PROC_BROWSER_TEST_F(DevToolsExtensionTest,
738 TestDevToolsExtensionAPI) {
739 LoadExtension("devtools_extension");
740 RunTest("waitForTestResultsInConsole", std::string());
743 // Disabled on Windows due to flakiness. http://crbug.com/183649
745 #define MAYBE_TestDevToolsExtensionMessaging DISABLED_TestDevToolsExtensionMessaging
747 #define MAYBE_TestDevToolsExtensionMessaging TestDevToolsExtensionMessaging
750 // Tests that chrome.devtools extension can communicate with background page
751 // using extension messaging.
752 IN_PROC_BROWSER_TEST_F(DevToolsExtensionTest,
753 MAYBE_TestDevToolsExtensionMessaging) {
754 LoadExtension("devtools_messaging");
755 RunTest("waitForTestResultsInConsole", std::string());
758 // Tests that chrome.experimental.devtools extension is correctly exposed
759 // when the extension has experimental permission.
760 IN_PROC_BROWSER_TEST_F(DevToolsExperimentalExtensionTest,
761 TestDevToolsExperimentalExtensionAPI) {
762 LoadExtension("devtools_experimental");
763 RunTest("waitForTestResultsInConsole", std::string());
766 // Tests that a content script is in the scripts list.
767 // History of flakiness: http://crbug.com/114104, http://crbug.com/315288.
768 IN_PROC_BROWSER_TEST_F(DevToolsExtensionTest,
769 DISABLED_TestContentScriptIsPresent) {
770 LoadExtension("simple_content_script");
771 RunTest("testContentScriptIsPresent", kPageWithContentScript);
774 // Fails quite consistently on Win XP: crbug.com/317725.
775 #if defined(OS_WIN) || defined(OS_MACOSX)
776 #define MAYBE_TestNoScriptDuplicatesOnPanelSwitch \
777 DISABLED_TestNoScriptDuplicatesOnPanelSwitch
779 #define MAYBE_TestNoScriptDuplicatesOnPanelSwitch \
780 TestNoScriptDuplicatesOnPanelSwitch
783 // Tests that scripts are not duplicated after Scripts Panel switch.
784 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
785 MAYBE_TestNoScriptDuplicatesOnPanelSwitch) {
786 RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage);
789 // Tests that debugger works correctly if pause event occurs when DevTools
790 // frontend is being loaded.
791 // Disabled because of flakiness on all platforms: crbug.com/329036
792 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
793 DISABLED_TestPauseWhenLoadingDevTools) {
794 RunTest("testPauseWhenLoadingDevTools", kPauseWhenLoadingDevTools);
797 // Tests that pressing 'Pause' will pause script execution if the script
798 // is already running.
800 // Timing out on windows tryservers: http://crbug.com/219515
801 #define MAYBE_TestPauseWhenScriptIsRunning DISABLED_TestPauseWhenScriptIsRunning
802 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
803 // Timing out on linux ARM bot: https://crbug/238453
804 #define MAYBE_TestPauseWhenScriptIsRunning DISABLED_TestPauseWhenScriptIsRunning
806 #define MAYBE_TestPauseWhenScriptIsRunning TestPauseWhenScriptIsRunning
808 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
809 MAYBE_TestPauseWhenScriptIsRunning) {
810 RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning);
813 // Tests network timing.
814 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestNetworkTiming) {
815 RunTest("testNetworkTiming", kSlowTestPage);
818 // Tests network size.
819 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestNetworkSize) {
820 RunTest("testNetworkSize", kChunkedTestPage);
823 // Tests raw headers text.
824 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestNetworkSyncSize) {
825 RunTest("testNetworkSyncSize", kChunkedTestPage);
828 // Tests raw headers text.
829 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestNetworkRawHeadersText) {
830 RunTest("testNetworkRawHeadersText", kChunkedTestPage);
833 // Tests that console messages are not duplicated on navigation back.
834 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestConsoleOnNavigateBack) {
835 RunTest("testConsoleOnNavigateBack", kNavigateBackTestPage);
839 // Tests that external navigation from inspector page is always handled by
840 // DevToolsWindow and results in inspected page navigation.
841 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestDevToolsExternalNavigation) {
842 OpenDevToolsWindow(kDebuggerTestPage, true);
843 GURL url = test_server()->GetURL(kNavigateBackTestPage);
844 // TODO(dgozman): remove this once notifications are gone.
845 // Right now notifications happen after observers, so DevTools window is
846 // already loaded, but we still catch it's notification when looking for
848 content::WaitForLoadStop(window_->web_contents());
849 content::WindowedNotificationObserver observer(
850 content::NOTIFICATION_LOAD_STOP,
851 content::NotificationService::AllSources());
852 ASSERT_TRUE(content::ExecuteScript(
853 window_->web_contents(),
854 std::string("window.location = \"") + url.spec() + "\""));
857 ASSERT_TRUE(window_->web_contents()->GetURL().
858 SchemeIs(content::kChromeDevToolsScheme));
859 ASSERT_EQ(url, GetInspectedTab()->GetURL());
860 CloseDevToolsWindow();
863 // Tests that inspector will reattach to inspected page when it is reloaded
864 // after a crash. See http://crbug.com/101952
865 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestReattachAfterCrash) {
866 RunTest("testReattachAfterCrash", std::string());
869 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPageWithNoJavaScript) {
870 OpenDevToolsWindow("about:blank", false);
873 content::ExecuteScriptAndExtractString(
874 window_->web_contents()->GetRenderViewHost(),
875 "window.domAutomationController.send("
876 " '' + (window.uiTests && (typeof uiTests.runTest)));",
878 ASSERT_EQ("function", result) << "DevTools front-end is broken.";
879 CloseDevToolsWindow();
882 #if defined(OS_MACOSX)
883 #define MAYBE_InspectSharedWorker DISABLED_InspectSharedWorker
885 #define MAYBE_InspectSharedWorker InspectSharedWorker
887 // Flakily fails with 25s timeout: http://crbug.com/89845
888 IN_PROC_BROWSER_TEST_F(WorkerDevToolsSanityTest, MAYBE_InspectSharedWorker) {
889 #if defined(OS_WIN) && defined(USE_ASH)
890 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
891 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
895 RunTest("testSharedWorker", kSharedWorkerTestPage);
898 // http://crbug.com/100538
899 #if defined(OS_MACOSX) || defined(OS_WIN)
900 #define MAYBE_PauseInSharedWorkerInitialization DISABLED_PauseInSharedWorkerInitialization
902 #define MAYBE_PauseInSharedWorkerInitialization PauseInSharedWorkerInitialization
905 // http://crbug.com/106114 is masking
906 // MAYBE_PauseInSharedWorkerInitialization into
907 // DISABLED_PauseInSharedWorkerInitialization
908 IN_PROC_BROWSER_TEST_F(WorkerDevToolsSanityTest,
909 MAYBE_PauseInSharedWorkerInitialization) {
910 ASSERT_TRUE(test_server()->Start());
911 GURL url = test_server()->GetURL(kReloadSharedWorkerTestPage);
912 ui_test_utils::NavigateToURL(browser(), url);
914 scoped_refptr<WorkerData> worker_data = WaitForFirstSharedWorker();
915 OpenDevToolsWindowForSharedWorker(worker_data.get());
917 TerminateWorker(worker_data);
919 // Reload page to restart the worker.
920 ui_test_utils::NavigateToURL(browser(), url);
922 // Wait until worker script is paused on the debugger statement.
923 RunTestFunction(window_, "testPauseInSharedWorkerInitialization");
924 CloseDevToolsWindow();
927 class DevToolsAgentHostTest : public InProcessBrowserTest {};
929 // Tests DevToolsAgentHost retention by its target.
930 IN_PROC_BROWSER_TEST_F(DevToolsAgentHostTest, TestAgentHostReleased) {
931 ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
932 RenderViewHost* rvh = browser()->tab_strip_model()->GetWebContentsAt(0)->
934 DevToolsAgentHost* agent_raw = DevToolsAgentHost::GetOrCreateFor(rvh).get();
935 const std::string agent_id = agent_raw->GetId();
936 ASSERT_EQ(agent_raw, DevToolsAgentHost::GetForId(agent_id)) <<
937 "DevToolsAgentHost cannot be found by id";
938 browser()->tab_strip_model()->
939 CloseWebContentsAt(0, TabStripModel::CLOSE_NONE);
940 ASSERT_FALSE(DevToolsAgentHost::GetForId(agent_id).get())
941 << "DevToolsAgentHost is not released when the tab is closed";
944 class RemoteDebuggingTest: public ExtensionApiTest {
945 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
946 ExtensionApiTest::SetUpCommandLine(command_line);
947 command_line->AppendSwitchASCII(switches::kRemoteDebuggingPort, "9222");
949 // Override the extension root path.
950 PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
951 test_data_dir_ = test_data_dir_.AppendASCII("devtools");
955 IN_PROC_BROWSER_TEST_F(RemoteDebuggingTest, RemoteDebugger) {
956 #if defined(OS_WIN) && defined(USE_ASH)
957 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
958 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
962 ASSERT_TRUE(RunExtensionTest("target_list")) << message_;