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

zopefoundation / zope.testbrowser / 16098871825

05 Mar 2025 04:01PM UTC coverage: 91.403%. Remained the same
16098871825

push

github

icemac
Back to development: 7.1

427 of 520 branches covered (82.12%)

Branch coverage included in aggregate %.

1859 of 1981 relevant lines covered (93.84%)

0.94 hits per line

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

100.0
/src/zope/testbrowser/interfaces.py
1
##############################################################################
2
#
3
# Copyright (c) 2005 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
"""Browser-like functional doctest interfaces
15
"""
16

17
import zope.interface
1✔
18
import zope.interface.common.mapping
1✔
19
import zope.schema
1✔
20

21

22
__docformat__ = "reStructuredText"
1✔
23

24

25
class AlreadyExpiredError(ValueError):
1✔
26
    pass
1✔
27

28

29
class ICookies(zope.interface.common.mapping.IExtendedReadMapping,
1✔
30
               zope.interface.common.mapping.IExtendedWriteMapping,
31
               zope.interface.common.mapping.IMapping):  # NOT copy
32
    """A mapping of cookies for a given url"""
33

34
    url = zope.schema.URI(
1✔
35
        title="URL",
36
        description="The URL the mapping is currently exposing.",
37
        required=True)
38

39
    header = zope.schema.TextLine(
1✔
40
        title="Header",
41
        description="The current value for the Cookie header for the URL",
42
        required=True)
43

44
    def forURL(url):
1✔
45
        """Returns another ICookies instance for the given URL."""
46

47
    def getinfo(name):
1✔
48
        """returns dict of settings for the given cookie name.
49

50
        This includes only the following cookie values:
51

52
        - name (str)
53
        - value (str),
54
        - port (int or None),
55
        - domain (str),
56
        - path (str or None),
57
        - secure (bool), and
58
        - expires (datetime.datetime with pytz.UTC timezone or None),
59
        - comment (str or None),
60
        - commenturl (str or None).
61

62
        (Method name is not camelCase because it is intended to feel like an
63
        extension to the mapping interface, which uses all lower case, e.g.
64
        iterkeys.)
65
        """
66

67
    def iterinfo(name=None):
1✔
68
        """iterate over the information about all the cookies for the URL.
69

70
        Each result is a dictionary as described for ``getinfo``.
71

72
        If name is given, iterates over all cookies for given name.
73

74
        (Method name is not camelCase because it is intended to feel like an
75
        extension to the mapping interface, which uses all lower case, e.g.
76
        iterkeys.)
77
        """
78

79
    def create(name, value,
1✔
80
               domain=None, expires=None, path=None, secure=None, comment=None,
81
               commenturl=None, port=None):
82
        """Create a new cookie with the given values.
83

84
        If cookie of the same name, domain, and path exists, raises a
85
        ValueError.
86

87
        Expires is a string or a datetime.datetime.  timezone-naive datetimes
88
        are interpreted as in UTC.  If expires is before now, raises
89
        AlreadyExpiredError.
90

91
        If the domain or path do not generally match the current URL, raises
92
        ValueError.
93
        """
94

95
    def change(name, value=None, domain=None, expires=None, path=None,
1✔
96
               secure=None, comment=None, commenturl=None, port=None):
97
        """Change an attribute of an existing cookie.
98

99
        If cookie does not exist, raises a KeyError."""
100

101
    def clearAll():
1✔
102
        """Clear all cookies for the associated browser, irrespective of URL
103
        """
104

105
    def clearAllSession():
1✔
106
        """Clear session cookies for associated browser, irrespective of URL
107
        """
108

109

110
class IBrowser(zope.interface.Interface):
1✔
111
    """A Programmatic Web Browser."""
112

113
    cookies = zope.schema.Field(
1✔
114
        title="Cookies",
115
        description=("An ICookies mapping for the browser's current URL."),
116
        required=True)
117

118
    url = zope.schema.URI(
1✔
119
        title="URL",
120
        description="The URL the browser is currently showing.",
121
        required=True)
122

123
    headers = zope.schema.Field(
1✔
124
        title="Headers",
125
        description=("Headers of the HTTP response; a "
126
                     "``httplib.HTTPMessage``."),
127
        required=True)
128

129
    contents = zope.schema.Text(
1✔
130
        title="Contents",
131
        description="The complete response body of the HTTP request.",
132
        required=True)
133

134
    isHtml = zope.schema.Bool(
1✔
135
        title="Is HTML",
136
        description="Tells whether the output is HTML or not.",
137
        required=True)
138

139
    title = zope.schema.TextLine(
1✔
140
        title="Title",
141
        description="Title of the displayed page",
142
        required=False)
143

144
    handleErrors = zope.schema.Bool(
1✔
145
        title="Handle Errors",
146
        description=("Describes whether server-side errors will be handled "
147
                     "by the publisher. If set to ``False``, the error will "
148
                     "progress all the way to the test, which is good for "
149
                     "debugging."),
150
        default=True,
151
        required=True)
152

153
    followRedirects = zope.schema.Bool(
1✔
154
        title="Follow Redirects",
155
        description=("Describes whether the browser follows redirects. If "
156
                     "set to ``True``, it will automatically issue ``GET`` "
157
                     "requests for redirect responses; if set to ``False``, "
158
                     "it will return redirect responses directly, allowing "
159
                     "the caller to make assertions about them."),
160
        default=True,
161
        required=True)
162

163
    def addHeader(key, value):
1✔
164
        """Adds a header to each HTTP request.
165

166
        Adding additional headers can be useful in many ways, from setting the
167
        credentials token to specifying the browser identification string.
168
        """
169

170
    def open(url, data=None):
1✔
171
        """Open a URL in the browser.
172

173
        The URL must be fully qualified. However, note that the server name
174
        and port is arbitrary for Zope 3 functional tests, since the request
175
        is sent to the publisher directly.
176

177
        The ``data`` argument describes the data that will be sent as the body
178
        of the request.
179
        """
180

181
    def reload():
1✔
182
        """Reload the current page.
183

184
        Like a browser reload, if the past request included a form submission,
185
        the form data will be resubmitted."""
186

187
    def goBack(count=1):
1✔
188
        """Go back in history by a certain amount of visisted pages.
189

190
        The ``count`` argument specifies how far to go back. It is set to 1 by
191
        default.
192
        """
193

194
    def getLink(text=None, url=None, id=None, index=0):
1✔
195
        """Return an ILink from the page.
196

197
        The link is found by the arguments of the method.  One or more may be
198
        used together.
199

200
          o ``text`` -- A regular expression trying to match the link's text,
201
            in other words everything between <a> and </a> or the value of the
202
            submit button.
203

204
          o ``url`` -- The URL the link is going to. This is either the
205
            ``href`` attribute of an anchor tag or the action of a form.
206

207
          o ``id`` -- The id attribute of the anchor tag submit button.
208

209
          o ``index`` -- When there's more than one link that matches the
210
            text/URL, you can specify which one you want.
211

212
        """
213

214
    lastRequestSeconds = zope.schema.Field(
1✔
215
        title="Seconds to Process Last Request",
216
        description=(
217
            """Return how many seconds (or fractions) the last request took.
218

219
        The values returned have the same resolution as the results from
220
        ``time.clock``.
221
        """),
222
        required=True,
223
        readonly=True)
224

225
    def getControl(label=None, name=None, index=None):
1✔
226
        """Get a control from the page.
227

228
        Only one of ``label`` and ``name`` may be provided.  ``label``
229
        searches form labels (including submit button values, per the HTML 4.0
230
        spec), and ``name`` searches form field names.
231

232
        Label value is searched as case-sensitive whole words within
233
        the labels for each control--that is, a search for 'Add' will match
234
        'Add a contact' but not 'Address'.  A word is defined as one or more
235
        alphanumeric characters or the underline.
236

237
        If no values are found, the code raises a LookupError.
238

239
        If ``index`` is None (the default) and more than one field matches the
240
        search, the code raises an AmbiguityError.  If an index is provided,
241
        it is used to choose the index from the ambiguous choices.  If the
242
        index does not exist, the code raises a LookupError.
243
        """
244

245
    def getForm(id=None, name=None, action=None, index=None):
1✔
246
        """Get a form from the page.
247

248
        Zero or one of ``id``, ``name``, and ``action`` may be provided.  If
249
        none are provided the index alone is used to determine the return
250
        value.
251

252
        If no values are found, the code raises a LookupError.
253

254
        If ``index`` is None (the default) and more than one form matches the
255
        search, the code raises an AmbiguityError.  If an index is provided,
256
        it is used to choose the index from the ambiguous choices.  If the
257
        index does not exist, the code raises a LookupError.
258
        """
259

260

261
class ExpiredError(Exception):
1✔
262
    """The browser page to which this was attached is no longer active"""
263

264

265
class IControl(zope.interface.Interface):
1✔
266
    """A control (input field) of a page."""
267

268
    name = zope.schema.TextLine(
1✔
269
        title="Name",
270
        description="The name of the control.",
271
        required=True)
272

273
    value = zope.schema.Field(
1✔
274
        title="Value",
275
        description="The value of the control",
276
        default=None,
277
        required=True)
278

279
    type = zope.schema.Choice(
1✔
280
        title="Type",
281
        description="The type of the control",
282
        values=['text', 'password', 'hidden', 'submit', 'checkbox', 'select',
283
                'radio', 'image', 'file'],
284
        required=True)
285

286
    disabled = zope.schema.Bool(
1✔
287
        title="Disabled",
288
        description="Describes whether a control is disabled.",
289
        default=False,
290
        required=False)
291

292
    multiple = zope.schema.Bool(
1✔
293
        title="Multiple",
294
        description=(
295
            "Describes whether this control can hold multiple values."),
296
        default=False,
297
        required=False)
298

299
    def clear():
1✔
300
        """Clear the value of the control."""
301

302

303
class IListControl(IControl):
1✔
304
    """A radio button, checkbox, or select control"""
305

306
    options = zope.schema.List(
1✔
307
        title="Options",
308
        description="""\
309
        A list of possible values for the control.""",
310
        required=True)
311

312
    displayOptions = zope.schema.List(
1✔
313
        # TODO: currently only implemented for select
314
        title="Options",
315
        description="""\
316
        A list of possible display values for the control.""",
317
        required=True)
318

319
    displayValue = zope.schema.Field(
1✔
320
        # TODO: currently only implemented for select
321
        title="Value",
322
        description="The value of the control, as rendered by the display",
323
        default=None,
324
        required=True)
325

326
    def getControl(label=None, value=None, index=None):
1✔
327
        """return subcontrol for given label or value, disambiguated by index
328
        if given.  Label value is searched as case-sensitive whole words within
329
        the labels for each item--that is, a search for 'Add' will match
330
        'Add a contact' but not 'Address'.  A word is defined as one or more
331
        alphanumeric characters or the underline."""
332

333
    controls = zope.interface.Attribute(
1✔
334
        """a list of subcontrols for the control.  mutating list has no effect
335
        on control (although subcontrols may be changed as usual).""")
336

337

338
class ISubmitControl(IControl):
1✔
339

340
    def click():
1✔
341
        "click the submit button"
342

343

344
class IImageSubmitControl(ISubmitControl):
1✔
345

346
    def click(coord=(1, 1)):
1✔
347
        "click the submit button with optional coordinates"
348

349

350
class IItemControl(zope.interface.Interface):
1✔
351
    """a radio button or checkbox within a larger multiple-choice control"""
352

353
    control = zope.schema.Object(
1✔
354
        title="Control",
355
        description=("The parent control element."),
356
        schema=IControl,
357
        required=True)
358

359
    disabled = zope.schema.Bool(
1✔
360
        title="Disabled",
361
        description="Describes whether a subcontrol is disabled.",
362
        default=False,
363
        required=False)
364

365
    selected = zope.schema.Bool(
1✔
366
        title="Selected",
367
        description="Whether the subcontrol is selected",
368
        default=None,
369
        required=True)
370

371
    optionValue = zope.schema.TextLine(
1✔
372
        title="Value",
373
        description="The value of the subcontrol",
374
        default=None,
375
        required=False)
376

377

378
class ILink(zope.interface.Interface):
1✔
379

380
    def click():
1✔
381
        """click the link, going to the URL referenced"""
382

383
    url = zope.schema.TextLine(
1✔
384
        title="URL",
385
        description="The normalized URL of the link",
386
        required=False)
387

388
    attrs = zope.schema.Dict(
1✔
389
        title='Attributes',
390
        description='The attributes of the link tag',
391
        required=False)
392

393
    text = zope.schema.TextLine(
1✔
394
        title='Text',
395
        description='The contained text of the link',
396
        required=False)
397

398
    tag = zope.schema.TextLine(
1✔
399
        title='Tag',
400
        description='The tag name of the link (a or area, typically)',
401
        required=True)
402

403

404
class IForm(zope.interface.Interface):
1✔
405
    """An HTML form of the page."""
406

407
    action = zope.schema.TextLine(
1✔
408
        title="Action",
409
        description="The action (or URI) that is opened upon submittance.",
410
        required=True)
411

412
    method = zope.schema.Choice(
1✔
413
        title="Method",
414
        description="The method used to submit the form.",
415
        values=['post', 'get', 'put'],
416
        required=True)
417

418
    enctype = zope.schema.TextLine(
1✔
419
        title="Encoding Type",
420
        description="The type of encoding used to encode the form data.",
421
        required=True)
422

423
    name = zope.schema.TextLine(
1✔
424
        title="Name",
425
        description="The value of the `name` attribute in the form tag, "
426
                    "if specified.",
427
        required=True)
428

429
    id = zope.schema.TextLine(
1✔
430
        title="Id",
431
        description="The value of the `id` attribute in the form tag, "
432
                    "if specified.",
433
        required=True)
434

435
    def getControl(label=None, name=None, index=None):
1✔
436
        """Get a control in the page.
437

438
        Only one of ``label`` and ``name`` may be provided.  ``label``
439
        searches form labels (including submit button values, per the HTML 4.0
440
        spec), and ``name`` searches form field names.
441

442
        Label value is searched as case-sensitive whole words within
443
        the labels for each control--that is, a search for 'Add' will match
444
        'Add a contact' but not 'Address'.  A word is defined as one or more
445
        alphanumeric characters or the underline.
446

447
        If no values are found, the code raises a LookupError.
448

449
        If ``index`` is None (the default) and more than one field matches the
450
        search, the code raises an AmbiguityError.  If an index is provided,
451
        it is used to choose the index from the ambiguous choices.  If the
452
        index does not exist, the code raises a LookupError.
453
        """
454

455
    def submit(label=None, name=None, index=None, coord=(1, 1)):
1✔
456
        """Submit this form.
457

458
        The `label`, `name`, and `index` arguments select the submit button to
459
        use to submit the form.  You may label or name, with index to
460
        disambiguate.
461

462
        Label value is searched as case-sensitive whole words within
463
        the labels for each control--that is, a search for 'Add' will match
464
        'Add a contact' but not 'Address'.  A word is defined as one or more
465
        alphanumeric characters or the underline.
466

467
        The control code works identically to 'get' except that searches are
468
        filtered to find only submit and image controls.
469
        """
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