| // Copyright (c) 2010 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 "base/command_line.h" |
| #include "base/path_service.h" |
| #include "base/string_util.h" |
| #include "base/utf_string_conversions.h" |
| #include "chrome/browser/debugger/devtools_client_host.h" |
| #include "chrome/browser/debugger/devtools_manager.h" |
| #include "chrome/browser/debugger/devtools_window.h" |
| #include "chrome/browser/extensions/extension_host.h" |
| #include "chrome/browser/extensions/extensions_service.h" |
| #include "chrome/browser/profile.h" |
| #include "chrome/browser/renderer_host/render_view_host.h" |
| #include "chrome/browser/tab_contents/tab_contents.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/notification_registrar.h" |
| #include "chrome/common/notification_service.h" |
| #include "chrome/test/in_process_browser_test.h" |
| #include "chrome/test/ui_test_utils.h" |
| #include "net/test/test_server.h" |
| |
| namespace { |
| |
| // Used to block until a dev tools client window's browser is closed. |
| class BrowserClosedObserver : public NotificationObserver { |
| public: |
| explicit BrowserClosedObserver(Browser* browser) { |
| registrar_.Add(this, NotificationType::BROWSER_CLOSED, |
| Source<Browser>(browser)); |
| ui_test_utils::RunMessageLoop(); |
| } |
| |
| virtual void Observe(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| MessageLoopForUI::current()->Quit(); |
| } |
| |
| private: |
| NotificationRegistrar registrar_; |
| DISALLOW_COPY_AND_ASSIGN(BrowserClosedObserver); |
| }; |
| |
| // The delay waited in some cases where we don't have a notifications for an |
| // action we take. |
| const int kActionDelayMs = 500; |
| |
| const char kConsoleTestPage[] = "files/devtools/console_test_page.html"; |
| const char kDebuggerTestPage[] = "files/devtools/debugger_test_page.html"; |
| const char kJsPage[] = "files/devtools/js_page.html"; |
| const char kHeapProfilerPage[] = "files/devtools/heap_profiler.html"; |
| const char kPauseWhenLoadingDevTools[] = |
| "files/devtools/pause_when_loading_devtools.html"; |
| const char kPauseWhenScriptIsRunning[] = |
| "files/devtools/pause_when_script_is_running.html"; |
| const char kResourceContentLengthTestPage[] = "files/devtools/image.html"; |
| const char kResourceTestPage[] = "files/devtools/resource_test_page.html"; |
| const char kSimplePage[] = "files/devtools/simple_page.html"; |
| const char kCompletionOnPause[] = |
| "files/devtools/completion_on_pause.html"; |
| const char kPageWithContentScript[] = |
| "files/devtools/page_with_content_script.html"; |
| |
| |
| class DevToolsSanityTest : public InProcessBrowserTest { |
| public: |
| DevToolsSanityTest() { |
| set_show_window(true); |
| EnableDOMAutomation(); |
| } |
| |
| protected: |
| void RunTest(const std::string& test_name, const std::string& test_page) { |
| OpenDevToolsWindow(test_page); |
| std::string result; |
| |
| // At first check that JavaScript part of the front-end is loaded by |
| // checking that global variable uiTests exists(it's created after all js |
| // files have been loaded) and has runTest method. |
| ASSERT_TRUE( |
| ui_test_utils::ExecuteJavaScriptAndExtractString( |
| client_contents_->render_view_host(), |
| L"", |
| L"window.domAutomationController.send(" |
| L"'' + (window.uiTests && (typeof uiTests.runTest)));", |
| &result)); |
| |
| if (result == "function") { |
| ASSERT_TRUE( |
| ui_test_utils::ExecuteJavaScriptAndExtractString( |
| client_contents_->render_view_host(), |
| L"", |
| UTF8ToWide(StringPrintf("uiTests.runTest('%s')", |
| test_name.c_str())), |
| &result)); |
| EXPECT_EQ("[OK]", result); |
| } else { |
| FAIL() << "DevTools front-end is broken."; |
| } |
| CloseDevToolsWindow(); |
| } |
| |
| void OpenDevToolsWindow(const std::string& test_page) { |
| ASSERT_TRUE(test_server()->Start()); |
| GURL url = test_server()->GetURL(test_page); |
| ui_test_utils::NavigateToURL(browser(), url); |
| |
| inspected_rvh_ = GetInspectedTab()->render_view_host(); |
| DevToolsManager* devtools_manager = DevToolsManager::GetInstance(); |
| devtools_manager->OpenDevToolsWindow(inspected_rvh_); |
| |
| DevToolsClientHost* client_host = |
| devtools_manager->GetDevToolsClientHostFor(inspected_rvh_); |
| window_ = client_host->AsDevToolsWindow(); |
| RenderViewHost* client_rvh = window_->GetRenderViewHost(); |
| client_contents_ = client_rvh->delegate()->GetAsTabContents(); |
| ui_test_utils::WaitForNavigation(&client_contents_->controller()); |
| } |
| |
| TabContents* GetInspectedTab() { |
| return browser()->GetTabContentsAt(0); |
| } |
| |
| void CloseDevToolsWindow() { |
| DevToolsManager* devtools_manager = DevToolsManager::GetInstance(); |
| // UnregisterDevToolsClientHostFor may destroy window_ so store the browser |
| // first. |
| Browser* browser = window_->browser(); |
| devtools_manager->UnregisterDevToolsClientHostFor(inspected_rvh_); |
| |
| // Wait only when DevToolsWindow has a browser. For docked DevTools, this |
| // is NULL and we skip the wait. |
| if (browser) |
| BrowserClosedObserver close_observer(browser); |
| } |
| |
| TabContents* client_contents_; |
| DevToolsWindow* window_; |
| RenderViewHost* inspected_rvh_; |
| }; |
| |
| |
| class CancelableQuitTask : public Task { |
| public: |
| explicit CancelableQuitTask(const std::string& timeout_message) |
| : timeout_message_(timeout_message), |
| cancelled_(false) { |
| } |
| |
| void cancel() { |
| cancelled_ = true; |
| } |
| |
| virtual void Run() { |
| if (cancelled_) { |
| return; |
| } |
| FAIL() << timeout_message_; |
| MessageLoop::current()->Quit(); |
| } |
| |
| private: |
| std::string timeout_message_; |
| bool cancelled_; |
| }; |
| |
| |
| // Base class for DevTools tests that test devtools functionality for |
| // extensions and content scripts. |
| class DevToolsExtensionDebugTest : public DevToolsSanityTest, |
| public NotificationObserver { |
| public: |
| DevToolsExtensionDebugTest() : DevToolsSanityTest() { |
| PathService::Get(chrome::DIR_TEST_DATA, &test_extensions_dir_); |
| test_extensions_dir_ = test_extensions_dir_.AppendASCII("devtools"); |
| test_extensions_dir_ = test_extensions_dir_.AppendASCII("extensions"); |
| } |
| |
| protected: |
| // Load an extention from test\data\devtools\extensions\<extension_name> |
| void LoadExtension(const char* extension_name) { |
| FilePath path = test_extensions_dir_.AppendASCII(extension_name); |
| ASSERT_TRUE(LoadExtensionFromPath(path)) << "Failed to load extension."; |
| } |
| |
| private: |
| bool LoadExtensionFromPath(const FilePath& path) { |
| ExtensionsService* service = browser()->profile()->GetExtensionsService(); |
| size_t num_before = service->extensions()->size(); |
| { |
| NotificationRegistrar registrar; |
| registrar.Add(this, NotificationType::EXTENSION_LOADED, |
| NotificationService::AllSources()); |
| CancelableQuitTask* delayed_quit = |
| new CancelableQuitTask("Extension load timed out."); |
| MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit, |
| 4*1000); |
| service->LoadExtension(path); |
| ui_test_utils::RunMessageLoop(); |
| delayed_quit->cancel(); |
| } |
| size_t num_after = service->extensions()->size(); |
| if (num_after != (num_before + 1)) |
| return false; |
| |
| return WaitForExtensionHostsToLoad(); |
| } |
| |
| bool WaitForExtensionHostsToLoad() { |
| // Wait for all the extension hosts that exist to finish loading. |
| // NOTE: This assumes that the extension host list is not changing while |
| // this method is running. |
| |
| NotificationRegistrar registrar; |
| registrar.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING, |
| NotificationService::AllSources()); |
| CancelableQuitTask* delayed_quit = |
| new CancelableQuitTask("Extension host load timed out."); |
| MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit, |
| 4*1000); |
| |
| ExtensionProcessManager* manager = |
| browser()->profile()->GetExtensionProcessManager(); |
| for (ExtensionProcessManager::const_iterator iter = manager->begin(); |
| iter != manager->end();) { |
| if ((*iter)->did_stop_loading()) |
| ++iter; |
| else |
| ui_test_utils::RunMessageLoop(); |
| } |
| |
| delayed_quit->cancel(); |
| return true; |
| } |
| |
| void Observe(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| switch (type.value) { |
| case NotificationType::EXTENSION_LOADED: |
| case NotificationType::EXTENSION_HOST_DID_STOP_LOADING: |
| MessageLoopForUI::current()->Quit(); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| FilePath test_extensions_dir_; |
| }; |
| |
| // Fails after WebKit roll 69808:70011, http://crbug.com/59727. |
| #if defined(OS_LINUX) || defined(OS_WIN) |
| #define MAYBE_TestEnableResourcesTab DISABLED_TestEnableResourcesTab |
| #else |
| #define MAYBE_TestEnableResourcesTab TestEnableResourcesTab |
| #endif // defined(OS_LINUX) || defined(OS_WIN) |
| |
| // Tests resources panel enabling. |
| IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestEnableResourcesTab) { |
| RunTest("testEnableResourcesTab", kSimplePage); |
| } |
| |
| // Fails after WebKit roll 59365:59477, http://crbug.com/44202. |
| #if defined(OS_LINUX) |
| #define MAYBE_TestResourceContentLength FLAKY_TestResourceContentLength |
| #else |
| #define MAYBE_TestResourceContentLength TestResourceContentLength |
| #endif // defined(OS_LINUX) |
| |
| // Tests profiler panel. |
| IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, FLAKY_TestProfilerTab) { |
| RunTest("testProfilerTab", kJsPage); |
| } |
| |
| // Tests heap profiler. |
| IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestHeapProfiler) { |
| RunTest("testHeapProfiler", kHeapProfilerPage); |
| } |
| |
| // Tests scripts panel showing. |
| IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowScriptsTab) { |
| RunTest("testShowScriptsTab", kDebuggerTestPage); |
| } |
| |
| // Tests that scripts tab is populated with inspected scripts even if it |
| // hadn't been shown by the moment inspected paged refreshed. |
| // @see http://crbug.com/26312 |
| IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, |
| TestScriptsTabIsPopulatedOnInspectedPageRefresh) { |
| // Clear inspector settings to ensure that Elements will be |
| // current panel when DevTools window is open. |
| GetInspectedTab()->render_view_host()->delegate()->ClearInspectorSettings(); |
| RunTest("testScriptsTabIsPopulatedOnInspectedPageRefresh", |
| kDebuggerTestPage); |
| } |
| |
| // Tests that a content script is in the scripts list. |
| // This test is disabled, see bug 28961. |
| IN_PROC_BROWSER_TEST_F(DevToolsExtensionDebugTest, |
| TestContentScriptIsPresent) { |
| LoadExtension("simple_content_script"); |
| RunTest("testContentScriptIsPresent", kPageWithContentScript); |
| } |
| |
| // Tests that scripts are not duplicated after Scripts Panel switch. |
| IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, |
| TestNoScriptDuplicatesOnPanelSwitch) { |
| RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage); |
| } |
| |
| // Tests that debugger works correctly if pause event occurs when DevTools |
| // frontend is being loaded. |
| IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenLoadingDevTools) { |
| RunTest("testPauseWhenLoadingDevTools", kPauseWhenLoadingDevTools); |
| } |
| |
| // Tests that pressing 'Pause' will pause script execution if the script |
| // is already running. |
| IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenScriptIsRunning) { |
| RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning); |
| } |
| |
| // Fails after WebKit roll 66724:66804, http://crbug.com/54592 |
| #if defined(OS_LINUX) || defined(OS_WIN) |
| #define MAYBE_TestCompletionOnPause FAILS_TestCompletionOnPause |
| #else |
| #define MAYBE_TestCompletionOnPause TestCompletionOnPause |
| #endif // defined(OS_LINUX) || defined(OS_WIN) |
| IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestCompletionOnPause) { |
| RunTest("testCompletionOnPause", kCompletionOnPause); |
| } |
| |
| // Tests that 'Pause' button works for eval. |
| IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestPauseInEval) { |
| RunTest("testPauseInEval", kDebuggerTestPage); |
| } |
| |
| } // namespace |