def __init__(self, app_name, app_id, device=False): self.device = device if self.device: call(['adb', 'forward', 'tcp:2828', 'tcp:2828']) self._app_name = app_name self._app_id = app_id self._marionette = Marionette() self._marionette.start_session() self._gaia_apps = GaiaApps(self._marionette) self._gaia_data = GaiaData(self._marionette) self._gaia_device = GaiaDevice(self._marionette) ''' Deprecated
def setupMarionette(self): self.marionette = marionette.Marionette() self._logger.info("Waiting for Marionette...") self.marionette.wait_for_port() self._logger.info("Marionette ready, starting session") self.marionette.start_session() if 'b2g' not in self.marionette.session: raise mozdevice.DMError( "bad session value %s returned by start_session" % self.marionette.session) self.marionette.set_script_timeout(60000) self.marionette.timeouts(self.marionette.TIMEOUT_SEARCH, 10000) self._logger.info("Marionette ready!") self.b2gpopulate = B2GPopulate(self.marionette) self.gaiaApps = GaiaApps(self.marionette) self.gaiaDevice = GaiaDevice(self.marionette)
def setupMarionette(self): self.marionette = marionette.Marionette() self._logger.info("Waiting for Marionette...") self.marionette.wait_for_port() self.marionette.start_session() if 'b2g' not in self.marionette.session: raise mozdevice.DMError("bad session value %s returned by start_session" % self.marionette.session) self.marionette.set_script_timeout(60000) self.marionette.timeouts(self.marionette.TIMEOUT_SEARCH, 10000) self._logger.info("Marionette ready!") self.b2gpopulate = B2GPopulate(self.marionette) self.gaiaApps = GaiaApps(self.marionette) self.gaiaDevice = GaiaDevice(self.marionette)
class B2gExecutor(Executor): def __init__(self, app_name, app_id, device=False): self.device = device if self.device: call(['adb', 'forward', 'tcp:2828', 'tcp:2828']) self._app_name = app_name self._app_id = app_id self._marionette = Marionette() self._marionette.start_session() self._gaia_apps = GaiaApps(self._marionette) self._gaia_data = GaiaData(self._marionette) self._gaia_device = GaiaDevice(self._marionette) ''' Deprecated # https://github.com/mozilla-b2g/gaia/blob/b568b7ae8adb6ee3651bd75acbaaedff86a08912/tests/python/gaia-ui-tests/gaiatest/gaia_test.py js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_apps.js")) self._marionette.import_script(js) js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_data_layer.js")) self._marionette.set_context(self._marionette.CONTEXT_CHROME) self._marionette.import_script(js) self._marionette.set_context(self._marionette.CONTEXT_CONTENT) # C:\Users\Jun-Wei\Desktop\b2g\battery\manifest.webapp #app = GaiaApps(self._marionette).launch(self._app_name) #app = GaiaApps(self._marionette).launch('Battery', manifest_url='C:/Users/Jun-Wei/Desktop/b2g/battery/manifest.webapp', entry_point='/index.html') app = GaiaApps(self._marionette).launch('Battery') print app.frame print app.src print app.origin print app.name #print g_app.manifest_url #self._app_frame = g_app.frame self._app_frame_id = app.frame self._app_src = app.src self._app_origin = app.origin #self.app_manifest_url = g_app.manifest_url #self.gaia_apps = GaiaApps(self.__marionette) #print self.gaia_apps.displayed_app.name #print self.gaia_apps.installed_apps #print self.gaia_apps.running_apps() #js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_apps.js")) #self.__marionette.import_script(js) ''' def fire_event(self, clickable): logger.info('fire_event: id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath()) try: # id staring with DomAnalyzer.serial_prefix is given by our monkey and should be ignored when locating if clickable.get_id() and not clickable.get_id().startswith(DomAnalyzer.serial_prefix): self._marionette.find_element('id', clickable.get_id()).tap() elif clickable.get_xpath(): self._marionette.find_element('xpath', clickable.get_xpath()).tap() else: logger.error('No id nor xpath for the clickable: id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath()) sys.exit() except (ElementNotVisibleException, InvalidElementStateException, NoSuchElementException): logger.info('Element is not interactable in fire_event(): id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath()) except Exception as e: logger.error('Unknown Exception: %s in fire_event(): id: %s (xpath: %s)', str(e), clickable.get_id(), clickable.get_xpath()) sys.exit() def fill_form(self, clickable): for f in clickable.get_forms(): for input_field in f.get_inputs(): try: if input_field.get_id() and not input_field.get_id().startswith(DomAnalyzer.serial_prefix): self._marionette.find_element('id', input_field.get_id()).send_keys(input_field.get_value()) elif input_field.get_xpath(): self._marionette.find_element('xpath', input_field.get_xpath()).send_keys(input_field.get_value()) else: logger.error('No id nor xpath for an input field in the form id: %s (xpath: %s)', f.get_id(), f.get_xpath()) sys.exit() except (ElementNotVisibleException, InvalidElementStateException, NoSuchElementException): logger.info('Element is not interactable in fill_form(): id: %s (xpath: %s)', f.get_id(), f.get_xpath()) except Exception as e: logger.error('Unknown Exception: %s in fill_form(): id: %s (xpath: %s)', str(e), f.get_id(), f.get_xpath()) sys.exit() def empty_form(self, clickable): for f in clickable.get_forms(): for input_field in f.get_inputs(): try: if input_field.get_id() and not input_field.get_id().startswith(DomAnalyzer.serial_prefix): self._marionette.find_element('id', input_field.get_id()).clear() elif input_field.get_xpath(): self._marionette.find_element('xpath', input_field.get_xpath()).clear() else: logger.error('No id nor xpath for an input field in the form %s (%s)', f.get_id(), f.get_xpath()) sys.exit() except (ElementNotVisibleException, InvalidElementStateException, NoSuchElementException): logger.info('Element is not interactable in empty_form(): id: %s (xpath: %s)', f.get_id(), f.get_xpath()) except Exception as e: logger.error('Unknown Exception: %s in empty_form(): id: %s (xpath: %s)', str(e), f.get_id(), f.get_xpath()) sys.exit() def get_source(self): return self._marionette.page_source.encode(sys.stdout.encoding, 'ignore') def get_screenshot(self, clickable=None): element = None if clickable: try: if clickable.get_id() and not clickable.get_id().startswith(DomAnalyzer.serial_prefix): element = self._marionette.find_element('id', clickable.get_id()) elif clickable.get_xpath(): element = self._marionette.find_element('xpath', clickable.get_xpath()) else: logger.error('No id nor xpath for the clickable: id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath()) sys.exit() except (ElementNotVisibleException, InvalidElementStateException, NoSuchElementException): logger.info('Element is not interactable in get_screenshot(): id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath()) except Exception as e: logger.error('Unknown Exception: %s in get_screenshot(): id: %s (xpath: %s)', str(e), clickable.get_id(), clickable.get_xpath()) sys.exit() if not element: # set context to CHROME to capture whole screen # system frame e.g. FileNotFound cannot be captured without CONTEXT_CHROME (Don't know why) self._marionette.set_context(self._marionette.CONTEXT_CHROME) screenshot = self._marionette.screenshot(element) self._marionette.set_context(self._marionette.CONTEXT_CONTENT) return screenshot def switch_to_frame(self, by, frame_str): """ :param by: options: "id", "xpath", "link text", "partial link text", "name", "tag name", "class name", "css selector", "anon attribute" """ # self.switch_to_top_frame() frame = self._marionette.find_element(by, frame_str) self._marionette.switch_to_frame(frame) def switch_to_top_frame(self): self._marionette.switch_to_frame() # switch to the top-level frame def restart_app(self): # remember to disable screen timeout and screen lock before testing # todo: open b2g simulator, install app, # unlock_screen # self._marionette.execute_script('window.wrappedJSObject.lockScreen.unlock();') self.kill_all_apps() # kill_all_apps() will also kill the 'homescreen app' on real device # so trigger a home event to restore homescreen if self.device: self._dispatch_home_button_event() self.clear_data() self.touch_home_button() # launch the app self._gaia_apps.launch(self._app_name) ''' Deprecated if self.device: icon = self._marionette.find_element('xpath', "//li[contains(@aria-label, '" + self._app_name + "')]") else: icon = self._marionette.find_element('xpath', "//div[contains(@class, 'icon')]//span[contains(text(),'" + self._app_name + "')]") icon.tap() ''' time.sleep(5) # wait for app screen self._marionette.switch_to_frame() # this wait seems not working, need to find another useful one Wait(self._marionette).until(lambda m: m.find_element('css selector', "iframe[data-url*='" + self._app_id + "']").is_displayed()) app_frame = self._marionette.find_element('css selector', "iframe[data-url*='" + self._app_id + "']") self._marionette.switch_to_frame(app_frame) def touch_home_button(self): # ref: https://github.com/mozilla-b2g/gaia/blob/master/tests/python/gaia-ui-tests/gaiatest/gaia_test.py#L751 apps = self._gaia_apps if apps.displayed_app.name.lower() != 'homescreen': # touching home button will return to homescreen self._dispatch_home_button_event() Wait(self._marionette).until( lambda m: apps.displayed_app.name.lower() == 'homescreen') apps.switch_to_displayed_app() else: apps.switch_to_displayed_app() mode = self._marionette.find_element(By.TAG_NAME, 'body').get_attribute('class') self._dispatch_home_button_event() apps.switch_to_displayed_app() if 'edit-mode' in mode: # touching home button will exit edit mode Wait(self._marionette).until(lambda m: m.find_element( By.TAG_NAME, 'body').get_attribute('class') != mode) else: # touching home button inside homescreen will scroll it to the top Wait(self._marionette).until(lambda m: m.execute_script( "return window.wrappedJSObject.scrollY") == 0) def _dispatch_home_button_event(self): self._gaia_device._dispatch_home_button_event() ''' Deprecated self._marionette.switch_to_frame() self._marionette.execute_script("window.wrappedJSObject.dispatchEvent(new Event('home'));") ''' time.sleep(0.5) def clear_data(self): # for now, clear contact data # https://github.com/mozilla-b2g/gaia/blob/v2.2/tests/python/gaia-ui-tests/gaiatest/gaia_test.py#L208 self._marionette.set_context(self._marionette.CONTEXT_CHROME) result = self._marionette.execute_async_script('return GaiaDataLayer.removeAllContacts();') assert result, 'Unable to remove all contacts' self._marionette.set_context(self._marionette.CONTEXT_CONTENT) time.sleep(0.5) def kill_all_apps(self): self._marionette.switch_to_frame() self._marionette.execute_async_script(""" // Kills all running apps, except the homescreen. function killAll() { let manager = window.wrappedJSObject.appWindowManager; let apps = manager.getApps(); for (let id in apps) { let origin = apps[id].origin; if (origin.indexOf('verticalhome') == -1) { manager.kill(origin); } } }; killAll(); // return true so execute_async_script knows the script is complete marionetteScriptFinished(true); """) time.sleep(0.5)
class EidetickerB2GMixin(EidetickerMixin): """B2G-specific extensions to the eideticker mixin""" marionette = None def setupMarionette(self): self.marionette = marionette.Marionette() self._logger.info("Waiting for Marionette...") self.marionette.wait_for_port() self._logger.info("Marionette ready, starting session") self.marionette.start_session() if 'b2g' not in self.marionette.session: raise mozdevice.DMError( "bad session value %s returned by start_session" % self.marionette.session) self.marionette.set_script_timeout(60000) self.marionette.timeouts(self.marionette.TIMEOUT_SEARCH, 10000) self._logger.info("Marionette ready!") self.b2gpopulate = B2GPopulate(self.marionette) self.gaiaApps = GaiaApps(self.marionette) self.gaiaData = GaiaData(self.marionette) self.gaiaDevice = GaiaDevice(self.marionette) def connectWIFI(self, wifiSettings): """ Tries to connect to the wifi network """ self._logger.info("Setting up wifi...") self.gaiaData.connect_to_wifi(wifiSettings) self._logger.info("WIFI ready!") def cleanup(self): self.removeDir('/data/local/storage/persistent') self.removeDir('/data/b2g/mozilla') for item in self.listFiles('/sdcard/'): self.removeDir('/'.join(['/sdcard', item])) def stopB2G(self): self._logger.info("Stopping B2G") if self.marionette and self.marionette.session: self.marionette.delete_session() self.marionette = None self.shellCheckOutput(['stop', 'b2g']) # Wait for a bit to make sure B2G has completely shut down. tries = 100 while "b2g" in self.shellCheckOutput(['ps', 'b2g']) and tries > 0: tries -= 1 time.sleep(0.1) if tries == 0: raise mozdevice.DMError("Could not kill b2g process") def startB2G(self): self._logger.info("Starting B2G") self.shellCheckOutput(['start', 'b2g']) self.setupMarionette() self.marionette.execute_async_script(""" window.addEventListener('mozbrowserloadend', function loaded(aEvent) { if (aEvent.target.src.indexOf('ftu') != -1 || aEvent.target.src.indexOf('homescreen') != -1) { window.removeEventListener('mozbrowserloadend', loaded); marionetteScriptFinished(); } });""", script_timeout=60000) # TODO: Remove this sleep when Bug 924912 is addressed time.sleep(5) # run the fake update checker FakeUpdateChecker(self.marionette).check_updates() # unlock device, so it doesn't go to sleep self._logger.info("Unlocking screen...") self.gaiaDevice.unlock() # turn off automatic brightness adjustments and set to 100% self.gaiaData.set_setting('screen.automatic-brightness', '') self.gaiaData.set_setting('screen.brightness', 1) # kill running apps so they don't interfere with the test self._logger.info("Killing all running apps...") self.gaiaApps.kill_all() # set correct orientation self._logger.info("Setting orientation") self.marionette.execute_script( "screen.mozLockOrientation('%s');" % self.deviceProperties['defaultOrientation']) def restartB2G(self): """ Restarts the b2g process on the device. """ self.stopB2G() self.startB2G()
class EidetickerB2GMixin(EidetickerMixin): """B2G-specific extensions to the eideticker mixin""" marionette = None def setupMarionette(self): self.marionette = marionette.Marionette() self._logger.info("Waiting for Marionette...") self.marionette.wait_for_port() self._logger.info("Marionette ready, starting session") self.marionette.start_session() if 'b2g' not in self.marionette.session: raise mozdevice.DMError( "bad session value %s returned by start_session" % self.marionette.session) self.marionette.set_script_timeout(60000) self.marionette.timeouts(self.marionette.TIMEOUT_SEARCH, 10000) self._logger.info("Marionette ready!") self.b2gpopulate = B2GPopulate(self.marionette) self.gaiaApps = GaiaApps(self.marionette) self.gaiaDevice = GaiaDevice(self.marionette) def connectWIFI(self, wifiSettings): """ Tries to connect to the wifi network """ self._logger.info("Setting up wifi...") data = GaiaData(self.marionette) data.connect_to_wifi(wifiSettings) self._logger.info("WIFI ready!") def cleanup(self): self.removeDir('/data/local/storage/persistent') self.removeDir('/data/b2g/mozilla') for item in self.listFiles('/sdcard/'): self.removeDir('/'.join(['/sdcard', item])) def stopB2G(self): self._logger.info("Stopping B2G") if self.marionette and self.marionette.session: self.marionette.delete_session() self.marionette = None self.shellCheckOutput(['stop', 'b2g']) # Wait for a bit to make sure B2G has completely shut down. tries = 100 while "b2g" in self.shellCheckOutput(['ps', 'b2g']) and tries > 0: tries -= 1 time.sleep(0.1) if tries == 0: raise mozdevice.DMError("Could not kill b2g process") def startB2G(self): self.shellCheckOutput(['start', 'b2g']) self.setupMarionette() self.marionette.execute_async_script(""" window.addEventListener('mozbrowserloadend', function loaded(aEvent) { if (aEvent.target.src.indexOf('ftu') != -1 || aEvent.target.src.indexOf('homescreen') != -1) { window.removeEventListener('mozbrowserloadend', loaded); marionetteScriptFinished(); } });""", script_timeout=60000) # TODO: Remove this sleep when Bug 924912 is addressed time.sleep(5) def restartB2G(self): """ Restarts the b2g process on the device. """ self.stopB2G() self.startB2G() def resetOrientation(self): self.setOrientation(self.deviceProperties['defaultOrientation']) def setOrientation(self, orientation): # set landscape or portrait mode self._logger.info("Setting orientation: %s" % orientation) self.marionette.execute_script("screen.mozLockOrientation('%s');" % orientation) def unlock(self): # unlock device, so it doesn't go to sleep self._logger.info("Unlocking screen...") self.gaiaDevice.unlock() def killApps(self): self._logger.info("Killing all running apps...") self.gaiaApps.kill_all()
class EidetickerB2GMixin(EidetickerMixin): """B2G-specific extensions to the eideticker mixin""" marionette = None _devicePixelRatio = None def setupMarionette(self): self.marionette = marionette.Marionette() self._logger.info("Waiting for Marionette...") self.marionette.wait_for_port() self._logger.info("Marionette ready, starting session") self.marionette.start_session() if 'b2g' not in self.marionette.session: raise mozdevice.DMError( "bad session value %s returned by start_session" % self.marionette.session) self.marionette.set_script_timeout(60000) self.marionette.timeouts(self.marionette.TIMEOUT_SEARCH, 10000) self._logger.info("Marionette ready!") self.b2gpopulate = B2GPopulate(self.marionette) self.gaiaApps = GaiaApps(self.marionette) self.gaiaData = GaiaData(self.marionette) self.gaiaDevice = GaiaDevice(self.marionette) self.gaiaCompat = GaiaCompat() def connectWIFI(self, wifiSettings): """ Tries to connect to the wifi network """ self._logger.info("Setting up wifi...") self.gaiaData.connect_to_wifi(wifiSettings) self._logger.info("WIFI ready!") def cleanup(self): self.removeDir('/data/local/storage/persistent') self.removeDir('/data/b2g/mozilla') for item in self.listFiles('/sdcard/'): self.removeDir('/'.join(['/sdcard', item])) def stopB2G(self): self._logger.info("Stopping B2G") if self.marionette and self.marionette.session: self.marionette.delete_session() self.marionette = None self.shellCheckOutput(['stop', 'b2g']) # Wait for a bit to make sure B2G has completely shut down. tries = 100 while "b2g" in self.shellCheckOutput(['ps', 'b2g']) and tries > 0: tries -= 1 time.sleep(0.1) if tries == 0: raise mozdevice.DMError("Could not kill b2g process") def startB2G(self): self._logger.info("Starting B2G") self.shellCheckOutput(['start', 'b2g']) self.setupMarionette() self.gaiaCompat.wait_for_b2g(self.marionette) # run the fake update checker self.gaiaCompat.supress_update_check(self.marionette) # unlock device, so it doesn't go to sleep self._logger.info("Unlocking screen...") self.gaiaDevice.unlock() # turn off automatic brightness adjustments and set to 100% self.gaiaData.set_setting('screen.automatic-brightness', '') self.gaiaData.set_setting('screen.brightness', 1) # kill running apps so they don't interfere with the test self._logger.info("Killing all running apps...") self.gaiaApps.kill_all() # set correct orientation self._logger.info("Setting orientation") self.marionette.execute_script( "screen.mozLockOrientation('%s');" % self.deviceProperties['defaultOrientation']) def restartB2G(self): """ Restarts the b2g process on the device. """ self.stopB2G() self.startB2G() @property def devicePixelRatio(self): if not self._devicePixelRatio: if self.marionette and self.marionette.session: self._devicePixelRatio = self.marionette.execute_script( 'return window.wrappedJSObject.devicePixelRatio;') return self._devicePixelRatio or 1
class B2gExecutor(Executor): def __init__(self, app_name, app_id, device=False): self.device = device if self.device: call(['adb', 'forward', 'tcp:2828', 'tcp:2828']) self._app_name = app_name self._app_id = app_id self._marionette = Marionette() self._marionette.start_session() self._gaia_apps = GaiaApps(self._marionette) self._gaia_data = GaiaData(self._marionette) self._gaia_device = GaiaDevice(self._marionette) ''' Deprecated # https://github.com/mozilla-b2g/gaia/blob/b568b7ae8adb6ee3651bd75acbaaedff86a08912/tests/python/gaia-ui-tests/gaiatest/gaia_test.py js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_apps.js")) self._marionette.import_script(js) js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_data_layer.js")) self._marionette.set_context(self._marionette.CONTEXT_CHROME) self._marionette.import_script(js) self._marionette.set_context(self._marionette.CONTEXT_CONTENT) # C:\Users\Jun-Wei\Desktop\b2g\battery\manifest.webapp #app = GaiaApps(self._marionette).launch(self._app_name) #app = GaiaApps(self._marionette).launch('Battery', manifest_url='C:/Users/Jun-Wei/Desktop/b2g/battery/manifest.webapp', entry_point='/index.html') app = GaiaApps(self._marionette).launch('Battery') print app.frame print app.src print app.origin print app.name #print g_app.manifest_url #self._app_frame = g_app.frame self._app_frame_id = app.frame self._app_src = app.src self._app_origin = app.origin #self.app_manifest_url = g_app.manifest_url #self.gaia_apps = GaiaApps(self.__marionette) #print self.gaia_apps.displayed_app.name #print self.gaia_apps.installed_apps #print self.gaia_apps.running_apps() #js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_apps.js")) #self.__marionette.import_script(js) ''' def fire_event(self, clickable): logger.info('fire_event: id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath()) try: # id staring with DomAnalyzer.serial_prefix is given by our monkey and should be ignored when locating if clickable.get_id() and not clickable.get_id().startswith( DomAnalyzer.serial_prefix): self._marionette.find_element('id', clickable.get_id()).tap() elif clickable.get_xpath(): self._marionette.find_element('xpath', clickable.get_xpath()).tap() else: logger.error( 'No id nor xpath for the clickable: id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath()) sys.exit() except (ElementNotVisibleException, InvalidElementStateException, NoSuchElementException): logger.info( 'Element is not interactable in fire_event(): id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath()) except Exception as e: logger.error( 'Unknown Exception: %s in fire_event(): id: %s (xpath: %s)', str(e), clickable.get_id(), clickable.get_xpath()) sys.exit() def fill_form(self, clickable): for f in clickable.get_forms(): for input_field in f.get_inputs(): try: if input_field.get_id() and not input_field.get_id( ).startswith(DomAnalyzer.serial_prefix): self._marionette.find_element( 'id', input_field.get_id()).send_keys( input_field.get_value()) elif input_field.get_xpath(): self._marionette.find_element( 'xpath', input_field.get_xpath()).send_keys( input_field.get_value()) else: logger.error( 'No id nor xpath for an input field in the form id: %s (xpath: %s)', f.get_id(), f.get_xpath()) sys.exit() except (ElementNotVisibleException, InvalidElementStateException, NoSuchElementException): logger.info( 'Element is not interactable in fill_form(): id: %s (xpath: %s)', f.get_id(), f.get_xpath()) except Exception as e: logger.error( 'Unknown Exception: %s in fill_form(): id: %s (xpath: %s)', str(e), f.get_id(), f.get_xpath()) sys.exit() def empty_form(self, clickable): for f in clickable.get_forms(): for input_field in f.get_inputs(): try: if input_field.get_id() and not input_field.get_id( ).startswith(DomAnalyzer.serial_prefix): self._marionette.find_element( 'id', input_field.get_id()).clear() elif input_field.get_xpath(): self._marionette.find_element( 'xpath', input_field.get_xpath()).clear() else: logger.error( 'No id nor xpath for an input field in the form %s (%s)', f.get_id(), f.get_xpath()) sys.exit() except (ElementNotVisibleException, InvalidElementStateException, NoSuchElementException): logger.info( 'Element is not interactable in empty_form(): id: %s (xpath: %s)', f.get_id(), f.get_xpath()) except Exception as e: logger.error( 'Unknown Exception: %s in empty_form(): id: %s (xpath: %s)', str(e), f.get_id(), f.get_xpath()) sys.exit() def get_source(self): return self._marionette.page_source.encode(sys.stdout.encoding, 'ignore') def get_screenshot(self, clickable=None): element = None if clickable: try: if clickable.get_id() and not clickable.get_id().startswith( DomAnalyzer.serial_prefix): element = self._marionette.find_element( 'id', clickable.get_id()) elif clickable.get_xpath(): element = self._marionette.find_element( 'xpath', clickable.get_xpath()) else: logger.error( 'No id nor xpath for the clickable: id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath()) sys.exit() except (ElementNotVisibleException, InvalidElementStateException, NoSuchElementException): logger.info( 'Element is not interactable in get_screenshot(): id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath()) except Exception as e: logger.error( 'Unknown Exception: %s in get_screenshot(): id: %s (xpath: %s)', str(e), clickable.get_id(), clickable.get_xpath()) sys.exit() if not element: # set context to CHROME to capture whole screen # system frame e.g. FileNotFound cannot be captured without CONTEXT_CHROME (Don't know why) self._marionette.set_context(self._marionette.CONTEXT_CHROME) screenshot = self._marionette.screenshot(element) self._marionette.set_context(self._marionette.CONTEXT_CONTENT) return screenshot def switch_to_frame(self, by, frame_str): """ :param by: options: "id", "xpath", "link text", "partial link text", "name", "tag name", "class name", "css selector", "anon attribute" """ # self.switch_to_top_frame() frame = self._marionette.find_element(by, frame_str) self._marionette.switch_to_frame(frame) def switch_to_top_frame(self): self._marionette.switch_to_frame() # switch to the top-level frame def restart_app(self): # remember to disable screen timeout and screen lock before testing # todo: open b2g simulator, install app, # unlock_screen # self._marionette.execute_script('window.wrappedJSObject.lockScreen.unlock();') self.kill_all_apps() # kill_all_apps() will also kill the 'homescreen app' on real device # so trigger a home event to restore homescreen if self.device: self._dispatch_home_button_event() self.clear_data() self.touch_home_button() # launch the app self._gaia_apps.launch(self._app_name) ''' Deprecated if self.device: icon = self._marionette.find_element('xpath', "//li[contains(@aria-label, '" + self._app_name + "')]") else: icon = self._marionette.find_element('xpath', "//div[contains(@class, 'icon')]//span[contains(text(),'" + self._app_name + "')]") icon.tap() ''' time.sleep(5) # wait for app screen self._marionette.switch_to_frame() # this wait seems not working, need to find another useful one Wait(self._marionette).until(lambda m: m.find_element( 'css selector', "iframe[data-url*='" + self._app_id + "']"). is_displayed()) app_frame = self._marionette.find_element( 'css selector', "iframe[data-url*='" + self._app_id + "']") self._marionette.switch_to_frame(app_frame) def touch_home_button(self): # ref: https://github.com/mozilla-b2g/gaia/blob/master/tests/python/gaia-ui-tests/gaiatest/gaia_test.py#L751 apps = self._gaia_apps if apps.displayed_app.name.lower() != 'homescreen': # touching home button will return to homescreen self._dispatch_home_button_event() Wait(self._marionette).until( lambda m: apps.displayed_app.name.lower() == 'homescreen') apps.switch_to_displayed_app() else: apps.switch_to_displayed_app() mode = self._marionette.find_element(By.TAG_NAME, 'body').get_attribute('class') self._dispatch_home_button_event() apps.switch_to_displayed_app() if 'edit-mode' in mode: # touching home button will exit edit mode Wait(self._marionette).until(lambda m: m.find_element( By.TAG_NAME, 'body').get_attribute('class') != mode) else: # touching home button inside homescreen will scroll it to the top Wait(self._marionette).until(lambda m: m.execute_script( "return window.wrappedJSObject.scrollY") == 0) def _dispatch_home_button_event(self): self._gaia_device._dispatch_home_button_event() ''' Deprecated self._marionette.switch_to_frame() self._marionette.execute_script("window.wrappedJSObject.dispatchEvent(new Event('home'));") ''' time.sleep(0.5) def clear_data(self): # for now, clear contact data # https://github.com/mozilla-b2g/gaia/blob/v2.2/tests/python/gaia-ui-tests/gaiatest/gaia_test.py#L208 self._marionette.set_context(self._marionette.CONTEXT_CHROME) result = self._marionette.execute_async_script( 'return GaiaDataLayer.removeAllContacts();') assert result, 'Unable to remove all contacts' self._marionette.set_context(self._marionette.CONTEXT_CONTENT) time.sleep(0.5) def kill_all_apps(self): self._marionette.switch_to_frame() self._marionette.execute_async_script(""" // Kills all running apps, except the homescreen. function killAll() { let manager = window.wrappedJSObject.appWindowManager; let apps = manager.getApps(); for (let id in apps) { let origin = apps[id].origin; if (origin.indexOf('verticalhome') == -1) { manager.kill(origin); } } }; killAll(); // return true so execute_async_script knows the script is complete marionetteScriptFinished(true); """) time.sleep(0.5)
class EidetickerB2GMixin(EidetickerMixin): """B2G-specific extensions to the eideticker mixin""" marionette = None _devicePixelRatio = None def setupMarionette(self): self.marionette = marionette.Marionette() self._logger.info("Waiting for Marionette...") self.marionette.wait_for_port() self._logger.info("Marionette ready, starting session") self.marionette.start_session() if 'b2g' not in self.marionette.session: raise mozdevice.DMError( "bad session value %s returned by start_session" % self.marionette.session) self.marionette.set_script_timeout(60000) self.marionette.timeouts(self.marionette.TIMEOUT_SEARCH, 10000) self._logger.info("Marionette ready!") self.b2gpopulate = B2GPopulate(self.marionette) self.gaiaApps = GaiaApps(self.marionette) self.gaiaData = GaiaData(self.marionette) self.gaiaDevice = GaiaDevice(self.marionette) self.gaiaCompat = GaiaCompat() def connectWIFI(self, wifiSettings): """ Tries to connect to the wifi network """ self._logger.info("Setting up wifi...") self.gaiaData.connect_to_wifi(wifiSettings) self._logger.info("WIFI ready!") def cleanup(self): self.removeDir('/data/local/storage/persistent') self.removeDir('/data/b2g/mozilla') for item in self.listFiles('/sdcard/'): self.removeDir('/'.join(['/sdcard', item])) def stopB2G(self): self._logger.info("Stopping B2G") if self.marionette and self.marionette.session: self.marionette.delete_session() self.marionette = None self.shellCheckOutput(['stop', 'b2g']) # Wait for a bit to make sure B2G has completely shut down. tries = 100 while "b2g" in self.shellCheckOutput(['ps', 'b2g']) and tries > 0: tries -= 1 time.sleep(0.1) if tries == 0: raise mozdevice.DMError("Could not kill b2g process") def startB2G(self): self._logger.info("Starting B2G") self.shellCheckOutput(['start', 'b2g']) self.setupMarionette() self.gaiaCompat.wait_for_b2g(self.marionette) # run the fake update checker self.gaiaCompat.supress_update_check(self.marionette) # unlock device, so it doesn't go to sleep self._logger.info("Unlocking screen...") self.gaiaDevice.unlock() # turn off automatic brightness adjustments and set to 100% self.gaiaData.set_setting('screen.automatic-brightness', '') self.gaiaData.set_setting('screen.brightness', 1) # kill running apps so they don't interfere with the test self._logger.info("Killing all running apps...") self.gaiaApps.kill_all() # set correct orientation self._logger.info("Setting orientation") self.marionette.execute_script("screen.mozLockOrientation('%s');" % self.deviceProperties['defaultOrientation']) def restartB2G(self): """ Restarts the b2g process on the device. """ self.stopB2G() self.startB2G() @property def devicePixelRatio(self): if not self._devicePixelRatio: if self.marionette and self.marionette.session: self._devicePixelRatio = self.marionette.execute_script( 'return window.wrappedJSObject.devicePixelRatio;') return self._devicePixelRatio or 1