def _load_family(driver: Remote, url: str) -> Bundle: builder = Bundle.builder() driver.get(url) # todo: compare with store currency currency = driver.execute_script("return Currency.currentCurrency;") meta = driver.execute_script("return window.ShopifyAnalytics.meta;") element = driver.find_element_by_id("product-form-{}".format( meta["page"]["resourceId"])) family_json = ujson.loads(element.get_attribute("data-product")) family = _new_family(url, family_json) builder.family(family) for product_json in family_json["variants"]: product = _new_product(family.id, product_json) builder.product(product) image_json = product_json["featured_image"] if image_json: builder.image(_new_product_image(family.id, product.id, image_json)) bundle = builder.build() logger.debug( "Loaded product family '%s' with %d products and %d images from '%s'", bundle.family.name, len(bundle.products), len(bundle.images), bundle.family.url) return bundle
def create_window(browser: webdriver.Remote) -> webdriver.Remote: windows_before = browser.window_handles browser.execute_script("window.open('');") WebDriverWait(browser, 10).until( EC.number_of_windows_to_be(len(windows_before) + 1) ) windows_after = browser.window_handles new_windows = set(windows_after) - set(windows_before) browser.switch_to.window(new_windows.pop()) return browser
def navigate(driver: Remote): """ 目的のページに遷移する。 """ logging.info('Navigating...') driver.get('https://note.mu/') # noteのトップページを開く。 assert 'note' in driver.title # タイトルに'note'が含まれていることを確認する。 # 3回繰り返す。 for _ in range(3): # ページの一番下までスクロールする。 driver.execute_script('scroll(0, document.body.scrollHeight)') logging.info('Waiting for contents to be loaded...') time.sleep(2) # 2秒間待つ。
def attach_photos(self, photo_paths: list, browser: webdriver.Remote) -> None: attach_field = self._get_element_by_xpath("//input[@type=\"file\"]", browser) label = attach_field.find_element_by_xpath("./..") js = "arguments[0].style.height='100px'; \ arguments[0].style.width='100px'; \ arguments[0].style.overflow='visible'; \ arguments[0].style.visibility='visible'; \ arguments[0].style.opacity = 1" browser.execute_script(js, label) for path in photo_paths: try: self._fill_field(attach_field, path) except Exception as exc: logger.info(f'Фотка не прикрепляется {path} - {str(exc)}') logger.info("Прикрепили файлы")
def navigate(driver: Remote): """ 目的のページに遷移する。 """ logging.info('Navigating...') driver.get('https://note.mu/') # noteのトップページを開く。 assert 'note' in driver.title # タイトルに'note'が含まれていることを確認する。 # 3回繰り返す。 for _ in range(3): # 待つべき要素の番号(現在の要素数 + 10)を計算する。 # 最初の2要素だけ親要素が異なるので、現在の要素数の計算からは除く。 n = len( driver.find_elements_by_css_selector( '.o-timeline > div > .o-timeline__item')) + 10 # ページの一番下までスクロールする。 driver.execute_script('scroll(0, document.body.scrollHeight)') logging.info('Waiting for contents to be loaded...') # n番目のコンテンツに対応する要素が表示されるまで待つ。nth-of-type()の番号は1始まり。 # タイムアウトは10秒で、10秒待っても表示されない場合は例外が発生する。 WebDriverWait(driver, 10).until( EC.visibility_of_element_located( (By.CSS_SELECTOR, f'.o-timeline__item:nth-of-type({n})')))
def enter_appeal(self, xpath: str, appeal_text: str, browser: webdriver.Remote): text_for_js = json.dumps(appeal_text, ensure_ascii=False) browser.execute_script( f'document.getElementById("input_20").value={text_for_js};')
def make_visible(self, element, browser: webdriver.Remote) -> None: # returns dict of X, Y coordinates coordinates = element.location_once_scrolled_into_view browser.execute_script( f'window.scrollTo({coordinates["x"]}, {coordinates["y"]});')
class _SeleniumWrapper: def __init__(self, context): """Constructor pulls capabilities and other webdriver config from the context which should allow user to set whatever browser configuration that they want. Anything which needs a dictionary or object will be imported from a definition using a spec_import'""" self._context = context # Should only need the capabilities setting, other options for selenium experts self._command_executor = RemoteConnection( self._context.config.get("webdriver_command_executor", "http://127.0.0.1:4444/wd/hub"), resolve_ip=False, ) self._keep_alive = self._context.config.get("webdriver_keep_alive", False) self._file_detector = self._spec_import_if_not_none( "webdriver_file_detector") self._proxy = self._spec_import_if_not_none("webdriver_proxy") self._browser_profile = self._spec_import_if_not_none( "webdriver_browser_profile") self._options = self._spec_import_if_not_none("webdriver_options") # Required param self._capabilities = self._context.config.get("webdriver_capabilities") self._capabilities = spec_import(self._capabilities) def _spec_import_if_not_none(self, config_option): value = self._context.config.get(config_option, None) if value: value = spec_import(value) return value def _start(self): self._context.browser = self self._remote = SeleniumRemote( desired_capabilities=self._capabilities, command_executor=self._command_executor, browser_profile=self._browser_profile, proxy=self._proxy, keep_alive=self._keep_alive, file_detector=self._file_detector, options=self._options, ) self._context.raw_webdriver = self._remote def _quit(self): if hasattr(self, "_remote"): self._remote.quit() def _browser_has_timing_capabilities(self): return self._remote.capabilities["browserName"] == "chrome" def _is_using_tls(self, name): return name.startswith("https") def _get_tls_timing(self, timings): if self._is_using_tls(timings["name"]): return timings["connectEnd"] - timings["secureConnectionStart"] else: logger.info( "Secure TLS connection not used, defaulting tls_time to 0") return 0 def _get_tcp_timing(self, timings): if self._is_using_tls(timings["name"]): return timings["secureConnectionStart"] - timings["connectStart"] else: return timings["connectEnd"] - timings["connectStart"] def _send_page_load_metrics(self): if self._browser_has_timing_capabilities(): performance_entries = self._remote.execute_script( "return performance.getEntriesByType('navigation')") paint_entries = self._remote.execute_script( "return performance.getEntriesByType('paint')") _timings = self._extract_entries(performance_entries) timings = _timings[0] if _timings else None if timings: protocol = timings.get("nextHopProtocol") if protocol != "http/1.1": logger.warning( f"Timings may be inaccurate as protocol is not http/1.1: {protocol}" ) metrics = { "dns_lookup_time": timings["domainLookupEnd"] - timings["domainLookupStart"], "dom_interactive": timings["domInteractive"], "js_onload_time": timings["domContentLoadedEventEnd"] - timings["domContentLoadedEventStart"], "page_weight": timings["transferSize"], "render_time": timings["domInteractive"] - timings["responseEnd"], "tcp_time": self._get_tcp_timing(timings), "time_to_first_byte": timings["responseStart"] - timings["connectEnd"], "time_to_interactive": timings["domInteractive"] - timings["requestStart"], "time_to_last_byte": timings["responseEnd"] - timings["connectEnd"], "tls_time": self._get_tls_timing(timings), "total_time": timings["duration"], } else: metrics = {} _paint_timings = self._extract_entries(paint_entries, expected=2) paint_timings = (self._format_paint_timings(_paint_timings) if _paint_timings else None) if paint_timings: metrics["first_contentful_paint"] = paint_timings[ "first-contentful-paint"] metrics["first_paint"] = paint_timings["first-paint"] if metrics: self._context.send( "selenium_page_load_metrics", **self._extract_and_convert_metrics_to_seconds(metrics), ) def _extract_entries(self, entries, expected=1): if len(entries) != expected: logger.error( f"Performance entries did not return the expected count: expected 1 - actual {len(entries)}" ) return else: return entries[:expected] def _format_paint_timings(self, entries): return {metric["name"]: metric["startTime"] for metric in entries} def _extract_and_convert_metrics_to_seconds(self, metrics): converted_metrics = dict() non_time_based_metrics = ["page_weight", "resource_path"] for k, v in metrics.items(): if k not in non_time_based_metrics: converted_metrics[k] = self._convert_ms_to_seconds(v) else: converted_metrics[k] = v return converted_metrics def _convert_ms_to_seconds(self, value_ms): return value_ms / 1000 def _retrieve_javascript_metrics(self): try: return self._remote.execute_script( "return performance.getEntriesByType('resource')") except Exception: logger.error("Failed to retrieve resource performance entries") return [] def _clear_resource_timings(self): self._remote.execute_script("performance.clearResourceTimings()") def get(self, url): self._remote.get(url) self._send_page_load_metrics() def get_js_metrics_context(self): return JsMetricsContext(self) def wait_for_elements(self, locator, timeout=5): return self._wait_for( EC.presence_of_all_elements_located, locator, f"Timed out trying to find elements '{locator}' in the dom", timeout, ) def wait_for_element(self, locator, timeout=5): return self._wait_for( EC.presence_of_element_located, locator, f"Timed out trying to find element '{locator}' in the dom", timeout, ) def wait_for_url(self, locator, timeout=5): return self._wait_for( EC.url_to_be, locator, f"Timed out waiting for url to be '{locator}' in the dom", timeout, ) def _wait_for(self, condition_func, locator, err_msg, timeout=5): try: return WebDriverWait(self._remote, timeout).until(condition_func(locator)) except TimeoutException as te: raise MiteError(err_msg) from te def switch_to_default(self): self._remote.switch_to.default_content() def switch_to_iframe(self, locator): self._remote.switch_to.frame(self._remote.find_element(*locator)) def switch_to_parent(self): self._remote.switch_to.parent_frame() @property def current_url(self): return self._remote.current_url
class BasePage(object): def __init__(self, project_name): self.driver = '' self.loc = '' self.project_name = project_name yamlPath = "user.yaml" yaml.load(yamlPath, Loader=yaml.BaseLoader) yaml.warnings({'YAMLLoadWarning': False}) f = open(yamlPath, 'r') temp = yaml.load(f.read()) self.url = temp[project_name]['url'] self.username = temp[project_name]['username'] self.password = temp[project_name]['password'] def open(self, browser="chrome", host='http://localhost:8081/wd/hub' ): # 初始化 打开浏览器 并最大化 self 与java中的this中一样,调用时不用传入self参数 try: self.driver = Remote(command_executor=host, desired_capabilities={ 'platform': 'ANY', 'browserName': browser, 'version': '', 'javascriptEnabled': True }) self.driver.maximize_window() except Exception as e: print(e) logger_cls.info(u"打开{0}浏览器".format(browser)) logger_cls.info(u"最大化") def get(self): try: self.driver.get(self.url) self.driver.implicitly_wait(10) # 隐性等待,最长等10秒 logger_cls.info(u'打开:{0}'.format(self.url)) except BaseException: logger_cls.error(u'打开{0}失败'.format(self.url)) self.loc = loc.Analyze(self.project_name) #初始化,读取xml 赋值给loc def find(self, name): #元素定位,并返回定位好的元素 try: el = WebDriverWait(self.driver, 3, 0.5).until( #设置显示等待时间,每0.5秒检查一次,如果超出指定值就报错 EC.presence_of_element_located( (self.loc[name].type, self.loc[name].UIIdentifier))) logger_cls.info(u'定位元素:{0}'.format(name)) # logger_cls.info(loc[name].value) except BaseException: logger_cls.error(u'定位元素:{0}失败'.format(name)) return el def send_keys(self, name, text): try: self.find(name).send_keys(text) logger_cls.info(u'在:{0}输入{1}'.format(name, text)) time.sleep(3) except BaseException: logger_cls.error(u'在:{0}输入{1}失败'.format(name, text)) def click(self, name): try: self.find(name).click() logger_cls.info(u'点击:{0}'.format(name)) time.sleep(3) except BaseException: logger_cls.error(u'点击:{0}失败'.format(name)) def being(self, name): t = False try: self.driver.find_element_by_xpath(self.loc[name].UIIdentifier) t = True logger_cls.info(u'{0}元素存在'.format(name)) except BaseException: logger_cls.info(u'{0}元素不存在'.format(name)) return t def login(self): self.get() self.send_keys(u'用户名', self.username) self.send_keys(u'密码', self.password) self.click(u'登录') time.sleep(3) if self.being(u'不再提示'): self.click(u'不再提示') # self.get_version() def clearmonitor(self): names = [u'博主', u'博主圈'] self.click(u'事件') if self.being(u'是否有事件'): self.focus(u'找回') self.click(u'多选') self.click(u'全选') self.click(u'删除') for name in names: self.click(name) if self.being(u'是否有博主'): self.focus(u'找回') self.click(u'多选') self.click(u'全选') self.click(u'删除') def randomclick(self, name, div=None): text = '' i = len(self.driver.find_elements_by_xpath( self.loc[name].UIIdentifier)) logger_cls.info(u'{0}列表中有{1}个参数'.format(name, i)) y = random.randint(1, i) if div == None: path = self.loc[name].UIIdentifier + '[' + str(y) + ']' text = self.driver.find_element_by_xpath(path).text self.driver.find_element_by_xpath(path).click() logger_cls.info(u'随机选择列表中的{0}第个参数并点击'.format(y)) else: i2 = len( self.driver.find_elements_by_xpath( self.loc[name].UIIdentifier + '[' + str(y) + ']')) y2 = random.randint(1, i2) path = self.loc[name].UIIdentifier + '[' + str(y2) + ']' + div text = self.driver.find_element_by_xpath(path).text self.driver.find_element_by_xpath(path).click() logger_cls.info(u'随机选择列表中的{0}第个参数并点击'.format(y2)) logger_cls.info(u'{0}:文本的值为:{1}'.format(name, text)) time.sleep(3) return text def close(self): logger_cls.info(u'3秒后关闭当前页面') time.sleep(3) self.driver.close() def quit(self): logger_cls.info(u'3秒后关闭浏览器') time.sleep(3) self.driver.quit() def get_url(self): url = self.driver.current_url logger_cls.info(u'当前页面url:' + url) return url def get_text(self, name): text = self.find(name).text logger_cls.info(u'{0}文本框的值为:{1}'.format(name, text)) return text def back(self): self.driver.back() logger_cls.info(u'返回上一页面') def clear(self, name): self.find(name).clear() logger_cls.info(u'清空文本框:{0}'.format(name)) def get_name(self): name = self.driver.name logger_cls.info(u'浏览器名称:{0}'.format(name)) def get_driver(self): return self.driver def get_version(self): version = self.driver.capabilities['version'] logger_cls.info(u'浏览器版本:{0}'.format(version)) return version def switch_to(self): self.driver.switch_to.window(self.driver.window_handles[-1]) logger_cls.info(u'切换页面') def focus(self, name): ele = self.find(name) ActionChains(self.driver).move_to_element(ele).perform() logger_cls.info(u'鼠标悬停到元素:{0}'.format(name)) def refresh(self): self.driver.refresh() logger_cls.info(u'刷新页面') def title(self): title = self.driver.title logger_cls.info(u'当前页面标题' + title) return title def Slide(self, height): js = "var q=document.documentElement.scrollTop={0}".format(str(height)) self.driver.execute_script(js) logger_cls.info(u'上下滑动' + str(height)) def sleep(self, i): logger_cls.info(u'暂停{0}秒'.format(i)) time.sleep(int(i)) def Screenshot(self, name): # name='screenshot_' isExists = os.path.exists("../images\\") # 判断结果 if not isExists: # 如果不存在则创建目录 # 创建目录操作函数 os.makedirs("../images\\") print u'创建images目录' timestrmap = time.strftime('%Y%m%d_%H%M%S') imgPath = os.path.join('../images\\', str(timestrmap) + name + '.png') self.driver.save_screenshot(imgPath) logger_cls.info(u'截图:{0}{1}.png'.format(str(timestrmap), name))
class Browser: __AWAIT_TIMEOUT = 60 __browser = None __browser_kwargs = {} __config = {} __refs_num = 0 def get_browser(self): return self.__browser def __init__(self, headless=True, config={}, **kwargs): self.__config = config self.__config['SELENIUM_HEADLESS'] = headless self.__browser_kwargs = kwargs if self.__config.get('SELENIUM_URL'): self.__create_browser_session() else: self.__create_browser_instanse() def __del__(self): if self.__browser: self.__browser.quit() logging.debug("%s: Quitted browser at __del__()", self.__config['CELERY_TASK_DEFAULT_QUEUE']) del self.__browser def __create_browser_instanse(self): options = Options() if self.__config.get('SELENIUM_HEADLESS'): options.headless = True if self.__config.get('SELENIUM_BROWSER'): options.add_experimental_option("debuggerAddress", self.__config['SELENIUM_BROWSER']) if self.__config.get('SELENIUM_DRIVER'): self.__browser_kwargs['executable_path'] = self.__config[ 'SELENIUM_DRIVER'] if self.__config.get( 'LOG_LEVEL') and self.__config['LOG_LEVEL'] == logging.DEBUG: if self.__config.get('SELENIUM_LOG_PATH'): self.__browser_kwargs['service_log_path'] = self.__config[ 'SELENIUM_LOG_PATH'] self.__browser_kwargs['service_args'] = ['--verbose'] if not self.__browser_kwargs.get('executable_path'): self.__browser_kwargs['executable_path'] = '/usr/bin/chromedriver' self.__browser = Chrome(options=options, **self.__browser_kwargs) logging.debug("%s: Created browser instance", self.__config['CELERY_TASK_DEFAULT_QUEUE']) def __create_browser_session(self): options = Options() if self.__config.get('SELENIUM_HEADLESS'): options.headless = True self.__browser = Remote(command_executor=self.__config['SELENIUM_URL'], options=options) logging.debug("Connected to remote browser") def __get_by(self, criterium, value): ignored_exceptions = ( NoSuchElementException, StaleElementReferenceException, ) try: return WebDriverWait(self.__browser, self.__AWAIT_TIMEOUT, ignored_exceptions=ignored_exceptions).until( EC.presence_of_element_located( (criterium, value))) except UnexpectedAlertPresentException as ex: raise ex except TimeoutException as ex: raise NoSuchElementException( f"No element with {criterium} {value} was found", ex) def click_by_id(self, element_id): self.__browser.execute_script(f'$("#{element_id}").click()') def doubleclick(self, element): ActionChains(self.__browser).double_click(element).perform() def execute_script(self, script, *args): return self.__browser.execute_script(script, *args) def dismiss_alert(self): try: self.__browser.switch_to_alert().dismiss() except NoAlertPresentException: pass def find_element_by_xpath(self, xpath): return self.__browser.find_element_by_xpath(xpath) def find_elements_by_xpath(self, xpath): return self.__browser.find_elements_by_xpath(xpath) def find_elements_by_css_selector(self, css): return self.__browser.find_elements_by_css_selector(css) def get(self, url): exception = None for attempt in range(3): try: self.__browser.get(url) exception = None break except Exception as ex: self.quit() self.__create_browser_instanse() exception = ex if exception: raise exception def get_alert(self): try: alert = self.__browser.switch_to_alert() text = alert.text alert.dismiss() return text except NoAlertPresentException: return None def get_element_by_class(self, class_name): return self.__get_by(By.CLASS_NAME, class_name) def get_element_by_css(self, css): return self.__get_by(By.CSS_SELECTOR, css) def get_element_by_id(self, id): return self.__get_by(By.ID, id) def get_element_by_name(self, name): return self.__get_by(By.NAME, name) def switch_to_alert(self): return self.__browser.switch_to.alert def wait_for_url(self, url): try: WebDriverWait(self.__browser, 20).until(EC.url_to_be(url)) except UnexpectedAlertPresentException as ex: raise UnexpectedAlertPresentException(ex.alert_text, f"Didn't get URL {url}") except Exception as ex: raise Exception(f"Didn't get URL {url}", ex) def close(self): self.__browser.get('about:blank') def quit(self): if self.__browser: self.__browser.quit() logging.debug("%s: Quitted browser at quit()", self.__config['CELERY_TASK_DEFAULT_QUEUE']) del self.__browser @property def title(self): return self.__browser.title
def scroll_to_view(remote: webdriver.Remote, *args): remote.execute_script("arguments[0].scrollIntoView(true);", *args)
class Browser(object): def __init__(self, harness, selenium_server_url, selenium_browser, width=1024, height=600): self.harness = harness self.selenium_server_url = selenium_server_url self.selenium_browser = selenium_browser self.width = width self.height = height self.selenium = Remote( self.selenium_server_url.encode('ascii'), desired_capabilities = { 'browserName': self.selenium_browser, }, ) self.selenium.set_window_size(width, height) def __enter__(self): self.harness.browser_stack.append(self) return self def __exit__(self, type, value, traceback): if self.harness.browser_stack[-1] != self: raise Exception("Unexpected browser on the top of the stack") self.harness.browser_stack.pop() return def shutdown(self): self.selenium.quit() def back(self): self.selenium.back() def refresh(self): self.selenium.refresh() def title(self): return self.selenium.title def source(self): return self.selenium.page_source def get(self, uri): self.selenium.get(uri) def find(self, selector): return WebElementSet(self, elements=self.selenium).find(selector) def add_cookie(self, cookie_dict): self.selenium.add_cookie(cookie_dict) def get_cookie(self, name): return self.selenium.get_cookie(name) def endpoint(self): return self.find('html').attr('id').replace('endpoint-', '').replace('-', '.') def endpoint_is(self, endpoint): is_equal(self.endpoint(), endpoint, "Endpoint is correct") def wait_for_bootstrap_modal(self): last = [None] def inner_wait(driver): value = self.find('.modal')[-1].css('top') if last[0] and last[0] == value: return True last[0] = value return False WebDriverWait(self.selenium, 3).until(inner_wait) return self def url(self): return furl(self.selenium.current_url) def execute_script(self, script): return self.selenium.execute_script(script) def wait_for_ajax(self): WebDriverWait(self.selenium, 10).until_not(lambda x: x.execute_script('return jQuery.active')) return self def wait_for_jquery(self): WebDriverWait(self.selenium, 10).until(lambda x: x.execute_script('return window.jQuery ? true : false')) return self def screenshot(self, message="Screenshot: "): if 's3_access_key' not in app.settings.options('test'): print "No screenshot S3 instance configured - skipping screenshot" return if not hasattr(self, 's3_connection'): if 's3_host' in app.settings.options('test'): self.s3_connection = boto.s3.connection.S3Connection( app.settings.get('test', 's3_access_key'), app.settings.get('test', 's3_secret_key'), host = app.settings.get('test', 's3_host'), ) else: self.s3_connection = boto.s3.connection.S3Connection( app.settings.get('test', 's3_access_key'), app.settings.get('test', 's3_secret_key'), ) bucket = self.s3_connection.get_bucket(app.settings.get('test', 's3_bucket')) filename = "%s-%s.png" % (token.create_url_token(), self.harness.current_test_object.__class__.__name__) key = bucket.new_key(filename) key.metadata['Content-Type'] = 'image/png' key.metadata['Cache-Control'] = 'public, max-age=86400' key.set_contents_from_string(self.selenium.get_screenshot_as_png()) key.make_public() print "%s%s" % (message, key.generate_url(expires_in=0, query_auth=False))
class AdminSeleniumWebDriverTestCase(LiveServerTestCase): available_apps = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.sites", ] def _get_remote_capabilities(self, specs): platforms = { "s": "Windows 2008", "x": "Windows 2003", "e": "Windows 2012", "l": "Linux", "m": "Mac 10.6", "i": "Mac 10.8", } browsers = { "ff": "firefox", "op": "opera", "ie": "internet explorer", "sa": "safari", "ip": "ipad", "ih": "iphone", "an": "android", "gc": "chrome", } browser = browsers[specs[:2]] if specs[-1] in platforms: platform = platforms.get(specs[-1]) version = specs[2:-1] else: platform = None version = specs[2:] caps = {"browserName": browser, "version": version, "platform": platform, "public": "public"} if "BUILD_NUMBER" in os.environ: caps["build"] = os.environ["BUILD_NUMBER"] elif "TRAVIS_BUILD_NUMBER" in os.environ: caps["build"] = os.environ["TRAVIS_BUILD_NUMBER"] return caps def _get_local_webdriver_class(self, specs): browsers = { "ff": "selenium.webdriver.Firefox", "op": "selenium.webdriver.Opera", "ie": "selenium.webdriver.Ie", "gc": "selenium.webdriver.Chrome", } return import_by_path(browsers[specs[:2]]) def setUp(self): test_method = getattr(self, self._testMethodName) if not hasattr(test_method, "spec"): raise SkipTest("Please make sure your test class is decorated with @browserize") elif not test_method.spec: raise SkipTest("Selenium tests not requested") try: selenium_specs = test_method.spec if os.environ.get("DJANGO_SELENIUM_REMOTE", False): webdriver_class = import_by_path("selenium.webdriver.Remote") else: webdriver_class = self._get_local_webdriver_class(selenium_specs) except Exception as e: raise SkipTest( 'Selenium specifications "%s" not valid or ' "corresponding WebDriver not installed: %s" % (selenium_specs, str(e)) ) from selenium.webdriver import Remote if webdriver_class is Remote: if not (os.environ.get("REMOTE_USER") and os.environ.get("REMOTE_KEY")): raise self.failureException( "Both REMOTE_USER and REMOTE_KEY environment variables are required for remote tests." ) capabilities = self._get_remote_capabilities(selenium_specs) capabilities["name"] = self.id() auth = "%(REMOTE_USER)s:%(REMOTE_KEY)s" % os.environ hub = os.environ.get("REMOTE_HUB", "ondemand.saucelabs.com:80") self.selenium = Remote( command_executor="http://%s@%s/wd/hub" % (auth, hub), desired_capabilities=capabilities ) else: self.selenium = webdriver_class() super(AdminSeleniumWebDriverTestCase, self).setUp() def tearDown(self): if hasattr(self, "selenium"): from selenium.webdriver import Remote if isinstance(self.selenium, Remote): self._report_sauce_pass_fail() self.selenium.quit() super(AdminSeleniumWebDriverTestCase, self).tearDown() def _report_sauce_pass_fail(self): # Sauce Labs has no way of knowing if the test passed or failed, so we # let it know. base64string = base64.encodestring("%s:%s" % (os.environ.get("REMOTE_USER"), os.environ.get("REMOTE_KEY")))[:-1] result = json.dumps({"passed": sys.exc_info() == (None, None, None)}) url = "/rest/v1/%s/jobs/%s" % (os.environ.get("REMOTE_USER"), self.selenium.session_id) connection = httplib.HTTPConnection("saucelabs.com") connection.request("PUT", url, result, headers={"Authorization": "Basic %s" % base64string}) result = connection.getresponse() return result.status == 200 def wait_until(self, callback, timeout=10): """ Helper function that blocks the execution of the tests until the specified callback returns a value that is not falsy. This function can be called, for example, after clicking a link or submitting a form. See the other public methods that call this function for more details. """ from selenium.webdriver.support.wait import WebDriverWait WebDriverWait(self.selenium, timeout).until(callback) def wait_loaded_tag(self, tag_name, timeout=10): """ Helper function that blocks until the element with the given tag name is found on the page. """ self.wait_until(lambda driver: driver.find_element_by_tag_name(tag_name), timeout) def wait_page_loaded(self): """ Block until page has started to load. """ from selenium.common.exceptions import TimeoutException try: # Wait for the next page to be loaded self.wait_loaded_tag("body") except TimeoutException: # IE7 occasionnally returns an error "Internet Explorer cannot # display the webpage" and doesn't load the next page. We just # ignore it. pass def admin_login(self, username, password, login_url="/admin/"): """ Helper function to log into the admin. """ self.selenium.get("%s%s" % (self.live_server_url, login_url)) username_input = self.selenium.find_element_by_name("username") username_input.send_keys(username) password_input = self.selenium.find_element_by_name("password") password_input.send_keys(password) login_text = _("Log in") self.selenium.find_element_by_xpath('//input[@value="%s"]' % login_text).click() self.wait_page_loaded() def get_css_value(self, selector, attribute): """ Helper function that returns the value for the CSS attribute of an DOM element specified by the given selector. Uses the jQuery that ships with Django. """ return self.selenium.execute_script('return django.jQuery("%s").css("%s")' % (selector, attribute)) def get_select_option(self, selector, value): """ Returns the <OPTION> with the value `value` inside the <SELECT> widget identified by the CSS selector `selector`. """ from selenium.common.exceptions import NoSuchElementException options = self.selenium.find_elements_by_css_selector("%s > option" % selector) for option in options: if option.get_attribute("value") == value: return option raise NoSuchElementException('Option "%s" not found in "%s"' % (value, selector)) def assertSelectOptions(self, selector, values): """ Asserts that the <SELECT> widget identified by `selector` has the options with the given `values`. """ options = self.selenium.find_elements_by_css_selector("%s > option" % selector) actual_values = [] for option in options: actual_values.append(option.get_attribute("value")) self.assertEqual(values, actual_values) def has_css_class(self, selector, klass): """ Returns True if the element identified by `selector` has the CSS class `klass`. """ return self.selenium.find_element_by_css_selector(selector).get_attribute("class").find(klass) != -1