• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gocept / gocept.selenium / 6444675817

05 Oct 2023 09:33AM UTC coverage: 77.82%. Remained the same
6444675817

push

github

web-flow
Fix path

284 of 370 branches covered (0.0%)

Branch coverage included in aggregate %.

951 of 1217 relevant lines covered (78.14%)

3.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.2
/src/gocept/selenium/webdriver.py
1
#############################################################################
2
#
3
# Copyright (c) 2012 Zope Foundation and Contributors.
4
# All Rights Reserved.
5
#
6
# This software is subject to the provisions of the Zope Public License,
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
# FOR A PARTICULAR PURPOSE.
12
#
13
##############################################################################
14

15
from selenium.common.exceptions import JavascriptException
5✔
16
from selenium.common.exceptions import WebDriverException
5✔
17
from selenium.webdriver.chrome.service import Service as ChromeService
5✔
18
from selenium.webdriver.edge.service import Service as EdgeService
5✔
19
from selenium.webdriver.firefox.service import Service as FirefoxService
5✔
20
from webdriver_manager.chrome import ChromeDriverManager
5✔
21
from webdriver_manager.firefox import GeckoDriverManager
5✔
22
from webdriver_manager.microsoft import EdgeChromiumDriverManager
5✔
23
import atexit
5✔
24
import gocept.selenium.wd_selenese
5✔
25
import os
5✔
26
import pathlib
5✔
27
import plone.testing
5✔
28
import selenium.webdriver
5✔
29
import selenium.webdriver.edge.options
5✔
30
import sys
5✔
31
import tempfile
5✔
32
import warnings
5✔
33

34

35
class Layer(plone.testing.Layer):
5✔
36

37
    profile = None
5✔
38
    _default_headless = False
5✔
39
    _default_browser = 'firefox'
5✔
40
    _supported_browsers = ('chrome', 'edge', 'firefox')
5✔
41

42
    def setUp(self):
5✔
43
        if 'http_address' not in self:
5✔
44
            raise KeyError("No base layer has set self['http_address']")
5✔
45

46
        browser = os.environ.get('GOCEPT_WEBDRIVER_BROWSER', '').lower()
5✔
47
        headless = os.environ.get('GOCEPT_SELENIUM_HEADLESS', '').lower()
5✔
48

49
        if headless not in {'true', 'false'}:
5!
50
            warnings.warn(
×
51
                "The environment variable 'GOCEPT_SELENIUM_HEADLESS' has an"
52
                " invalid value. Allowed values are 'true' and 'false'."
53
                f" Got: {os.environ.get('GOCEPT_SELENIUM_HEADLESS')!r}."
54
                " Falling back to default ('false').")
55
            headless = 'false'
×
56

57
        self['headless'] = (headless == 'true')
5✔
58

59
        if browser not in self._supported_browsers:
5✔
60
            warnings.warn(
5✔
61
                "The environment variable 'GOCEPT_WEBDRIVER_BROWSER' has an "
62
                "invalid value. Possible values are:"
63
                f" {self._supported_browsers}."
64
                f" Got: {os.environ.get('GOCEPT_WEBDRIVER_BROWSER')!r}."
65
                " Falling back to 'firefox'.")
66
            browser = 'firefox'
5✔
67

68
        if browser in self._supported_browsers:
5!
69
            self['browser'] = browser
5✔
70
        else:
71
            self['browser'] = self._default_browser
×
72

73
        # Setup download dir.
74
        self['selenium_download_dir'] = pathlib.Path(tempfile.mkdtemp(
5✔
75
            prefix='gocept.selenium.download-dir'))
76

77
        self._start_selenium()
5✔
78
        atexit.register(self._stop_selenium)
5✔
79

80
    def tearDown(self):
5✔
81
        self._stop_selenium()
5✔
82
        self['selenium_download_dir'].rmdir()
5✔
83
        del self['selenium_download_dir']
5✔
84
        # XXX upstream bug, quit should reset session_id
85
        self['seleniumrc'].session_id = None
5✔
86
        del self['seleniumrc']
5✔
87
        del self['browser']
5✔
88
        del self['headless']
5✔
89

90
    def get_firefox_webdriver_args(self):
5✔
91
        options = selenium.webdriver.FirefoxOptions()
5✔
92

93
        if self['headless']:
5!
94
            options.add_argument('-headless')
5✔
95

96
        profile_path = os.environ.get(
5✔
97
            'GOCEPT_WEBDRIVER_FF_PROFILE',
98
            os.environ.get('GOCEPT_SELENIUM_FF_PROFILE'))
99
        if profile_path:
5!
100
            options.set_preference('profile', profile_path)
5✔
101

102
        # Save downloads always to disk into a predefined dir.
103
        options.set_preference("browser.download.folderList", 2)
5✔
104
        options.set_preference(
5✔
105
            "browser.download.manager.showWhenStarting", False)
106
        options.set_preference(
5✔
107
            "browser.download.dir", str(self['selenium_download_dir']))
108
        options.set_preference(
5✔
109
            "browser.helperApps.neverAsk.saveToDisk", "application/pdf")
110
        options.set_preference("pdfjs.disabled", True)
5✔
111

112
        return {
5✔
113
            'options': options,
114
            'service': FirefoxService(
115
                GeckoDriverManager().install(),
116
                log_output=open("geckodriver.log", "a+", encoding="utf-8"))}
117

118
    def get_edge_webdriver_args(self):
5✔
119
        options = selenium.webdriver.edge.options.Options()
×
120
        if self['headless']:
×
121
            options.add_argument('headless')
×
122

123
        return {'options': options,
×
124
                'service': EdgeService(EdgeChromiumDriverManager().install())}
125

126
    def get_chrome_webdriver_args(self):
5✔
127
        options = selenium.webdriver.ChromeOptions()
5✔
128
        options.add_argument('--disable-dev-shm-usage')
5✔
129

130
        if self['headless']:
5!
131
            options.add_argument('--headless')
5✔
132

133
        # Save downloads always to disk into a predefined dir.
134
        prefs = {
5✔
135
            'download.default_directory': str(self['selenium_download_dir']),
136
            'download.prompt_for_download': False,
137
        }
138

139
        options.add_experimental_option('prefs', prefs)
5✔
140

141
        mobile_emulation = {
5✔
142
            'deviceMetrics': {
143
                'pixelRatio': 1.0,
144
                'width': 1600,
145
                'height': 1200,
146
            }
147
        }
148

149
        options.add_experimental_option('mobileEmulation', mobile_emulation)
5✔
150

151
        return {
5✔
152
            'options': options,
153
            'service': ChromeService(
154
                ChromeDriverManager().install(),
155
                service_args=['--log-path=chromedriver.log']),
156
        }
157

158
    def _start_selenium(self):
5✔
159
        if self['browser'] == 'firefox':
5✔
160
            self['seleniumrc'] = selenium.webdriver.Firefox(
5✔
161
                **self.get_firefox_webdriver_args(),
162
            )
163

164
        if self['browser'] == 'chrome':
5✔
165
            self['seleniumrc'] = selenium.webdriver.Chrome(
5✔
166
                **self.get_chrome_webdriver_args(),
167
            )
168
        if self['browser'] == 'edge':
5!
169
            self['seleniumrc'] = selenium.webdriver.Edge(
×
170
                **self.get_edge_webdriver_args(),
171
            )
172

173
    def _stop_selenium(self):
5✔
174
        # Only stop selenium if it is still active.
175
        if (self.get('seleniumrc') is None or
5✔
176
                self['seleniumrc'].session_id is None):
177
            return
5✔
178

179
        # Quit also removes the tempdir the ff profile is copied in.
180
        self['seleniumrc'].quit()
5✔
181

182
    def testTearDown(self):
5✔
183
        try:
5✔
184
            self['seleniumrc'].execute_script('window.localStorage.clear()')
5✔
185
        except (JavascriptException, WebDriverException):
5✔
186
            # We can't do anything here, there might be no current_url
187
            pass
5✔
188
        for path in self['selenium_download_dir'].iterdir():
5✔
189
            path.unlink()
5✔
190

191

192
class WebdriverSeleneseLayer(plone.testing.Layer):
5✔
193

194
    _timeout = int(os.environ.get('GOCEPT_SELENIUM_TIMEOUT', 30))
5✔
195

196
    def setUp(self):
5✔
197
        self['selenium'] = gocept.selenium.wd_selenese.Selenese(
5✔
198
            self['seleniumrc'], self['http_address'], self._timeout)
199

200
    def testSetUp(self):
5✔
201
        # BBB reset settings
202
        self['selenium'].setTimeout(self._timeout * 1000)
5✔
203
        class_ = gocept.selenium.wd_selenese.Selenese
5✔
204
        for name in ['screenshot_directory', 'capture_screenshot']:
5✔
205
            setattr(self['selenium'], name, getattr(class_, name))
5✔
206

207
    def tearDown(self):
5✔
208
        del self['selenium']
5✔
209

210

211
class IntegrationBase:
5✔
212

213
    # hostname and port of the local application.
214
    host = os.environ.get('GOCEPT_SELENIUM_APP_HOST', 'localhost')
5✔
215
    port = int(os.environ.get('GOCEPT_SELENIUM_APP_PORT', 0))
5✔
216

217
    def __init__(self, *args, **kw):
5✔
218
        kw['module'] = sys._getframe(1).f_globals['__name__']
5✔
219
        super().__init__(*args, **kw)
5✔
220
        self.SELENIUM_LAYER = Layer(
5✔
221
            name='IntegratedSeleniumLayer', bases=[self])
222
        self.SELENESE_LAYER = WebdriverSeleneseLayer(
5✔
223
            name='IntegratedSeleneseLayer', bases=[self.SELENIUM_LAYER])
224

225
    def make_layer_name(self, bases):
5✔
226
        if bases:
5!
227
            base = bases[0]
×
228
            name = f'({base.__module__}.{base.__name__})'
×
229
        else:
230
            name = self.__class__.__name__
5✔
231
        return name
5✔
232

233
    def setUp(self):
5✔
234
        super().setUp()
5✔
235
        self.SELENIUM_LAYER.setUp()
5✔
236
        self.SELENESE_LAYER.setUp()
5✔
237
        self['seleniumrc'] = self.SELENIUM_LAYER['seleniumrc']
5✔
238

239
    def tearDown(self):
5✔
240
        self.SELENESE_LAYER.tearDown()
5✔
241
        self.SELENIUM_LAYER.tearDown()
5✔
242
        del self['seleniumrc']
5✔
243
        super().tearDown()
5✔
244

245
    def testSetUp(self):
5✔
246
        super().testSetUp()
5✔
247
        self.SELENIUM_LAYER.testSetUp()
5✔
248
        self.SELENESE_LAYER.testSetUp()
5✔
249
        self['selenium'] = self.SELENESE_LAYER['selenium']
5✔
250

251
    def testTearDown(self):
5✔
252
        self.SELENESE_LAYER.testTearDown()
5✔
253
        self.SELENIUM_LAYER.testTearDown()
5✔
254
        super().testTearDown()
5✔
255

256

257
class WebdriverSeleneseTestCase:
5✔
258

259
    @property
5✔
260
    def selenium(self):
4✔
261
        return self.layer['selenium']
5✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc