Commit 8fc28d72 authored by aboxhall@chromium.org's avatar aboxhall@chromium.org

Allow requesting Automation tree by tabId

BUG=309681
R=asvitkine@chromium.org, dtseng@chromium.org, kalman@chromium.org

Review URL: https://codereview.chromium.org/308003003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@273958 0039d316-1c4b-4281-b951-d872f2087c98
parent 2a3c6817
...@@ -92,6 +92,12 @@ IN_PROC_BROWSER_TEST_F(AutomationApiTest, SanityCheck) { ...@@ -92,6 +92,12 @@ IN_PROC_BROWSER_TEST_F(AutomationApiTest, SanityCheck) {
<< message_; << message_;
} }
IN_PROC_BROWSER_TEST_F(AutomationApiTest, GetTreeByTabId) {
StartEmbeddedTestServer();
ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "tab_id.html"))
<< message_;
}
IN_PROC_BROWSER_TEST_F(AutomationApiTest, Events) { IN_PROC_BROWSER_TEST_F(AutomationApiTest, Events) {
StartEmbeddedTestServer(); StartEmbeddedTestServer();
ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "events.html")) ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "events.html"))
......
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
#include <vector> #include <vector>
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/extensions/api/automation_internal/automation_action_adapter.h" #include "chrome/browser/extensions/api/automation_internal/automation_action_adapter.h"
#include "chrome/browser/extensions/api/automation_internal/automation_util.h" #include "chrome/browser/extensions/api/automation_internal/automation_util.h"
#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
#include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h"
...@@ -120,21 +122,32 @@ class RenderWidgetHostActionAdapter : public AutomationActionAdapter { ...@@ -120,21 +122,32 @@ class RenderWidgetHostActionAdapter : public AutomationActionAdapter {
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostActionAdapter); DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostActionAdapter);
}; };
// TODO(aboxhall/dtseng): ensure that the initial data is sent down for the tab
// if this doesn't turn accessibility on for the first time (e.g. if a
// RendererAccessibility object existed already because a screenreader has been
// run at some point).
ExtensionFunction::ResponseAction ExtensionFunction::ResponseAction
AutomationInternalEnableCurrentTabFunction::Run() { AutomationInternalEnableTabFunction::Run() {
const AutomationInfo* automation_info = AutomationInfo::Get(GetExtension()); const AutomationInfo* automation_info = AutomationInfo::Get(GetExtension());
EXTENSION_FUNCTION_VALIDATE(automation_info); EXTENSION_FUNCTION_VALIDATE(automation_info);
Browser* current_browser = GetCurrentBrowser(); using api::automation_internal::EnableTab::Params;
TabStripModel* tab_strip = current_browser->tab_strip_model(); scoped_ptr<Params> params(Params::Create(*args_));
content::WebContents* contents = EXTENSION_FUNCTION_VALIDATE(params.get());
tab_strip->GetWebContentsAt(tab_strip->active_index()); content::WebContents* contents = NULL;
if (!contents) if (params->tab_id.get()) {
return RespondNow(Error("No active tab")); int tab_id = *params->tab_id;
if (!ExtensionTabUtil::GetTabById(tab_id,
GetProfile(),
include_incognito(),
NULL, /* browser out param*/
NULL, /* tab_strip out param */
&contents,
NULL /* tab_index out param */)) {
return RespondNow(
Error(tabs_constants::kTabNotFoundError, base::IntToString(tab_id)));
}
} else {
contents = GetCurrentBrowser()->tab_strip_model()->GetActiveWebContents();
if (!contents)
return RespondNow(Error("No active tab"));
}
content::RenderWidgetHost* rwh = content::RenderWidgetHost* rwh =
contents->GetRenderWidgetHostView()->GetRenderWidgetHost(); contents->GetRenderWidgetHostView()->GetRenderWidgetHost();
if (!rwh) if (!rwh)
...@@ -147,9 +160,9 @@ AutomationInternalEnableCurrentTabFunction::Run() { ...@@ -147,9 +160,9 @@ AutomationInternalEnableCurrentTabFunction::Run() {
AutomationWebContentsObserver::CreateForWebContents(contents); AutomationWebContentsObserver::CreateForWebContents(contents);
rwh->EnableTreeOnlyAccessibilityMode(); rwh->EnableTreeOnlyAccessibilityMode();
return RespondNow( return RespondNow(
ArgumentList(api::automation_internal::EnableCurrentTab::Results::Create( ArgumentList(api::automation_internal::EnableTab::Results::Create(
rwh->GetProcess()->GetID(), rwh->GetRoutingID()))); rwh->GetProcess()->GetID(), rwh->GetRoutingID())));
} }
ExtensionFunction::ResponseAction ExtensionFunction::ResponseAction
AutomationInternalPerformActionFunction::Run() { AutomationInternalPerformActionFunction::Run() {
......
...@@ -32,12 +32,12 @@ struct AXNodeData; ...@@ -32,12 +32,12 @@ struct AXNodeData;
namespace extensions { namespace extensions {
// Implementation of the chrome.automation API. // Implementation of the chrome.automation API.
class AutomationInternalEnableCurrentTabFunction class AutomationInternalEnableTabFunction
: public ChromeUIThreadExtensionFunction { : public ChromeUIThreadExtensionFunction {
DECLARE_EXTENSION_FUNCTION("automationInternal.enableCurrentTab", DECLARE_EXTENSION_FUNCTION("automationInternal.enableTab",
AUTOMATIONINTERNAL_ENABLECURRENTTAB) AUTOMATIONINTERNAL_ENABLETAB)
protected: protected:
virtual ~AutomationInternalEnableCurrentTabFunction() {} virtual ~AutomationInternalEnableTabFunction() {}
virtual ExtensionFunction::ResponseAction Run() OVERRIDE; virtual ExtensionFunction::ResponseAction Run() OVERRIDE;
}; };
......
...@@ -133,12 +133,14 @@ bool GetTabById(int tab_id, ...@@ -133,12 +133,14 @@ bool GetTabById(int tab_id,
int* tab_index, int* tab_index,
std::string* error_message) { std::string* error_message) {
if (ExtensionTabUtil::GetTabById(tab_id, profile, include_incognito, if (ExtensionTabUtil::GetTabById(tab_id, profile, include_incognito,
browser, tab_strip, contents, tab_index)) browser, tab_strip, contents, tab_index)) {
return true; return true;
}
if (error_message) if (error_message) {
*error_message = ErrorUtils::FormatErrorMessage( *error_message = ErrorUtils::FormatErrorMessage(
keys::kTabNotFoundError, base::IntToString(tab_id)); keys::kTabNotFoundError, base::IntToString(tab_id));
}
return false; return false;
} }
......
...@@ -89,12 +89,12 @@ ...@@ -89,12 +89,12 @@
callback RootCallback = void(AutomationTree tree); callback RootCallback = void(AutomationTree tree);
interface Functions { interface Functions {
// Get the automation tree for the current tab, enabling automation if // Get the automation tree for the tab with the given tabId, or the current
// necessary. Returns a tree with a placeholder root node; listen for // tab if no tabID is given, enabling automation if necessary. Returns a
// the "load_complete" event to get a notification that the tree has fully // tree with a placeholder root node; listen for the "loadComplete" event to
// loaded (the previous root node reference will stop working at or before // get a notification that the tree has fully loaded (the previous root node
// this point). // reference will stop working at or before this point).
[nocompile] static void getTree(RootCallback callback); [nocompile] static void getTree(optional long tabId, RootCallback callback);
// Get the automation tree for the desktop. // Get the automation tree for the desktop.
[nocompile] static void getDesktop(RootCallback callback); [nocompile] static void getDesktop(RootCallback callback);
......
...@@ -83,9 +83,10 @@ namespace automationInternal { ...@@ -83,9 +83,10 @@ namespace automationInternal {
callback EnableDesktopCallback = void(); callback EnableDesktopCallback = void();
interface Functions { interface Functions {
// Enable automation of the active tab and retrieves its routing id for use // Enable automation of the tab with the given id, or the active tab if no
// in future updates. // tab id is given, and retrieves its process and routing ids for use in
static void enableCurrentTab(EnableTabCallback callback); // future updates.
static void enableTab(optional long tabId, EnableTabCallback callback);
// Enables desktop automation. // Enables desktop automation.
static void enableDesktop(EnableDesktopCallback callback); static void enableDesktop(EnableDesktopCallback callback);
......
...@@ -35,15 +35,15 @@ automation.registerCustomHook(function(bindingsAPI) { ...@@ -35,15 +35,15 @@ automation.registerCustomHook(function(bindingsAPI) {
var apiFunctions = bindingsAPI.apiFunctions; var apiFunctions = bindingsAPI.apiFunctions;
// TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj. // TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj.
apiFunctions.setHandleRequest('getTree', function(callback) { apiFunctions.setHandleRequest('getTree', function getTree(tabId, callback) {
// enableCurrentTab() ensures the renderer for the current tab has // enableTab() ensures the renderer for the active or specified tab has
// accessibility enabled, and fetches its process and routing ids to use as // accessibility enabled, and fetches its process and routing ids to use as
// a key in the idToAutomationTree map. The callback to enableCurrentTab is // a key in the idToAutomationTree map. The callback to enableActiveTab is
// bound to the callback passed in to getTree(), so that once the tree is // bound to the callback passed in to getTree(), so that once the tree is
// available (either due to having been cached earlier, or after an // available (either due to having been cached earlier, or after an
// accessibility event occurs which causes the tree to be populated), the // accessibility event occurs which causes the tree to be populated), the
// callback can be called. // callback can be called.
automationInternal.enableCurrentTab(function(pid, rid) { automationInternal.enableTab(tabId, function onEnable(pid, rid) {
if (lastError.hasError(chrome)) { if (lastError.hasError(chrome)) {
callback(); callback();
return; return;
......
...@@ -12,20 +12,30 @@ var StateType = chrome.automation.StateType; ...@@ -12,20 +12,30 @@ var StateType = chrome.automation.StateType;
var tree = null; var tree = null;
function createTab(url, callback) {
chrome.tabs.create({"url": url}, function(tab) {
callback(tab);
});
}
function setUpAndRunTests(allTests) { function setUpAndRunTests(allTests) {
getUrlFromConfig(function(url) {
createTab(url, function(unused_tab) {
chrome.automation.getTree(function (returnedTree) {
tree = returnedTree;
tree.addEventListener('loadComplete', function() {
chrome.test.runTests(allTests);
});
});
});
});
}
function getUrlFromConfig(callback) {
chrome.test.getConfig(function(config) { chrome.test.getConfig(function(config) {
assertTrue('testServer' in config, 'Expected testServer in config'); assertTrue('testServer' in config, 'Expected testServer in config');
var url = 'http://a.com:PORT/index.html' var url = 'http://a.com:PORT/index.html'
.replace(/PORT/, config.testServer.port); .replace(/PORT/, config.testServer.port);
callback(url)
function gotTree(returnedTree) {
tree = returnedTree;
tree.addEventListener('loadComplete', function() {
chrome.test.runTests(allTests);
});
}
chrome.tabs.create({ 'url': url }, function() {
chrome.automation.getTree(gotTree);
});
}); });
} }
...@@ -20,13 +20,12 @@ var allTests = [ ...@@ -20,13 +20,12 @@ var allTests = [
tree.root.state); tree.root.state);
var children = tree.root.children(); var children = tree.root.children();
assertEq(1, children.length); assertEq(1, children.length);
var body = children[0]; var body = children[0];
assertEq('body', body.attributes.htmlTag); assertEq('body', body.attributes.htmlTag);
RemoveUntestedStates(body.state); RemoveUntestedStates(body.state);
assertEq({enabled: true, readOnly: true}, assertEq({enabled: true, readOnly: true},
body.state); body.state);
var contentChildren = body.children(); var contentChildren = body.children();
assertEq(3, contentChildren.length); assertEq(3, contentChildren.length);
......
<!--
* Copyright 2014 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.
-->
<script src="common.js"></script>
<script src="tab_id.js"></script>
// Copyright 2014 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.
function createBackgroundTab(url, callback) {
chrome.tabs.query({ active: true }, function(tabs) {
chrome.test.assertEq(1, tabs.length);
var originalActiveTab = tabs[0];
createTab(url, function(tab) {
chrome.tabs.update(originalActiveTab.id, { active: true }, function() {
callback(tab);
});
})
});
}
var allTests = [
function testGetTabById() {
getUrlFromConfig(function(url) {
// Keep the NTP as the active tab so that we know we're requesting the
// tab by ID rather than just getting the active tab still.
createBackgroundTab(url, function(tab) {
chrome.automation.getTree(tab.id, function(tree) {
tree.addEventListener('loadComplete', function() {
var title = tree.root.attributes['docTitle'];
chrome.test.assertEq('Automation Tests', title);
chrome.test.succeed();
});
})
});
});
}
];
chrome.test.runTests(allTests);
...@@ -757,7 +757,7 @@ enum HistogramValue { ...@@ -757,7 +757,7 @@ enum HistogramValue {
WEBVIEW_CONTEXTMENUSUPDATE, WEBVIEW_CONTEXTMENUSUPDATE,
WEBVIEW_CONTEXTMENUSREMOVE, WEBVIEW_CONTEXTMENUSREMOVE,
WEBVIEW_CONTEXTMENUSREMOVEALL, WEBVIEW_CONTEXTMENUSREMOVEALL,
AUTOMATIONINTERNAL_ENABLECURRENTTAB, AUTOMATIONINTERNAL_ENABLETAB,
APP_CURRENTWINDOWINTERNAL_SETSIZECONSTRAINTS, APP_CURRENTWINDOWINTERNAL_SETSIZECONSTRAINTS,
BLUETOOTH_GETDEVICE, BLUETOOTH_GETDEVICE,
GCM_UNREGISTER, GCM_UNREGISTER,
......
...@@ -35061,7 +35061,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. ...@@ -35061,7 +35061,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="696" label="WEBVIEW_CONTEXTMENUSUPDATE"/> <int value="696" label="WEBVIEW_CONTEXTMENUSUPDATE"/>
<int value="697" label="WEBVIEW_CONTEXTMENUSREMOVE"/> <int value="697" label="WEBVIEW_CONTEXTMENUSREMOVE"/>
<int value="698" label="WEBVIEW_CONTEXTMENUSREMOVEALL"/> <int value="698" label="WEBVIEW_CONTEXTMENUSREMOVEALL"/>
<int value="699" label="AUTOMATIONINTERNAL_ENABLECURRENTTAB"/> <int value="699" label="AUTOMATIONINTERNAL_ENABLETAB"/>
<int value="700" label="APP_CURRENTWINDOWINTERNAL_SETSIZECONSTRAINTS"/> <int value="700" label="APP_CURRENTWINDOWINTERNAL_SETSIZECONSTRAINTS"/>
<int value="701" label="BLUETOOTH_GETDEVICE"/> <int value="701" label="BLUETOOTH_GETDEVICE"/>
<int value="702" label="GCM_UNREGISTER"/> <int value="702" label="GCM_UNREGISTER"/>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment