devtools_sanity_unittest.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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. 4 5#include "base/command_line.h" 6#include "base/path_service.h" 7#include "base/string_util.h" 8#include "base/utf_string_conversions.h" 9#include "chrome/browser/debugger/devtools_client_host.h" 10#include "chrome/browser/debugger/devtools_manager.h" 11#include "chrome/browser/debugger/devtools_window.h" 12#include "chrome/browser/extensions/extension_host.h" 13#include "chrome/browser/extensions/extension_service.h" 14#include "chrome/browser/profiles/profile.h" 15#include "chrome/browser/renderer_host/render_view_host.h" 16#include "chrome/browser/tab_contents/tab_contents.h" 17#include "chrome/browser/ui/browser.h" 18#include "chrome/common/chrome_paths.h" 19#include "chrome/common/chrome_switches.h" 20#include "chrome/common/notification_registrar.h" 21#include "chrome/common/notification_service.h" 22#include "chrome/test/in_process_browser_test.h" 23#include "chrome/test/ui_test_utils.h" 24#include "net/test/test_server.h" 25 26namespace { 27 28// Used to block until a dev tools client window's browser is closed. 29class BrowserClosedObserver : public NotificationObserver { 30 public: 31 explicit BrowserClosedObserver(Browser* browser) { 32 registrar_.Add(this, NotificationType::BROWSER_CLOSED, 33 Source<Browser>(browser)); 34 ui_test_utils::RunMessageLoop(); 35 } 36 37 virtual void Observe(NotificationType type, 38 const NotificationSource& source, 39 const NotificationDetails& details) { 40 MessageLoopForUI::current()->Quit(); 41 } 42 43 private: 44 NotificationRegistrar registrar_; 45 DISALLOW_COPY_AND_ASSIGN(BrowserClosedObserver); 46}; 47 48// The delay waited in some cases where we don't have a notifications for an 49// action we take. 50const int kActionDelayMs = 500; 51 52const char kConsoleTestPage[] = "files/devtools/console_test_page.html"; 53const char kDebuggerTestPage[] = "files/devtools/debugger_test_page.html"; 54const char kJsPage[] = "files/devtools/js_page.html"; 55const char kHeapProfilerPage[] = "files/devtools/heap_profiler.html"; 56const char kPauseWhenLoadingDevTools[] = 57 "files/devtools/pause_when_loading_devtools.html"; 58const char kPauseWhenScriptIsRunning[] = 59 "files/devtools/pause_when_script_is_running.html"; 60const char kResourceContentLengthTestPage[] = "files/devtools/image.html"; 61const char kResourceTestPage[] = "files/devtools/resource_test_page.html"; 62const char kSimplePage[] = "files/devtools/simple_page.html"; 63const char kCompletionOnPause[] = 64 "files/devtools/completion_on_pause.html"; 65const char kPageWithContentScript[] = 66 "files/devtools/page_with_content_script.html"; 67 68 69class DevToolsSanityTest : public InProcessBrowserTest { 70 public: 71 DevToolsSanityTest() { 72 set_show_window(true); 73 EnableDOMAutomation(); 74 } 75 76 protected: 77 void RunTest(const std::string& test_name, const std::string& test_page) { 78 OpenDevToolsWindow(test_page); 79 std::string result; 80 81 // At first check that JavaScript part of the front-end is loaded by 82 // checking that global variable uiTests exists(it's created after all js 83 // files have been loaded) and has runTest method. 84 ASSERT_TRUE( 85 ui_test_utils::ExecuteJavaScriptAndExtractString( 86 client_contents_->render_view_host(), 87 L"", 88 L"window.domAutomationController.send(" 89 L"'' + (window.uiTests && (typeof uiTests.runTest)));", 90 &result)); 91 92 if (result == "function") { 93 ASSERT_TRUE( 94 ui_test_utils::ExecuteJavaScriptAndExtractString( 95 client_contents_->render_view_host(), 96 L"", 97 UTF8ToWide(StringPrintf("uiTests.runTest('%s')", 98 test_name.c_str())), 99 &result)); 100 EXPECT_EQ("[OK]", result); 101 } else { 102 FAIL() << "DevTools front-end is broken."; 103 } 104 CloseDevToolsWindow(); 105 } 106 107 void OpenDevToolsWindow(const std::string& test_page) { 108 ASSERT_TRUE(test_server()->Start()); 109 GURL url = test_server()->GetURL(test_page); 110 ui_test_utils::NavigateToURL(browser(), url); 111 112 inspected_rvh_ = GetInspectedTab()->render_view_host(); 113 DevToolsManager* devtools_manager = DevToolsManager::GetInstance(); 114 devtools_manager->OpenDevToolsWindow(inspected_rvh_); 115 116 DevToolsClientHost* client_host = 117 devtools_manager->GetDevToolsClientHostFor(inspected_rvh_); 118 window_ = client_host->AsDevToolsWindow(); 119 RenderViewHost* client_rvh = window_->GetRenderViewHost(); 120 client_contents_ = client_rvh->delegate()->GetAsTabContents(); 121 ui_test_utils::WaitForNavigation(&client_contents_->controller()); 122 } 123 124 TabContents* GetInspectedTab() { 125 return browser()->GetTabContentsAt(0); 126 } 127 128 void CloseDevToolsWindow() { 129 DevToolsManager* devtools_manager = DevToolsManager::GetInstance(); 130 // UnregisterDevToolsClientHostFor may destroy window_ so store the browser 131 // first. 132 Browser* browser = window_->browser(); 133 devtools_manager->UnregisterDevToolsClientHostFor(inspected_rvh_); 134 135 // Wait only when DevToolsWindow has a browser. For docked DevTools, this 136 // is NULL and we skip the wait. 137 if (browser) 138 BrowserClosedObserver close_observer(browser); 139 } 140 141 TabContents* client_contents_; 142 DevToolsWindow* window_; 143 RenderViewHost* inspected_rvh_; 144}; 145 146 147class CancelableQuitTask : public Task { 148 public: 149 explicit CancelableQuitTask(const std::string& timeout_message) 150 : timeout_message_(timeout_message), 151 cancelled_(false) { 152 } 153 154 void cancel() { 155 cancelled_ = true; 156 } 157 158 virtual void Run() { 159 if (cancelled_) { 160 return; 161 } 162 FAIL() << timeout_message_; 163 MessageLoop::current()->Quit(); 164 } 165 166 private: 167 std::string timeout_message_; 168 bool cancelled_; 169}; 170 171 172// Base class for DevTools tests that test devtools functionality for 173// extensions and content scripts. 174class DevToolsExtensionDebugTest : public DevToolsSanityTest, 175 public NotificationObserver { 176 public: 177 DevToolsExtensionDebugTest() : DevToolsSanityTest() { 178 PathService::Get(chrome::DIR_TEST_DATA, &test_extensions_dir_); 179 test_extensions_dir_ = test_extensions_dir_.AppendASCII("devtools"); 180 test_extensions_dir_ = test_extensions_dir_.AppendASCII("extensions"); 181 } 182 183 protected: 184 // Load an extention from test\data\devtools\extensions\<extension_name> 185 void LoadExtension(const char* extension_name) { 186 FilePath path = test_extensions_dir_.AppendASCII(extension_name); 187 ASSERT_TRUE(LoadExtensionFromPath(path)) << "Failed to load extension."; 188 } 189 190 private: 191 bool LoadExtensionFromPath(const FilePath& path) { 192 ExtensionService* service = browser()->profile()->GetExtensionService(); 193 size_t num_before = service->extensions()->size(); 194 { 195 NotificationRegistrar registrar; 196 registrar.Add(this, NotificationType::EXTENSION_LOADED, 197 NotificationService::AllSources()); 198 CancelableQuitTask* delayed_quit = 199 new CancelableQuitTask("Extension load timed out."); 200 MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit, 201 4*1000); 202 service->LoadExtension(path); 203 ui_test_utils::RunMessageLoop(); 204 delayed_quit->cancel(); 205 } 206 size_t num_after = service->extensions()->size(); 207 if (num_after != (num_before + 1)) 208 return false; 209 210 return WaitForExtensionHostsToLoad(); 211 } 212 213 bool WaitForExtensionHostsToLoad() { 214 // Wait for all the extension hosts that exist to finish loading. 215 // NOTE: This assumes that the extension host list is not changing while 216 // this method is running. 217 218 NotificationRegistrar registrar; 219 registrar.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING, 220 NotificationService::AllSources()); 221 CancelableQuitTask* delayed_quit = 222 new CancelableQuitTask("Extension host load timed out."); 223 MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit, 224 4*1000); 225 226 ExtensionProcessManager* manager = 227 browser()->profile()->GetExtensionProcessManager(); 228 for (ExtensionProcessManager::const_iterator iter = manager->begin(); 229 iter != manager->end();) { 230 if ((*iter)->did_stop_loading()) 231 ++iter; 232 else 233 ui_test_utils::RunMessageLoop(); 234 } 235 236 delayed_quit->cancel(); 237 return true; 238 } 239 240 void Observe(NotificationType type, 241 const NotificationSource& source, 242 const NotificationDetails& details) { 243 switch (type.value) { 244 case NotificationType::EXTENSION_LOADED: 245 case NotificationType::EXTENSION_HOST_DID_STOP_LOADING: 246 MessageLoopForUI::current()->Quit(); 247 break; 248 default: 249 NOTREACHED(); 250 break; 251 } 252 } 253 254 FilePath test_extensions_dir_; 255}; 256 257// Fails after WebKit roll 69808:70011, http://crbug.com/59727. 258#if defined(OS_LINUX) || defined(OS_WIN) 259#define MAYBE_TestEnableResourcesTab DISABLED_TestEnableResourcesTab 260#else 261#define MAYBE_TestEnableResourcesTab TestEnableResourcesTab 262#endif // defined(OS_LINUX) || defined(OS_WIN) 263 264// Tests resources panel enabling. 265IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestEnableResourcesTab) { 266 RunTest("testEnableResourcesTab", kSimplePage); 267} 268 269// Fails after WebKit roll 59365:59477, http://crbug.com/44202. 270#if defined(OS_LINUX) 271#define MAYBE_TestResourceContentLength FLAKY_TestResourceContentLength 272#else 273#define MAYBE_TestResourceContentLength TestResourceContentLength 274#endif // defined(OS_LINUX) 275 276// Tests profiler panel. 277IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestProfilerTab) { 278 RunTest("testProfilerTab", kJsPage); 279} 280 281// Tests heap profiler. 282IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestHeapProfiler) { 283 RunTest("testHeapProfiler", kHeapProfilerPage); 284} 285 286// Tests scripts panel showing. 287IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowScriptsTab) { 288 RunTest("testShowScriptsTab", kDebuggerTestPage); 289} 290 291// Tests that scripts tab is populated with inspected scripts even if it 292// hadn't been shown by the moment inspected paged refreshed. 293// @see http://crbug.com/26312 294IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, 295 TestScriptsTabIsPopulatedOnInspectedPageRefresh) { 296 // Clear inspector settings to ensure that Elements will be 297 // current panel when DevTools window is open. 298 GetInspectedTab()->render_view_host()->delegate()->ClearInspectorSettings(); 299 RunTest("testScriptsTabIsPopulatedOnInspectedPageRefresh", 300 kDebuggerTestPage); 301} 302 303// Tests that a content script is in the scripts list. 304// This test is disabled, see bug 28961. 305IN_PROC_BROWSER_TEST_F(DevToolsExtensionDebugTest, 306 TestContentScriptIsPresent) { 307 LoadExtension("simple_content_script"); 308 RunTest("testContentScriptIsPresent", kPageWithContentScript); 309} 310 311// Tests that scripts are not duplicated after Scripts Panel switch. 312IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, 313 TestNoScriptDuplicatesOnPanelSwitch) { 314 RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage); 315} 316 317// Tests that debugger works correctly if pause event occurs when DevTools 318// frontend is being loaded. 319IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenLoadingDevTools) { 320 RunTest("testPauseWhenLoadingDevTools", kPauseWhenLoadingDevTools); 321} 322 323// Tests that pressing 'Pause' will pause script execution if the script 324// is already running. 325IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenScriptIsRunning) { 326 RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning); 327} 328 329// Fails after WebKit roll 66724:66804, http://crbug.com/54592 330#if defined(OS_LINUX) || defined(OS_WIN) 331#define MAYBE_TestCompletionOnPause FAILS_TestCompletionOnPause 332#else 333#define MAYBE_TestCompletionOnPause TestCompletionOnPause 334#endif // defined(OS_LINUX) || defined(OS_WIN) 335IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestCompletionOnPause) { 336 RunTest("testCompletionOnPause", kCompletionOnPause); 337} 338 339// Tests that 'Pause' button works for eval. 340IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestPauseInEval) { 341 RunTest("testPauseInEval", kDebuggerTestPage); 342} 343 344} // namespace 345