diff options
author | alyssad@chromium.org <alyssad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-27 16:35:42 +0000 |
---|---|---|
committer | alyssad@chromium.org <alyssad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-27 16:35:42 +0000 |
commit | 3dda5b0f1bb73a437ca6e6f2741580451030ac25 (patch) | |
tree | 4546385566b7b28211e416a4862fbe4699ea7b0d /chrome | |
parent | 0f86277de42193b543d0b33e4c82c750f0642141 (diff) | |
download | chromium_src-3dda5b0f1bb73a437ca6e6f2741580451030ac25.zip chromium_src-3dda5b0f1bb73a437ca6e6f2741580451030ac25.tar.gz chromium_src-3dda5b0f1bb73a437ca6e6f2741580451030ac25.tar.bz2 |
New pyauto hook for the translate feature.
Review URL: http://codereview.chromium.org/3026016
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@53791 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/automation/automation_provider.cc | 129 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider.h | 13 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider_observers.cc | 78 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider_observers.h | 42 | ||||
-rw-r--r-- | chrome/test/functional/PYAUTO_TESTS | 1 | ||||
-rw-r--r-- | chrome/test/functional/translate.py | 138 | ||||
-rw-r--r-- | chrome/test/pyautolib/pyauto.py | 95 |
7 files changed, 496 insertions, 0 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 5b3fe45..e29f025 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -2744,6 +2744,131 @@ void AutomationProvider::ClearBrowsingData(Browser* browser, // The observer also deletes itself after sending the reply. } +namespace { + + // Get the TabContents from a dictionary of arguments. + TabContents* GetTabContentsFromDict(const Browser* browser, + const DictionaryValue* args, + std::string* error_message) { + int tab_index; + if (!args->GetInteger(L"tab_index", &tab_index)) { + *error_message = "Must include tab_index."; + return NULL; + } + + TabContents* tab_contents = browser->GetTabContentsAt(tab_index); + if (!tab_contents) { + *error_message = StringPrintf("No tab at index %d.", tab_index); + return NULL; + } + return tab_contents; + } + + // Get the TranslateInfoBarDelegate from TabContents. + TranslateInfoBarDelegate* GetTranslateInfoBarDelegate( + TabContents* tab_contents) { + for (int i = 0; i < tab_contents->infobar_delegate_count(); i++) { + InfoBarDelegate* infobar = tab_contents->GetInfoBarDelegateAt(i); + if (infobar->AsTranslateInfoBarDelegate()) + return infobar->AsTranslateInfoBarDelegate(); + } + // No translate infobar. + return NULL; + } + +} // namespace + +// See GetTranslateInfo() in chrome/test/pyautolib/pyauto.py for sample json +// input and output. +void AutomationProvider::GetTranslateInfo(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + std::string error_message; + TabContents* tab_contents = GetTabContentsFromDict(browser, args, + &error_message); + if (!tab_contents) { + AutomationJSONReply(this, reply_message).SendError(error_message); + return; + } + + // Get the translate bar if there is one and pass it to the observer. + // The observer will check for null and populate the information accordingly. + TranslateInfoBarDelegate* translate_bar = + GetTranslateInfoBarDelegate(tab_contents); + + TabLanguageDeterminedObserver* observer = new TabLanguageDeterminedObserver( + this, reply_message, tab_contents, translate_bar); + // If the language for the page hasn't been loaded yet, then just make + // the observer, otherwise call observe directly. + std::string language = tab_contents->language_state().original_language(); + if (!language.empty()) { + observer->Observe(NotificationType::TAB_LANGUAGE_DETERMINED, + Source<TabContents>(tab_contents), + Details<std::string>(&language)); + } +} + +// See SelectTranslateOption() in chrome/test/pyautolib/pyauto.py for sample +// json input. +// Sample json output: {} +void AutomationProvider::SelectTranslateOption(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message) { + std::string option; + std::string error_message; + TabContents* tab_contents = GetTabContentsFromDict(browser, args, + &error_message); + if (!tab_contents) { + AutomationJSONReply(this, reply_message).SendError(error_message); + return; + } + + TranslateInfoBarDelegate* translate_bar = + GetTranslateInfoBarDelegate(tab_contents); + if (!translate_bar) { + AutomationJSONReply(this, reply_message) + .SendError("There is no translate bar open."); + return; + } + + if (!args->GetString(L"option", &option)) { + AutomationJSONReply(this, reply_message).SendError("Must include option"); + return; + } + + if (option == "translate_page") { + // Make a new notification observer which will send the reply. + new PageTranslatedObserver(this, reply_message, tab_contents); + translate_bar->Translate(); + return; + } + + AutomationJSONReply reply(this, reply_message); + if (option == "never_translate_language") { + if (translate_bar->IsLanguageBlacklisted()) { + reply.SendError("The language was already blacklisted."); + return; + } + translate_bar->ToggleLanguageBlacklist(); + reply.SendSuccess(NULL); + } else if (option == "never_translate_site") { + if (translate_bar->IsSiteBlacklisted()) { + reply.SendError("The site was already blacklisted."); + return; + } + translate_bar->ToggleSiteBlacklist(); + reply.SendSuccess(NULL); + } else if (option == "toggle_always_translate") { + translate_bar->ToggleAlwaysTranslate(); + reply.SendSuccess(NULL); + } else if (option == "revert_translation") { + translate_bar->RevertTranslation(); + reply.SendSuccess(NULL); + } else { + reply.SendError("Invalid string found for option."); + } +} + // Sample json input: { "command": "GetThemeInfo" } // Refer GetThemeInfo() in chrome/test/pyautolib/pyauto.py for sample output. void AutomationProvider::GetThemeInfo(Browser* browser, @@ -3091,6 +3216,10 @@ void AutomationProvider::SendJSONRequest(int handle, // SetTheme() implemented using InstallExtension(). handler_map["GetThemeInfo"] = &AutomationProvider::GetThemeInfo; + handler_map["SelectTranslateOption"] = + &AutomationProvider::SelectTranslateOption; + handler_map["GetTranslateInfo"] = &AutomationProvider::GetTranslateInfo; + handler_map["GetAutoFillProfile"] = &AutomationProvider::GetAutoFillProfile; handler_map["FillAutoFillProfile"] = &AutomationProvider::FillAutoFillProfile; diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h index 1286e2b..4095ab9 100644 --- a/chrome/browser/automation/automation_provider.h +++ b/chrome/browser/automation/automation_provider.h @@ -57,6 +57,7 @@ class LoginHandler; class MetricEventDurationObserver; class InitialLoadObserver; class NavigationControllerRestoredObserver; +class TranslateInfoBarDelegate; struct AutocompleteMatchData; namespace gfx { @@ -506,6 +507,18 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>, DictionaryValue* args, IPC::Message* reply_message); + // Returns information about translation for a given tab. Includes + // information about the translate bar if it is showing. + void GetTranslateInfo(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message); + + // Takes the specified action on the translate bar. + // Uses the JSON interface for input/output. + void SelectTranslateOption(Browser* browser, + DictionaryValue* args, + IPC::Message* reply_message); + // Get the profiles that are currently saved to the DB. // Uses the JSON interface for input/output. void GetAutoFillProfile(Browser* browser, diff --git a/chrome/browser/automation/automation_provider_observers.cc b/chrome/browser/automation/automation_provider_observers.cc index a9414be..a6a6b2a 100644 --- a/chrome/browser/automation/automation_provider_observers.cc +++ b/chrome/browser/automation/automation_provider_observers.cc @@ -23,6 +23,8 @@ #include "chrome/browser/profile.h" #include "chrome/browser/tab_contents/navigation_controller.h" #include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/translate/page_translated_details.h" +#include "chrome/browser/translate/translate_infobar_delegate.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/notification_service.h" #include "chrome/test/automation/automation_constants.h" @@ -929,6 +931,82 @@ void MetricEventDurationObserver::Observe(NotificationType type, metric_event_duration->duration_ms; } +PageTranslatedObserver::PageTranslatedObserver(AutomationProvider* automation, + IPC::Message* reply_message, + TabContents* tab_contents) + : automation_(automation), + reply_message_(reply_message) { + registrar_.Add(this, NotificationType::PAGE_TRANSLATED, + Source<TabContents>(tab_contents)); +} + +void PageTranslatedObserver::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(type == NotificationType::PAGE_TRANSLATED); + AutomationJSONReply reply(automation_, reply_message_); + + PageTranslatedDetails* translated_details = + Details<PageTranslatedDetails>(details).ptr(); + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + return_value->SetBoolean( + L"translation_success", + translated_details->error_type == TranslateErrors::NONE); + reply.SendSuccess(return_value.get()); + delete this; +} + +TabLanguageDeterminedObserver::TabLanguageDeterminedObserver( + AutomationProvider* automation, IPC::Message* reply_message, + TabContents* tab_contents, TranslateInfoBarDelegate* translate_bar) + : automation_(automation), + reply_message_(reply_message), + tab_contents_(tab_contents), + translate_bar_(translate_bar) { + registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED, + Source<TabContents>(tab_contents)); +} + +void TabLanguageDeterminedObserver::Observe( + NotificationType type, const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(type == NotificationType::TAB_LANGUAGE_DETERMINED); + + scoped_ptr<DictionaryValue> return_value(new DictionaryValue); + return_value->SetBoolean(L"page_translated", + tab_contents_->language_state().IsPageTranslated()); + return_value->SetBoolean( + L"can_translate_page", TranslatePrefs::CanTranslate( + automation_->profile()->GetPrefs(), + tab_contents_->language_state().original_language(), + tab_contents_->GetURL())); + return_value->SetString( + L"original_language", + tab_contents_->language_state().original_language()); + if (translate_bar_) { + DictionaryValue* bar_info = new DictionaryValue; + std::map<TranslateInfoBarDelegate::Type, std::string> type_to_string; + type_to_string[TranslateInfoBarDelegate::BEFORE_TRANSLATE] = + "BEFORE_TRANSLATE"; + type_to_string[TranslateInfoBarDelegate::TRANSLATING] = + "TRANSLATING"; + type_to_string[TranslateInfoBarDelegate::AFTER_TRANSLATE] = + "AFTER_TRANSLATE"; + type_to_string[TranslateInfoBarDelegate::TRANSLATION_ERROR] = + "TRANSLATION_ERROR"; + + bar_info->SetString(L"bar_state", type_to_string[translate_bar_->type()]); + bar_info->SetString(L"target_lang_code", + translate_bar_->GetTargetLanguageCode()); + bar_info->SetString(L"original_lang_code", + translate_bar_->GetOriginalLanguageCode()); + return_value->Set(L"translate_bar", bar_info); + } + AutomationJSONReply(automation_, reply_message_) + .SendSuccess(return_value.get()); + delete this; +} + #if defined(OS_CHROMEOS) LoginManagerObserver::LoginManagerObserver( AutomationProvider* automation, diff --git a/chrome/browser/automation/automation_provider_observers.h b/chrome/browser/automation/automation_provider_observers.h index 90e2045..5d53cd3 100644 --- a/chrome/browser/automation/automation_provider_observers.h +++ b/chrome/browser/automation/automation_provider_observers.h @@ -30,6 +30,7 @@ class ExtensionProcessManager; class NavigationController; class SavePackage; class TabContents; +class TranslateInfoBarDelegate; namespace IPC { class Message; @@ -487,6 +488,47 @@ class MetricEventDurationObserver : public NotificationObserver { DISALLOW_COPY_AND_ASSIGN(MetricEventDurationObserver); }; +class PageTranslatedObserver : public NotificationObserver { + public: + PageTranslatedObserver(AutomationProvider* automation, + IPC::Message* reply_message, + TabContents* tab_contents); + + // NotificationObserver interface. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + private: + NotificationRegistrar registrar_; + scoped_refptr<AutomationProvider> automation_; + IPC::Message* reply_message_; + + DISALLOW_COPY_AND_ASSIGN(PageTranslatedObserver); +}; + +class TabLanguageDeterminedObserver : public NotificationObserver { + public: + TabLanguageDeterminedObserver(AutomationProvider* automation, + IPC::Message* reply_message, + TabContents* tab_contents, + TranslateInfoBarDelegate* translate_bar); + + // NotificationObserver interface. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + private: + NotificationRegistrar registrar_; + AutomationProvider* automation_; + IPC::Message* reply_message_; + TabContents* tab_contents_; + TranslateInfoBarDelegate* translate_bar_; + + DISALLOW_COPY_AND_ASSIGN(TabLanguageDeterminedObserver); +}; + #if defined(OS_CHROMEOS) // Collects LOGIN_AUTHENTICATION notifications and returns // whether authentication succeeded to the automation provider. diff --git a/chrome/test/functional/PYAUTO_TESTS b/chrome/test/functional/PYAUTO_TESTS index 7097c12..cf57c7e 100644 --- a/chrome/test/functional/PYAUTO_TESTS +++ b/chrome/test/functional/PYAUTO_TESTS @@ -40,6 +40,7 @@ 'special_tabs', 'test_basic.SimpleTest.testCanOpenGoogle', 'themes', + 'translate', ], 'win': [ diff --git a/chrome/test/functional/translate.py b/chrome/test/functional/translate.py new file mode 100644 index 0000000..4b7aabb --- /dev/null +++ b/chrome/test/functional/translate.py @@ -0,0 +1,138 @@ +#!/usr/bin/python +# Copyright (c) 2010 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. + +import pyauto_functional # Must be imported before pyauto +import pyauto + + +class TranslateTest(pyauto.PyUITest): + """Tests that translate works correctly""" + + spanish_google = 'http://www.google.com/webhp?hl=es' + spanish = 'es' + after_translate = 'AFTER_TRANSLATE' + before_translate = 'BEFORE_TRANSLATE' + translating = 'TRANSLATING' + translation_error = 'TRANSLATION_ERROR' + + def Debug(self): + """ Test method for experimentation. """ + import pprint + pp = pprint.PrettyPrinter(indent=2) + while True: + raw_input('Hit <enter> to dump translate info.. ') + pp.pprint(self.GetTranslateInfo()) + + def _NavigateAndWaitForBar(self, url): + self.NavigateToURL(url) + self.WaitForInfobarCount(1) + + def _ClickTranslateUntilSuccess(self): + """Since the translate can fail due to server error, continue trying until + it is successful or until it has tried too many times.""" + max_tries = 10 + curr_try = 0 + while curr_try < max_tries and not self.ClickTranslateBarTranslate(): + curr_try = curr_try + 1 + if curr_try == 10: + self.fail('Translation failed more than %d times.' % max_tries) + + def testTranslate(self): + """Tests that a page was translated if the user chooses to translate.""" + self._NavigateAndWaitForBar(self.spanish_google) + self._ClickTranslateUntilSuccess() + translate_info = self.GetTranslateInfo() + self.assertEqual(self.spanish, translate_info['original_language']) + self.assertTrue(translate_info['page_translated']) + self.assertTrue(translate_info['can_translate_page']) + self.assertTrue('translate_bar' in translate_info) + self.assertEquals(self.after_translate, + translate_info['translate_bar']['bar_state']) + + def testNoTranslate(self): + """Tests that a page isn't translated if the user declines translate.""" + self._NavigateAndWaitForBar(self.spanish_google) + self.PerformActionOnInfobar('dismiss', 0) + translate_info = self.GetTranslateInfo() + self.assertEqual(self.spanish, translate_info['original_language']) + self.assertFalse(translate_info['page_translated']) + self.assertTrue(translate_info['can_translate_page']) + # If the user goes to the site again, the infobar should drop down but + # the page should not be automatically translated. + self._NavigateAndWaitForBar(self.spanish_google) + translate_info = self.GetTranslateInfo() + self.assertFalse(translate_info['page_translated']) + self.assertTrue(translate_info['can_translate_page']) + self.assertTrue('translate_bar' in translate_info) + self.assertEquals(self.before_translate, + translate_info['translate_bar']['bar_state']) + + def testNeverTranslateLanguage(self): + """Tests that blacklisting a language for translate works.""" + self._NavigateAndWaitForBar(self.spanish_google) + self.SelectTranslateOption('never_translate_language') + translate_info = self.GetTranslateInfo() + self.assertEqual(self.spanish, translate_info['original_language']) + self.assertFalse(translate_info['page_translated']) + self.assertFalse(translate_info['can_translate_page']) + spanish_wikipedia = 'http://es.wikipedia.org/wiki/Wikipedia:Portada' + self.NavigateToURL(spanish_wikipedia) + translate_info = self.GetTranslateInfo() + self.assertEqual(self.spanish, translate_info['original_language']) + self.assertFalse(translate_info['page_translated']) + self.assertFalse(translate_info['can_translate_page']) + + def testAlwaysTranslateLanguage(self): + """Tests that the always translate a language option works.""" + self._NavigateAndWaitForBar(self.spanish_google) + self.SelectTranslateOption('toggle_always_translate') + self._ClickTranslateUntilSuccess() + translate_info = self.GetTranslateInfo() + self.assertEquals(self.spanish, translate_info['original_language']) + self.assertTrue(translate_info['page_translated']) + self.assertTrue(translate_info['can_translate_page']) + self.assertTrue('translate_bar' in translate_info) + self.assertEquals(self.after_translate, + translate_info['translate_bar']['bar_state']) + # Go to another spanish site and verify that it is translated. + # Note that the 'This page has been translated..." bar will show up. + self._NavigateAndWaitForBar( + 'http://es.wikipedia.org/wiki/Wikipedia:Portada') + translate_info = self.GetTranslateInfo() + self.assertTrue('translate_bar' in translate_info) + curr_bar_state = translate_info['translate_bar']['bar_state'] + # We don't care whether the translation has finished, just that it is + # trying to translate. + self.assertTrue(curr_bar_state is self.after_translate or + self.translating or self.translation_error, + 'Bar state was %s.' % curr_bar_state) + + def testNeverTranslateSite(self): + """Tests that blacklisting a site for translate works.""" + self._NavigateAndWaitForBar(self.spanish_google) + self.SelectTranslateOption('never_translate_site') + translate_info = self.GetTranslateInfo() + self.assertFalse(translate_info['page_translated']) + self.assertFalse(translate_info['can_translate_page']) + french_google = 'http://www.google.com/webhp?hl=fr' + # Go to another page in the same site and verify that the page can't be + # translated even though it's in a different language. + self.NavigateToURL(french_google) + translate_info = self.GetTranslateInfo() + self.assertFalse(translate_info['page_translated']) + self.assertFalse(translate_info['can_translate_page']) + + def testRevert(self): + """Tests that reverting a site to its original language works.""" + self._NavigateAndWaitForBar(self.spanish_google) + self._ClickTranslateUntilSuccess() + self.RevertPageTranslation() + translate_info = self.GetTranslateInfo() + self.assertFalse(translate_info['page_translated']) + self.assertTrue(translate_info['can_translate_page']) + + +if __name__ == '__main__': + pyauto_functional.Main() diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py index 28e39ed..4cd634f 100644 --- a/chrome/test/pyautolib/pyauto.py +++ b/chrome/test/pyautolib/pyauto.py @@ -646,6 +646,101 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase): return history_info.HistoryInfo( self._SendJSONRequest(0, json.dumps(cmd_dict))) + def GetTranslateInfo(self, tab_index=0, window_index=0): + """Returns info about translate for the given page. + + If the translate bar is showing, also returns information about the bar. + + Args: + tab_index: The tab index, default is 0. + window_index: The window index, default is 0. + + Returns: + A dictionary of information about translate for the page. Example: + { u'can_translate_page': True, + u'original_language': u'es', + u'page_translated': False, + # The below will only appear if the translate bar is showing. + u'translate_bar': { u'bar_state': u'BEFORE_TRANSLATE', + u'original_lang_code': u'es', + u'target_lang_code': u'en'}} + """ + cmd_dict = { # Prepare command for the json interface + 'command': 'GetTranslateInfo', + 'tab_index': tab_index + } + return self._GetResultFromJSONRequest(cmd_dict, windex=window_index) + + def ClickTranslateBarTranslate(self, tab_index=0, window_index=0): + """If the translate bar is showing, clicks the 'Translate' button on the + bar. This will show the 'this page has been translated...' infobar. + + Args: + tab_index: The index of the tab, default is 0. + window_index: The index of the window, default is 0. + + Returns: + True if the translation was successful or false if there was an error. + Note that an error shouldn't neccessarily mean a failed test - retry the + call on error. + + Raises: + pyauto_errors.JSONInterfaceError if the automation returns an error. + """ + cmd_dict = { # Prepare command for the json interface + 'command': 'SelectTranslateOption', + 'tab_index': tab_index, + 'option': 'translate_page' + } + return self._GetResultFromJSONRequest( + cmd_dict, windex=window_index)['translation_success'] + + def RevertPageTranslation(self, tab_index=0, window_index=0): + """Select the 'Show original' button on the 'this page has been + translated...' infobar. This will remove the infobar and revert the + page translation. + + Args: + tab_index: The index of the tab, default is 0. + window_index: The index of the window, default is 0. + """ + cmd_dict = { # Prepare command for the json interface + 'command': 'SelectTranslateOption', + 'tab_index': tab_index, + 'option': 'revert_translation' + } + self._GetResultFromJSONRequest(cmd_dict, windex=window_index) + + def SelectTranslateOption(self, option, tab_index=0, window_index=0): + """Selects one of the options in the drop-down menu for the translate bar. + + Args: + option: One of 'never_translate_language', 'never_translate_site', or + 'toggle_always_translate'. See notes on each below. + tab_index: The index of the tab, default is 0. + window_index: The index of the window, default is 0. + + *Notes* + never translate language: Selecting this means that no sites in this + language will be translated. This dismisses the infobar. + never translate site: Selecting this means that this site will never be + translated, regardless of the language. This dismisses the infobar. + toggle always translate: This does not dismiss the infobar or translate the + page. See ClickTranslateBarTranslate and PerformActioOnInfobar to do + those. If a language is selected to be always translated, then whenver + the user visits a page with that language, the infobar will show the + 'This page has been translated...' message. + + Raises: + pyauto_errors.JSONInterfaceError if the automation returns an error. + """ + cmd_dict = { # Prepare command for the json interface + 'command': 'SelectTranslateOption', + 'option': option, + 'tab_index': tab_index + } + self._GetResultFromJSONRequest(cmd_dict, windex=window_index) + def FillAutoFillProfile(self, profiles=None, credit_cards=None, tab_index=0, window_index=0): """Set the autofill profile to contain the given profiles and credit cards. |