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