diff options
Diffstat (limited to 'testing/webcompat')
143 files changed, 5403 insertions, 0 deletions
diff --git a/testing/webcompat/__init__.py b/testing/webcompat/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/webcompat/__init__.py diff --git a/testing/webcompat/client.py b/testing/webcompat/client.py new file mode 100644 index 0000000000..88208e5507 --- /dev/null +++ b/testing/webcompat/client.py @@ -0,0 +1,759 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import asyncio +import contextlib +import time +from urllib.parse import quote + +import webdriver +from webdriver.bidi.modules.script import ContextTarget + + +class Client: + def __init__(self, session, event_loop): + self.session = session + self.event_loop = event_loop + self.content_blocker_loaded = False + + @property + def current_url(self): + return self.session.url + + @property + def alert(self): + return self.session.alert + + @property + def context(self): + return self.session.send_session_command("GET", "moz/context") + + @context.setter + def context(self, context): + self.session.send_session_command("POST", "moz/context", {"context": context}) + + @contextlib.contextmanager + def using_context(self, context): + orig_context = self.context + needs_change = context != orig_context + + if needs_change: + self.context = context + + try: + yield + finally: + if needs_change: + self.context = orig_context + + def wait_for_content_blocker(self): + if not self.content_blocker_loaded: + with self.using_context("chrome"): + self.session.execute_async_script( + """ + const done = arguments[0], + signal = "safebrowsing-update-finished"; + function finish() { + Services.obs.removeObserver(finish, signal); + done(); + } + Services.obs.addObserver(finish, signal); + """ + ) + self.content_blocker_loaded = True + + @property + def keyboard(self): + return self.session.actions.sequence("key", "keyboard_id") + + @property + def mouse(self): + return self.session.actions.sequence( + "pointer", "pointer_id", {"pointerType": "mouse"} + ) + + @property + def pen(self): + return self.session.actions.sequence( + "pointer", "pointer_id", {"pointerType": "pen"} + ) + + @property + def touch(self): + return self.session.actions.sequence( + "pointer", "pointer_id", {"pointerType": "touch"} + ) + + @property + def wheel(self): + return self.session.actions.sequence("wheel", "wheel_id") + + @property + def modifier_key(self): + if self.session.capabilities["platformName"] == "mac": + return "\ue03d" # meta (command) + else: + return "\ue009" # control + + def inline(self, doc): + return "data:text/html;charset=utf-8,{}".format(quote(doc)) + + async def top_context(self): + contexts = await self.session.bidi_session.browsing_context.get_tree() + return contexts[0] + + async def navigate(self, url, timeout=None, **kwargs): + return await asyncio.wait_for( + asyncio.ensure_future(self._navigate(url, **kwargs)), timeout=timeout + ) + + async def _navigate(self, url, wait="complete", await_console_message=None): + if self.session.test_config.get("use_pbm") or self.session.test_config.get( + "use_strict_etp" + ): + print("waiting for content blocker...") + self.wait_for_content_blocker() + if await_console_message is not None: + console_message = await self.promise_console_message_listener( + await_console_message + ) + if wait == "load": + page_load = await self.promise_readystate_listener("load", url=url) + try: + await self.session.bidi_session.browsing_context.navigate( + context=(await self.top_context())["context"], + url=url, + wait=wait if wait != "load" else None, + ) + except webdriver.bidi.error.UnknownErrorException as u: + m = str(u) + if ( + "NS_BINDING_ABORTED" not in m + and "NS_ERROR_ABORT" not in m + and "NS_ERROR_WONT_HANDLE_CONTENT" not in m + ): + raise u + if wait == "load": + await page_load + if await_console_message is not None: + await console_message + + async def promise_event_listener(self, events, check_fn=None, timeout=20): + if type(events) is not list: + events = [events] + + await self.session.bidi_session.session.subscribe(events=events) + + future = self.event_loop.create_future() + + listener_removers = [] + + def remove_listeners(): + for listener_remover in listener_removers: + try: + listener_remover() + except Exception: + pass + + async def on_event(method, data): + print("on_event", method, data) + val = None + if check_fn is not None: + val = check_fn(method, data) + if val is None: + return + future.set_result(val) + + for event in events: + r = self.session.bidi_session.add_event_listener(event, on_event) + listener_removers.append(r) + + async def task(): + try: + return await asyncio.wait_for(future, timeout=timeout) + finally: + remove_listeners() + try: + await asyncio.wait_for( + self.session.bidi_session.session.unsubscribe(events=events), + timeout=4, + ) + except asyncio.exceptions.TimeoutError: + print("Unexpectedly timed out unsubscribing", events) + pass + + return asyncio.create_task(task()) + + async def promise_console_message_listener(self, msg, **kwargs): + def check(method, data): + if "text" in data: + if msg in data["text"]: + return data + if "args" in data and len(data["args"]): + for arg in data["args"]: + if "value" in arg and msg in arg["value"]: + return data + + return await self.promise_event_listener("log.entryAdded", check, **kwargs) + + async def is_console_message(self, message): + try: + await (await self.promise_console_message_listener(message, timeout=2)) + return True + except asyncio.exceptions.TimeoutError: + return False + + async def promise_readystate_listener(self, state, url=None, **kwargs): + event = f"browsingContext.{state}" + + def check(method, data): + if url is None or url in data["url"]: + return data + + return await self.promise_event_listener(event, check, **kwargs) + + async def promise_frame_listener(self, url, state="domContentLoaded", **kwargs): + event = f"browsingContext.{state}" + + def check(method, data): + if url is None or url in data["url"]: + return Client.Context(self, data["context"]) + + return await self.promise_event_listener(event, check, **kwargs) + + async def find_frame_context_by_url(self, url): + def find_in(arr, url): + for context in arr: + if url in context["url"]: + return context + for context in arr: + found = find_in(context["children"], url) + if found: + return found + + return find_in([await self.top_context()], url) + + class Context: + def __init__(self, client, id): + self.client = client + self.target = ContextTarget(id) + + async def find_css(self, selector, all=False): + all = "All" if all else "" + return await self.client.session.bidi_session.script.evaluate( + expression=f"document.querySelector{all}('{selector}')", + target=self.target, + await_promise=False, + ) + + def timed_js(self, timeout, poll, fn, is_displayed=False): + return f"""() => new Promise((_good, _bad) => {{ + {self.is_displayed_js()} + var _poll = {poll} * 1000; + var _time = {timeout} * 1000; + var _done = false; + var resolve = val => {{ + if ({is_displayed}) {{ + if (val.length) {{ + val = val.filter(v = is_displayed(v)); + }} else {{ + val = is_displayed(val) && val; + }} + if (!val.length && !val.matches) {{ + return; + }} + }} + _done = true; + clearInterval(_int); + _good(val); + }}; + var reject = str => {{ + _done = true; + clearInterval(_int); + _bad(val); + }}; + var _int = setInterval(() => {{ + {fn}; + if (!_done) {{ + _time -= _poll; + if (_time <= 0) {{ + reject(); + }} + }} + }}, poll); + }})""" + + def is_displayed_js(self): + return """ + function is_displayed(e) { + const s = window.getComputedStyle(e), + v = s.visibility === "visible", + o = Math.abs(parseFloat(s.opacity)); + return e.getClientRects().length > 0 && v && (isNaN(o) || o === 1.0); + } + """ + + async def await_css( + self, + selector, + all=False, + timeout=10, + poll=0.25, + condition=False, + is_displayed=False, + ): + all = "All" if all else "" + condition = ( + f"var elem=arguments[0]; if ({condition})" if condition else False + ) + return await self.client.session.bidi_session.script.evaluate( + expression=self.timed_js( + timeout, + poll, + f""" + var ele = document.querySelector{all}('{selector}')"; + if (ele && (!"length" in ele || ele.length > 0)) {{ + '{condition}' + resolve(ele); + }} + """, + ), + target=self.target, + await_promise=True, + ) + + async def await_text(self, text, **kwargs): + xpath = f"//*[contains(text(),'{text}')]" + return await self.await_xpath(self, xpath, **kwargs) + + async def await_xpath( + self, xpath, all=False, timeout=10, poll=0.25, is_displayed=False + ): + all = "true" if all else "false" + return await self.client.session.bidi_session.script.evaluate( + expression=self.timed_js( + timeout, + poll, + """ + var ret = []; + var r, res = document.evaluate(`{xpath}`, document, null, 4); + while (r = res.iterateNext()) { + ret.push(r); + } + resolve({all} ? ret : ret[0]); + """, + ), + target=self.target, + await_promise=True, + ) + + def wrap_script_args(self, args): + if args is None: + return args + out = [] + for arg in args: + if arg is None: + out.append({"type": "undefined"}) + continue + t = type(arg) + if t == int or t == float: + out.append({"type": "number", "value": arg}) + elif t == bool: + out.append({"type": "boolean", "value": arg}) + elif t == str: + out.append({"type": "string", "value": arg}) + else: + if "type" in arg: + out.push(arg) + continue + raise ValueError(f"Unhandled argument type: {t}") + return out + + class PreloadScript: + def __init__(self, client, script, target): + self.client = client + self.script = script + if type(target) == list: + self.target = target[0] + else: + self.target = target + + def stop(self): + return self.client.session.bidi_session.script.remove_preload_script( + script=self.script + ) + + async def run(self, fn, *args, await_promise=False): + val = await self.client.session.bidi_session.script.call_function( + arguments=self.client.wrap_script_args(args), + await_promise=await_promise, + function_declaration=fn, + target=self.target, + ) + if val and "value" in val: + return val["value"] + return val + + async def make_preload_script(self, text, sandbox, args=None, context=None): + if not context: + context = (await self.top_context())["context"] + target = ContextTarget(context, sandbox) + if args is None: + text = f"() => {{ {text} }}" + script = await self.session.bidi_session.script.add_preload_script( + function_declaration=text, + arguments=self.wrap_script_args(args), + sandbox=sandbox, + ) + return Client.PreloadScript(self, script, target) + + async def await_alert(self, text): + if not hasattr(self, "alert_preload_script"): + self.alert_preload_script = await self.make_preload_script( + """ + window.__alerts = []; + window.wrappedJSObject.alert = function(text) { + window.__alerts.push(text); + } + """, + "alert_detector", + ) + return self.alert_preload_script.run( + """(msg) => new Promise(done => { + const to = setInterval(() => { + if (window.__alerts.includes(msg)) { + clearInterval(to); + done(); + } + }, 200); + }) + """, + text, + await_promise=True, + ) + + async def await_popup(self, url=None): + if not hasattr(self, "popup_preload_script"): + self.popup_preload_script = await self.make_preload_script( + """ + window.__popups = []; + window.wrappedJSObject.open = function(url) { + window.__popups.push(url); + } + """, + "popup_detector", + ) + return self.popup_preload_script.run( + """(url) => new Promise(done => { + const to = setInterval(() => { + if (url === undefined && window.__popups.length) { + clearInterval(to); + return done(window.__popups[0]); + } + const found = window.__popups.find(u => u.includes(url)); + if (found !== undefined) { + clearInterval(to); + done(found); + } + }, 1000); + }) + """, + url, + await_promise=True, + ) + + async def track_listener(self, type, selector): + if not hasattr(self, "listener_preload_script"): + self.listener_preload_script = await self.make_preload_script( + """ + window.__listeners = {}; + var proto = EventTarget.wrappedJSObject.prototype; + var def = Object.getOwnPropertyDescriptor(proto, "addEventListener"); + var old = def.value; + def.value = function(type, fn, opts) { + if ("matches" in this) { + if (!window.__listeners[type]) { + window.__listeners[type] = new Set(); + } + window.__listeners[type].add(this); + } + return old.call(this, type, fn, opts) + }; + Object.defineProperty(proto, "addEventListener", def); + """, + "listener_detector", + ) + return Client.ListenerTracker(self.listener_preload_script, type, selector) + + @contextlib.asynccontextmanager + async def preload_script(self, text, *args): + script = await self.make_preload_script(text, "preload", args=args) + yield script + await script.stop() + + def back(self): + self.session.back() + + def switch_to_frame(self, frame): + return self.session.transport.send( + "POST", + "session/{session_id}/frame".format(**vars(self.session)), + {"id": frame}, + encoder=webdriver.protocol.Encoder, + decoder=webdriver.protocol.Decoder, + session=self.session, + ) + + def switch_frame(self, frame): + self.session.switch_frame(frame) + + async def load_page_and_wait_for_iframe( + self, url, finder, loads=1, timeout=None, **kwargs + ): + while loads > 0: + await self.navigate(url, **kwargs) + frame = self.await_element(finder, timeout=timeout) + loads -= 1 + self.switch_frame(frame) + return frame + + def execute_script(self, script, *args): + return self.session.execute_script(script, args=args) + + def execute_async_script(self, script, *args, **kwargs): + return self.session.execute_async_script(script, args, **kwargs) + + def clear_all_cookies(self): + self.session.transport.send( + "DELETE", "session/%s/cookie" % self.session.session_id + ) + + def send_element_command(self, element, method, uri, body=None): + url = "element/%s/%s" % (element.id, uri) + return self.session.send_session_command(method, url, body) + + def get_element_attribute(self, element, name): + return self.send_element_command(element, "GET", "attribute/%s" % name) + + def _do_is_displayed_check(self, ele, is_displayed): + if ele is None: + return None + + if type(ele) in [list, tuple]: + return [x for x in ele if self._do_is_displayed_check(x, is_displayed)] + + if is_displayed is False and ele and self.is_displayed(ele): + return None + if is_displayed is True and ele and not self.is_displayed(ele): + return None + return ele + + def find_css(self, *args, all=False, is_displayed=None, **kwargs): + try: + ele = self.session.find.css(*args, all=all, **kwargs) + return self._do_is_displayed_check(ele, is_displayed) + except webdriver.error.NoSuchElementException: + return None + + def find_xpath(self, xpath, all=False, is_displayed=None): + route = "elements" if all else "element" + body = {"using": "xpath", "value": xpath} + try: + ele = self.session.send_session_command("POST", route, body) + return self._do_is_displayed_check(ele, is_displayed) + except webdriver.error.NoSuchElementException: + return None + + def find_text(self, text, is_displayed=None, **kwargs): + try: + ele = self.find_xpath(f"//*[contains(text(),'{text}')]", **kwargs) + return self._do_is_displayed_check(ele, is_displayed) + except webdriver.error.NoSuchElementException: + return None + + def find_element(self, finder, is_displayed=None, **kwargs): + ele = finder.find(self, **kwargs) + return self._do_is_displayed_check(ele, is_displayed) + + def await_css(self, selector, **kwargs): + return self.await_element(self.css(selector), **kwargs) + + def await_xpath(self, selector, **kwargs): + return self.await_element(self.xpath(selector), **kwargs) + + def await_text(self, selector, *args, **kwargs): + return self.await_element(self.text(selector), **kwargs) + + def await_element(self, finder, **kwargs): + return self.await_first_element_of([finder], **kwargs)[0] + + class css: + def __init__(self, selector): + self.selector = selector + + def find(self, client, **kwargs): + return client.find_css(self.selector, **kwargs) + + class xpath: + def __init__(self, selector): + self.selector = selector + + def find(self, client, **kwargs): + return client.find_xpath(self.selector, **kwargs) + + class text: + def __init__(self, selector): + self.selector = selector + + def find(self, client, **kwargs): + return client.find_text(self.selector, **kwargs) + + def await_first_element_of( + self, finders, timeout=None, delay=0.25, condition=False, **kwargs + ): + t0 = time.time() + condition = f"var elem=arguments[0]; return {condition}" if condition else False + + if timeout is None: + timeout = 10 + + found = [None for finder in finders] + + exc = None + while time.time() < t0 + timeout: + for i, finder in enumerate(finders): + try: + result = finder.find(self, **kwargs) + if result and ( + not condition + or self.session.execute_script(condition, [result]) + ): + found[i] = result + return found + except webdriver.error.NoSuchElementException as e: + exc = e + time.sleep(delay) + raise exc if exc is not None else webdriver.error.NoSuchElementException + return found + + async def dom_ready(self, timeout=None): + if timeout is None: + timeout = 20 + + async def wait(): + return self.session.execute_async_script( + """ + const cb = arguments[0]; + setInterval(() => { + if (document.readyState === "complete") { + cb(); + } + }, 500); + """ + ) + + task = asyncio.create_task(wait()) + return await asyncio.wait_for(task, timeout) + + def is_float_cleared(self, elem1, elem2): + return self.session.execute_script( + """return (function(a, b) { + // Ensure that a is placed under b (and not to its right) + return a?.offsetTop >= b?.offsetTop + b?.offsetHeight && + a?.offsetLeft < b?.offsetLeft + b?.offsetWidth; + }(arguments[0], arguments[1]));""", + elem1, + elem2, + ) + + @contextlib.contextmanager + def assert_getUserMedia_called(self): + self.execute_script( + """ + navigator.mediaDevices.getUserMedia = + navigator.mozGetUserMedia = + navigator.getUserMedia = + () => { window.__gumCalled = true; }; + """ + ) + yield + assert self.execute_script("return window.__gumCalled === true;") + + def await_element_hidden(self, finder, timeout=None, delay=0.25): + t0 = time.time() + + if timeout is None: + timeout = 20 + + elem = finder.find(self) + while time.time() < t0 + timeout: + try: + if not self.is_displayed(elem): + return + time.sleep(delay) + except webdriver.error.StaleElementReferenceException: + return + + def soft_click(self, element): + self.execute_script("arguments[0].click()", element) + + def remove_element(self, element): + self.execute_script("arguments[0].remove()", element) + + def scroll_into_view(self, element): + self.execute_script( + "arguments[0].scrollIntoView({block:'center', inline:'center', behavior: 'instant'})", + element, + ) + + @contextlib.asynccontextmanager + async def ensure_fastclick_activates(self): + fastclick_preload_script = await self.make_preload_script( + """ + var _ = document.createElement("webcompat_test"); + _.style = "position:absolute;right:-1px;width:1px;height:1px"; + document.documentElement.appendChild(_); + """, + "fastclick_forcer", + ) + yield + fastclick_preload_script.stop() + + def test_for_fastclick(self, element): + # FastClick cancels touchend, breaking default actions on Fenix. + # It instead fires a mousedown or click, which we can detect. + self.execute_script( + """ + const sel = arguments[0]; + window.fastclicked = false; + const evt = sel.nodeName === "SELECT" ? "mousedown" : "click"; + document.addEventListener(evt, e => { + if (e.target === sel && !e.isTrusted) { + window.fastclicked = true; + } + }, true); + """, + element, + ) + self.scroll_into_view(element) + # tap a few times in case the site's other code interferes + self.touch.click(element=element).perform() + self.touch.click(element=element).perform() + self.touch.click(element=element).perform() + return self.execute_script("return window.fastclicked") + + def is_displayed(self, element): + if element is None: + return False + + return self.session.execute_script( + """ + const e = arguments[0], + s = window.getComputedStyle(e), + v = s.visibility === "visible", + o = Math.abs(parseFloat(s.opacity)); + return e.getClientRects().length > 0 && v && (isNaN(o) || o === 1.0); + """, + args=[element], + ) diff --git a/testing/webcompat/config.json.sample b/testing/webcompat/config.json.sample new file mode 100644 index 0000000000..8f1b2275e0 --- /dev/null +++ b/testing/webcompat/config.json.sample @@ -0,0 +1,5 @@ +{ + "bug number 1": {"username": "name", "password": "pass"}], + "bug number 2": {"username": "name", "password": "pass"}] +} + diff --git a/testing/webcompat/fixtures.py b/testing/webcompat/fixtures.py new file mode 100644 index 0000000000..443adfae81 --- /dev/null +++ b/testing/webcompat/fixtures.py @@ -0,0 +1,255 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import asyncio +import json +import re +import subprocess + +import pytest +import webdriver + +from client import Client + +APS_PREF = "privacy.partition.always_partition_third_party_non_cookie_storage" +CB_PBM_PREF = "network.cookie.cookieBehavior.pbmode" +CB_PREF = "network.cookie.cookieBehavior" +INJECTIONS_PREF = "extensions.webcompat.perform_injections" +PBM_PREF = "browser.privatebrowsing.autostart" +PIP_OVERRIDES_PREF = "extensions.webcompat.enable_picture_in_picture_overrides" +SHIMS_PREF = "extensions.webcompat.enable_shims" +STRICT_ETP_PREF = "privacy.trackingprotection.enabled" +UA_OVERRIDES_PREF = "extensions.webcompat.perform_ua_overrides" + + +class WebDriver: + def __init__(self, config): + self.browser_binary = config.getoption("browser_binary") + self.device_serial = config.getoption("device_serial") + self.package_name = config.getoption("package_name") + self.addon = config.getoption("addon") + self.webdriver_binary = config.getoption("webdriver_binary") + self.port = config.getoption("webdriver_port") + self.wsPort = config.getoption("webdriver_ws_port") + self.headless = config.getoption("headless") + self.proc = None + + def command_line_driver(self): + raise NotImplementedError + + def capabilities(self, test_config): + raise NotImplementedError + + def __enter__(self): + assert self.proc is None + self.proc = subprocess.Popen(self.command_line_driver()) + return self + + def __exit__(self, *args, **kwargs): + self.proc.kill() + + +class FirefoxWebDriver(WebDriver): + def command_line_driver(self): + return [ + self.webdriver_binary, + "--port", + str(self.port), + "--websocket-port", + str(self.wsPort), + "-vv", + ] + + def capabilities(self, test_config): + prefs = {} + + if "aps" in test_config: + prefs[APS_PREF] = test_config["aps"] + + if "use_interventions" in test_config: + value = test_config["use_interventions"] + prefs[INJECTIONS_PREF] = value + prefs[UA_OVERRIDES_PREF] = value + prefs[PIP_OVERRIDES_PREF] = value + + if "use_pbm" in test_config: + prefs[PBM_PREF] = test_config["use_pbm"] + + if "use_shims" in test_config: + prefs[SHIMS_PREF] = test_config["use_shims"] + + if "use_strict_etp" in test_config: + prefs[STRICT_ETP_PREF] = test_config["use_strict_etp"] + + # remote/cdp/CDP.sys.mjs sets cookieBehavior to 0, + # which we definitely do not want, so set it back to 5. + cookieBehavior = 4 if test_config.get("without_tcp") else 5 + prefs[CB_PREF] = cookieBehavior + prefs[CB_PBM_PREF] = cookieBehavior + + fx_options = {"prefs": prefs} + + if self.browser_binary: + fx_options["binary"] = self.browser_binary + if self.headless: + fx_options["args"] = ["--headless"] + + if self.device_serial: + fx_options["androidDeviceSerial"] = self.device_serial + fx_options["androidPackage"] = self.package_name + + if self.addon: + prefs["xpinstall.signatures.required"] = False + prefs["extensions.experiments.enabled"] = True + + return { + "pageLoadStrategy": "normal", + "moz:firefoxOptions": fx_options, + } + + +@pytest.fixture(scope="session") +def should_do_2fa(request): + return request.config.getoption("do2fa", False) + + +@pytest.fixture(scope="session") +def config_file(request): + path = request.config.getoption("config") + if not path: + return None + with open(path) as f: + return json.load(f) + + +@pytest.fixture +def bug_number(request): + return re.findall("\d+", str(request.fspath.basename))[0] + + +@pytest.fixture +def credentials(bug_number, config_file): + if not config_file: + pytest.skip(f"login info required for bug #{bug_number}") + return None + + try: + credentials = config_file[bug_number] + except KeyError: + pytest.skip(f"no login for bug #{bug_number} found") + return + + return {"username": credentials["username"], "password": credentials["password"]} + + +@pytest.fixture(scope="session") +def driver(pytestconfig): + if pytestconfig.getoption("browser") == "firefox": + cls = FirefoxWebDriver + else: + assert False + + with cls(pytestconfig) as driver_instance: + yield driver_instance + + +@pytest.fixture(scope="session") +def event_loop(): + return asyncio.get_event_loop_policy().new_event_loop() + + +@pytest.fixture(scope="function") +async def client(session, event_loop): + return Client(session, event_loop) + + +def install_addon(session, addon_file_path): + context = session.send_session_command("GET", "moz/context") + session.send_session_command("POST", "moz/context", {"context": "chrome"}) + session.execute_async_script( + """ + const addon_file_path = arguments[0]; + const cb = arguments[1]; + const { AddonManager } = ChromeUtils.import( + "resource://gre/modules/AddonManager.jsm" + ); + const { ExtensionPermissions } = ChromeUtils.import( + "resource://gre/modules/ExtensionPermissions.jsm" + ); + const { FileUtils } = ChromeUtils.importESModule( + "resource://gre/modules/FileUtils.sys.mjs" + ); + const file = new FileUtils.File(arguments[0]); + AddonManager.installTemporaryAddon(file).then(addon => { + // also make sure the addon works in private browsing mode + const incognitoPermission = { + permissions: ["internal:privateBrowsingAllowed"], + origins: [], + }; + ExtensionPermissions.add(addon.id, incognitoPermission).then(() => { + addon.reload().then(cb); + }); + }); + """, + [addon_file_path], + ) + session.send_session_command("POST", "moz/context", {"context": context}) + + +@pytest.fixture(scope="function") +async def session(driver, test_config): + caps = driver.capabilities(test_config) + caps.update( + { + "acceptInsecureCerts": True, + "webSocketUrl": True, + } + ) + caps = {"alwaysMatch": caps} + print(caps) + + session = None + for i in range(0, 15): + try: + if not session: + session = webdriver.Session( + "localhost", driver.port, capabilities=caps, enable_bidi=True + ) + session.test_config = test_config + session.start() + break + except (ConnectionRefusedError, webdriver.error.TimeoutException): + await asyncio.sleep(0.5) + + await session.bidi_session.start() + + if driver.addon: + install_addon(session, driver.addon) + + yield session + + await session.bidi_session.end() + session.end() + + +@pytest.fixture(autouse=True) +def platform(session): + return session.capabilities["platformName"] + + +@pytest.fixture(autouse=True) +def only_platforms(bug_number, platform, request, session): + if request.node.get_closest_marker("only_platforms"): + for only in request.node.get_closest_marker("only_platforms").args: + if only == platform: + return + pytest.skip(f"Bug #{bug_number} skipped on platform ({platform})") + + +@pytest.fixture(autouse=True) +def skip_platforms(bug_number, platform, request, session): + if request.node.get_closest_marker("skip_platforms"): + for skipped in request.node.get_closest_marker("skip_platforms").args: + if skipped == platform: + pytest.skip(f"Bug #{bug_number} skipped on platform ({platform})") diff --git a/testing/webcompat/interventions/__init__.py b/testing/webcompat/interventions/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/webcompat/interventions/__init__.py diff --git a/testing/webcompat/interventions/conftest.py b/testing/webcompat/interventions/conftest.py new file mode 100644 index 0000000000..3cfd25436b --- /dev/null +++ b/testing/webcompat/interventions/conftest.py @@ -0,0 +1,56 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +from ..fixtures import * # noqa: F403 + + +def pytest_generate_tests(metafunc): + """Generate tests based on markers.""" + + if "session" not in metafunc.fixturenames: + return + + marks = [mark.name for mark in metafunc.function.pytestmark] + + otherargs = {} + argvalues = [] + ids = [] + + if "only_platforms" in marks: + for mark in metafunc.function.pytestmark: + if mark.name == "only_platforms": + otherargs["only_platforms"] = mark.args + + if "skip_platforms" in marks: + for mark in metafunc.function.pytestmark: + if mark.name == "skip_platforms": + otherargs["skip_platforms"] = mark.args + + if "with_interventions" in marks: + argvalues.append([dict({"interventions": True}, **otherargs)]) + ids.append("with_interventions") + + if "without_interventions" in marks: + argvalues.append([dict({"interventions": False}, **otherargs)]) + ids.append("without_interventions") + + metafunc.parametrize(["session"], argvalues, ids=ids, indirect=True) + + +@pytest.fixture(scope="function") # noqa: F405 +async def test_config(request, driver): + params = request.node.callspec.params.get("session") + + use_interventions = params.get("interventions") + print(f"use_interventions {use_interventions}") + if use_interventions is None: + raise ValueError( + "Missing intervention marker in %s:%s" + % (request.fspath, request.function.__name__) + ) + + return { + "use_interventions": use_interventions, + } diff --git a/testing/webcompat/interventions/pytest.ini b/testing/webcompat/interventions/pytest.ini new file mode 100644 index 0000000000..270690aed7 --- /dev/null +++ b/testing/webcompat/interventions/pytest.ini @@ -0,0 +1,7 @@ +[pytest] +console_output_style = classic +markers = + only_platforms: only run tests on specific platforms (mac, linux, windows, android) + skip_platforms: skip tests on specific platforms (mac, linux, windows, android) + with_interventions: enable web-compat interventions + without_interventions: disable web-compat interventions diff --git a/testing/webcompat/interventions/tests/__init__.py b/testing/webcompat/interventions/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/webcompat/interventions/tests/__init__.py diff --git a/testing/webcompat/interventions/tests/test_1385206_rakuten_co_jp.py b/testing/webcompat/interventions/tests/test_1385206_rakuten_co_jp.py new file mode 100644 index 0000000000..a5dec6d9d8 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1385206_rakuten_co_jp.py @@ -0,0 +1,23 @@ +import pytest + +URL = "http://www.rakuten.co.jp/" +MOBILE_CSS = "#top-area" +DESKTOP_CSS = "#header-group" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(MOBILE_CSS) + assert not client.find_css(DESKTOP_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(DESKTOP_CSS) + assert not client.find_css(MOBILE_CSS) diff --git a/testing/webcompat/interventions/tests/test_1448747_124385_drafthouse_com.py b/testing/webcompat/interventions/tests/test_1448747_124385_drafthouse_com.py new file mode 100644 index 0000000000..e212eb0991 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1448747_124385_drafthouse_com.py @@ -0,0 +1,24 @@ +import pytest + +URL = "https://drafthouse.com/food-and-drink" +SELECT_CSS = "select[name='market']" + + +async def is_fastclick_active(client): + async with client.ensure_fastclick_activates(): + await client.navigate(URL) + return client.test_for_fastclick(client.await_css(SELECT_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_fastclick_active(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_fastclick_active(client) diff --git a/testing/webcompat/interventions/tests/test_1448747_bathpublishing_com.py b/testing/webcompat/interventions/tests/test_1448747_bathpublishing_com.py new file mode 100644 index 0000000000..862664c8ea --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1448747_bathpublishing_com.py @@ -0,0 +1,33 @@ +import pytest +from webdriver.error import NoSuchElementException + +URL = "https://bathpublishing.com/products/clinical-negligence-made-clear-a-guide-for-patients-professionals" +POPUP_CSS = "button.recommendation-modal__close-button" +SELECT_CSS = "select#productSelect--product-template-option-0" + + +async def is_fastclick_active(client): + async with client.ensure_fastclick_activates(): + await client.navigate(URL) + + try: + client.soft_click(client.await_css(POPUP_CSS, timeout=3)) + client.await_element_hidden(client.css(POPUP_CSS)) + except NoSuchElementException: + pass + + return client.test_for_fastclick(client.await_css(SELECT_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_fastclick_active(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_fastclick_active(client) diff --git a/testing/webcompat/interventions/tests/test_1448747_bluetokaicoffee_com.py b/testing/webcompat/interventions/tests/test_1448747_bluetokaicoffee_com.py new file mode 100644 index 0000000000..4636b75da8 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1448747_bluetokaicoffee_com.py @@ -0,0 +1,24 @@ +import pytest + +URL = "https://bluetokaicoffee.com/collections/cold-brew-can" +SELECT_CSS = "select#SortBy" + + +async def is_fastclick_active(client): + async with client.ensure_fastclick_activates(): + await client.navigate(URL) + return client.test_for_fastclick(client.await_css(SELECT_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_fastclick_active(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_fastclick_active(client) diff --git a/testing/webcompat/interventions/tests/test_1448747_co2meter_com.py b/testing/webcompat/interventions/tests/test_1448747_co2meter_com.py new file mode 100644 index 0000000000..3e94d02a2f --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1448747_co2meter_com.py @@ -0,0 +1,41 @@ +import pytest +from webdriver.error import NoSuchElementException + +URL = "https://www.co2meter.com/collections/restaurants-food" +ITEM_CSS = "a.grid__image" +ADD_CSS = "#AddToCart" +SELECT_CSS = "select#address_country" +POPUP_CLOSE_CSS = "button.needsclick.klaviyo-close-form" + + +async def is_fastclick_active(client): + async with client.ensure_fastclick_activates(): + await client.navigate(URL) + + client.soft_click(client.await_css(ITEM_CSS)) + client.soft_click(client.await_css(ADD_CSS)) + + try: + popup_close_finder = client.css(POPUP_CLOSE_CSS) + popup_close = client.await_element(popup_close_finder, timeout=5) + if popup_close: + client.soft_click(popup_close) + client.await_element_hidden(popup_close_finder) + except NoSuchElementException: + pass + + return client.test_for_fastclick(client.await_css(SELECT_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_fastclick_active(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_fastclick_active(client) diff --git a/testing/webcompat/interventions/tests/test_1448747_discountcoffee_co_uk.py b/testing/webcompat/interventions/tests/test_1448747_discountcoffee_co_uk.py new file mode 100644 index 0000000000..6e895c923d --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1448747_discountcoffee_co_uk.py @@ -0,0 +1,24 @@ +import pytest + +URL = "https://www.discountcoffee.co.uk/collections/wholesale-coffee-beans" +SELECT_CSS = "#collection-filter-type select" + + +async def is_fastclick_active(client): + async with client.ensure_fastclick_activates(): + await client.navigate(URL) + return client.test_for_fastclick(client.await_css(SELECT_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_fastclick_active(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_fastclick_active(client) diff --git a/testing/webcompat/interventions/tests/test_1448747_dylantalkstone_com.py b/testing/webcompat/interventions/tests/test_1448747_dylantalkstone_com.py new file mode 100644 index 0000000000..cf271fb91e --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1448747_dylantalkstone_com.py @@ -0,0 +1,24 @@ +import pytest + +URL = "https://dylantalkstone.com/collections/tele-pickups/products/flat-6-tele-pickups" +SELECT_CSS = "select#productSelect-option-0" + + +async def is_fastclick_active(client): + async with client.ensure_fastclick_activates(): + await client.navigate(URL) + return client.test_for_fastclick(client.await_css(SELECT_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_fastclick_active(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_fastclick_active(client) diff --git a/testing/webcompat/interventions/tests/test_1448747_fourbarrelcoffee_com.py b/testing/webcompat/interventions/tests/test_1448747_fourbarrelcoffee_com.py new file mode 100644 index 0000000000..7ac39c05d1 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1448747_fourbarrelcoffee_com.py @@ -0,0 +1,24 @@ +import pytest + +URL = "https://www.fourbarrelcoffee.com/" +ADD_TO_CART_CSS = "#container a#menu-link" + + +async def is_fastclick_active(client): + async with client.ensure_fastclick_activates(): + await client.navigate(URL) + return client.test_for_fastclick(client.await_css(ADD_TO_CART_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_fastclick_active(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_fastclick_active(client) diff --git a/testing/webcompat/interventions/tests/test_1448747_franmar_com.py b/testing/webcompat/interventions/tests/test_1448747_franmar_com.py new file mode 100644 index 0000000000..8667f094df --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1448747_franmar_com.py @@ -0,0 +1,24 @@ +import pytest + +URL = "https://products.franmar.com/collections/consumer-products/" +SELECT_CSS = "#sortBy" + + +async def is_fastclick_active(client): + async with client.ensure_fastclick_activates(): + await client.navigate(URL) + return client.test_for_fastclick(client.await_css(SELECT_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_fastclick_active(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_fastclick_active(client) diff --git a/testing/webcompat/interventions/tests/test_1448747_renewd_com_au.py b/testing/webcompat/interventions/tests/test_1448747_renewd_com_au.py new file mode 100644 index 0000000000..0ebc2025ab --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1448747_renewd_com_au.py @@ -0,0 +1,24 @@ +import pytest + +URL = "https://renewd.com.au" +ADD_TO_CART_CSS = "button[id].btn.add_to_cart" + + +async def is_fastclick_active(client): + async with client.ensure_fastclick_activates(): + await client.navigate(URL) + return client.test_for_fastclick(client.await_css(ADD_TO_CART_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_fastclick_active(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_fastclick_active(client) diff --git a/testing/webcompat/interventions/tests/test_1448747_thehawksmoor_com.py b/testing/webcompat/interventions/tests/test_1448747_thehawksmoor_com.py new file mode 100644 index 0000000000..eecfc8a9c3 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1448747_thehawksmoor_com.py @@ -0,0 +1,32 @@ +import pytest +from webdriver.error import NoSuchElementException + +URL = "https://thehawksmoor.com/book-a-table/?location=11335" +POPUP_CSS = ".pum-overlay button.pum-close" +SELECT_CSS = "select#booktable_restaurants" + + +async def is_fastclick_active(client): + async with client.ensure_fastclick_activates(): + await client.navigate(URL) + + try: + client.soft_click(client.await_css(POPUP_CSS, timeout=3)) + except NoSuchElementException: + pass + + return client.test_for_fastclick(client.await_css(SELECT_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_fastclick_active(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_fastclick_active(client) diff --git a/testing/webcompat/interventions/tests/test_1452707_absa.py b/testing/webcompat/interventions/tests/test_1452707_absa.py new file mode 100644 index 0000000000..a7e3c4d0fc --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1452707_absa.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://ib.absa.co.za/absa-online/login.jsp" +UNSUPPORTED_ALERT = "Browser unsupported" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.find_css("html.gecko") + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + alert = await client.await_alert(UNSUPPORTED_ALERT) + await client.navigate(URL) + await alert + assert client.find_css("html.unknown") diff --git a/testing/webcompat/interventions/tests/test_1457335_histography.py b/testing/webcompat/interventions/tests/test_1457335_histography.py new file mode 100644 index 0000000000..af87ca43aa --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1457335_histography.py @@ -0,0 +1,20 @@ +import pytest + +URL = "http://histography.io/" +SUPPORT_URL = "http://histography.io/browser_support.htm" + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL, wait="load") + assert client.current_url == URL + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL, wait="load") + assert client.current_url == SUPPORT_URL diff --git a/testing/webcompat/interventions/tests/test_1472075_bankofamerica.py b/testing/webcompat/interventions/tests/test_1472075_bankofamerica.py new file mode 100644 index 0000000000..d49c141c46 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1472075_bankofamerica.py @@ -0,0 +1,19 @@ +import pytest + +URL = "https://www.bankofamerica.com/" + + +@pytest.mark.asyncio +@pytest.mark.skip_platforms("android", "windows") +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert not client.find_css("#browserUpgradeNoticeBar") + + +@pytest.mark.asyncio +@pytest.mark.skip_platforms("android", "windows") +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.is_displayed(client.await_css("#browserUpgradeNoticeBar")) diff --git a/testing/webcompat/interventions/tests/test_1509873_viewer_zmags_com.py b/testing/webcompat/interventions/tests/test_1509873_viewer_zmags_com.py new file mode 100644 index 0000000000..50a48f1ccd --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1509873_viewer_zmags_com.py @@ -0,0 +1,21 @@ +import pytest + +URL = "https://secure.viewer.zmags.com/services/htmlviewer/content/ddc3f3b9?pubVersion=46&locale=en&viewerID=85cfd72f#/ddc3f3b9/1" +BLOCKED_TEXT = "This browser is not supported" +UNBLOCKED_CSS = "#viewer .MainViewEnabled" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(UNBLOCKED_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_text(BLOCKED_TEXT) diff --git a/testing/webcompat/interventions/tests/test_1570108_steamcommunity.py b/testing/webcompat/interventions/tests/test_1570108_steamcommunity.py new file mode 100644 index 0000000000..e76f6cabaf --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1570108_steamcommunity.py @@ -0,0 +1,122 @@ +import pytest + +URL = "https://steamcommunity.com/chat" + + +USERID_CSS = "input[type='text'][class*='newlogindialog']" +PASSWORD_CSS = "input[type='password'][class*='newlogindialog']" +SIGNIN_CSS = "button[type='submit'][class*='newlogindialog']" +GEAR_CSS = ".friendListButton" +LOGIN_FAIL_XPATH = ( + "//*[contains(text(), 'try again') and " "contains(@class, 'FormError')]" +) +AUTH_CSS = "[class*='newlogindialog_ProtectingAccount']" +AUTH_DIGITS_CSS = "[class*='segmentedinputs_SegmentedCharacterInput'] input.Focusable" +AUTH_RETRY_CSS = "[class*='newlogindialog_FormError']" +AUTH_RETRY_LOADER_CSS = "[class*='newlogindialog_Loading']" +RATE_TEXT = "too many login failures" +VOICE_XPATH = ( + "//*[contains(text(), 'Voice') and " + "contains(@class, 'pagedsettings_PagedSettingsDialog_PageListItem')]" +) +MIC_BUTTON_CSS = "button.LocalMicTestButton" +UNSUPPORTED_TEXT = "currently unsupported in Firefox" + + +async def do_2fa(client): + digits = client.await_css(AUTH_DIGITS_CSS, all=True) + assert len(digits) > 0 + + loader = client.css(AUTH_RETRY_LOADER_CSS) + if client.find_element(loader): + client.await_element_hidden(loader) + for digit in digits: + if digit.property("value"): + digit.send_keys("\ue003") # backspace + + code = input("**** Enter two-factor authentication code: ") + for i, digit in enumerate(code): + if len(digits) > i: + digits[i].send_keys(digit) + + client.await_element(loader, timeout=10) + client.await_element_hidden(loader) + + +async def load_mic_test(client, credentials, should_do_2fa): + await client.navigate(URL) + + async def login(): + userid = client.await_css(USERID_CSS) + password = client.find_css(PASSWORD_CSS) + submit = client.find_css(SIGNIN_CSS) + assert client.is_displayed(userid) + assert client.is_displayed(password) + assert client.is_displayed(submit) + + userid.send_keys(credentials["username"]) + password.send_keys(credentials["password"]) + submit.click() + + await login() + + while True: + auth, retry, gear, fail, rate = client.await_first_element_of( + [ + client.css(AUTH_CSS), + client.css(AUTH_RETRY_CSS), + client.css(GEAR_CSS), + client.xpath(LOGIN_FAIL_XPATH), + client.text(RATE_TEXT), + ], + is_displayed=True, + timeout=20, + ) + + if retry: + await do_2fa(client) + continue + + if rate: + pytest.skip( + "Too many Steam login attempts in a short time; try again later." + ) + return None + elif auth: + if should_do_2fa: + await do_2fa(client) + continue + + pytest.skip( + "Two-factor authentication requested; disable Steam Guard" + " or run this test with --do-2fa to live-input codes" + ) + return None + elif fail: + pytest.skip("Invalid login provided.") + return None + else: + break + + assert gear + gear.click() + + voice = client.await_xpath(VOICE_XPATH, is_displayed=True) + voice.click() + + mic_test = client.await_css(MIC_BUTTON_CSS, is_displayed=True) + return mic_test + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client, credentials, should_do_2fa): + mic_test = await load_mic_test(client, credentials, should_do_2fa) + if not mic_test: + return + + with client.assert_getUserMedia_called(): + mic_test.click() + + assert not client.find_text(UNSUPPORTED_TEXT) diff --git a/testing/webcompat/interventions/tests/test_1570328_developer_apple_com.py b/testing/webcompat/interventions/tests/test_1570328_developer_apple_com.py new file mode 100644 index 0000000000..c40b530a62 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1570328_developer_apple_com.py @@ -0,0 +1,29 @@ +import pytest + +URL = "https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/AboutBundles/AboutBundles.html" +TOC_CSS = "#toc" + + +def toc_is_onscreen(client): + assert client.await_css(TOC_CSS, is_displayed=True) + return client.execute_script( + """ + return document.querySelector("#toc").getBoundingClientRect().left >= 0; + """ + ) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert toc_is_onscreen(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert not toc_is_onscreen(client) diff --git a/testing/webcompat/interventions/tests/test_1574522_enuri_com.py b/testing/webcompat/interventions/tests/test_1574522_enuri_com.py new file mode 100644 index 0000000000..156d2b2f36 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1574522_enuri_com.py @@ -0,0 +1,23 @@ +import pytest + +# The site puts an exclamation mark in front of width="703" +# for Chrome UAs, but not for Firefox. + +URL = "http://enuri.com/knowcom/detail.jsp?kbno=474985" +CHECK_CSS = "td[width='703']" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert not client.find_css(CHECK_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.find_css(CHECK_CSS) diff --git a/testing/webcompat/interventions/tests/test_1575000_lloydsbank.py b/testing/webcompat/interventions/tests/test_1575000_lloydsbank.py new file mode 100644 index 0000000000..cfa3d18d87 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1575000_lloydsbank.py @@ -0,0 +1,53 @@ +import pytest +from webdriver.error import NoSuchElementException + +URL = ( + "https://apply.lloydsbank.co.uk/sales-content/cwa/l/pca/index-app.html" + "?product=classicaccountLTB" +) + +NO_CSS = "[data-selector='existingCustomer-toggle-button-no']" +CONT_CSS = "[data-selector='ib-yes-continue-without-login-not-existing-customer-continue-button']" +CONT2_CSS = "[data-selector='beforeYouStart-continue-button']" +RADIO_CSS = "[name='aboutYou-gender-radio'] + span" +ACCEPT_COOKIES_CSS = "#lbganalyticsCookies button#accept" + + +async def get_radio_position(client): + loadedProperly = False + for i in range(0, 10): + await client.navigate(URL, wait="none") + try: + loadedProperly = client.await_css(NO_CSS, timeout=3) + except NoSuchElementException: + continue + accept = client.find_css(ACCEPT_COOKIES_CSS) + if accept: + accept.click() + client.await_css(NO_CSS).click() + client.await_css(NO_CSS).click() + client.await_css(CONT_CSS).click() + client.await_css(CONT2_CSS).click() + break + if not loadedProperly: + pytest.xfail("The website seems to not be loading properly") + return False + radio = client.await_css(RADIO_CSS) + return client.execute_script( + """ + return window.getComputedStyle(arguments[0]).position; + """, + radio, + ) + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert "relative" == await get_radio_position(client) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert "relative" != await get_radio_position(client) diff --git a/testing/webcompat/interventions/tests/test_1577267_metfone_com_kh.py b/testing/webcompat/interventions/tests/test_1577267_metfone_com_kh.py new file mode 100644 index 0000000000..3cc4870b42 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1577267_metfone_com_kh.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.metfone.com.kh/en/4g-lte" +DESKTOP_CSS = "section.quickLinks" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert not client.find_css(DESKTOP_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.find_css(DESKTOP_CSS) diff --git a/testing/webcompat/interventions/tests/test_1577519_stream_directv_com.py b/testing/webcompat/interventions/tests/test_1577519_stream_directv_com.py new file mode 100644 index 0000000000..fde07de470 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1577519_stream_directv_com.py @@ -0,0 +1,37 @@ +import pytest + +URL = "https://stream.directv.com/" +LOGIN_CSS = "#userID" +UNSUPPORTED_CSS = ".title-new-browse-ff" +DENIED_XPATH = "//h1[text()='Access Denied']" + + +async def check_site(client, should_pass): + await client.navigate(URL) + + denied, login, unsupported = client.await_first_element_of( + [ + client.xpath(DENIED_XPATH), + client.css(LOGIN_CSS), + client.css(UNSUPPORTED_CSS), + ], + is_displayed=True, + ) + + if denied: + pytest.skip("Region-locked, cannot test. Try using a VPN set to USA.") + return + + assert (should_pass and login) or (not should_pass and unsupported) + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await check_site(client, should_pass=True) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await check_site(client, should_pass=False) diff --git a/testing/webcompat/interventions/tests/test_1579159_m_tailieu_vn.py b/testing/webcompat/interventions/tests/test_1579159_m_tailieu_vn.py new file mode 100644 index 0000000000..59f48097f3 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1579159_m_tailieu_vn.py @@ -0,0 +1,26 @@ +import pytest + +URL = ( + "https://m.tailieu.vn/index/mobile/id/1654340/hash/654d7ea9c2853e5be07e2c792ea7f168" +) +PAGE_CSS = "#viewer > #pageContainer1" +OK_ERROR_CSS = "#errorMessage" +ERROR_MSG = "may not load data from http://tailieu.vn/html5/pdf.js" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + page, ok_error = client.await_first_element_of( + [client.css(PAGE_CSS), client.css(OK_ERROR_CSS)], is_displayed=True + ) + assert page or ok_error + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL, await_console_message=ERROR_MSG) diff --git a/testing/webcompat/interventions/tests/test_1582582_sling_com.py b/testing/webcompat/interventions/tests/test_1582582_sling_com.py new file mode 100644 index 0000000000..71f6910af9 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1582582_sling_com.py @@ -0,0 +1,26 @@ +import pytest + +URL = "https://watch.sling.com/" +INCOMPATIBLE_CSS = "[class*='unsupported-browser']" +LOADER_CSS = ".loader-container" +VPN_TEXT = "ONLY AVAILABLE INSIDE THE US" + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + loader, vpn = client.await_first_element_of( + [client.css(LOADER_CSS), client.text(VPN_TEXT)], timeout=20 + ) + assert loader or vpn + assert not client.find_css(INCOMPATIBLE_CSS) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(INCOMPATIBLE_CSS, timeout=2000) diff --git a/testing/webcompat/interventions/tests/test_1595215_uniqlo_com.py b/testing/webcompat/interventions/tests/test_1595215_uniqlo_com.py new file mode 100644 index 0000000000..f87f8349b0 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1595215_uniqlo_com.py @@ -0,0 +1,21 @@ +import pytest + +URL = "https://store-kr.uniqlo.com/" +REDIRECT_CSS = "[onload='javascript:redirectPage();']" +APP_CSS = "uni-root" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(APP_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(REDIRECT_CSS) diff --git a/testing/webcompat/interventions/tests/test_1610026_mobilesuica.py b/testing/webcompat/interventions/tests/test_1610026_mobilesuica.py new file mode 100644 index 0000000000..444fe8471f --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1610026_mobilesuica.py @@ -0,0 +1,49 @@ +import pytest + +ADDRESS_CSS = "input[name=MailAddress]" +PASSWORD_CSS = "input[name=Password]" +CLOSE_BUTTON_CSS = "input[name=winclosebutton]" +UNAVAILABLE_TEXT = "時間をお確かめの上、再度実行してください。" +UNSUPPORTED_TEXT = "ご利用のブラウザでは正しく" + + +async def load_site(client): + await client.navigate("https://www.mobilesuica.com/") + + address = client.find_css(ADDRESS_CSS) + password = client.find_css(PASSWORD_CSS) + error1 = client.find_css(CLOSE_BUTTON_CSS) + error2 = client.find_text(UNSUPPORTED_TEXT) + + # The page can be down at certain times, making testing impossible. For instance: + # "モバイルSuicaサービスが可能な時間は4:00~翌日2:00です。 + # 時間をお確かめの上、再度実行してください。" + # "Mobile Suica service is available from 4:00 to 2:00 the next day. + # Please check the time and try again." + site_is_down = client.find_text(UNAVAILABLE_TEXT) + if site_is_down is not None: + pytest.xfail("Site is currently down") + + return address, password, error1 or error2, site_is_down + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + address, password, error, site_is_down = await load_site(client) + if site_is_down: + return + assert client.is_displayed(address) + assert client.is_displayed(password) + assert error is None + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + address, password, error, site_is_down = await load_site(client) + if site_is_down: + return + assert address is None + assert password is None + assert client.is_displayed(error) diff --git a/testing/webcompat/interventions/tests/test_1610344_directv_com_co.py b/testing/webcompat/interventions/tests/test_1610344_directv_com_co.py new file mode 100644 index 0000000000..ec74d4609f --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1610344_directv_com_co.py @@ -0,0 +1,55 @@ +import pytest + +URL = "https://www.directv.com.co/" +IFRAME_CSS = "#main-iframe" +INCOMPATIBLE_CSS = ".browser-compatible.compatible.incompatible" +BLOCKED_TEXT = "blocked by the security rules" +DENIED_TEXT = "not available in your region" +FORBIDDEN_TEXT = "403 Forbidden" +CAPTCHA_CSS = "img[src*='https://captcha.perfdrive.com/']" + + +async def check_unsupported_visibility(client, should_show): + await client.navigate(URL) + + # their region-block page sometimes wraps the content in an iframe + frame = client.find_css(IFRAME_CSS) + if frame: + client.switch_frame(frame) + + denied, blocked, forbidden, captcha, incompatible = client.await_first_element_of( + [ + client.text(DENIED_TEXT), + client.text(BLOCKED_TEXT), + client.text(FORBIDDEN_TEXT), + client.css(CAPTCHA_CSS), + client.css(INCOMPATIBLE_CSS), + ] + ) + + if captcha: + pytest.skip( + "Got a Captcha page. Please visit https://www.directv.com.co/, pass the captcha, and re-run this test." + ) + return + + if denied or blocked or forbidden: + pytest.skip("Region-locked, cannot test. Try using a VPN set to USA.") + return + + shown = client.is_displayed(incompatible) + assert (should_show and shown) or (not should_show and not shown) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await check_unsupported_visibility(client, should_show=False) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await check_unsupported_visibility(client, should_show=True) diff --git a/testing/webcompat/interventions/tests/test_1622063_wp1-ext_usps_gov.py b/testing/webcompat/interventions/tests/test_1622063_wp1-ext_usps_gov.py new file mode 100644 index 0000000000..e55adf0dbe --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1622063_wp1-ext_usps_gov.py @@ -0,0 +1,21 @@ +import pytest + +URL = "https://wp1-ext.usps.gov/sap/bc/webdynpro/sap/hrrcf_a_unreg_job_search" +BLOCKED_TEXT = "This browser is not supported" +UNBLOCKED_CSS = "#sapwd_main_window_root_" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(UNBLOCKED_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_text(BLOCKED_TEXT) diff --git a/testing/webcompat/interventions/tests/test_1631811_datastudio.py b/testing/webcompat/interventions/tests/test_1631811_datastudio.py new file mode 100644 index 0000000000..adb68d9e20 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1631811_datastudio.py @@ -0,0 +1,40 @@ +import pytest + +# the problem is intermittent, so we have to try loading the page a few times +# and check whether a SecurityError was thrown by any of them, and that text +# in the iframe didn't load in order to be relatively sure that it failed. +# The problem seems even more intermittent on Android, so not running there. + + +URL = "https://ageor.dipot.com/2020/03/Covid-19-in-Greece.html" +FRAME_FINAL_URL = "lookerstudio.google.com/embed/reporting/" +FRAME_TEXT = "Coranavirus SARS-CoV-2 (Covid-19) in Greece" +FAIL_CONSOLE_MSG = "SecurityError" + + +async def checkFrameFailsToLoadForAnyAttempt(client, timeout=10): + for i in range(5): + promise = await client.promise_frame_listener(FRAME_FINAL_URL, timeout=timeout) + await client.navigate(URL, wait="none") + frame = await promise + if frame is None: + return True + if not await frame.await_text(FRAME_TEXT, is_displayed=True, timeout=5): + return True + if await client.is_console_message(FAIL_CONSOLE_MSG): + return True + return False + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await checkFrameFailsToLoadForAnyAttempt(client, timeout=None) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await checkFrameFailsToLoadForAnyAttempt(client) diff --git a/testing/webcompat/interventions/tests/test_1644830_missingmail_usps.py b/testing/webcompat/interventions/tests/test_1644830_missingmail_usps.py new file mode 100644 index 0000000000..39a2db683a --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1644830_missingmail_usps.py @@ -0,0 +1,63 @@ +import pytest + +URL = ( + "https://missingmail.usps.com/?_gl=1*veidlp*_gcl_aw*R0NMLjE1OTE3MjUyNTkuRUF" + "JYUlRb2JDaE1Jd3AzaTBhYjE2UUlWa01EQUNoMlBBUVlrRUFBWUFTQUFFZ0lMeFBEX0J3RQ..*" + "_gcl_dc*R0NMLjE1OTE3MjUyNTkuRUFJYUlRb2JDaE1Jd3AzaTBhYjE2UUlWa01EQUNoMlBBUV" + "lrRUFBWUFTQUFFZ0lMeFBEX0J3RQ..#/" +) + +USERNAME_CSS = "#username" +PASSWORD_CSS = "#password" +SIGN_IN_CSS = "#btn-submit" +TERMS_CHECKBOX_CSS = "#tc-checkbox" +TERMS_FAUX_CHECKBOX_CSS = "#tc-checkbox + .mrc-custom-checkbox" + +# The USPS missing mail website takes a very long time to load (multiple +# minutes). We give them a very generous amount of time here, but will +# give up after that and just skip the rest of the test. +TIMEOUT = 900 +TIMEOUT_MESSAGE = "USPS website is too slow, skipping test" + + +async def are_checkboxes_clickable(client, credentials): + await client.navigate(URL) + + username = client.await_css(USERNAME_CSS) + password = client.find_css(PASSWORD_CSS) + sign_in = client.find_css(SIGN_IN_CSS) + assert client.is_displayed(username) + assert client.is_displayed(password) + assert client.is_displayed(sign_in) + + username.send_keys(credentials["username"]) + password.send_keys(credentials["password"]) + sign_in.click() + + tc = client.await_css(TERMS_CHECKBOX_CSS, timeout=TIMEOUT) + if tc is None: + pytest.skip(TIMEOUT_MESSAGE) + return + + assert not tc.selected + + # we need to simulate a real click on the checkbox + tfc = client.find_css(TERMS_FAUX_CHECKBOX_CSS) + await client.dom_ready() + client.execute_script("arguments[0].scrollIntoView(true)", tfc) + client.mouse.click(tfc).perform() + return tc.selected + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client, credentials): + assert await are_checkboxes_clickable(client, credentials) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client, credentials): + assert not await are_checkboxes_clickable(client, credentials) diff --git a/testing/webcompat/interventions/tests/test_1650317_livescience_com.py b/testing/webcompat/interventions/tests/test_1650317_livescience_com.py new file mode 100644 index 0000000000..f9cb71c571 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1650317_livescience_com.py @@ -0,0 +1,40 @@ +import pytest + +URL = "https://www.livescience.com/" +TEXT_TO_TEST = ".trending__link" + + +async def is_text_visible(client): + # the page does not properly load, so we just time out + # and wait for the element we're interested in to appear + await client.navigate(URL, timeout=1) + link = client.await_css(TEXT_TO_TEST) + assert client.is_displayed(link) + return client.execute_async_script( + """ + const link = arguments[0]; + const cb = arguments[1]; + const fullHeight = link.scrollHeight; + const parentVisibleHeight = link.parentElement.clientHeight; + link.style.paddingBottom = "0"; + window.requestAnimationFrame(() => { + const bottomPaddingHeight = fullHeight - link.scrollHeight; + cb(fullHeight - parentVisibleHeight <= bottomPaddingHeight); + }); + """, + link, + ) + + +@pytest.mark.skip_platforms("android", "mac") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert await is_text_visible(client) + + +@pytest.mark.skip_platforms("android", "mac") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert not await is_text_visible(client) diff --git a/testing/webcompat/interventions/tests/test_1651292_www_jp_square-enix_com.py b/testing/webcompat/interventions/tests/test_1651292_www_jp_square-enix_com.py new file mode 100644 index 0000000000..d8c7844c54 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1651292_www_jp_square-enix_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.jp.square-enix.com/music/sem/page/FF7R/ost/" +ERROR_MSG = 'can\'t access property "slice", e.match(...) is null' +UNBLOCKED_CSS = "h1.logo.visible" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(UNBLOCKED_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL, await_console_message=ERROR_MSG) diff --git a/testing/webcompat/interventions/tests/test_1651917_www_teletrader_com.py b/testing/webcompat/interventions/tests/test_1651917_www_teletrader_com.py new file mode 100644 index 0000000000..deda666ebb --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1651917_www_teletrader_com.py @@ -0,0 +1,27 @@ +import pytest + +URL = "https://www.teletrader.com/" + + +def body_is_offscreen(client): + return client.execute_script( + """ + return document.body.getBoundingClientRect().left > 0; + """ + ) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert not body_is_offscreen(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert body_is_offscreen(client) diff --git a/testing/webcompat/interventions/tests/test_1654877_preev_com.py b/testing/webcompat/interventions/tests/test_1654877_preev_com.py new file mode 100644 index 0000000000..398dd8b6e3 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1654877_preev_com.py @@ -0,0 +1,32 @@ +import pytest + +URL = "http://preev.com/" +INPUT_CSS = "#invField" + + +def no_number_arrows_appear(client): + inp = client.await_css(INPUT_CSS, is_displayed=True) + assert inp + inp.click() + return client.execute_script( + """ + return getComputedStyle(arguments[0]).appearance == "textfield"; + """, + inp, + ) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert no_number_arrows_appear(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert not no_number_arrows_appear(client) diff --git a/testing/webcompat/interventions/tests/test_1654907_reactine_ca.py b/testing/webcompat/interventions/tests/test_1654907_reactine_ca.py new file mode 100644 index 0000000000..6b277db8c0 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1654907_reactine_ca.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.reactine.ca/products/" +BANNER_CSS = "#browser-alert" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(BANNER_CSS, is_displayed=False) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(BANNER_CSS, is_displayed=True) diff --git a/testing/webcompat/interventions/tests/test_1694470_m_myvidster_com.py b/testing/webcompat/interventions/tests/test_1694470_m_myvidster_com.py new file mode 100644 index 0000000000..1daec3fa83 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1694470_m_myvidster_com.py @@ -0,0 +1,31 @@ +import pytest + +URL = "https://m.myvidster.com/" +CONTAINER_CSS = "#home_refresh_var" + + +def content_is_cropped(client): + container = client.await_css(CONTAINER_CSS, is_displayed=True) + assert container + return client.execute_script( + """ + return arguments[0].clientHeight < 100 + """, + container, + ) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert not content_is_cropped(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert content_is_cropped(client) diff --git a/testing/webcompat/interventions/tests/test_1697324_mobile2_bmo_com.py b/testing/webcompat/interventions/tests/test_1697324_mobile2_bmo_com.py new file mode 100644 index 0000000000..72f3e16fa5 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1697324_mobile2_bmo_com.py @@ -0,0 +1,21 @@ +import pytest + +URL = "https://mobile2.bmo.com/" +BLOCKED_TEXT = "This browser is out-of-date" +UNBLOCKED_CSS = "auth-field" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(UNBLOCKED_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_text(BLOCKED_TEXT) diff --git a/testing/webcompat/interventions/tests/test_1704673_app_xiaomi_com.py b/testing/webcompat/interventions/tests/test_1704673_app_xiaomi_com.py new file mode 100644 index 0000000000..14f32373fe --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1704673_app_xiaomi_com.py @@ -0,0 +1,24 @@ +import pytest +from webdriver.bidi.error import UnknownErrorException + +# This site fails with a redirect loop with a Firefox UA + +URL = "http://app.xiaomi.com/" +REDIR_FAILURE_EXC = r".*NS_ERROR_REDIRECT_LOOP.*" +SUCCESS_CSS = "#J_mingleList" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(SUCCESS_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + with pytest.raises(UnknownErrorException, match=REDIR_FAILURE_EXC): + await client.navigate(URL, timeout=15) diff --git a/testing/webcompat/interventions/tests/test_1712807_www_dealnews_com.py b/testing/webcompat/interventions/tests/test_1712807_www_dealnews_com.py new file mode 100644 index 0000000000..d33bc01a76 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1712807_www_dealnews_com.py @@ -0,0 +1,31 @@ +import pytest + +URL = "https://www.dealnews.com/" + + +# The page sets the style.width of images too wide on +# Firefox, making the page wider than the viewport + + +def is_wider_than_window(client): + return client.execute_script( + """ + return document.body.scrollWidth > document.body.clientWidth; + """ + ) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert not is_wider_than_window(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert is_wider_than_window(client) diff --git a/testing/webcompat/interventions/tests/test_1712833_desuca.py b/testing/webcompat/interventions/tests/test_1712833_desuca.py new file mode 100644 index 0000000000..60796fa54f --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1712833_desuca.py @@ -0,0 +1,18 @@ +import pytest + +URL = "https://buskocchi.desuca.co.jp/smartPhone.html" +SCRIPT = "return document.getElementById('map_canvas')?.clientHeight" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.execute_script(SCRIPT) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.execute_script(SCRIPT) diff --git a/testing/webcompat/interventions/tests/test_1719859_saxoinvestor.py b/testing/webcompat/interventions/tests/test_1719859_saxoinvestor.py new file mode 100644 index 0000000000..c46259b150 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1719859_saxoinvestor.py @@ -0,0 +1,28 @@ +import pytest + +URL = ( + "https://www.saxoinvestor.fr/login/?adobe_mc=" + "MCORGID%3D173338B35278510F0A490D4C%2540AdobeOrg%7CTS%3D1621688498" +) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + userid = client.find_css("input#field_userid") + password = client.find_css("input#field_password") + submit = client.find_css("input#button_login") + assert client.is_displayed(userid) + assert client.is_displayed(password) + assert client.is_displayed(submit) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + warning = client.find_css("#browser_support_section") + assert client.is_displayed(warning) diff --git a/testing/webcompat/interventions/tests/test_1722954_granbluefantasy_jp.py b/testing/webcompat/interventions/tests/test_1722954_granbluefantasy_jp.py new file mode 100644 index 0000000000..93fdf940b7 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1722954_granbluefantasy_jp.py @@ -0,0 +1,27 @@ +import pytest + +URL = "https://game.granbluefantasy.jp/" + + +def content_is_full_width(client): + return client.execute_script( + """ + return document.querySelector("#wrapper").offsetWidth == document.body.clientWidth; + """ + ) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert content_is_full_width(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert not content_is_full_width(client) diff --git a/testing/webcompat/interventions/tests/test_1722955_frontgate_com.py b/testing/webcompat/interventions/tests/test_1722955_frontgate_com.py new file mode 100644 index 0000000000..1b33259b58 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1722955_frontgate_com.py @@ -0,0 +1,26 @@ +import pytest + +URL = "https://www.frontgate.com/resort-cotton-bath-towels/155771" +MOBILE_CSS = "#app" +DESKTOP_CSS = "#cbiBody" + +# Note that this intervention doesn't seem to work 100% of +# the time so this test may intermittently fail. + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(MOBILE_CSS, timeout=30) + assert not client.find_css(DESKTOP_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(DESKTOP_CSS, timeout=30) + assert not client.find_css(MOBILE_CSS) diff --git a/testing/webcompat/interventions/tests/test_1738317_vmos_cn.py b/testing/webcompat/interventions/tests/test_1738317_vmos_cn.py new file mode 100644 index 0000000000..275b8b453d --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1738317_vmos_cn.py @@ -0,0 +1,23 @@ +import pytest + +URL = "https://www.vmos.cn/" +MOBILE_CSS = ".bg_wave_blue" +DESKTOP_CSS = "#content" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(MOBILE_CSS) + assert not client.find_css(DESKTOP_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(DESKTOP_CSS) + assert not client.find_css(MOBILE_CSS) diff --git a/testing/webcompat/interventions/tests/test_1738319_yebocasino_co_za.py b/testing/webcompat/interventions/tests/test_1738319_yebocasino_co_za.py new file mode 100644 index 0000000000..6b09cbec87 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1738319_yebocasino_co_za.py @@ -0,0 +1,29 @@ +import pytest + +URL = "https://www.yebocasino.co.za/webplay/" +PRACTICE_CSS = "#lobbybox_featuredgames .gamebox .cta.practice" +IFRAME_CSS = "#gameiframe" +UNSUPPORTED_CSS = ".unsupported-device-box" +SUPPORTED_CSS = "#game_main" + + +async def get_to_page(client): + await client.navigate(URL) + client.soft_click(client.await_css(PRACTICE_CSS)) + client.switch_to_frame(client.await_css(IFRAME_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await get_to_page(client) + assert client.await_css(SUPPORTED_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await get_to_page(client) + assert client.await_css(UNSUPPORTED_CSS) diff --git a/testing/webcompat/interventions/tests/test_1741234_alphalabs.py b/testing/webcompat/interventions/tests/test_1741234_alphalabs.py new file mode 100644 index 0000000000..65fd9c06dc --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1741234_alphalabs.py @@ -0,0 +1,35 @@ +import pytest + +URL = "https://patient.alphalabs.ca/Report/CovidReport" + +CONTINUE_CSS = ".btnNormal[type='submit']" +FOOTER_CSS = "footer" + + +async def is_continue_above_footer(client): + await client.navigate(URL) + cont = client.find_css(CONTINUE_CSS) + assert cont + footer = client.find_css(FOOTER_CSS) + assert footer + return client.execute_script( + """ + const cont = arguments[0].getClientRects()[0]; + const footer = arguments[1].getClientRects()[0]; + return cont.bottom < footer.top; + """, + cont, + footer, + ) + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert await is_continue_above_footer(client) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert not await is_continue_above_footer(client) diff --git a/testing/webcompat/interventions/tests/test_1743627_renrenaud-bray_com.py b/testing/webcompat/interventions/tests/test_1743627_renrenaud-bray_com.py new file mode 100644 index 0000000000..51752b3a04 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1743627_renrenaud-bray_com.py @@ -0,0 +1,25 @@ +import pytest + +URL = "https://www.renaud-bray.com/accueil.aspx" +ERROR_MSG = "ua.split(...)[1] is undefined" +MENU_CSS = "#pageHeader_menuStores" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.execute_script( + """ + return arguments[0].style.zIndex == "7000"; + """, + client.await_css(MENU_CSS), + ) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL, await_console_message=ERROR_MSG) diff --git a/testing/webcompat/interventions/tests/test_1743751_slrclub_com.py b/testing/webcompat/interventions/tests/test_1743751_slrclub_com.py new file mode 100644 index 0000000000..30b52fc98b --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1743751_slrclub_com.py @@ -0,0 +1,23 @@ +import pytest + +URL = "http://www.slrclub.com/" +MOBILE_CSS = "#logo-wrap" +DESKTOP_CSS = "#header" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(MOBILE_CSS) + assert not client.find_css(DESKTOP_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(DESKTOP_CSS) + assert not client.find_css(MOBILE_CSS) diff --git a/testing/webcompat/interventions/tests/test_1743754_workflow_base_vn.py b/testing/webcompat/interventions/tests/test_1743754_workflow_base_vn.py new file mode 100644 index 0000000000..a64c02b227 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1743754_workflow_base_vn.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://workflow.base.vn/todos" +ERROR_MSG = 'can\'t access property "split", a.ua.split(...)[1] is undefined' +SUCCESS_CSS = "#authform" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(SUCCESS_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL, await_console_message=ERROR_MSG) diff --git a/testing/webcompat/interventions/tests/test_1753461_naver.py b/testing/webcompat/interventions/tests/test_1753461_naver.py new file mode 100644 index 0000000000..03266ef415 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1753461_naver.py @@ -0,0 +1,22 @@ +import pytest + +URL = "https://serieson.naver.com/v2/movie/335790?isWebtoonAgreePopUp=true" + +SUPPORTED_CSS = "#playerWrapper" +UNSUPPORTED_CSS = ".end_player_unavailable .download_links" + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(SUPPORTED_CSS) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(UNSUPPORTED_CSS) diff --git a/testing/webcompat/interventions/tests/test_1756872_www_dolcegabbana_com.py b/testing/webcompat/interventions/tests/test_1756872_www_dolcegabbana_com.py new file mode 100644 index 0000000000..f498aa0e3c --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1756872_www_dolcegabbana_com.py @@ -0,0 +1,33 @@ +import pytest +from webdriver.error import NoSuchElementException + +URL = "https://www.dolcegabbana.com/en/" +COOKIES_CSS = "#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll" +FAIL_CSS = "#p-homepage" +SUCCESS_CSS = "#app" + + +async def load_page(client): + await client.navigate(URL) + try: + client.remove_element(client.await_css(COOKIES_CSS, timeout=4)) + except NoSuchElementException: + pass + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await load_page(client) + assert client.await_css(SUCCESS_CSS) + assert not client.find_css(FAIL_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await load_page(client) + assert client.await_css(FAIL_CSS) + assert not client.find_css(SUCCESS_CSS) diff --git a/testing/webcompat/interventions/tests/test_1765947_veniceincoming_com.py b/testing/webcompat/interventions/tests/test_1765947_veniceincoming_com.py new file mode 100644 index 0000000000..84ad99a3a4 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1765947_veniceincoming_com.py @@ -0,0 +1,42 @@ +import pytest +from webdriver.error import NoSuchElementException + +URL = "https://veniceincoming.com/it_IT/search_results?page=1&start_date_start=&start_date_end=&k=" +COOKIES_CSS = "[aria-label='cookieconsent'] .cc-allow" +IMG_CSS = ".tour-details" +TOUR_DATA_CSS = "#tour_data" + + +async def check_filter_opens(client): + await client.navigate(URL) + + try: + cookies = client.await_css(COOKIES_CSS, is_displayed=True, timeout=5) + client.soft_click(cookies) + client.await_element_hidden(client.css(COOKIES_CSS)) + except NoSuchElementException: + pass + + img = client.await_css(IMG_CSS) + client.scroll_into_view(img) + client.mouse.click(element=img).perform() + + try: + client.await_css(TOUR_DATA_CSS, is_displayed=True, timeout=5) + except NoSuchElementException: + return False + return True + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert await check_filter_opens(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert not await check_filter_opens(client) diff --git a/testing/webcompat/interventions/tests/test_1774490_rainews_it.py b/testing/webcompat/interventions/tests/test_1774490_rainews_it.py new file mode 100644 index 0000000000..33a6c5a776 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1774490_rainews_it.py @@ -0,0 +1,32 @@ +import pytest + +URL = ( + "https://www.rainews.it/photogallery/2022/06/fotorassegna-stampa-le-prime" + "-pagine-dei-quotidiani-di-sabato-04-giugno--cd5414b3-65b9-429b-85d5-e53fadd59f4c.html" +) + +PICTURE_CSS = ".swiper-slide picture" +GALLERY_CSS = ".swiper-wrapper" + + +async def get_picture_width(client): + await client.navigate(URL, wait="load") + client.await_css(GALLERY_CSS) + return client.execute_script( + f""" + const p = document.querySelector("{PICTURE_CSS}"); + return window.getComputedStyle(p).width; + """ + ) + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert "0px" != await get_picture_width(client) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert "0px" == await get_picture_width(client) diff --git a/testing/webcompat/interventions/tests/test_1776897_www_edencast_fr.py b/testing/webcompat/interventions/tests/test_1776897_www_edencast_fr.py new file mode 100644 index 0000000000..4823aa0c39 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1776897_www_edencast_fr.py @@ -0,0 +1,59 @@ +import pytest + +# The page will asyncronously write out an <audio> element on success, but +# will not do anything easily detectable otherwise. +# +# The problem is that the podPressShowHidePlayer function thinks to write +# out a Flash embed unless WebKit is in the UA string, but ends up doing +# nothing at all. However, it calls a different function for html5 vs SWF, +# and we can detect which one it calls to confirm it calls the html5 one. + +URL = "https://www.edencast.fr/zoomcastlost-in-blindness/" + +AUDIO_CSS = "audio#podpresshtml5_1" + +SCRIPT = """ + var done = arguments[0]; + + if (!window?.podPressShowHidePlayer) { + done("none"); + } + + window.podPressenprintHTML5audio = function() { + done("html5"); + }; + + window.podpress_audioplayer_swfobject = { + embedSWF: function() { + done("swf"); + }, + }; + + const d = document.createElement("div"); + d.id = "podPressPlayerSpace_test"; + document.documentElement.appendChild(d); + + const p = document.createElement("div"); + p.id = "podPressPlayerSpace_test_PlayLink"; + document.documentElement.appendChild(p); + + podPressShowHidePlayer("test", "https//x/test.mp3", 100, 100, "force"); + """ + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + await client.dom_ready() + assert "html5" == client.execute_async_script(SCRIPT) + assert client.find_css(AUDIO_CSS) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + await client.dom_ready() + assert "swf" == client.execute_async_script(SCRIPT) + assert not client.find_css(AUDIO_CSS) diff --git a/testing/webcompat/interventions/tests/test_1778168_watch_antennaplus_gr.py b/testing/webcompat/interventions/tests/test_1778168_watch_antennaplus_gr.py new file mode 100644 index 0000000000..ab145fe21d --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1778168_watch_antennaplus_gr.py @@ -0,0 +1,22 @@ +import pytest + +URL = ( + "https://watch.antennaplus.gr/#/shows/agries_melisses/seasons/" + "3/episode/agries_melisses_S03_E137_v1" +) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(".login-pf-page") + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(".ua-barrier") diff --git a/testing/webcompat/interventions/tests/test_1784141_acuvue_com.py b/testing/webcompat/interventions/tests/test_1784141_acuvue_com.py new file mode 100644 index 0000000000..9d61591576 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784141_acuvue_com.py @@ -0,0 +1,22 @@ +import pytest + +URL = "https://www.acuvue.com/" +UNSUPPORTED_CSS = "#browser-alert" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784141_aveeno_com.py b/testing/webcompat/interventions/tests/test_1784141_aveeno_com.py new file mode 100644 index 0000000000..fe787cd044 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784141_aveeno_com.py @@ -0,0 +1,22 @@ +import pytest + +URL = "https://www.aveeno.com/products/calm-restore-oat-gel-moisturizer-for-sensitive-skin" +UNSUPPORTED_CSS = "#browser-alert" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784199_aptsovation_com.py b/testing/webcompat/interventions/tests/test_1784199_aptsovation_com.py new file mode 100644 index 0000000000..a7f22edac0 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784199_aptsovation_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.aptsovation.com/" +UNSUPPORTED_CSS = "[aria-label='Your browser is not supported']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784199_avanabayview_com.py b/testing/webcompat/interventions/tests/test_1784199_avanabayview_com.py new file mode 100644 index 0000000000..17ab789bee --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784199_avanabayview_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.avanabayview.com/" +UNSUPPORTED_CSS = "[aria-label='Your browser is not supported']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784199_breakpointeandcoronado_com.py b/testing/webcompat/interventions/tests/test_1784199_breakpointeandcoronado_com.py new file mode 100644 index 0000000000..3af30def4a --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784199_breakpointeandcoronado_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.breakpointeandcoronado.com/" +UNSUPPORTED_CSS = "[aria-label='Your browser is not supported']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784199_entrata_platform.py b/testing/webcompat/interventions/tests/test_1784199_entrata_platform.py new file mode 100644 index 0000000000..d10776d5fd --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784199_entrata_platform.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.liveobserverpark.com/" +UNSUPPORTED_BANNER = ".banner_overlay" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported_banner = client.await_css(UNSUPPORTED_BANNER) + assert not client.is_displayed(unsupported_banner) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported_banner = client.await_css(UNSUPPORTED_BANNER) + assert client.is_displayed(unsupported_banner) diff --git a/testing/webcompat/interventions/tests/test_1784199_liveatlasathens_com.py b/testing/webcompat/interventions/tests/test_1784199_liveatlasathens_com.py new file mode 100644 index 0000000000..37b5f0cf4a --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784199_liveatlasathens_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.liveatlasathens.com/" +UNSUPPORTED_CSS = "[aria-label='Your browser is not supported']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784199_liveobserverpark_com.py b/testing/webcompat/interventions/tests/test_1784199_liveobserverpark_com.py new file mode 100644 index 0000000000..ffc6b2d702 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784199_liveobserverpark_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.liveobserverpark.com/" +UNSUPPORTED_CSS = "[aria-label='Your browser is not supported']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784199_midwayurban_com.py b/testing/webcompat/interventions/tests/test_1784199_midwayurban_com.py new file mode 100644 index 0000000000..2c90d9468e --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784199_midwayurban_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.midwayurban.com/" +UNSUPPORTED_CSS = "[aria-label='Your browser is not supported']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784199_nhcalaska_com.py b/testing/webcompat/interventions/tests/test_1784199_nhcalaska_com.py new file mode 100644 index 0000000000..37ebce9be0 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784199_nhcalaska_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.nhcalaska.com/" +UNSUPPORTED_CSS = "[aria-label='Your browser is not supported']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784199_securityproperties_com.py b/testing/webcompat/interventions/tests/test_1784199_securityproperties_com.py new file mode 100644 index 0000000000..bb7840ec66 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784199_securityproperties_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.securityproperties.com/thornton/reserve-at-thornton-i-ii-apartments" +UNSUPPORTED_CSS = "[aria-label='Your browser is not supported']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784199_theloftsorlando_com.py b/testing/webcompat/interventions/tests/test_1784199_theloftsorlando_com.py new file mode 100644 index 0000000000..6aea9fd25c --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784199_theloftsorlando_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.theloftsorlando.com/" +UNSUPPORTED_CSS = "[aria-label='Your browser is not supported']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784199_thepointeatcentral_prospectportal_com.py b/testing/webcompat/interventions/tests/test_1784199_thepointeatcentral_prospectportal_com.py new file mode 100644 index 0000000000..50ec397f75 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784199_thepointeatcentral_prospectportal_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://thepointeatcentral.prospectportal.com/Apartments/module/application_authentication?_ga=2.250831814.1585158328.1588776830-1793033216.1588776830" +UNSUPPORTED_CSS = "[aria-label='Your browser is not supported']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784199_vanallenapartments_com.py b/testing/webcompat/interventions/tests/test_1784199_vanallenapartments_com.py new file mode 100644 index 0000000000..aff3d7d3ad --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784199_vanallenapartments_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.vanallenapartments.com/" +UNSUPPORTED_CSS = "[aria-label='Your browser is not supported']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1784361_coldwellbankerhomes_com.py b/testing/webcompat/interventions/tests/test_1784361_coldwellbankerhomes_com.py new file mode 100644 index 0000000000..32892b2087 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1784361_coldwellbankerhomes_com.py @@ -0,0 +1,23 @@ +import pytest + +# The gallery on this page only sets img[src] to a non-1x1-spacer if the error +# doesn't happen during page load, which doesn't happen with a Chrome UA. + +URL = "https://www.coldwellbankerhomes.com/ri/little-compton/kvc-17_1,17_2/" +ERROR_MSG = 'can\'t access property "dataset", v[0] is undefined' +SUCCESS_CSS = "img.psr-lazy:not([src*='spacer'])" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(SUCCESS_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL, await_console_message=ERROR_MSG) diff --git a/testing/webcompat/interventions/tests/test_1786404_business_help_royalmail_com.py b/testing/webcompat/interventions/tests/test_1786404_business_help_royalmail_com.py new file mode 100644 index 0000000000..59a95ff8d9 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1786404_business_help_royalmail_com.py @@ -0,0 +1,70 @@ +import time + +import pytest +from webdriver.error import StaleElementReferenceException + +URL = "https://business.help.royalmail.com/app/webforms/stampsenquiries" + +COOKIES_ACCEPT_CSS = "#consent_prompt_submit" +POSTCODE_CSS = "input[name='rn_AddressControl_16textbox']" +OPTION_CSS = "option.addr_pick_line:not(:disabled)" +ADDY1_CSS = "[name='Incident.CustomFields.c.address1_1']" + + +async def getResult(client): + await client.navigate(URL) + + client.await_css(COOKIES_ACCEPT_CSS).click() + + # the viewport scrolls around while we try to interact + # with the postcode in webdriver, so we take care here + code = client.await_css(POSTCODE_CSS) + client.scroll_into_view(code) + time.sleep(1) + client.mouse.click(element=code).perform() + code.send_keys("W1A 1AV") + + # now wait for the options to open, scroll them back + # into view, and carefully click on the first one. + time.sleep(1) + client.scroll_into_view(code) + opt = client.await_css(OPTION_CSS) + client.mouse.click(element=opt).perform() + + # the options should hide on click + time.sleep(2) + try: + if client.is_displayed(opt): + return False + except StaleElementReferenceException: + return False + + # a address line should end up being prefilled + addy = client.await_css(ADDY1_CSS) + return client.execute_async_script( + """ + var addy = arguments[0]; + var done = arguments[1]; + var to = setTimeout(() => { + if (addy.value) { + clearTimeout(to); + done(true); + } + }, 200); + """, + addy, + ) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert await getResult(client) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert not await getResult(client) diff --git a/testing/webcompat/interventions/tests/test_1793761_schoolnutritionandfitness_com.py b/testing/webcompat/interventions/tests/test_1793761_schoolnutritionandfitness_com.py new file mode 100644 index 0000000000..9bb0be584c --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1793761_schoolnutritionandfitness_com.py @@ -0,0 +1,32 @@ +import pytest + +URL = "https://www.schoolnutritionandfitness.com/webmenus2/#/view?id=6331c49ce96f1e9c468b45be&siteCode=1641" +ELEM_CSS = "react-app td > div" +HEIGHT_CUTOFF = 10 + + +def get_elem_height(client): + elem = client.await_css(ELEM_CSS, is_displayed=True) + assert elem + return client.execute_script( + """ + return arguments[0].getBoundingClientRect().height; + """, + elem, + ) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert get_elem_height(client) > HEIGHT_CUTOFF + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert get_elem_height(client) < HEIGHT_CUTOFF diff --git a/testing/webcompat/interventions/tests/test_1795490_www_china-airlines_com.py b/testing/webcompat/interventions/tests/test_1795490_www_china-airlines_com.py new file mode 100644 index 0000000000..8a38a633a4 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1795490_www_china-airlines_com.py @@ -0,0 +1,25 @@ +import pytest + +URL = "https://www.china-airlines.com/tw/en/booking/book-flights/flight-search?lang=en-us&deptstn=TPE&arrstn=LAX" +DATE_CSS = "#departureDateMobile" +DATE_DISABLED_CSS = "#departureDateMobile[disabled]" + + +async def check_date_disabled(client): + await client.navigate(URL) + client.await_css(DATE_CSS) + return client.find_css(DATE_DISABLED_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await check_date_disabled(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await check_date_disabled(client) diff --git a/testing/webcompat/interventions/tests/test_1797400_mobilevikings_be.py b/testing/webcompat/interventions/tests/test_1797400_mobilevikings_be.py new file mode 100644 index 0000000000..c3575b9735 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1797400_mobilevikings_be.py @@ -0,0 +1,31 @@ +import pytest +from webdriver.error import NoSuchElementException + +URL = "https://mobilevikings.be/en/registration/?product_id=155536813-1-1" +COOKIES_CSS = "#btn-accept-cookies" +DATE_CSS = "input.date-input[name='birth_date']" + + +async def date_after_typing(client): + await client.navigate(URL) + try: + client.await_css(COOKIES_CSS, timeout=3).click() + client.await_element_hidden(client.css(COOKIES_CSS)) + except NoSuchElementException: + pass + date = client.await_css(DATE_CSS) + client.scroll_into_view(date) + date.send_keys("1") + return date.property("value") + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert "1_/__/____" == await date_after_typing(client) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert "__/__/____" == await date_after_typing(client) diff --git a/testing/webcompat/interventions/tests/test_1799968_samsung_com.py b/testing/webcompat/interventions/tests/test_1799968_samsung_com.py new file mode 100644 index 0000000000..4b4fc408aa --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1799968_samsung_com.py @@ -0,0 +1,21 @@ +import pytest + +URL = "https://www.samsung.com/in/watches/galaxy-watch/galaxy-watch5-44mm-graphite-bluetooth-sm-r910nzaainu/" +GOOD_CSS = "html.linux.firefox" +ERROR_MSG = "DOMTokenList.add: The empty string is not a valid token." + + +@pytest.mark.only_platforms("linux") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(GOOD_CSS) + + +@pytest.mark.only_platforms("linux") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL, await_console_message=ERROR_MSG) + assert not client.find_css(GOOD_CSS) diff --git a/testing/webcompat/interventions/tests/test_1800000_www_honda_co_uk.py b/testing/webcompat/interventions/tests/test_1800000_www_honda_co_uk.py new file mode 100644 index 0000000000..55065cde71 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1800000_www_honda_co_uk.py @@ -0,0 +1,53 @@ +import time + +import pytest +from webdriver.error import NoSuchElementException + +URL = "https://www.honda.co.uk/cars/book-a-service.html#search?query=tf33bu" +COOKIES_CSS = "#onetrust-accept-btn-handler" +CHOOSE_DEALER_CSS = "a[data-analytics-template*='Make a booking']" +BOOK_ONLINE_CSS = "select#requiredService" +SITE_DOWN_CSS = ".no-results" + + +async def check_choose_dealer_works(client): + await client.navigate(URL) + + cookies = client.css(COOKIES_CSS) + client.await_element(cookies).click() + client.await_element_hidden(cookies) + time.sleep(0.5) + + down, dealer = client.await_first_element_of( + [ + client.css(SITE_DOWN_CSS), + client.css(CHOOSE_DEALER_CSS), + ], + timeout=5, + ) + + if down: + pytest.skip("Service is down right now, so testing is impossible") + return True + + client.scroll_into_view(dealer) + client.mouse.click(element=dealer).perform() + try: + client.await_css(BOOK_ONLINE_CSS, is_displayed=True, timeout=3) + except NoSuchElementException: + return False + return True + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert await check_choose_dealer_works(client) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert not await check_choose_dealer_works(client) diff --git a/testing/webcompat/interventions/tests/test_1800241_mms_telekom_de.py b/testing/webcompat/interventions/tests/test_1800241_mms_telekom_de.py new file mode 100644 index 0000000000..37778ea804 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1800241_mms_telekom_de.py @@ -0,0 +1,19 @@ +import pytest + +URL = "https://www.mms.telekom.de/OTP/" +LOGIN_CSS = ".LoginbackgroundDiv" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + login_element = client.await_css(LOGIN_CSS) + assert client.is_displayed(login_element) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert not client.find_css(LOGIN_CSS) diff --git a/testing/webcompat/interventions/tests/test_1800936_cov19ent_kdca_go_kr.py b/testing/webcompat/interventions/tests/test_1800936_cov19ent_kdca_go_kr.py new file mode 100644 index 0000000000..8caa33b53d --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1800936_cov19ent_kdca_go_kr.py @@ -0,0 +1,30 @@ +import pytest + +URL = "https://cov19ent.kdca.go.kr/cpassportal/biz/beffatstmnt/step1.do?flightPortSe=1&lang=en" +HEADER_CSS = "header.mouseOn" + + +# This site can be very slow, and prone to not finishing loading + + +async def get_header_position(client): + await client.navigate(URL, wait="complete") + header = client.await_css(HEADER_CSS, timeout=60) + return client.execute_script( + """ + return window.getComputedStyle(arguments[0]).position; + """, + header, + ) + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert "absolute" == await get_header_position(client) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert "absolute" != await get_header_position(client) diff --git a/testing/webcompat/interventions/tests/test_1817520_ersthelfer_tv.py b/testing/webcompat/interventions/tests/test_1817520_ersthelfer_tv.py new file mode 100644 index 0000000000..e8addbeb68 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1817520_ersthelfer_tv.py @@ -0,0 +1,36 @@ +import pytest + +URL = "https://book.ersthelfer.tv/" +DATE = "12.12.2020" +PLACEHOLDER = "__.__.____" + +CITY_CSS = "#city_id" +PERSON_CSS = "#no_of_person" +CITY_OPTION_XPATH = "//select[@name='city_id']/option[2]" +PERSON_OPTION_XPATH = "//select[@name='no_of_person']/option[2]" +DATE_PICKER_CSS = "[class*='date-picker-custom-wrapper'] input" + + +async def set_date(client): + client.await_css(CITY_CSS).click() + client.await_xpath(CITY_OPTION_XPATH).click() + + client.await_css(PERSON_CSS).click() + client.await_xpath(PERSON_OPTION_XPATH).click() + date_input = client.await_css(DATE_PICKER_CSS, is_displayed=True) + date_input.send_keys(DATE) + return date_input.property("value") + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert DATE == await set_date(client) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert PLACEHOLDER == await set_date(client) diff --git a/testing/webcompat/interventions/tests/test_1818818_wellcare_com.py b/testing/webcompat/interventions/tests/test_1818818_wellcare_com.py new file mode 100644 index 0000000000..caacf5df0b --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1818818_wellcare_com.py @@ -0,0 +1,31 @@ +import pytest + +URL = "https://www.wellcare.com/en/Oregon/Members/Prescription-Drug-Plans-2023/Wellcare-Value-Script" +ALERT_CSS = ".alert-box radius" +MENU_CSS = "a[title='login DDL']" +SELECT_CSS = "select#userSelect" + + +async def is_fastclick_active(client): + async with client.ensure_fastclick_activates(): + await client.navigate(URL, wait="load") + alert = client.find_css(ALERT_CSS) + if alert: + client.remove_element(alert) + menu = client.await_css(MENU_CSS) + client.soft_click(menu) + return client.test_for_fastclick(client.await_css(SELECT_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_fastclick_active(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_fastclick_active(client) diff --git a/testing/webcompat/interventions/tests/test_1819450_cmbchina_com.py b/testing/webcompat/interventions/tests/test_1819450_cmbchina_com.py new file mode 100644 index 0000000000..c711596114 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1819450_cmbchina_com.py @@ -0,0 +1,21 @@ +import pytest + +URL = "https://www.cmbchina.com/" +DESKTOP_CSS = "#aspnetForm" +MOBILE_CSS = "#app .mobile-header" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(MOBILE_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(DESKTOP_CSS) diff --git a/testing/webcompat/interventions/tests/test_1819476_axisbank_com.py b/testing/webcompat/interventions/tests/test_1819476_axisbank_com.py new file mode 100644 index 0000000000..a53ed14538 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1819476_axisbank_com.py @@ -0,0 +1,18 @@ +import pytest + +URL = "https://www.axisbank.com/retail/cards/credit-card" +SITE_CSS = "#ulCreditCard:not(:empty)" +ERROR_MSG = "webkitSpeechRecognition is not defined" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(SITE_CSS, timeout=120) # the site can be slow + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL, await_console_message=ERROR_MSG, timeout=10) diff --git a/testing/webcompat/interventions/tests/test_1819702_feelgoodcontacts_com.py b/testing/webcompat/interventions/tests/test_1819702_feelgoodcontacts_com.py new file mode 100644 index 0000000000..039e08cadc --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1819702_feelgoodcontacts_com.py @@ -0,0 +1,21 @@ +import pytest + +URL = "https://feelgoodcontacts.com/" +MOBILE_CSS = "#aHomeMob" +DESKTOP_CSS = "#mmenu" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(MOBILE_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(DESKTOP_CSS) diff --git a/testing/webcompat/interventions/tests/test_1829126_otsuka_co_jp.py b/testing/webcompat/interventions/tests/test_1829126_otsuka_co_jp.py new file mode 100644 index 0000000000..fe7ad3071c --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1829126_otsuka_co_jp.py @@ -0,0 +1,28 @@ +import pytest + +URL = "https://www.otsuka.co.jp/fib/" +SPLASH_CSS = ".splash" + +# Note this site can be really slow + + +async def splash_is_hidden(client): + await client.navigate(URL, wait="none") + splash = client.await_css(SPLASH_CSS, is_displayed=True, timeout=20) + assert splash + client.await_element_hidden(client.css(SPLASH_CSS), timeout=20) + return not client.is_displayed(splash) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert await splash_is_hidden(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert not await splash_is_hidden(client) diff --git a/testing/webcompat/interventions/tests/test_1829944_411_ca.py b/testing/webcompat/interventions/tests/test_1829944_411_ca.py new file mode 100644 index 0000000000..8147063c7d --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1829944_411_ca.py @@ -0,0 +1,18 @@ +import pytest + +URL = "https://411.ca" +UNSUPPORTED_CSS = "ngb-alert.header-outdated-alert" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert not client.find_css(UNSUPPORTED_CSS) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.find_css(UNSUPPORTED_CSS) diff --git a/testing/webcompat/interventions/tests/test_1829947_torguard_net.py b/testing/webcompat/interventions/tests/test_1829947_torguard_net.py new file mode 100644 index 0000000000..6e895c923d --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1829947_torguard_net.py @@ -0,0 +1,24 @@ +import pytest + +URL = "https://www.discountcoffee.co.uk/collections/wholesale-coffee-beans" +SELECT_CSS = "#collection-filter-type select" + + +async def is_fastclick_active(client): + async with client.ensure_fastclick_activates(): + await client.navigate(URL) + return client.test_for_fastclick(client.await_css(SELECT_CSS)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_fastclick_active(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_fastclick_active(client) diff --git a/testing/webcompat/interventions/tests/test_1830739_casinoextreme_eu.py b/testing/webcompat/interventions/tests/test_1830739_casinoextreme_eu.py new file mode 100644 index 0000000000..a895cc9d7a --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830739_casinoextreme_eu.py @@ -0,0 +1,28 @@ +import pytest + +URL = "https://casinoextreme.eu/games" +RUN_CSS = "a.playgame-demo[onclick^='playGame']" +IFRAME_CSS = "#gameplay > iframe" +GOOD_MSG = "GameViewModel" +BAD_MSG = "UnsupportedDevice" + + +async def check_for_message(client, message): + await client.navigate(URL) + client.soft_click(client.await_css(RUN_CSS)) + client.switch_to_frame(client.await_css(IFRAME_CSS)) + await (await client.promise_console_message_listener(message)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await check_for_message(client, GOOD_MSG) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await check_for_message(client, BAD_MSG) diff --git a/testing/webcompat/interventions/tests/test_1830739_www_cryptoloko_com.py b/testing/webcompat/interventions/tests/test_1830739_www_cryptoloko_com.py new file mode 100644 index 0000000000..d562ea4a91 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830739_www_cryptoloko_com.py @@ -0,0 +1,26 @@ +import pytest + +URL = "https://www.cryptoloko.com/webplay/?play=sweet-16-blast" +IFRAME_CSS = "#gameiframe" +GOOD_MSG = "GameViewModel" +BAD_MSG = "UnsupportedDevice" + + +async def check_for_message(client, message): + await client.navigate(URL) + client.switch_to_frame(client.await_css(IFRAME_CSS)) + await (await client.promise_console_message_listener(message)) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await check_for_message(client, GOOD_MSG) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await check_for_message(client, BAD_MSG) diff --git a/testing/webcompat/interventions/tests/test_1830739_www_heapsofwins_com.py b/testing/webcompat/interventions/tests/test_1830739_www_heapsofwins_com.py new file mode 100644 index 0000000000..d2f44b4656 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830739_www_heapsofwins_com.py @@ -0,0 +1,35 @@ +import time + +import pytest +from webdriver.error import NoSuchElementException + +URL = "https://www.heapsofwins.com/games/all" +RUN_CSS = "#pagehero.games a[href*='games?play']" +IFRAME_CSS = "#gamemodal iframe" +GOOD_MSG = "GameViewModel" +BAD_MSG = "UnsupportedDevice" + + +async def check_for_message(client, message): + await client.navigate(URL) + time.sleep(1) + try: + client.soft_click(client.await_css(RUN_CSS)) + client.switch_to_frame(client.await_css(IFRAME_CSS)) + await (await client.promise_console_message_listener(message, timeout=30)) + except NoSuchElementException: + pytest.xfail("Cannot test; all games seem to require login right now") + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await check_for_message(client, GOOD_MSG) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await check_for_message(client, BAD_MSG) diff --git a/testing/webcompat/interventions/tests/test_1830739_www_planet7casino_com.py b/testing/webcompat/interventions/tests/test_1830739_www_planet7casino_com.py new file mode 100644 index 0000000000..97901efe77 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830739_www_planet7casino_com.py @@ -0,0 +1,34 @@ +import asyncio + +import pytest + +URL = "https://www.planet7casino.com/lobby/?play=alien-wins" +IFRAME_CSS = "#gameiframe" +GOOD_MSG = "GameViewModel" +BAD_MSG = "UnsupportedDevice" +DOWN_TEXT = "temporarily out of order" + + +async def check_for_message(client, message): + await client.navigate(URL) + client.switch_to_frame(client.await_css(IFRAME_CSS)) + down = client.async_await_element(client.text(DOWN_TEXT)) + good = await client.promise_console_message_listener(message) + down, good = await asyncio.wait([down, good], return_when=asyncio.FIRST_COMPLETED) + if down: + pytest.skip("Cannot test: casino is 'temporarily out of order'") + return good + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert check_for_message(client, GOOD_MSG) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert check_for_message(client, BAD_MSG) diff --git a/testing/webcompat/interventions/tests/test_1830747_babbel_com.py b/testing/webcompat/interventions/tests/test_1830747_babbel_com.py new file mode 100644 index 0000000000..cfefe31412 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830747_babbel_com.py @@ -0,0 +1,35 @@ +import pytest +from webdriver.error import NoSuchElementException + +URL = "https://my.babbel.com/en/welcome/1?bsc=engmag-rus&btp=default&learn_lang=RUS" +COOKIES_CSS = "#onetrust-accept-btn-handler" +BUTTON_CSS = "button.button[type=submit]" + + +async def button_visible(client): + await client.navigate(URL) + try: + client.soft_click(client.await_css(COOKIES_CSS, timeout=3)) + except NoSuchElementException: + pass + btn = client.await_css(BUTTON_CSS) + return client.execute_script( + """ + return window.innerHeight > arguments[0].getBoundingClientRect().bottom; + """, + btn, + ) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert await button_visible(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert not await button_visible(client) diff --git a/testing/webcompat/interventions/tests/test_1830752_afisha_ru.py b/testing/webcompat/interventions/tests/test_1830752_afisha_ru.py new file mode 100644 index 0000000000..5a2a51acc1 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830752_afisha_ru.py @@ -0,0 +1,45 @@ +import time + +import pytest +from webdriver.error import ElementClickInterceptedException, NoSuchElementException + +URL = "https://www.afisha.ru/msk/theatre/" +COOKIES_CSS = "button.Txfw7" +OPT_CSS = "button[data-name='price']" +SLIDER_CSS = "input[type='range'][data-index='0']" + + +async def slider_is_clickable(client): + await client.navigate(URL) + + try: + client.soft_click(client.await_css(COOKIES_CSS)) + client.await_element_hidden(client.css(COOKIES_CSS)) + except NoSuchElementException: + pass + + try: + client.soft_click(client.await_css(OPT_CSS, is_displayed=True)) + except NoSuchElementException: + pytest.xfail("Site may have shown a captcha; please run this test again") + + try: + slider = client.await_css(SLIDER_CSS, is_displayed=True) + time.sleep(2) + slider.click() + except ElementClickInterceptedException: + return False + + return True + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert await slider_is_clickable(client) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert not await slider_is_clickable(client) diff --git a/testing/webcompat/interventions/tests/test_1830761_91mobiles_com.py b/testing/webcompat/interventions/tests/test_1830761_91mobiles_com.py new file mode 100644 index 0000000000..4f83c371b7 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830761_91mobiles_com.py @@ -0,0 +1,27 @@ +import pytest + +URL = "https://www.91mobiles.com/compare/realme/9+SE+5G/vs/Moto/G72-amp" +CONTENT_CSS = "#fixed-table tr td .cmp-summary-box" + + +async def content_has_height(client): + await client.navigate(URL) + elem = client.await_css(CONTENT_CSS) + return client.execute_script( + """ + return arguments[0].getBoundingClientRect().height > 0; + """, + elem, + ) + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert await content_has_height(client) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert not await content_has_height(client) diff --git a/testing/webcompat/interventions/tests/test_1830776_blueshieldca_com.py b/testing/webcompat/interventions/tests/test_1830776_blueshieldca_com.py new file mode 100644 index 0000000000..cfe67c62bc --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830776_blueshieldca_com.py @@ -0,0 +1,18 @@ +import pytest + +URL = "https://www.blueshieldca.com/provider" +UNSUPPORTED_CSS = "#browserErrorModal" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.find_css(UNSUPPORTED_CSS, is_displayed=False) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.find_css(UNSUPPORTED_CSS, is_displayed=True) diff --git a/testing/webcompat/interventions/tests/test_1830796_copyleaks_com.py b/testing/webcompat/interventions/tests/test_1830796_copyleaks_com.py new file mode 100644 index 0000000000..56817c705b --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830796_copyleaks_com.py @@ -0,0 +1,26 @@ +import time + +import pytest + +URL = "https://copyleaks.com/ai-content-detector" +IFRAME_CSS = "#ai-content-detector" +UNSUPPORTED_CSS = "#outdated" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + client.switch_to_frame(client.await_css(IFRAME_CSS)) + time.sleep(2) + assert not client.find_css(UNSUPPORTED_CSS, is_displayed=True) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + client.switch_to_frame(client.await_css(IFRAME_CSS)) + assert client.await_css(UNSUPPORTED_CSS, is_displayed=True) diff --git a/testing/webcompat/interventions/tests/test_1830810_interceramic_com.py b/testing/webcompat/interventions/tests/test_1830810_interceramic_com.py new file mode 100644 index 0000000000..78620fd343 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830810_interceramic_com.py @@ -0,0 +1,21 @@ +import time + +import pytest + +URL = "https://interceramic.com/mx_202VWME/galeria/index" +UNSUPPORTED_CSS = "#ff-modal" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + time.sleep(3) + assert client.find_css(UNSUPPORTED_CSS, is_displayed=False) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(UNSUPPORTED_CSS, is_displayed=True) diff --git a/testing/webcompat/interventions/tests/test_1830813_onstove_com.py b/testing/webcompat/interventions/tests/test_1830813_onstove_com.py new file mode 100644 index 0000000000..626f71f92b --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830813_onstove_com.py @@ -0,0 +1,29 @@ +import pytest + +URL = "https://page.onstove.com/epicseven/global/" +BANNER_CSS = ".gnb-alerts.gnb-old-browser" + + +async def get_banner_height(client): + await client.navigate(URL) + banner = client.await_css(BANNER_CSS) + return client.execute_script( + """ + return arguments[0].getBoundingClientRect().height; + """, + banner, + ) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert 0 == await get_banner_height(client) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert 0 < await get_banner_height(client) diff --git a/testing/webcompat/interventions/tests/test_1830821_enjoy_point_auone_jp.py b/testing/webcompat/interventions/tests/test_1830821_enjoy_point_auone_jp.py new file mode 100644 index 0000000000..f8ccf39674 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830821_enjoy_point_auone_jp.py @@ -0,0 +1,21 @@ +import pytest + +URL = "https://enjoy.point.auone.jp/" +SUPPORTED_CSS = "main.tmr-page" +UNSUPPORTED_TEXT = "Android:標準ブラウザ、Chrome" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(SUPPORTED_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_text(UNSUPPORTED_TEXT) diff --git a/testing/webcompat/interventions/tests/test_1830821_webcartop_jp.py b/testing/webcompat/interventions/tests/test_1830821_webcartop_jp.py new file mode 100644 index 0000000000..a1b105ed15 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1830821_webcartop_jp.py @@ -0,0 +1,23 @@ +import pytest + +URL = "https://www.webcartop.jp/" +DESKTOP_CSS = "#page" +MOBILE_CSS = "#my-page" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(MOBILE_CSS) + assert not client.find_css(DESKTOP_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(DESKTOP_CSS) + assert not client.find_css(MOBILE_CSS) diff --git a/testing/webcompat/interventions/tests/test_1836103_autostar_novoross_ru.py b/testing/webcompat/interventions/tests/test_1836103_autostar_novoross_ru.py new file mode 100644 index 0000000000..d63fd666fe --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1836103_autostar_novoross_ru.py @@ -0,0 +1,29 @@ +import pytest + +URL = "https://autostar-novoross.ru/" +IFRAME_CSS = "iframe[src*='google.com/maps']" + + +async def map_is_correct_height(client): + await client.navigate(URL) + iframe = client.await_css(IFRAME_CSS) + assert iframe + return client.execute_script( + """ + const iframe = arguments[0]; + return iframe.clientHeight == iframe.parentNode.clientHeight; + """, + iframe, + ) + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert await map_is_correct_height(client) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert not await map_is_correct_height(client) diff --git a/testing/webcompat/interventions/tests/test_1836109_watch_tonton_com_my.py b/testing/webcompat/interventions/tests/test_1836109_watch_tonton_com_my.py new file mode 100644 index 0000000000..e36eaaa53a --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1836109_watch_tonton_com_my.py @@ -0,0 +1,26 @@ +import pytest + +URL = "https://watch.tonton.com.my/#/" +UNSUPPORTED_CSS = ".ua-barrier" +LOGIN_CSS = ".login-page-container" + + +# The site can take a little time to load, and this includes +# interstitial ads, so for now we give it 10 seconds. + + +# Skip Android as the site blocks many Android devices including the emulator +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(LOGIN_CSS, timeout=10) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(UNSUPPORTED_CSS, timeout=10) diff --git a/testing/webcompat/interventions/tests/test_1836112_www_capcut_cn.py b/testing/webcompat/interventions/tests/test_1836112_www_capcut_cn.py new file mode 100644 index 0000000000..a57e678110 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1836112_www_capcut_cn.py @@ -0,0 +1,19 @@ +import pytest + +URL = "https://www.slushy.com/" +UNSUPPORTED_TEXT = "If you wanna see this content" +LOGIN_TEXT = "you must be at least 18" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_text(LOGIN_TEXT) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_text(UNSUPPORTED_TEXT) diff --git a/testing/webcompat/interventions/tests/test_1836116_www_slushy_com.py b/testing/webcompat/interventions/tests/test_1836116_www_slushy_com.py new file mode 100644 index 0000000000..69c5d1d1a3 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1836116_www_slushy_com.py @@ -0,0 +1,20 @@ +import pytest + +URL = "https://www.slushy.com/" + + +# skip Android, as the site blocks low-res devices like the emulator +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL, wait="load") + assert not client.execute_script("return location.href.includes('unsupported')") + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL, wait="load") + assert client.execute_script("return location.href.includes('unsupported')") diff --git a/testing/webcompat/interventions/tests/test_1836135_gts_pro_sdimedia_com.py b/testing/webcompat/interventions/tests/test_1836135_gts_pro_sdimedia_com.py new file mode 100644 index 0000000000..67e1aa761b --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1836135_gts_pro_sdimedia_com.py @@ -0,0 +1,19 @@ +import pytest + +URL = "https://gts-pro.sdimedia.com/" +UNSUPPORTED_CSS = "#invalid-browser" +LOGIN_CSS = "button[data-qa='open-login-page']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(LOGIN_CSS, is_displayed=True) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(UNSUPPORTED_CSS, is_displayed=True) diff --git a/testing/webcompat/interventions/tests/test_1836140_indices_iriworldwide_com.py b/testing/webcompat/interventions/tests/test_1836140_indices_iriworldwide_com.py new file mode 100644 index 0000000000..1ffaf5c09f --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1836140_indices_iriworldwide_com.py @@ -0,0 +1,18 @@ +import pytest + +URL = "https://indices.iriworldwide.com/covid19/register.html" +BAD_CSS = ".hiddPage" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL, wait="complete") + assert not client.find_css(BAD_CSS) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL, wait="complete") + assert client.find_css(BAD_CSS) diff --git a/testing/webcompat/interventions/tests/test_1836141_yabbycasino_com.py b/testing/webcompat/interventions/tests/test_1836141_yabbycasino_com.py new file mode 100644 index 0000000000..bcf6de192d --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1836141_yabbycasino_com.py @@ -0,0 +1,24 @@ +import pytest + +URL = "https://yabbycasino.com/game/aces-and-eights" +IFRAME_CSS = "iframe#game" +GOOD_CSS = "#rotateDevice" +BAD_CSS = ".unsupported-device-box" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + client.switch_to_frame(client.await_css(IFRAME_CSS)) + assert client.await_css(GOOD_CSS, is_displayed=True) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + client.switch_to_frame(client.await_css(IFRAME_CSS)) + assert client.await_css(BAD_CSS, is_displayed=True) diff --git a/testing/webcompat/interventions/tests/test_1836157_thai_masszazs_net.py b/testing/webcompat/interventions/tests/test_1836157_thai_masszazs_net.py new file mode 100644 index 0000000000..66f25283fd --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1836157_thai_masszazs_net.py @@ -0,0 +1,26 @@ +import pytest + +URL = "https://www.thai-masszazs.net/" + + +async def is_scrolling_broken(client): + await client.navigate(URL) + return client.execute_script( + """ + return document.querySelector("html").style.overflow == "hidden" + """ + ) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_scrolling_broken(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_scrolling_broken(client) diff --git a/testing/webcompat/interventions/tests/test_1836178_atracker_pro.py b/testing/webcompat/interventions/tests/test_1836178_atracker_pro.py new file mode 100644 index 0000000000..78dbbaf1dd --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1836178_atracker_pro.py @@ -0,0 +1,23 @@ +import pytest + +URL = "https://atracker.pro/" +LOGIN_CSS = "a[onclick='openWebVersionWindow()']" + + +async def get_login_popup_url(client, popup_url): + popup = await client.await_popup(popup_url) + await client.navigate(URL, wait="load") + client.soft_click(client.await_css(LOGIN_CSS)) + return await popup + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert await get_login_popup_url(client, "index.html") + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await get_login_popup_url(client, "BrowserCheck") diff --git a/testing/webcompat/interventions/tests/test_1836182_www_flatsatshadowglen_com.py b/testing/webcompat/interventions/tests/test_1836182_www_flatsatshadowglen_com.py new file mode 100644 index 0000000000..069167092f --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1836182_www_flatsatshadowglen_com.py @@ -0,0 +1,18 @@ +import pytest + +URL = "https://apply.flatsatshadowglen.com/manor/the-flats-at-shadowglen/" +UNSUPPORTED_CSS = "[aria-label='Your browser is not supported']" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert not client.find_css(UNSUPPORTED_CSS) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.find_css(UNSUPPORTED_CSS) diff --git a/testing/webcompat/interventions/tests/test_1848711_vio_com.py b/testing/webcompat/interventions/tests/test_1848711_vio_com.py new file mode 100644 index 0000000000..7d571887d8 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1848711_vio_com.py @@ -0,0 +1,43 @@ +import time +from datetime import datetime, timedelta + +import pytest + +today = datetime.now() +three_months = today + timedelta(days=90) +plus_week = three_months + timedelta(days=7) +formatted_start = three_months.strftime("%Y-%m-%d") +formatted_end = plus_week.strftime("%Y-%m-%d") + +URL = f"https://www.vio.com/Hotel/Search?hotelId=17293575&checkIn={formatted_start}&checkOut={formatted_end}&rooms=2&homeSearch=1&userSearch=1&layout=map" +MAP_CSS = ".mapboxgl-map" +MIN_HEIGHT = 100 + + +def get_elem_height(client): + elem = client.await_css(MAP_CSS, is_displayed=True) + assert elem + return client.execute_script( + """ + return arguments[0].getBoundingClientRect().height; + """, + elem, + ) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + time.sleep(3) + await client.navigate(URL) + assert get_elem_height(client) > MIN_HEIGHT + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + time.sleep(3) + await client.navigate(URL) + assert get_elem_height(client) < MIN_HEIGHT diff --git a/testing/webcompat/interventions/tests/test_1848716_elal_com.py b/testing/webcompat/interventions/tests/test_1848716_elal_com.py new file mode 100644 index 0000000000..835fb67b18 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1848716_elal_com.py @@ -0,0 +1,22 @@ +import pytest + +URL = "https://www.elal.com/he/Israel/Pages/default.aspx" +UNSUPPORTED_CSS = "#upgrade-browser-wrap" + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert not client.is_displayed(unsupported) + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + unsupported = client.await_css(UNSUPPORTED_CSS) + assert client.is_displayed(unsupported) diff --git a/testing/webcompat/interventions/tests/test_1849018_carefirst_com.py b/testing/webcompat/interventions/tests/test_1849018_carefirst_com.py new file mode 100644 index 0000000000..9ac3131866 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1849018_carefirst_com.py @@ -0,0 +1,19 @@ +import pytest + +URL = "https://www.carefirst.com/myaccount" +BLOCKED_TEXT = "Application Blocked" +UNBLOCKED_CSS = "#maincontent" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(UNBLOCKED_CSS) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_text(BLOCKED_TEXT) diff --git a/testing/webcompat/interventions/tests/test_1849019_123068_axa_assistance_pl.py b/testing/webcompat/interventions/tests/test_1849019_123068_axa_assistance_pl.py new file mode 100644 index 0000000000..2caaf50cfc --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1849019_123068_axa_assistance_pl.py @@ -0,0 +1,39 @@ +import pytest +from webdriver.error import NoSuchElementException + +URL = "https://www.axa-assistance.pl/ubezpieczenie-turystyczne/?externalpartner=13100009&gclid=Cj0KCQjw4NujBhC5ARIsAF4Iv6eUnfuIEl9YkvO6pXP-I8g0ImynOMqpS7eMdBhyhjOj7G4eZzfSr_oaAnEUEALw_wcB#" +DATE_CSS = ".hiddenDate" +COOKIES_CSS = "#onetrust-accept-btn-handler" +MIN_WIDTH = 100 + + +def get_elem_width(client): + try: + client.soft_click(client.await_css(COOKIES_CSS)) + client.await_element_hidden(client.css(COOKIES_CSS)) + except NoSuchElementException: + pass + + elem = client.await_css(DATE_CSS) + return client.execute_script( + """ + return arguments[0].getBoundingClientRect().width; + """, + elem, + ) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert get_elem_width(client) > MIN_WIDTH + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert get_elem_width(client) < MIN_WIDTH diff --git a/testing/webcompat/interventions/tests/test_1849029_publi24_ro.py b/testing/webcompat/interventions/tests/test_1849029_publi24_ro.py new file mode 100644 index 0000000000..317f1bb0ff --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1849029_publi24_ro.py @@ -0,0 +1,28 @@ +import pytest + +URL = "https://www.publi24.ro/anunturi/imobiliare/" +MOBILE_CSS = ".filter.mobile" +DESKTOP_CSS = ".filter.desktop" +BLOCKED_CSS = "[data-translate='block_headline']" + + +async def load_page(client): + await client.navigate(URL, wait="complete") + if client.find_css(BLOCKED_CSS): + pytest.xfail("Site has blocked us, please test manually") + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await load_page(client) + assert client.await_css(MOBILE_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await load_page(client) + assert client.await_css(DESKTOP_CSS) diff --git a/testing/webcompat/interventions/tests/test_1849058_nicochannel_jp.py b/testing/webcompat/interventions/tests/test_1849058_nicochannel_jp.py new file mode 100644 index 0000000000..ba66992c7a --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1849058_nicochannel_jp.py @@ -0,0 +1,19 @@ +import pytest + +URL = "https://nicochannel.jp/engage-kiss/video/smBAc4UhdTUivpbuzBexSa9d" +BLOCKED_TEXT = "このブラウザはサポートされていません。" +PLAY_BUTTON_CSS = ".nfcp-overlay-play-lg" + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(PLAY_BUTTON_CSS, timeout=30) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_text(BLOCKED_TEXT, timeout=20) diff --git a/testing/webcompat/interventions/tests/test_1855014_77221_eksiseyler_com.py b/testing/webcompat/interventions/tests/test_1855014_77221_eksiseyler_com.py new file mode 100644 index 0000000000..9f615136bc --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1855014_77221_eksiseyler_com.py @@ -0,0 +1,21 @@ +import pytest + +URL = "https://eksiseyler.com/evrimin-kisa-surede-de-yasanabilecegini-kanitlayan-1971-hirvatistan-kertenkele-deneyi" +IMAGE_CSS = ".content-heading .cover-img img" +ERROR_MSG = "loggingEnabled is not defined" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + client.await_css(IMAGE_CSS, condition="!elem.src.includes('placeholder')") + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL, await_console_message=ERROR_MSG) + client.await_css(IMAGE_CSS, condition="elem.src.includes('placeholder')") diff --git a/testing/webcompat/interventions/tests/test_1855071_121197_www_meteoam_it.py b/testing/webcompat/interventions/tests/test_1855071_121197_www_meteoam_it.py new file mode 100644 index 0000000000..1a5a3c37ff --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1855071_121197_www_meteoam_it.py @@ -0,0 +1,36 @@ +import time + +import pytest + +URL = "https://www.meteoam.it/it/home" +IFRAME_CSS = "#iframe_map" +SEARCH_CSS = "#mobile_rightpanel .barbtnsearch" +INPUT_CSS = "#search_bar_txt" + + +def getWindowHeight(client): + return client.execute_script("return window.outerHeight") + + +async def doesHeightChange(client): + await client.navigate(URL) + client.switch_to_frame(client.await_css(IFRAME_CSS)) + initialHeight = getWindowHeight(client) + client.await_css(SEARCH_CSS).click() + client.await_css(INPUT_CSS, is_displayed=True).click() + time.sleep(2) + return getWindowHeight(client) != initialHeight + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert await doesHeightChange(client) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert not await doesHeightChange(client) diff --git a/testing/webcompat/interventions/tests/test_1855088_125039_hrmis2_eghrmis_gov_my.py b/testing/webcompat/interventions/tests/test_1855088_125039_hrmis2_eghrmis_gov_my.py new file mode 100644 index 0000000000..33f0193b9a --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1855088_125039_hrmis2_eghrmis_gov_my.py @@ -0,0 +1,25 @@ +import time + +import pytest + +URL = "https://hrmis2.eghrmis.gov.my/HRMISNET/Common/Main/Login.aspx" +DIALOG_CSS = "#dialog4" + + +async def is_dialog_shown(client): + await client.navigate(URL) + time.sleep(2) + dialog = client.await_css(DIALOG_CSS) + return client.is_displayed(dialog) + + +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + assert not await is_dialog_shown(client) + + +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + assert await is_dialog_shown(client) diff --git a/testing/webcompat/interventions/tests/test_1855102_121877_my_southerncross_co_nz.py b/testing/webcompat/interventions/tests/test_1855102_121877_my_southerncross_co_nz.py new file mode 100644 index 0000000000..00a17883f3 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_1855102_121877_my_southerncross_co_nz.py @@ -0,0 +1,23 @@ +import pytest + +URL = "https://my.southerncross.co.nz/browsernotsupported" +SUPPORTED_CSS = "svg.animated-success" +UNSUPPORTED_CSS = "svg.animated-failure" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + assert client.await_css(SUPPORTED_CSS) + assert not client.find_css(UNSUPPORTED_CSS) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + assert client.await_css(SUPPORTED_CSS) + assert client.find_css(UNSUPPORTED_CSS) diff --git a/testing/webcompat/interventions/tests/test_969844_mobile_de.py b/testing/webcompat/interventions/tests/test_969844_mobile_de.py new file mode 100644 index 0000000000..ddde96e0d4 --- /dev/null +++ b/testing/webcompat/interventions/tests/test_969844_mobile_de.py @@ -0,0 +1,27 @@ +import pytest + +# The site serves a different mobile page to Firefox than Chrome + +URL = "https://www.mobile.de/" +COOKIES_CSS = "button.mde-consent-accept-btn" +MOBILE_MENU_CSS = "header [data-testid='mobile-navigation-menu']" + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_interventions +async def test_enabled(client): + await client.navigate(URL) + client.soft_click(client.await_css(COOKIES_CSS)) + mobile_menu = client.await_css(MOBILE_MENU_CSS) + assert client.is_displayed(mobile_menu) + + +@pytest.mark.only_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_interventions +async def test_disabled(client): + await client.navigate(URL) + client.soft_click(client.await_css(COOKIES_CSS)) + mobile_menu = client.await_css(MOBILE_MENU_CSS) + assert not client.is_displayed(mobile_menu) diff --git a/testing/webcompat/mach_commands.py b/testing/webcompat/mach_commands.py new file mode 100644 index 0000000000..d67caadaec --- /dev/null +++ b/testing/webcompat/mach_commands.py @@ -0,0 +1,338 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import argparse +import io +import os +import platform +import sys + +from mach.decorators import Command +from mozbuild.base import MozbuildObject + +here = os.path.abspath(os.path.dirname(__file__)) + +GVE = "org.mozilla.geckoview_example" + + +def get(url): + import requests + + resp = requests.get(url) + resp.raise_for_status() + return resp + + +def untar(fileobj, dest): + import tarfile + + with tarfile.open(fileobj=fileobj, mode="r") as tar_data: + tar_data.extractall(path=dest) + + +def unzip(fileobj, dest): + import zipfile + + with zipfile.ZipFile(fileobj) as zip_data: + zip_data.extractall(path=dest) + + +def create_parser_interventions(): + from mozlog import commandline + + parser = argparse.ArgumentParser() + parser.add_argument("--webdriver-binary", help="Path to webdriver binary") + parser.add_argument( + "--webdriver-port", + action="store", + default="4444", + help="Port on which to run WebDriver", + ) + parser.add_argument( + "--webdriver-ws-port", + action="store", + default="9222", + help="Port on which to run WebDriver BiDi websocket", + ) + parser.add_argument("--bug", help="Bug to run tests for") + parser.add_argument( + "--do2fa", + action="store_true", + default=False, + help="Do two-factor auth live in supporting tests", + ) + parser.add_argument( + "--config", help="Path to JSON file containing logins and other settings" + ) + parser.add_argument( + "--debug", action="store_true", default=False, help="Debug failing tests" + ) + parser.add_argument( + "--headless", + action="store_true", + default=False, + help="Run firefox in headless mode", + ) + parser.add_argument( + "--interventions", + action="store", + default="both", + choices=["enabled", "disabled", "both", "none"], + help="Enable webcompat interventions", + ) + parser.add_argument( + "--shims", + action="store", + default="none", + choices=["enabled", "disabled", "both", "none"], + help="Enable SmartBlock shims", + ) + parser.add_argument( + "--platform", + action="store", + choices=["android", "desktop"], + help="Platform to target", + ) + + desktop_group = parser.add_argument_group("Desktop-specific arguments") + desktop_group.add_argument("--binary", help="Path to browser binary") + + android_group = parser.add_argument_group("Android-specific arguments") + android_group.add_argument( + "--device-serial", + action="store", + help="Running Android instances to connect to, if not emulator-5554", + ) + android_group.add_argument( + "--package-name", + action="store", + default=GVE, + help="Android package name to use", + ) + + commandline.add_logging_group(parser) + return parser + + +class InterventionTest(MozbuildObject): + def set_default_kwargs(self, logger, command_context, kwargs): + platform = kwargs["platform"] + binary = kwargs["binary"] + device_serial = kwargs["device_serial"] + is_gve_build = command_context.substs.get("MOZ_APP_NAME") == "fennec" + + if platform == "android" or ( + platform is None and binary is None and (device_serial or is_gve_build) + ): + kwargs["platform"] = "android" + else: + kwargs["platform"] = "desktop" + + if kwargs["platform"] == "desktop" and kwargs["binary"] is None: + kwargs["binary"] = self.get_binary_path() + + if kwargs["webdriver_binary"] is None: + webdriver_binary = self.get_binary_path( + "geckodriver", validate_exists=False + ) + + if not os.path.exists(webdriver_binary): + webdriver_binary = self.install_geckodriver( + logger, dest=os.path.dirname(webdriver_binary) + ) + + if not os.path.exists(webdriver_binary): + logger.error("Can't find geckodriver") + sys.exit(1) + kwargs["webdriver_binary"] = webdriver_binary + + def platform_string_geckodriver(self): + uname = platform.uname() + platform_name = {"Linux": "linux", "Windows": "win", "Darwin": "macos"}.get( + uname[0] + ) + + if platform_name in ("linux", "win"): + bits = "64" if uname[4] == "x86_64" else "32" + elif platform_name == "macos": + bits = "" + else: + raise ValueError(f"No precompiled geckodriver for platform {uname}") + + return f"{platform_name}{bits}" + + def install_geckodriver(self, logger, dest): + """Install latest Geckodriver.""" + if dest is None: + dest = os.path.join(self.distdir, "dist", "bin") + + is_windows = platform.uname()[0] == "Windows" + + release = get( + "https://api.github.com/repos/mozilla/geckodriver/releases/latest" + ).json() + ext = "zip" if is_windows else "tar.gz" + platform_name = self.platform_string_geckodriver() + name_suffix = f"-{platform_name}.{ext}" + for item in release["assets"]: + if item["name"].endswith(name_suffix): + url = item["browser_download_url"] + break + else: + raise ValueError(f"Failed to find geckodriver for platform {platform_name}") + + logger.info(f"Installing geckodriver from {url}") + + data = io.BytesIO(get(url).content) + data.seek(0) + decompress = unzip if ext == "zip" else untar + decompress(data, dest=dest) + + exe_ext = ".exe" if is_windows else "" + path = os.path.join(dest, f"geckodriver{exe_ext}") + + return path + + def setup_device(self, command_context, kwargs): + if kwargs["platform"] != "android": + return + + app = kwargs["package_name"] + device_serial = kwargs["device_serial"] + + if not device_serial: + from mozrunner.devices.android_device import ( + InstallIntent, + verify_android_device, + ) + + verify_android_device( + command_context, app=app, network=True, install=InstallIntent.YES + ) + + kwargs["device_serial"] = os.environ.get("DEVICE_SERIAL") + + # GVE does not have the webcompat addon by default. Add it. + if app == GVE: + kwargs["addon"] = "/data/local/tmp/webcompat.xpi" + push_to_device( + command_context.substs["ADB"], + device_serial, + webcompat_addon(command_context), + kwargs["addon"], + ) + + def run(self, command_context, **kwargs): + import mozlog + import runner + + mozlog.commandline.setup_logging( + "test-interventions", kwargs, {"mach": sys.stdout} + ) + logger = mozlog.get_default_logger("test-interventions") + status_handler = mozlog.handlers.StatusHandler() + logger.add_handler(status_handler) + + self.set_default_kwargs(logger, command_context, kwargs) + + self.setup_device(command_context, kwargs) + + if kwargs["interventions"] != "none": + interventions = ( + ["enabled", "disabled"] + if kwargs["interventions"] == "both" + else [kwargs["interventions"]] + ) + + for interventions_setting in interventions: + runner.run( + logger, + os.path.join(here, "interventions"), + kwargs["webdriver_binary"], + kwargs["webdriver_port"], + kwargs["webdriver_ws_port"], + browser_binary=kwargs.get("binary"), + device_serial=kwargs.get("device_serial"), + package_name=kwargs.get("package_name"), + addon=kwargs.get("addon"), + bug=kwargs["bug"], + debug=kwargs["debug"], + interventions=interventions_setting, + config=kwargs["config"], + headless=kwargs["headless"], + do2fa=kwargs["do2fa"], + ) + + if kwargs["shims"] != "none": + shims = ( + ["enabled", "disabled"] + if kwargs["shims"] == "both" + else [kwargs["shims"]] + ) + + for shims_setting in shims: + runner.run( + logger, + os.path.join(here, "shims"), + kwargs["webdriver_binary"], + kwargs["webdriver_port"], + kwargs["webdriver_ws_port"], + browser_binary=kwargs.get("binary"), + device_serial=kwargs.get("device_serial"), + package_name=kwargs.get("package_name"), + addon=kwargs.get("addon"), + bug=kwargs["bug"], + debug=kwargs["debug"], + shims=shims_setting, + config=kwargs["config"], + headless=kwargs["headless"], + do2fa=kwargs["do2fa"], + ) + + summary = status_handler.summarize() + passed = ( + summary.unexpected_statuses == 0 + and summary.log_level_counts.get("ERROR", 0) == 0 + and summary.log_level_counts.get("CRITICAL", 0) == 0 + ) + return passed + + +def webcompat_addon(command_context): + import shutil + + src = os.path.join(command_context.topsrcdir, "browser", "extensions", "webcompat") + dst = os.path.join( + command_context.virtualenv_manager.virtualenv_root, "webcompat.xpi" + ) + shutil.make_archive(dst, "zip", src) + shutil.move(f"{dst}.zip", dst) + return dst + + +def push_to_device(adb_path, device_serial, local_path, remote_path): + from mozdevice import ADBDeviceFactory + + device = ADBDeviceFactory(adb=adb_path, device=device_serial) + device.push(local_path, remote_path) + device.chmod(remote_path) + + +@Command( + "test-interventions", + category="testing", + description="Test the webcompat interventions", + parser=create_parser_interventions, + virtualenv_name="webcompat", +) +def test_interventions(command_context, **params): + here = os.path.abspath(os.path.dirname(__file__)) + command_context.virtualenv_manager.activate() + command_context.virtualenv_manager.install_pip_requirements( + os.path.join(here, "requirements.txt"), + require_hashes=False, + ) + + intervention_test = command_context._spawn(InterventionTest) + return 0 if intervention_test.run(command_context, **params) else 1 diff --git a/testing/webcompat/requirements.txt b/testing/webcompat/requirements.txt new file mode 100644 index 0000000000..1e5f90af3c --- /dev/null +++ b/testing/webcompat/requirements.txt @@ -0,0 +1,3 @@ +asyncio==3.4.3 +pytest-asyncio==0.16.0 +urllib3==1.26 diff --git a/testing/webcompat/runner.py b/testing/webcompat/runner.py new file mode 100644 index 0000000000..fefef7bf70 --- /dev/null +++ b/testing/webcompat/runner.py @@ -0,0 +1,263 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import errno +import os +import shutil +import tempfile + +import pytest + +GVE = "org.mozilla.geckoview_example" + + +def run( + logger, + path, + webdriver_binary, + webdriver_port, + webdriver_ws_port, + browser_binary=None, + device_serial=None, + package_name=None, + environ=None, + bug=None, + debug=False, + interventions=None, + shims=None, + config=None, + headless=False, + addon=None, + do2fa=False, +): + """""" + old_environ = os.environ.copy() + try: + with TemporaryDirectory() as cache: + if environ: + os.environ.update(environ) + + config_plugin = WDConfig() + result_recorder = ResultRecorder(logger) + + args = [ + "--strict", # turn warnings into errors + "-vv", # show each individual subtest and full failure logs + "--capture", + "no", # enable stdout/stderr from tests + "--basetemp", + cache, # temporary directory + "--showlocals", # display contents of variables in local scope + "-p", + "no:mozlog", # use the WPT result recorder + "--disable-warnings", + "-rfEs", + "-p", + "no:cacheprovider", # disable state preservation across invocations + "-o=console_output_style=classic", # disable test progress bar + "--browser", + "firefox", + "--webdriver-binary", + webdriver_binary, + "--webdriver-port", + webdriver_port, + "--webdriver-ws-port", + webdriver_ws_port, + ] + + if debug: + args.append("--pdb") + + if headless: + args.append("--headless") + + if browser_binary: + args.append("--browser-binary") + args.append(browser_binary) + + if device_serial: + args.append("--device-serial") + args.append(device_serial) + + if package_name: + args.append("--package-name") + args.append(package_name) + + if addon: + args.append("--addon") + args.append(addon) + + if bug: + args.append("--bug") + args.append(bug) + + if do2fa: + args.append("--do2fa") + + if config: + args.append("--config") + args.append(config) + + if interventions is not None and shims is not None: + raise ValueError( + "Must provide only one of interventions or shims argument" + ) + elif interventions is None and shims is None: + raise ValueError( + "Must provide either an interventions or shims argument" + ) + + name = "webcompat-interventions" + if interventions == "enabled": + args.extend(["-m", "with_interventions"]) + elif interventions == "disabled": + args.extend(["-m", "without_interventions"]) + elif interventions is not None: + raise ValueError(f"Invalid value for interventions {interventions}") + if shims == "enabled": + args.extend(["-m", "with_shims"]) + name = "smartblock-shims" + elif shims == "disabled": + args.extend(["-m", "without_shims"]) + name = "smartblock-shims" + elif shims is not None: + raise ValueError(f"Invalid value for shims {shims}") + else: + name = "smartblock-shims" + + if bug is not None: + args.extend(["-k", bug]) + + args.append(path) + try: + logger.suite_start([], name=name) + pytest.main(args, plugins=[config_plugin, result_recorder]) + except Exception as e: + logger.critical(str(e)) + finally: + logger.suite_end() + + finally: + os.environ = old_environ + + +class WDConfig: + def pytest_addoption(self, parser): + parser.addoption( + "--browser-binary", action="store", help="Path to browser binary" + ) + parser.addoption( + "--webdriver-binary", action="store", help="Path to webdriver binary" + ) + parser.addoption( + "--webdriver-port", + action="store", + default="4444", + help="Port on which to run WebDriver", + ) + parser.addoption( + "--webdriver-ws-port", + action="store", + default="9222", + help="Port on which to run WebDriver BiDi websocket", + ) + parser.addoption( + "--browser", action="store", choices=["firefox"], help="Name of the browser" + ) + parser.addoption("--bug", action="store", help="Bug number to run tests for") + parser.addoption( + "--do2fa", + action="store_true", + default=False, + help="Do two-factor auth live in supporting tests", + ) + parser.addoption( + "--config", + action="store", + help="Path to JSON file containing logins and other settings", + ) + parser.addoption( + "--addon", + action="store", + help="Path to the webcompat addon XPI to use", + ) + parser.addoption( + "--device-serial", + action="store", + help="Emulator device serial number", + ) + parser.addoption( + "--package-name", + action="store", + default=GVE, + help="Android package to run/connect to", + ) + parser.addoption( + "--headless", action="store_true", help="Run browser in headless mode" + ) + + +class ResultRecorder(object): + def __init__(self, logger): + self.logger = logger + + def pytest_runtest_logreport(self, report): + if report.passed and report.when == "call": + self.record_pass(report) + elif report.failed: + if report.when != "call": + self.record_error(report) + else: + self.record_fail(report) + elif report.skipped: + self.record_skip(report) + + def record_pass(self, report): + self.record(report.nodeid, "PASS") + + def record_fail(self, report): + # pytest outputs the stacktrace followed by an error message prefixed + # with "E ", e.g. + # + # def test_example(): + # > assert "fuu" in "foobar" + # > E AssertionError: assert 'fuu' in 'foobar' + message = "" + for line in report.longreprtext.splitlines(): + if line.startswith("E "): + message = line[1:].strip() + break + + self.record(report.nodeid, "FAIL", message=message, stack=report.longrepr) + + def record_error(self, report): + # error in setup/teardown + if report.when != "call": + message = "%s error" % report.when + self.record(report.nodeid, "ERROR", message, report.longrepr) + + def record_skip(self, report): + self.record(report.nodeid, "SKIP") + + def record(self, test, status, message=None, stack=None): + if stack is not None: + stack = str(stack) + self.logger.test_start(test) + self.logger.test_end( + test=test, status=status, expected="PASS", message=message, stack=stack + ) + + +class TemporaryDirectory(object): + def __enter__(self): + self.path = tempfile.mkdtemp(prefix="pytest-") + return self.path + + def __exit__(self, *args): + try: + shutil.rmtree(self.path) + except OSError as e: + # no such file or directory + if e.errno != errno.ENOENT: + raise diff --git a/testing/webcompat/shims/__init__.py b/testing/webcompat/shims/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/webcompat/shims/__init__.py diff --git a/testing/webcompat/shims/conftest.py b/testing/webcompat/shims/conftest.py new file mode 100644 index 0000000000..30807a1188 --- /dev/null +++ b/testing/webcompat/shims/conftest.py @@ -0,0 +1,68 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + +from ..fixtures import * # noqa: F403 + + +def pytest_generate_tests(metafunc): + """Generate tests based on markers.""" + + if "session" not in metafunc.fixturenames: + return + + marks = [mark.name for mark in metafunc.function.pytestmark] + + otherargs = {} + argvalues = [] + ids = [] + + if "only_platforms" in marks: + for mark in metafunc.function.pytestmark: + if mark.name == "only_platforms": + otherargs["only_platforms"] = mark.args + + if "skip_platforms" in marks: + for mark in metafunc.function.pytestmark: + if mark.name == "skip_platforms": + otherargs["skip_platforms"] = mark.args + + if "with_private_browsing" in marks: + otherargs["with_private_browsing"] = True + if "with_strict_etp" in marks: + otherargs["with_strict_etp"] = True + if "without_storage_partitioning" in marks: + otherargs["without_storage_partitioning"] = True + if "without_tcp " in marks: + otherargs["without_tcp "] = True + + if "with_shims" in marks: + argvalues.append([dict({"shims": True}, **otherargs)]) + ids.append("with_shims") + + if "without_shims" in marks: + argvalues.append([dict({"shims": False}, **otherargs)]) + ids.append("without_shims") + + metafunc.parametrize(["session"], argvalues, ids=ids, indirect=True) + + +@pytest.fixture(scope="function") # noqa: F405 +async def test_config(request, driver): + params = request.node.callspec.params.get("session") + + use_shims = params.get("shims") + if use_shims is None: + raise ValueError( + "Missing shims marker in %s:%s" + % (request.fspath, request.function.__name__) + ) + + return { + "aps": not params.get("without_storage_partitioning", False), + "use_pbm": params.get("with_private_browsing", False), + "use_shims": use_shims, + "use_strict_etp": params.get("with_strict_etp", False), + "without_tcp": params.get("without_tcp", False), + } diff --git a/testing/webcompat/shims/pytest.ini b/testing/webcompat/shims/pytest.ini new file mode 100644 index 0000000000..6f1f05efd9 --- /dev/null +++ b/testing/webcompat/shims/pytest.ini @@ -0,0 +1,11 @@ +[pytest] +console_output_style = classic +markers = + only_platforms: only run tests on specific platforms (mac, linux, windows, android) + skip_platforms: skip tests on specific platforms (mac, linux, windows, android) + with_shims: enable web-compat shims + without_shims: disable web-compat shims + without_storage_partitioning: disable partitioning of non-cookie third-party web storage + with_private_browsing: run test in a private browsing window + with_strict_etp: enable strict ETP mode + without_tcp: disable Total Cookie Protection diff --git a/testing/webcompat/shims/tests/__init__.py b/testing/webcompat/shims/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/webcompat/shims/tests/__init__.py diff --git a/testing/webcompat/shims/tests/common.py b/testing/webcompat/shims/tests/common.py new file mode 100644 index 0000000000..9a822e9e83 --- /dev/null +++ b/testing/webcompat/shims/tests/common.py @@ -0,0 +1,84 @@ +GPT_SHIM_MSG = "Google Publisher Tags is being shimmed by Firefox" +GAGTA_SHIM_MSG = "Google Analytics and Tag Manager is being shimmed by Firefox" + + +async def is_gtag_placeholder_displayed(client, url, finder, **kwargs): + await client.navigate(url, **kwargs) + client.execute_async_script( + """ + const done = arguments[0]; + if (window.dataLayer?.push?.toString() === [].push.toString()) { + return done(); + } + setTimeout(() => { + dataLayer.push({ + event: "datalayerReady", + eventTimeout: 1, + eventCallback: done, + }); + }, 100); + """ + ) + return client.is_displayed(client.find_element(finder)) + + +async def clicking_link_navigates(client, url, finder, **kwargs): + await client.navigate(url, **kwargs) + elem = client.await_element(finder) + return client.session.execute_async_script( + """ + const elem = arguments[0], + done = arguments[1]; + window.onbeforeunload = function() { + done(true); + }; + elem.click(); + setTimeout(() => { + done(false); + }, 1000); + """, + args=[elem], + ) + + +async def verify_redirectors(client, urls, expected="REDIRECTED"): + await client.navigate(client.inline("<html>")) + for url, type in urls.items(): + assert expected == client.execute_async_script( + """ + const [url, type, resolve] = arguments; + fetch(url).then(async response => { + if (!response.ok) { + return resolve("FAILED"); + } + + try { + if (type === "image") { + const blob = await response.blob(); + const url = URL.createObjectURL(blob); + const img = new Image(1, 1); + await new Promise((res, rej) => { + img.onerror = rej; + img.onload = res; + img.src = url; + }); + } else if (type === "js") { + const text = await response.text(); + if (!text.includes("This script is intentionally empty")) { + throw ""; + } + } else { + return resolve("UNKNOWN TYPE"); + } + } catch(_) { + return resolve("TYPE MISMATCH"); + } + + resolve(response.redirected ? "REDIRECTED" : "LOADED"); + }).catch(_ => { + resolve("BLOCKED"); + }); + """, + url, + type, + ) diff --git a/testing/webcompat/shims/tests/test_1624914_google_trends.py b/testing/webcompat/shims/tests/test_1624914_google_trends.py new file mode 100644 index 0000000000..1a11713cdc --- /dev/null +++ b/testing/webcompat/shims/tests/test_1624914_google_trends.py @@ -0,0 +1,29 @@ +import pytest + +URL = "https://knowyourmeme.com/memes/awesome-face-epic-smiley" +IFRAME = "iframe#trends-widget-1" + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.with_shims +async def test_works_with_shims(client): + await client.load_page_and_wait_for_iframe(URL, client.css(IFRAME)) + assert client.await_css("svg") + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_tcp +@pytest.mark.without_shims +async def test_works_without_etp(client): + await client.load_page_and_wait_for_iframe(URL, client.css(IFRAME)) + assert client.await_css("body.neterror") + + +@pytest.mark.skip_platforms("android") +@pytest.mark.asyncio +@pytest.mark.without_shims +async def test_needs_shims(client): + await client.load_page_and_wait_for_iframe(URL, client.css(IFRAME)) + assert client.await_css("body.neterror") diff --git a/testing/webcompat/shims/tests/test_1694168_google_analytics_and_tag_manager.py b/testing/webcompat/shims/tests/test_1694168_google_analytics_and_tag_manager.py new file mode 100644 index 0000000000..a00e617bdb --- /dev/null +++ b/testing/webcompat/shims/tests/test_1694168_google_analytics_and_tag_manager.py @@ -0,0 +1,23 @@ +import pytest + +URL = "https://agspares.co.nz/category/Super-Store-Tractor-Linkage-Pins-Lynch-Pins-R-Clips" +ITEM = ".productsListed.item a[onclick]" + + +from .common import GAGTA_SHIM_MSG, clicking_link_navigates + + +@pytest.mark.asyncio +@pytest.mark.with_strict_etp +@pytest.mark.with_shims +async def test_enabled(client): + assert await clicking_link_navigates( + client, URL, client.css(ITEM), await_console_message=GAGTA_SHIM_MSG + ) + + +@pytest.mark.asyncio +@pytest.mark.with_strict_etp +@pytest.mark.without_shims +async def test_disabled(client): + assert not await clicking_link_navigates(client, URL, client.css(ITEM)) diff --git a/testing/webcompat/shims/tests/test_1701685_advertising_com.py b/testing/webcompat/shims/tests/test_1701685_advertising_com.py new file mode 100644 index 0000000000..b89cf51135 --- /dev/null +++ b/testing/webcompat/shims/tests/test_1701685_advertising_com.py @@ -0,0 +1,22 @@ +import pytest + +from .common import verify_redirectors + +URLS = { + "https://ads.advertising.com/x.js?1": "js", + "https://ads.advertising.com/x?1": "image", +} + + +@pytest.mark.asyncio +@pytest.mark.with_strict_etp +@pytest.mark.with_shims +async def test_works_with_shims(client): + await verify_redirectors(client, URLS, "REDIRECTED") + + +@pytest.mark.asyncio +@pytest.mark.with_strict_etp +@pytest.mark.without_shims +async def test_works_without_etp(client): + await verify_redirectors(client, URLS, "BLOCKED") diff --git a/testing/webcompat/shims/tests/test_1717806_adsafeprotected.py b/testing/webcompat/shims/tests/test_1717806_adsafeprotected.py new file mode 100644 index 0000000000..e7a530e141 --- /dev/null +++ b/testing/webcompat/shims/tests/test_1717806_adsafeprotected.py @@ -0,0 +1,37 @@ +import pytest + +from .common import verify_redirectors + +URLS = { + "https://x.adsafeprotected.com/x.gif?1": "image", + "https://x.adsafeprotected.com/x.png?1": "image", + "https://x.adsafeprotected.com/x/x": "image", + "https://x.adsafeprotected.com/img": "image", + "https://x.adsafeprotected.com/x.js?1": "js", + "https://x.adsafeprotected.com/x/adj?1": "js", + "https://x.adsafeprotected.com/x/imp/1": "js", + "https://x.adsafeprotected.com/x/Serving/1": "js", + "https://x.adsafeprotected.com/x/unit/1": "js", + "https://x.adsafeprotected.com/jload": "js", + "https://x.adsafeprotected.com/jload?1": "js", + "https://x.adsafeprotected.com/jsvid": "js", + "https://x.adsafeprotected.com/jsvid?1": "js", + "https://x.adsafeprotected.com/mon?1": "js", + "https://x.adsafeprotected.com/tpl": "js", + "https://x.adsafeprotected.com/tpl?1": "js", + "https://x.adsafeprotected.com/services/pub?1": "js", +} + + +@pytest.mark.asyncio +@pytest.mark.with_strict_etp +@pytest.mark.with_shims +async def test_works_with_shims(client): + await verify_redirectors(client, URLS, "REDIRECTED") + + +@pytest.mark.asyncio +@pytest.mark.with_strict_etp +@pytest.mark.without_shims +async def test_works_without_etp(client): + await verify_redirectors(client, URLS, "BLOCKED") diff --git a/testing/webcompat/shims/tests/test_1717806_stickyadstv.py b/testing/webcompat/shims/tests/test_1717806_stickyadstv.py new file mode 100644 index 0000000000..74a895aa51 --- /dev/null +++ b/testing/webcompat/shims/tests/test_1717806_stickyadstv.py @@ -0,0 +1,22 @@ +import pytest + +from .common import verify_redirectors + +URLS = { + "https://ads.stickyadstv.com/auto-user-sync?1": "image", + "https://ads.stickyadstv.com/user-matching?1": "image", +} + + +@pytest.mark.asyncio +@pytest.mark.with_strict_etp +@pytest.mark.with_shims +async def test_works_with_shims(client): + await verify_redirectors(client, URLS, "REDIRECTED") + + +@pytest.mark.asyncio +@pytest.mark.with_strict_etp +@pytest.mark.without_shims +async def test_works_without_etp(client): + await verify_redirectors(client, URLS, "BLOCKED") diff --git a/testing/webcompat/shims/tests/test_1762851_google_publisher_tags.py b/testing/webcompat/shims/tests/test_1762851_google_publisher_tags.py new file mode 100644 index 0000000000..3b52ce8480 --- /dev/null +++ b/testing/webcompat/shims/tests/test_1762851_google_publisher_tags.py @@ -0,0 +1,23 @@ +import pytest + +URL = "https://www.carousell.sg/search/ps3/?searchId=DjgOQf" +PLACEHOLDER = "[id*='Desktop_Search_FWB']" + + +from .common import GPT_SHIM_MSG, is_gtag_placeholder_displayed + + +@pytest.mark.asyncio +@pytest.mark.with_strict_etp +@pytest.mark.with_shims +async def test_enabled(client): + assert not await is_gtag_placeholder_displayed( + client, URL, client.css(PLACEHOLDER), await_console_message=GPT_SHIM_MSG + ) + + +@pytest.mark.asyncio +@pytest.mark.with_strict_etp +@pytest.mark.without_shims +async def test_disabled(client): + assert not await is_gtag_placeholder_displayed(client, URL, client.css(PLACEHOLDER)) diff --git a/testing/webcompat/shims/tests/test_1767270_rva311_com_pbm_fix.py b/testing/webcompat/shims/tests/test_1767270_rva311_com_pbm_fix.py new file mode 100644 index 0000000000..2e30bae2cb --- /dev/null +++ b/testing/webcompat/shims/tests/test_1767270_rva311_com_pbm_fix.py @@ -0,0 +1,26 @@ +import pytest + +URL = "https://www.rva311.com/rvaone" +SHIM_ACTIVE_MSG = "Private Browsing Web APIs is being shimmed by Firefox" +IDB_FAILURE_MSG = "InvalidStateError: A mutation operation was attempted on a database" + + +@pytest.mark.asyncio +@pytest.mark.with_private_browsing +@pytest.mark.with_shims +async def test_with_shim(client, platform): + msg = None if platform == "android" else SHIM_ACTIVE_MSG + await client.navigate(URL, await_console_message=msg) + desktop, mobile = client.await_first_element_of( + [client.css("#root nav"), client.css("#mobilePageTitle")], is_displayed=True + ) + assert desktop or mobile + + +@pytest.mark.asyncio +@pytest.mark.with_private_browsing +@pytest.mark.without_shims +async def test_without_shim(client, platform): + msg = None if platform == "android" else IDB_FAILURE_MSG + await client.navigate(URL, await_console_message=msg) + assert client.find_css("#root [class*='loading-dot']", is_displayed=True) diff --git a/testing/webcompat/shims/tests/test_1775099_google_publisher_tags.py b/testing/webcompat/shims/tests/test_1775099_google_publisher_tags.py new file mode 100644 index 0000000000..1e4e595561 --- /dev/null +++ b/testing/webcompat/shims/tests/test_1775099_google_publisher_tags.py @@ -0,0 +1,23 @@ +import pytest + +URL = "https://themighty.com/topic/fibromyalgia/difficulties-sitting-chronic-pain-fibromyalgia/" +PLACEHOLDER = ".tm-ads" + + +from .common import GPT_SHIM_MSG, is_gtag_placeholder_displayed + + +@pytest.mark.asyncio +@pytest.mark.with_strict_etp +@pytest.mark.with_shims +async def test_enabled(client): + assert not await is_gtag_placeholder_displayed( + client, URL, client.css(PLACEHOLDER), await_console_message=GPT_SHIM_MSG + ) + + +@pytest.mark.asyncio +@pytest.mark.with_strict_etp +@pytest.mark.without_shims +async def test_disabled(client): + assert await is_gtag_placeholder_displayed(client, URL, client.css(PLACEHOLDER)) |