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) {
<< 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) {
StartEmbeddedTestServer();
ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "events.html"))
......
......@@ -6,8 +6,10 @@
#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_util.h"
#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
......@@ -120,21 +122,32 @@ class RenderWidgetHostActionAdapter : public AutomationActionAdapter {
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
AutomationInternalEnableCurrentTabFunction::Run() {
AutomationInternalEnableTabFunction::Run() {
const AutomationInfo* automation_info = AutomationInfo::Get(GetExtension());
EXTENSION_FUNCTION_VALIDATE(automation_info);
Browser* current_browser = GetCurrentBrowser();
TabStripModel* tab_strip = current_browser->tab_strip_model();
content::WebContents* contents =
tab_strip->GetWebContentsAt(tab_strip->active_index());
if (!contents)
return RespondNow(Error("No active tab"));
using api::automation_internal::EnableTab::Params;
scoped_ptr<Params> params(Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
content::WebContents* contents = NULL;
if (params->tab_id.get()) {
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 =
contents->GetRenderWidgetHostView()->GetRenderWidgetHost();
if (!rwh)
......@@ -147,9 +160,9 @@ AutomationInternalEnableCurrentTabFunction::Run() {
AutomationWebContentsObserver::CreateForWebContents(contents);
rwh->EnableTreeOnlyAccessibilityMode();
return RespondNow(
ArgumentList(api::automation_internal::EnableCurrentTab::Results::Create(
ArgumentList(api::automation_internal::EnableTab::Results::Create(
rwh->GetProcess()->GetID(), rwh->GetRoutingID())));
}
}
ExtensionFunction::ResponseAction
AutomationInternalPerformActionFunction::Run() {
......
......@@ -32,12 +32,12 @@ struct AXNodeData;
namespace extensions {
// Implementation of the chrome.automation API.
class AutomationInternalEnableCurrentTabFunction
class AutomationInternalEnableTabFunction
: public ChromeUIThreadExtensionFunction {
DECLARE_EXTENSION_FUNCTION("automationInternal.enableCurrentTab",
AUTOMATIONINTERNAL_ENABLECURRENTTAB)
DECLARE_EXTENSION_FUNCTION("automationInternal.enableTab",
AUTOMATIONINTERNAL_ENABLETAB)
protected:
virtual ~AutomationInternalEnableCurrentTabFunction() {}
virtual ~AutomationInternalEnableTabFunction() {}
virtual ExtensionFunction::ResponseAction Run() OVERRIDE;
};
......
......@@ -133,12 +133,14 @@ bool GetTabById(int tab_id,
int* tab_index,
std::string* error_message) {
if (ExtensionTabUtil::GetTabById(tab_id, profile, include_incognito,
browser, tab_strip, contents, tab_index))
browser, tab_strip, contents, tab_index)) {
return true;
}
if (error_message)
if (error_message) {
*error_message = ErrorUtils::FormatErrorMessage(
keys::kTabNotFoundError, base::IntToString(tab_id));
}
return false;
}
......
......@@ -89,12 +89,12 @@
callback RootCallback = void(AutomationTree tree);
interface Functions {
// Get the automation tree for the current tab, enabling automation if
// necessary. Returns a tree with a placeholder root node; listen for
// the "load_complete" event to get a notification that the tree has fully
// loaded (the previous root node reference will stop working at or before
// this point).
[nocompile] static void getTree(RootCallback callback);
// Get the automation tree for the tab with the given tabId, or the current
// tab if no tabID is given, enabling automation if necessary. Returns a
// tree with a placeholder root node; listen for the "loadComplete" event to
// get a notification that the tree has fully loaded (the previous root node
// reference will stop working at or before this point).
[nocompile] static void getTree(optional long tabId, RootCallback callback);
// Get the automation tree for the desktop.
[nocompile] static void getDesktop(RootCallback callback);
......
......@@ -83,9 +83,10 @@ namespace automationInternal {
callback EnableDesktopCallback = void();
interface Functions {
// Enable automation of the active tab and retrieves its routing id for use
// in future updates.
static void enableCurrentTab(EnableTabCallback callback);
// Enable automation of the tab with the given id, or the active tab if no
// tab id is given, and retrieves its process and routing ids for use in
// future updates.
static void enableTab(optional long tabId, EnableTabCallback callback);
// Enables desktop automation.
static void enableDesktop(EnableDesktopCallback callback);
......
......@@ -35,15 +35,15 @@ automation.registerCustomHook(function(bindingsAPI) {
var apiFunctions = bindingsAPI.apiFunctions;
// TODO(aboxhall, dtseng): Make this return the speced AutomationRootNode obj.
apiFunctions.setHandleRequest('getTree', function(callback) {
// enableCurrentTab() ensures the renderer for the current tab has
apiFunctions.setHandleRequest('getTree', function getTree(tabId, callback) {
// enableTab() ensures the renderer for the active or specified tab has
// 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
// available (either due to having been cached earlier, or after an
// accessibility event occurs which causes the tree to be populated), the
// callback can be called.
automationInternal.enableCurrentTab(function(pid, rid) {
automationInternal.enableTab(tabId, function onEnable(pid, rid) {
if (lastError.hasError(chrome)) {
callback();
return;
......
......@@ -12,20 +12,30 @@ var StateType = chrome.automation.StateType;
var tree = null;
function createTab(url, callback) {
chrome.tabs.create({"url": url}, function(tab) {
callback(tab);
});
}
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) {
assertTrue('testServer' in config, 'Expected testServer in config');
var url = 'http://a.com:PORT/index.html'
.replace(/PORT/, config.testServer.port);
function gotTree(returnedTree) {
tree = returnedTree;
tree.addEventListener('loadComplete', function() {
chrome.test.runTests(allTests);
});
}
chrome.tabs.create({ 'url': url }, function() {
chrome.automation.getTree(gotTree);
});
callback(url)
});
}
......@@ -20,13 +20,12 @@ var allTests = [
tree.root.state);
var children = tree.root.children();
assertEq(1, children.length);
var body = children[0];
assertEq('body', body.attributes.htmlTag);
RemoveUntestedStates(body.state);
assertEq({enabled: true, readOnly: true},
body.state);
body.state);
var contentChildren = body.children();
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 {
WEBVIEW_CONTEXTMENUSUPDATE,
WEBVIEW_CONTEXTMENUSREMOVE,
WEBVIEW_CONTEXTMENUSREMOVEALL,
AUTOMATIONINTERNAL_ENABLECURRENTTAB,
AUTOMATIONINTERNAL_ENABLETAB,
APP_CURRENTWINDOWINTERNAL_SETSIZECONSTRAINTS,
BLUETOOTH_GETDEVICE,
GCM_UNREGISTER,
......
......@@ -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="697" label="WEBVIEW_CONTEXTMENUSREMOVE"/>
<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="701" label="BLUETOOTH_GETDEVICE"/>
<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