devtools_sanity_unittest.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
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/browser.h" 10#include "chrome/browser/debugger/devtools_client_host.h" 11#include "chrome/browser/debugger/devtools_manager.h" 12#include "chrome/browser/debugger/devtools_window.h" 13#include "chrome/browser/extensions/extension_host.h" 14#include "chrome/browser/extensions/extensions_service.h" 15#include "chrome/browser/profile.h" 16#include "chrome/browser/renderer_host/render_view_host.h" 17#include "chrome/browser/tab_contents/tab_contents.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 ExtensionsService* service = browser()->profile()->GetExtensionsService(); 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// Tests resources panel enabling. 258IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEnableResourcesTab) { 259 RunTest("testEnableResourcesTab", kSimplePage); 260} 261 262// Fails after WebKit roll 59365:59477, http://crbug.com/44202. 263#if defined(OS_LINUX) 264#define MAYBE_TestResourceContentLength FLAKY_TestResourceContentLength 265#else 266#define MAYBE_TestResourceContentLength TestResourceContentLength 267#endif // defined(OS_LINUX) 268 269// Tests resources have correct sizes. 270IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestResourceContentLength) { 271 RunTest("testResourceContentLength", kResourceContentLengthTestPage); 272} 273 274// Tests resource headers. 275IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestResourceHeaders) { 276 RunTest("testResourceHeaders", kResourceTestPage); 277} 278 279// Tests cached resource mime type. 280// @see http://crbug.com/27364 281IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestCachedResourceMimeType) { 282 RunTest("testCachedResourceMimeType", kResourceTestPage); 283} 284 285// Tests profiler panel. 286IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestProfilerTab) { 287 RunTest("testProfilerTab", kJsPage); 288} 289 290// Tests heap profiler. 291IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestHeapProfiler) { 292 RunTest("testHeapProfiler", kHeapProfilerPage); 293} 294 295// Tests scripts panel showing. 296IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowScriptsTab) { 297 RunTest("testShowScriptsTab", kDebuggerTestPage); 298} 299 300// Tests that scripts tab is populated with inspected scripts even if it 301// hadn't been shown by the moment inspected paged refreshed. 302// @see http://crbug.com/26312 303IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, 304 TestScriptsTabIsPopulatedOnInspectedPageRefresh) { 305 // Clear inspector settings to ensure that Elements will be 306 // current panel when DevTools window is open. 307 GetInspectedTab()->render_view_host()->delegate()->ClearInspectorSettings(); 308 RunTest("testScriptsTabIsPopulatedOnInspectedPageRefresh", 309 kDebuggerTestPage); 310} 311 312// Tests that a content script is in the scripts list. 313// This test is disabled, see bug 28961. 314IN_PROC_BROWSER_TEST_F(DevToolsExtensionDebugTest, 315 TestContentScriptIsPresent) { 316 LoadExtension("simple_content_script"); 317 RunTest("testContentScriptIsPresent", kPageWithContentScript); 318} 319 320// Tests that scripts are not duplicated after Scripts Panel switch. 321IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, 322 TestNoScriptDuplicatesOnPanelSwitch) { 323 RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage); 324} 325 326// Tests that debugger works correctly if pause event occurs when DevTools 327// frontend is being loaded. 328IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenLoadingDevTools) { 329 RunTest("testPauseWhenLoadingDevTools", kPauseWhenLoadingDevTools); 330} 331 332// Tests that pressing 'Pause' will pause script execution if the script 333// is already running. 334IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenScriptIsRunning) { 335 RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning); 336} 337 338// Fails after WebKit roll 66724:66804, http://crbug.com/54592 339#if defined(OS_LINUX) || defined(OS_WIN) 340#define MAYBE_TestCompletionOnPause FAILS_TestCompletionOnPause 341#else 342#define MAYBE_TestCompletionOnPause TestCompletionOnPause 343#endif // defined(OS_LINUX) || defined(OS_WIN) 344IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, MAYBE_TestCompletionOnPause) { 345 RunTest("testCompletionOnPause", kCompletionOnPause); 346} 347 348// Tests that 'Pause' button works for eval. 349IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestPauseInEval) { 350 RunTest("testPauseInEval", kDebuggerTestPage); 351} 352 353} // namespace 354