1*9c5db199SXin Li# Lint as: python2, python3 2*9c5db199SXin Li# Copyright 2015 The Chromium OS Authors. All rights reserved. 3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 4*9c5db199SXin Li# found in the LICENSE file. 5*9c5db199SXin Li 6*9c5db199SXin Li"""A module providing common resources for different facades.""" 7*9c5db199SXin Li 8*9c5db199SXin Liimport logging 9*9c5db199SXin Liimport time 10*9c5db199SXin Li 11*9c5db199SXin Lifrom autotest_lib.client.bin import utils 12*9c5db199SXin Lifrom autotest_lib.client.common_lib import error 13*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import chrome 14*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import retry 15*9c5db199SXin Lifrom autotest_lib.client.cros import constants 16*9c5db199SXin Lifrom telemetry.internal.backends.chrome_inspector import devtools_http 17*9c5db199SXin Li 18*9c5db199SXin Liimport py_utils 19*9c5db199SXin Li 20*9c5db199SXin Li_FLAKY_CALL_RETRY_TIMEOUT_SEC = 60 21*9c5db199SXin Li_FLAKY_CHROME_CALL_RETRY_DELAY_SEC = 1 22*9c5db199SXin Li 23*9c5db199SXin Liretry_chrome_call = retry.retry( 24*9c5db199SXin Li (chrome.Error, IndexError, Exception), 25*9c5db199SXin Li timeout_min=_FLAKY_CALL_RETRY_TIMEOUT_SEC / 60.0, 26*9c5db199SXin Li delay_sec=_FLAKY_CHROME_CALL_RETRY_DELAY_SEC) 27*9c5db199SXin Li 28*9c5db199SXin Li 29*9c5db199SXin Liclass FacadeResoureError(Exception): 30*9c5db199SXin Li """Error in FacadeResource.""" 31*9c5db199SXin Li pass 32*9c5db199SXin Li 33*9c5db199SXin Li 34*9c5db199SXin Li_FLAKY_CHROME_START_RETRY_TIMEOUT_SEC = 120 35*9c5db199SXin Li_FLAKY_CHROME_START_RETRY_DELAY_SEC = 10 36*9c5db199SXin Li 37*9c5db199SXin Li 38*9c5db199SXin Li# Telemetry sometimes fails to start Chrome. 39*9c5db199SXin Liretry_start_chrome = retry.retry( 40*9c5db199SXin Li (Exception,), 41*9c5db199SXin Li timeout_min=_FLAKY_CHROME_START_RETRY_TIMEOUT_SEC / 60.0, 42*9c5db199SXin Li delay_sec=_FLAKY_CHROME_START_RETRY_DELAY_SEC, 43*9c5db199SXin Li exception_to_raise=FacadeResoureError, 44*9c5db199SXin Li label='Start Chrome') 45*9c5db199SXin Li 46*9c5db199SXin Li 47*9c5db199SXin Liclass FacadeResource(object): 48*9c5db199SXin Li """This class provides access to telemetry chrome wrapper.""" 49*9c5db199SXin Li 50*9c5db199SXin Li ARC_DISABLED = 'disabled' 51*9c5db199SXin Li ARC_ENABLED = 'enabled' 52*9c5db199SXin Li ARC_VERSION = 'CHROMEOS_ARC_VERSION' 53*9c5db199SXin Li EXTRA_BROWSER_ARGS = ['--enable-gpu-benchmarking', '--use-fake-ui-for-media-stream'] 54*9c5db199SXin Li 55*9c5db199SXin Li def __init__(self, chrome_object=None, restart=False): 56*9c5db199SXin Li """Initializes a FacadeResource. 57*9c5db199SXin Li 58*9c5db199SXin Li @param chrome_object: A chrome.Chrome object or None. 59*9c5db199SXin Li @param restart: Preserve the previous browser state. 60*9c5db199SXin Li 61*9c5db199SXin Li """ 62*9c5db199SXin Li self._chrome = chrome_object 63*9c5db199SXin Li 64*9c5db199SXin Li @property 65*9c5db199SXin Li def _browser(self): 66*9c5db199SXin Li """Gets the browser object from Chrome.""" 67*9c5db199SXin Li return self._chrome.browser 68*9c5db199SXin Li 69*9c5db199SXin Li 70*9c5db199SXin Li @retry_start_chrome 71*9c5db199SXin Li def _start_chrome(self, kwargs): 72*9c5db199SXin Li """Start a Chrome with given arguments. 73*9c5db199SXin Li 74*9c5db199SXin Li @param kwargs: A dict of keyword arguments passed to Chrome. 75*9c5db199SXin Li 76*9c5db199SXin Li @return: A chrome.Chrome object. 77*9c5db199SXin Li 78*9c5db199SXin Li """ 79*9c5db199SXin Li logging.debug('Try to start Chrome with kwargs: %s', kwargs) 80*9c5db199SXin Li return chrome.Chrome(**kwargs) 81*9c5db199SXin Li 82*9c5db199SXin Li 83*9c5db199SXin Li def start_custom_chrome(self, kwargs): 84*9c5db199SXin Li """Start a custom Chrome with given arguments. 85*9c5db199SXin Li 86*9c5db199SXin Li @param kwargs: A dict of keyword arguments passed to Chrome. 87*9c5db199SXin Li 88*9c5db199SXin Li @return: True on success, False otherwise. 89*9c5db199SXin Li 90*9c5db199SXin Li """ 91*9c5db199SXin Li # Close the previous Chrome. 92*9c5db199SXin Li if self._chrome: 93*9c5db199SXin Li self._chrome.close() 94*9c5db199SXin Li 95*9c5db199SXin Li # Start the new Chrome. 96*9c5db199SXin Li try: 97*9c5db199SXin Li self._chrome = self._start_chrome(kwargs) 98*9c5db199SXin Li except FacadeResoureError: 99*9c5db199SXin Li logging.error('Failed to start Chrome after retries') 100*9c5db199SXin Li return False 101*9c5db199SXin Li else: 102*9c5db199SXin Li logging.info('Chrome started successfully') 103*9c5db199SXin Li 104*9c5db199SXin Li # The opened tabs are stored by tab descriptors. 105*9c5db199SXin Li # Key is the tab descriptor string. 106*9c5db199SXin Li # We use string as the key because of RPC Call. Client can use the 107*9c5db199SXin Li # string to locate the tab object. 108*9c5db199SXin Li # Value is the tab object. 109*9c5db199SXin Li self._tabs = dict() 110*9c5db199SXin Li 111*9c5db199SXin Li # Workaround for issue crbug.com/588579. 112*9c5db199SXin Li # On daisy, Chrome freezes about 30 seconds after login because of 113*9c5db199SXin Li # TPM error. Avoid test accessing Chrome during this time. 114*9c5db199SXin Li # Check issue crbug.com/588579 and crbug.com/591646. 115*9c5db199SXin Li if utils.get_board() == 'daisy': 116*9c5db199SXin Li logging.warning('Delay 30s for issue 588579 on daisy') 117*9c5db199SXin Li time.sleep(30) 118*9c5db199SXin Li 119*9c5db199SXin Li return True 120*9c5db199SXin Li 121*9c5db199SXin Li 122*9c5db199SXin Li def start_default_chrome(self, restart=False, extra_browser_args=None, 123*9c5db199SXin Li disable_arc=False): 124*9c5db199SXin Li """Start the default Chrome. 125*9c5db199SXin Li 126*9c5db199SXin Li @param restart: True to start Chrome without clearing previous state. 127*9c5db199SXin Li @param extra_browser_args: A list containing extra browser args passed 128*9c5db199SXin Li to Chrome. This list will be appened to 129*9c5db199SXin Li default EXTRA_BROWSER_ARGS. 130*9c5db199SXin Li @param disable_arc: True to disable ARC++. 131*9c5db199SXin Li 132*9c5db199SXin Li @return: True on success, False otherwise. 133*9c5db199SXin Li 134*9c5db199SXin Li """ 135*9c5db199SXin Li # TODO: (crbug.com/618111) Add test driven switch for 136*9c5db199SXin Li # supporting arc_mode enabled or disabled. At this time 137*9c5db199SXin Li # if ARC build is tested, arc_mode is always enabled. 138*9c5db199SXin Li if not disable_arc and utils.get_board_property(self.ARC_VERSION): 139*9c5db199SXin Li arc_mode = self.ARC_ENABLED 140*9c5db199SXin Li else: 141*9c5db199SXin Li arc_mode = self.ARC_DISABLED 142*9c5db199SXin Li kwargs = { 143*9c5db199SXin Li 'extension_paths': [constants.AUDIO_TEST_EXTENSION, 144*9c5db199SXin Li constants.DISPLAY_TEST_EXTENSION], 145*9c5db199SXin Li 'extra_browser_args': self.EXTRA_BROWSER_ARGS, 146*9c5db199SXin Li 'clear_enterprise_policy': not restart, 147*9c5db199SXin Li 'arc_mode': arc_mode, 148*9c5db199SXin Li 'autotest_ext': True 149*9c5db199SXin Li } 150*9c5db199SXin Li if extra_browser_args: 151*9c5db199SXin Li kwargs['extra_browser_args'] += extra_browser_args 152*9c5db199SXin Li return self.start_custom_chrome(kwargs) 153*9c5db199SXin Li 154*9c5db199SXin Li 155*9c5db199SXin Li def __enter__(self): 156*9c5db199SXin Li return self 157*9c5db199SXin Li 158*9c5db199SXin Li 159*9c5db199SXin Li def __exit__(self, *args): 160*9c5db199SXin Li if self._chrome: 161*9c5db199SXin Li self._chrome.close() 162*9c5db199SXin Li self._chrome = None 163*9c5db199SXin Li 164*9c5db199SXin Li 165*9c5db199SXin Li @staticmethod 166*9c5db199SXin Li def _generate_tab_descriptor(tab): 167*9c5db199SXin Li """Generate tab descriptor by tab object. 168*9c5db199SXin Li 169*9c5db199SXin Li @param tab: the tab object. 170*9c5db199SXin Li @return a str, the tab descriptor of the tab. 171*9c5db199SXin Li 172*9c5db199SXin Li """ 173*9c5db199SXin Li return hex(id(tab)) 174*9c5db199SXin Li 175*9c5db199SXin Li 176*9c5db199SXin Li def clean_unexpected_tabs(self): 177*9c5db199SXin Li """Clean all tabs that are not opened by facade_resource 178*9c5db199SXin Li 179*9c5db199SXin Li It is used to make sure our chrome browser is clean. 180*9c5db199SXin Li 181*9c5db199SXin Li """ 182*9c5db199SXin Li # If they have the same length we can assume there is no unexpected 183*9c5db199SXin Li # tabs. 184*9c5db199SXin Li browser_tabs = self.get_tabs() 185*9c5db199SXin Li if len(browser_tabs) == len(self._tabs): 186*9c5db199SXin Li return 187*9c5db199SXin Li 188*9c5db199SXin Li for tab in browser_tabs: 189*9c5db199SXin Li if self._generate_tab_descriptor(tab) not in self._tabs: 190*9c5db199SXin Li # TODO(mojahsu): Reevaluate this code. crbug.com/719592 191*9c5db199SXin Li try: 192*9c5db199SXin Li tab.Close() 193*9c5db199SXin Li except py_utils.TimeoutException: 194*9c5db199SXin Li logging.warning('close tab timeout %r, %s', tab, tab.url) 195*9c5db199SXin Li 196*9c5db199SXin Li 197*9c5db199SXin Li @retry_chrome_call 198*9c5db199SXin Li def get_extension(self, extension_path=None): 199*9c5db199SXin Li """Gets the extension from the indicated path. 200*9c5db199SXin Li 201*9c5db199SXin Li @param extension_path: the path of the target extension. 202*9c5db199SXin Li Set to None to get autotest extension. 203*9c5db199SXin Li Defaults to None. 204*9c5db199SXin Li @return an extension object. 205*9c5db199SXin Li 206*9c5db199SXin Li @raise RuntimeError if the extension is not found. 207*9c5db199SXin Li @raise chrome.Error if the found extension has not yet been 208*9c5db199SXin Li retrieved succesfully. 209*9c5db199SXin Li 210*9c5db199SXin Li """ 211*9c5db199SXin Li try: 212*9c5db199SXin Li if extension_path is None: 213*9c5db199SXin Li extension = self._chrome.autotest_ext 214*9c5db199SXin Li else: 215*9c5db199SXin Li extension = self._chrome.get_extension(extension_path) 216*9c5db199SXin Li except KeyError as errmsg: 217*9c5db199SXin Li # Trigger retry_chrome_call to retry to retrieve the 218*9c5db199SXin Li # found extension. 219*9c5db199SXin Li raise chrome.Error(errmsg) 220*9c5db199SXin Li if not extension: 221*9c5db199SXin Li if extension_path is None: 222*9c5db199SXin Li raise RuntimeError('Autotest extension not found') 223*9c5db199SXin Li else: 224*9c5db199SXin Li raise RuntimeError('Extension not found in %r' 225*9c5db199SXin Li % extension_path) 226*9c5db199SXin Li return extension 227*9c5db199SXin Li 228*9c5db199SXin Li 229*9c5db199SXin Li def get_visible_notifications(self): 230*9c5db199SXin Li """Gets the visible notifications 231*9c5db199SXin Li 232*9c5db199SXin Li @return: Returns all visible notifications in list format. Ex: 233*9c5db199SXin Li [{title:'', message:'', prority:'', id:''}] 234*9c5db199SXin Li """ 235*9c5db199SXin Li return self._chrome.get_visible_notifications() 236*9c5db199SXin Li 237*9c5db199SXin Li 238*9c5db199SXin Li @retry_chrome_call 239*9c5db199SXin Li def load_url(self, url): 240*9c5db199SXin Li """Loads the given url in a new tab. The new tab will be active. 241*9c5db199SXin Li 242*9c5db199SXin Li @param url: The url to load as a string. 243*9c5db199SXin Li @return a str, the tab descriptor of the opened tab. 244*9c5db199SXin Li 245*9c5db199SXin Li """ 246*9c5db199SXin Li tab = self._browser.tabs.New() 247*9c5db199SXin Li tab.Navigate(url) 248*9c5db199SXin Li tab.Activate() 249*9c5db199SXin Li tab.WaitForDocumentReadyStateToBeComplete() 250*9c5db199SXin Li tab_descriptor = self._generate_tab_descriptor(tab) 251*9c5db199SXin Li self._tabs[tab_descriptor] = tab 252*9c5db199SXin Li self.clean_unexpected_tabs() 253*9c5db199SXin Li return tab_descriptor 254*9c5db199SXin Li 255*9c5db199SXin Li 256*9c5db199SXin Li def set_http_server_directories(self, directories): 257*9c5db199SXin Li """Starts an HTTP server. 258*9c5db199SXin Li 259*9c5db199SXin Li @param directories: Directories to start serving. 260*9c5db199SXin Li 261*9c5db199SXin Li @return True on success. False otherwise. 262*9c5db199SXin Li 263*9c5db199SXin Li """ 264*9c5db199SXin Li return self._chrome.browser.platform.SetHTTPServerDirectories(directories) 265*9c5db199SXin Li 266*9c5db199SXin Li 267*9c5db199SXin Li def http_server_url_of(self, fullpath): 268*9c5db199SXin Li """Converts a path to a URL. 269*9c5db199SXin Li 270*9c5db199SXin Li @param fullpath: String containing the full path to the content. 271*9c5db199SXin Li 272*9c5db199SXin Li @return the URL for the provided path. 273*9c5db199SXin Li 274*9c5db199SXin Li """ 275*9c5db199SXin Li return self._chrome.browser.platform.http_server.UrlOf(fullpath) 276*9c5db199SXin Li 277*9c5db199SXin Li 278*9c5db199SXin Li def get_tabs(self): 279*9c5db199SXin Li """Gets the tabs opened by browser. 280*9c5db199SXin Li 281*9c5db199SXin Li @returns: The tabs attribute in telemetry browser object. 282*9c5db199SXin Li 283*9c5db199SXin Li """ 284*9c5db199SXin Li return self._browser.tabs 285*9c5db199SXin Li 286*9c5db199SXin Li 287*9c5db199SXin Li def get_tab_by_descriptor(self, tab_descriptor): 288*9c5db199SXin Li """Gets the tab by the tab descriptor. 289*9c5db199SXin Li 290*9c5db199SXin Li @returns: The tab object indicated by the tab descriptor. 291*9c5db199SXin Li 292*9c5db199SXin Li """ 293*9c5db199SXin Li return self._tabs[tab_descriptor] 294*9c5db199SXin Li 295*9c5db199SXin Li 296*9c5db199SXin Li @retry_chrome_call 297*9c5db199SXin Li def close_tab(self, tab_descriptor): 298*9c5db199SXin Li """Closes the tab. 299*9c5db199SXin Li 300*9c5db199SXin Li @param tab_descriptor: Indicate which tab to be closed. 301*9c5db199SXin Li 302*9c5db199SXin Li """ 303*9c5db199SXin Li if tab_descriptor not in self._tabs: 304*9c5db199SXin Li raise RuntimeError('There is no tab for %s' % tab_descriptor) 305*9c5db199SXin Li tab = self._tabs[tab_descriptor] 306*9c5db199SXin Li del self._tabs[tab_descriptor] 307*9c5db199SXin Li tab.Close() 308*9c5db199SXin Li self.clean_unexpected_tabs() 309*9c5db199SXin Li 310*9c5db199SXin Li 311*9c5db199SXin Li def wait_for_javascript_expression( 312*9c5db199SXin Li self, tab_descriptor, expression, timeout): 313*9c5db199SXin Li """Waits for the given JavaScript expression to be True on the given tab 314*9c5db199SXin Li 315*9c5db199SXin Li @param tab_descriptor: Indicate on which tab to wait for the expression. 316*9c5db199SXin Li @param expression: Indiate for what expression to wait. 317*9c5db199SXin Li @param timeout: Indicate the timeout of the expression. 318*9c5db199SXin Li """ 319*9c5db199SXin Li if tab_descriptor not in self._tabs: 320*9c5db199SXin Li raise RuntimeError('There is no tab for %s' % tab_descriptor) 321*9c5db199SXin Li self._tabs[tab_descriptor].WaitForJavaScriptCondition( 322*9c5db199SXin Li expression, timeout=timeout) 323*9c5db199SXin Li 324*9c5db199SXin Li 325*9c5db199SXin Li def execute_javascript(self, tab_descriptor, statement, timeout): 326*9c5db199SXin Li """Executes a JavaScript statement on the given tab. 327*9c5db199SXin Li 328*9c5db199SXin Li @param tab_descriptor: Indicate on which tab to execute the statement. 329*9c5db199SXin Li @param statement: Indiate what statement to execute. 330*9c5db199SXin Li @param timeout: Indicate the timeout of the statement. 331*9c5db199SXin Li """ 332*9c5db199SXin Li if tab_descriptor not in self._tabs: 333*9c5db199SXin Li raise RuntimeError('There is no tab for %s' % tab_descriptor) 334*9c5db199SXin Li self._tabs[tab_descriptor].ExecuteJavaScript( 335*9c5db199SXin Li statement, timeout=timeout) 336*9c5db199SXin Li 337*9c5db199SXin Li 338*9c5db199SXin Li def evaluate_javascript(self, tab_descriptor, expression, timeout): 339*9c5db199SXin Li """Evaluates a JavaScript expression on the given tab. 340*9c5db199SXin Li 341*9c5db199SXin Li @param tab_descriptor: Indicate on which tab to evaluate the expression. 342*9c5db199SXin Li @param expression: Indiate what expression to evaluate. 343*9c5db199SXin Li @param timeout: Indicate the timeout of the expression. 344*9c5db199SXin Li @return the JSONized result of the given expression 345*9c5db199SXin Li """ 346*9c5db199SXin Li if tab_descriptor not in self._tabs: 347*9c5db199SXin Li raise RuntimeError('There is no tab for %s' % tab_descriptor) 348*9c5db199SXin Li return self._tabs[tab_descriptor].EvaluateJavaScript( 349*9c5db199SXin Li expression, timeout=timeout) 350*9c5db199SXin Li 351*9c5db199SXin Liclass Application(FacadeResource): 352*9c5db199SXin Li """ This class provides access to WebStore Applications""" 353*9c5db199SXin Li 354*9c5db199SXin Li APP_NAME_IDS = { 355*9c5db199SXin Li 'camera' : 'njfbnohfdkmbmnjapinfcopialeghnmh', 356*9c5db199SXin Li 'files' : 'hhaomjibdihmijegdhdafkllkbggdgoj' 357*9c5db199SXin Li } 358*9c5db199SXin Li # Time in seconds to load the app 359*9c5db199SXin Li LOAD_TIME = 5 360*9c5db199SXin Li 361*9c5db199SXin Li def __init__(self, chrome_object=None): 362*9c5db199SXin Li super(Application, self).__init__(chrome_object) 363*9c5db199SXin Li 364*9c5db199SXin Li @retry_chrome_call 365*9c5db199SXin Li def evaluate_javascript(self, code): 366*9c5db199SXin Li """Executes javascript and returns some result. 367*9c5db199SXin Li 368*9c5db199SXin Li Occasionally calls to EvaluateJavascript on the autotest_ext will fail 369*9c5db199SXin Li to find the extension. Instead of wrapping every call in a try/except, 370*9c5db199SXin Li calls will go through this function instead. 371*9c5db199SXin Li 372*9c5db199SXin Li @param code: The javascript string to execute 373*9c5db199SXin Li 374*9c5db199SXin Li """ 375*9c5db199SXin Li try: 376*9c5db199SXin Li result = self._chrome.autotest_ext.EvaluateJavaScript(code) 377*9c5db199SXin Li return result 378*9c5db199SXin Li except KeyError: 379*9c5db199SXin Li logging.exception('Could not find autotest_ext') 380*9c5db199SXin Li except (devtools_http.DevToolsClientUrlError, 381*9c5db199SXin Li devtools_http.DevToolsClientConnectionError): 382*9c5db199SXin Li logging.exception('Could not connect to DevTools') 383*9c5db199SXin Li 384*9c5db199SXin Li raise error.TestError("Could not execute %s" % code) 385*9c5db199SXin Li 386*9c5db199SXin Li def click_on(self, ui, name, isRegex=False, role=None): 387*9c5db199SXin Li """ 388*9c5db199SXin Li Click on given role and name matches 389*9c5db199SXin Li 390*9c5db199SXin Li @ui: ui_utils object 391*9c5db199SXin Li @param name: item node name. 392*9c5db199SXin Li @param isRegex: If name is in regex format then isRegex should be 393*9c5db199SXin Li True otherwise False. 394*9c5db199SXin Li @param role: role of the element. Example: button or window etc. 395*9c5db199SXin Li @raise error.TestError if the test is failed to find given node 396*9c5db199SXin Li """ 397*9c5db199SXin Li if not ui.item_present(name, isRegex=isRegex, role=role): 398*9c5db199SXin Li raise error.TestError("name=%s, role=%s did not appeared with in " 399*9c5db199SXin Li "time" % (name, role)) 400*9c5db199SXin Li ui.doDefault_on_obj(name, isRegex=isRegex, role=role) 401*9c5db199SXin Li 402*9c5db199SXin Li def is_app_opened(self, name): 403*9c5db199SXin Li """ 404*9c5db199SXin Li Verify if the Webstore app is opened or not 405*9c5db199SXin Li 406*9c5db199SXin Li @param name: Name of the app to verify. 407*9c5db199SXin Li 408*9c5db199SXin Li """ 409*9c5db199SXin Li self.evaluate_javascript("var isShown = null;") 410*9c5db199SXin Li is_app_shown_js = """ 411*9c5db199SXin Li chrome.autotestPrivate.isAppShown('%s', 412*9c5db199SXin Li function(appShown){isShown = appShown}); 413*9c5db199SXin Li """ % self.APP_NAME_IDS[name.lower()] 414*9c5db199SXin Li self.evaluate_javascript(is_app_shown_js) 415*9c5db199SXin Li return self.evaluate_javascript('isShown') 416*9c5db199SXin Li 417*9c5db199SXin Li def launch_app(self, name): 418*9c5db199SXin Li """ 419*9c5db199SXin Li Launch the app/extension by its ID and verify that it opens. 420*9c5db199SXin Li 421*9c5db199SXin Li @param name: Name of the app to launch. 422*9c5db199SXin Li 423*9c5db199SXin Li """ 424*9c5db199SXin Li logging.info("Launching %s app" % name) 425*9c5db199SXin Li if name == "camera": 426*9c5db199SXin Li webapps_js = "chrome.autotestPrivate.waitForSystemWebAppsInstall(" \ 427*9c5db199SXin Li "function(){})" 428*9c5db199SXin Li self.evaluate_javascript(webapps_js) 429*9c5db199SXin Li launch_js = "chrome.autotestPrivate.launchSystemWebApp('%s', '%s', " \ 430*9c5db199SXin Li "function(){})" % ("Camera", 431*9c5db199SXin Li "chrome://camera-app/views/main.html") 432*9c5db199SXin Li else: 433*9c5db199SXin Li launch_js = "chrome.autotestPrivate.launchApp('%s', function(){})" \ 434*9c5db199SXin Li % self.APP_NAME_IDS[name.lower()] 435*9c5db199SXin Li self.evaluate_javascript(launch_js) 436*9c5db199SXin Li def is_app_opened(): 437*9c5db199SXin Li return self.is_app_opened(name) 438*9c5db199SXin Li utils.poll_for_condition(condition=is_app_opened, 439*9c5db199SXin Li desc="%s app is not launched" % name, 440*9c5db199SXin Li timeout=self.LOAD_TIME) 441*9c5db199SXin Li logging.info('%s app is launched', name) 442*9c5db199SXin Li 443*9c5db199SXin Li def close_app(self, name): 444*9c5db199SXin Li """ 445*9c5db199SXin Li Close the app/extension by its ID and verify that it closes. 446*9c5db199SXin Li 447*9c5db199SXin Li @param name: Name of the app to close. 448*9c5db199SXin Li 449*9c5db199SXin Li """ 450*9c5db199SXin Li close_js = "chrome.autotestPrivate.closeApp('%s', function(){})" \ 451*9c5db199SXin Li % self.APP_NAME_IDS[name.lower()] 452*9c5db199SXin Li self.evaluate_javascript(close_js) 453*9c5db199SXin Li def is_app_closed(): 454*9c5db199SXin Li return not self.is_app_opened(name) 455*9c5db199SXin Li utils.poll_for_condition(condition=is_app_closed, 456*9c5db199SXin Li desc="%s app is not closed" % name, 457*9c5db199SXin Li timeout=self.LOAD_TIME) 458*9c5db199SXin Li logging.info('%s app is closed', name) 459