• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2023 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5from __future__ import annotations
6
7import re
8from typing import TYPE_CHECKING, Tuple
9
10from crossbench import plt
11from crossbench.browsers.attributes import BrowserAttributes
12from crossbench.browsers.browser import Browser
13from crossbench.browsers.viewport import Viewport
14from crossbench.browsers.webdriver import WebDriverBrowser
15
16if TYPE_CHECKING:
17  from crossbench.browsers.settings import Settings
18  from crossbench.flags.base import Flags
19  from crossbench.path import AnyPath
20  from crossbench.runner.groups.session import BrowserSessionRunGroup
21
22
23class Firefox(Browser):
24
25  @classmethod
26  def default_path(cls, platform: plt.Platform) -> AnyPath:
27    return platform.search_app_or_executable(
28        "Firefox",
29        macos=["Firefox.app"],
30        linux=["firefox"],
31        win=["Mozilla Firefox/firefox.exe"])
32
33  @classmethod
34  def developer_edition_path(cls, platform: plt.Platform) -> AnyPath:
35    return platform.search_app_or_executable(
36        "Firefox Developer Edition",
37        macos=["Firefox Developer Edition.app"],
38        linux=["firefox-developer-edition"],
39        win=["Firefox Developer Edition/firefox.exe"])
40
41  @classmethod
42  def nightly_path(cls, platform: plt.Platform) -> AnyPath:
43    return platform.search_app_or_executable(
44        "Firefox Nightly",
45        macos=["Firefox Nightly.app"],
46        linux=["firefox-nightly", "firefox-trunk"],
47        win=["Firefox Nightly/firefox.exe"])
48
49  def _setup_cache_dir(self, settings: Settings) -> None:
50    cache_dir = settings.cache_dir
51    if cache_dir:
52      self.cache_dir = cache_dir
53      self.clear_cache_dir = False
54    else:
55      self.cache_dir: AnyPath = settings.platform.mkdtemp(prefix="firefox")
56      self.clear_cache_dir = True
57
58  @property
59  def type_name(self) -> str:
60    return "firefox"
61
62  @property
63  def attributes(self) -> BrowserAttributes:
64    return BrowserAttributes.FIREFOX
65
66  def _extract_version(self) -> str:
67    assert self.path
68    version_string = self.platform.app_version(self.path)
69    # "Firefox 107.0" => "107.0"
70    return str(re.findall(r"[\d\.]+", version_string)[0])
71
72  def _get_browser_flags_for_session(
73      self, session: BrowserSessionRunGroup) -> Tuple[str, ...]:
74    flags_copy = self.flags.copy()
75    flags_copy.update(session.extra_flags)
76    flags_copy.update(self.network.extra_flags(self.attributes))
77    self._handle_viewport_flags(flags_copy)
78    if self.log_file:
79      flags_copy["--MOZ_LOG_FILE"] = str(self.log_file)
80    return tuple(flags_copy)
81
82  def _handle_viewport_flags(self, flags: Flags) -> None:
83    new_width, new_height = 0, 0
84    if self.viewport.has_size:
85      new_width, new_height = self.viewport.size
86    update_size = False
87    if "--width" in flags:
88      if self.viewport.is_default:
89        new_width = int(flags["--width"])
90        update_size = True
91      else:
92        assert self.viewport.width == int(flags["--width"])
93    if "--height" in flags:
94      if self.viewport.is_default:
95        new_height = int(flags["--height"])
96        update_size = True
97      else:
98        assert self.viewport.height == int(flags["--height"])
99    if update_size:
100      assert self.viewport.is_default
101      self.viewport = Viewport(new_width, new_height)
102    elif self.viewport.has_size:
103      flags["--width"] = str(self.viewport.width)
104      flags["--height"] = str(self.viewport.height)
105
106    self._sync_viewport_flag(flags, "--kiosk", self.viewport.is_fullscreen,
107                             Viewport.FULLSCREEN)
108    self._sync_viewport_flag(flags, "--headless", self.viewport.is_headless,
109                             Viewport.HEADLESS)
110
111    if self.viewport.has_size and not self.viewport.is_default:
112      if not isinstance(self,
113                        WebDriverBrowser) and self.viewport.size != (0, 0):
114        raise ValueError(f"Browser {self} cannot handle viewport position: "
115                         f"{self.viewport.position}")
116    else:
117      if not isinstance(self, WebDriverBrowser):
118        raise ValueError(
119            f"Browser {self} cannot handle viewport mode: {self.viewport}")
120