|
| 1 | +# -*- coding: UTF-8 -*- |
| 2 | +from contextlib import contextmanager |
| 3 | +import os |
| 4 | +import unittest |
| 5 | +import subprocess |
| 6 | +import time |
| 7 | + |
| 8 | +from selenium.webdriver.support.ui import WebDriverWait |
| 9 | +from selenium.webdriver.support import expected_conditions as EC |
| 10 | +from selenium.webdriver.common.by import By |
| 11 | +from selenium.common.exceptions import NoSuchWindowException |
| 12 | + |
| 13 | +import shim |
| 14 | + |
| 15 | +SEL_DEFAULT_WAIT_TIMEOUT = 10 |
| 16 | + |
| 17 | +parse_stdout = lambda res: res.strip().decode('utf-8') |
| 18 | + |
| 19 | +run_shell_command = lambda command: parse_stdout(subprocess.check_output(command)) |
| 20 | + |
| 21 | +get_git_root = lambda: run_shell_command(['git', 'rev-parse', '--show-toplevel']) |
| 22 | + |
| 23 | + |
| 24 | +class ExtensionTestCase(unittest.TestCase): |
| 25 | + |
| 26 | + shim = shim.Shim(shim.chrome_info, shim.firefox_info) |
| 27 | + |
| 28 | + @classmethod |
| 29 | + def setUpClass(cls): |
| 30 | + cls.manager = cls.shim.manager |
| 31 | + cls.base_url = cls.shim.bg_url |
| 32 | + cls.wants_xvfb = cls.shim.wants_xvfb |
| 33 | + if cls.wants_xvfb: |
| 34 | + from xvfbwrapper import Xvfb |
| 35 | + cls.vdisplay = Xvfb(width=1280, height=720) |
| 36 | + cls.vdisplay.start() |
| 37 | + |
| 38 | + # setting DBUS_SESSION_BUS_ADDRESS to nonsense prevents frequent |
| 39 | + # hangs of chromedriver (possibly due to crbug.com/309093). |
| 40 | + os.environ["DBUS_SESSION_BUS_ADDRESS"] = "/dev/null" |
| 41 | + cls.proj_root = get_git_root() |
| 42 | + |
| 43 | + @classmethod |
| 44 | + def tearDownClass(cls): |
| 45 | + if cls.wants_xvfb: |
| 46 | + cls.vdisplay.stop() |
| 47 | + |
| 48 | + def init(self, driver): |
| 49 | + self.driver = driver |
| 50 | + self.bg_url = self.base_url + "_generated_background_page.html" |
| 51 | + |
| 52 | + def run(self, result=None): |
| 53 | + with self.manager() as driver: |
| 54 | + self.init(driver) |
| 55 | + super(ExtensionTestCase, self).run(result) |
| 56 | + |
| 57 | + def query_selector(self, css_selector, timeout=SEL_DEFAULT_WAIT_TIMEOUT): |
| 58 | + return WebDriverWait(self.driver, timeout).until( |
| 59 | + EC.visibility_of_element_located((By.CSS_SELECTOR, css_selector))) |
| 60 | + |
| 61 | + def wait(self, func, timeout=SEL_DEFAULT_WAIT_TIMEOUT): |
| 62 | + return WebDriverWait(self.driver, timeout).until(func) |
| 63 | + |
| 64 | + def switch_to_url(self, target, open_url=False): |
| 65 | + for wh in self.driver.window_handles: |
| 66 | + self.driver.switch_to.window(wh) |
| 67 | + # use `in` bc we don't care about queries or fragments |
| 68 | + if target in self.driver.current_url: |
| 69 | + return self.driver.refresh() |
| 70 | + if open_url: |
| 71 | + return self.driver.get(target) |
| 72 | + raise ValueError('Target (%s) not found in current urls' % (target,)) |
| 73 | + |
| 74 | + def get_variable(self, name): |
| 75 | + return self.driver.execute_script('return %s;' % name) |
| 76 | + |
| 77 | + @contextmanager |
| 78 | + def load_popup_for(self, url='about:blank'): |
| 79 | + create_url_and_popup_js_str = ''' |
| 80 | + (function(done) { |
| 81 | + chrome.tabs.create({url: '%s'}, function(tab) { |
| 82 | + setTimeout( |
| 83 | + () => chrome.tabs.create({url: '%s' + '?tabId=' + String(tab.id)}, done), |
| 84 | + 250 |
| 85 | + ); |
| 86 | + }); |
| 87 | + })(arguments[0]); |
| 88 | + ''' |
| 89 | + script = create_url_and_popup_js_str % (url, self.shim.popup_url) |
| 90 | + |
| 91 | + self.driver.get(self.shim.bg_url) |
| 92 | + time.sleep(0.5) |
| 93 | + |
| 94 | + bg = self.driver.current_window_handle |
| 95 | + |
| 96 | + before_windows = set(self.driver.window_handles) |
| 97 | + self.driver.execute_async_script(script) |
| 98 | + new_windows = set(self.driver.window_handles) ^ before_windows |
| 99 | + |
| 100 | + self.switch_to_url(self.shim.popup_url) |
| 101 | + |
| 102 | + yield |
| 103 | + |
| 104 | + time.sleep(0.1) |
| 105 | + for wh in new_windows: |
| 106 | + if len(self.driver.window_handles) > 1: |
| 107 | + try: |
| 108 | + self.driver.switch_to.window(wh) |
| 109 | + self.driver.close() |
| 110 | + except NoSuchWindowException: |
| 111 | + pass |
| 112 | + |
| 113 | + self.driver.switch_to.window(bg) |
| 114 | + |
| 115 | + def toggle_disabled(self): |
| 116 | + selector = '#onoffswitch' |
| 117 | + with self.load_popup_for(): |
| 118 | + el = self.query_selector(selector) |
| 119 | + el.click() |
| 120 | + time.sleep(0.25) |
| 121 | + |
| 122 | + def toggle_http_nowhere(self): |
| 123 | + selector = '#http-nowhere-checkbox' |
| 124 | + with self.load_popup_for(): |
| 125 | + el = self.query_selector(selector) |
| 126 | + el.click() |
| 127 | + time.sleep(0.25) |
0 commit comments