selenium-selenium-4.18.1/0000755000175000017500000000000014565422564015142 5ustar carstencarstenselenium-selenium-4.18.1/CONTRIBUTING.md0000644000175000017500000002552314564764517017410 0ustar carstencarsten# Contributing to Selenium The Selenium project welcomes contributions from everyone. There are a number of ways you can help: ## Bug Reports When opening new issues or commenting on existing issues please make sure discussions are related to concrete technical issues with the Selenium software. It's imperative that issue reports outline the steps to reproduce the defect. If the issue can't be reproduced it will be closed. Please provide [concise reproducible test cases](http://sscce.org/) and describe what results you are seeing and what results you expect. Issues shouldn't be used for support. Please address questions to the [`selenium-users@` mailing list](https://groups.google.com/forum/#!forum/selenium-users). Discussion of high level project ideas or non-technical topics should move to the [`selenium-developers@` mailing list](https://groups.google.com/forum/#!forum/selenium-developers) instead. We also need help with triaging [issues that needs investigation](https://github.com/SeleniumHQ/selenium/labels/I-needs%20investigation). This means asking the right questions, procuring the right information to properly debug and verify the issue, and bisecting a commit range if the issue is a regression. ## Feature Requests If you find that Selenium is missing something, feel free to open an issue with details describing what feature(s) you'd like added or changed. If you'd like a hand at trying to implement the feature yourself, please refer to the [Code Contributions](#code-contributions) section of the document. ## Documentation Selenium is a big software project and documentation is key to understanding how things work and learning effective ways to exploit its potential. The [seleniumhq.github.io](https://github.com/SeleniumHQ/seleniumhq.github.io/) repository contains both Selenium’s site and documentation. This is an ongoing effort (not targeted at any specific release) to provide updated information on how to use Selenium effectively, how to get involved and how to contribute to Selenium. The official documentation of Selenium is at https://selenium.dev/documentation/. More details on how to get involved and contribute, please check the site's and documentation [contributing guidelines](https://www.selenium.dev/documentation/about/contributing/). ## Code Contributions The Selenium project welcomes new contributors. Individuals making significant and valuable contributions over time are made _Committers_ and given commit-access to the project. If you're looking for easy bugs, have a look at [issues labelled E-easy](https://github.com/SeleniumHQ/selenium/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy) on Github. This document will guide you through the contribution process. ### Step 1: Fork Fork the project [on Github](https://github.com/seleniumhq/selenium) and check out your copy locally. Use `--depth 1` for a quick check out. The repository is ~2GB and checking the whole history takes a while. ```shell % git clone git@github.com:username/selenium.git --depth 1 % cd selenium % git remote add upstream git://github.com/seleniumhq/selenium.git ``` #### Dependencies We bundle dependencies in the _third-party/_ directory that is not part of the proper project. Any changes to files in this directory or its subdirectories should be sent upstream to the respective projects. Please don't send your patch to us as we cannot accept it. We do accept help in upgrading our existing dependencies or removing superfluous dependencies. If you need to add a new dependency it's often a good idea to reach out to the committers on the [IRC channel or the mailing list](https://github.com/SeleniumHQ/selenium/blob/trunk/CONTRIBUTING.md#communication) to check that your approach aligns with the project's ideas. Nothing is more frustrating than seeing your hard work go to waste because your vision doesn't align with the project's. #### License Headers Every file in the Selenium project must carry the following license header boilerplate: ```text Licensed to the Software Freedom Conservancy (SFC) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The SFC licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ``` There's no need to include a copyright statement in the file's header. The copyright attributions can be reviewed in the [NOTICE](https://github.com/SeleniumHQ/selenium/blob/trunk/NOTICE) file found in the top-level directory. ### Step 2: Branch Create a feature branch and start hacking: ```shell % git checkout -b my-feature-branch ``` We practice HEAD-based development, which means all changes are applied directly on top of trunk. ### Step 3: Commit First make sure git knows your name and email address: ```shell % git config --global user.name 'Santa Claus' % git config --global user.email 'santa@example.com' ``` **Writing good commit messages is important.** A commit message should describe what changed, why, and reference issues fixed (if any). Follow these guidelines when writing one: 1. The first line should be around 50 characters or less and contain a short description of the change. 2. Keep the second line blank. 3. Wrap all other lines at 72 columns. 4. Include `Fixes #N`, where _N_ is the issue number the commit fixes, if any. A good commit message can look like this: ```text explain commit normatively in one line Body of commit message is a few lines of text, explaining things in more detail, possibly giving some background about the issue being fixed, etc. The body of the commit message can be several paragraphs, and please do proper word-wrap and keep columns shorter than about 72 characters or so. That way `git log` will show things nicely even when it is indented. Fixes #141 ``` The first line must be meaningful as it's what people see when they run `git shortlog` or `git log --oneline`. ### Step 4: Rebase Use `git rebase` (not `git merge`) to sync your work from time to time. ```shell % git fetch upstream % git rebase upstream/trunk ``` ### Step 5: Test Bug fixes and features **should have tests**. Look at other tests to see how they should be structured. Verify that new and existing tests are passing locally before pushing code. #### Running tests locally Build your code for the latest changes and run tests locally. ##### Python
Click to see How to run Python Tests. It's not mandatory to run tests sequentially but running Unit tests before browser testing is recommended. Unit Tests ```shell % bazel test //py:unit ``` Remote Tests ```shell % bazel test --jobs 1 //py:test-remote ``` Browser Tests ```shell % bazel test //py:test- #eg test-chrome, test-firefox ```
##### Javascript
Click to see How to run JavaScript Tests. Node Tests ```shell % bazel test //javascript/node/selenium-webdriver:tests ``` Firefox Atom Tests ```shell % bazel test --test_tag_filters=firefox //javascript/atoms/... //javascript/selenium-atoms/... //javascript/webdriver/... ``` Grid UI Unit Tests ```shell % cd javascript/grid-ui && npm install && npm test ```
##### Java
Click to see How to run Java Tests. Small Tests ```shell % bazel test --cache_test_results=no --test_size_filters=small grid java/test/... ``` Large Tests ```shell % bazel test --cache_test_results=no java/test/org/openqa/selenium/grid/router:large-tests ``` Browser Tests ```shell bazel test --test_size_filters=small,medium --cache_test_results=no --test_tag_filters=-browser-test //java/... ```
##### Ruby Please see https://github.com/SeleniumHQ/selenium#ruby for details about running tests. ### Step 6: Push ```shell % git push origin my-feature-branch ``` Go to https://github.com/yourusername/selenium.git and press the _Pull Request_ and fill out the form. Pull requests are usually reviewed within a few days. If there are comments to address, apply your changes in new commits (preferably [fixups](http://git-scm.com/docs/git-commit)) and push to the same branch. ### Step 7: Integration When code review is complete, a committer will take your PR and integrate it on Selenium's trunk branch. Because we like to keep a linear history on the trunk branch, we will normally squash and rebase your branch history. ## Stages of an Issue or PR From your create your issue or pull request, through code review and towards integration, it will be assigned different Github labels. The labels serve for the committers to more easily keep track of work that's pending or awaiting action. Component labels are yellow and carry the **C** prefix. They highlight the subsystem or component your PR makes changes in. The driver labels (**D**) indicate if the changes are related to a WebDriver implementation or the Selenium atoms. The review labels (**R**) are: * **awaiting answer**: awaits an answer from you * **awaiting merge**: waits for a committer to integrate the PR * **awaiting reviewer**: pending code review * **blocked on external**: a change in an upstream repo is required * **needs code changes**: waiting for you to fix a review issue * **needs rebase**: the branch isn't in sync with trunk and needs to be rebased Issues are labelled to make them easier to categorise and find by: * which **component** they relate to (java, cpp, dotnet, py, rb, nodejs) * which **driver** is affected * their presumed **difficulty** (easy, less easy, hard) * what **type** of issue they are (defect, race condition, cleanup) ## Communication Selenium contributors frequent the `#selenium` channel on [`irc.freenode.org`](https://webchat.freenode.net/). You can also join the [`selenium-developers@` mailing list](https://groups.google.com/forum/#!forum/selenium-developers). Check https://selenium.dev/support/ for a complete list of options to communicate. ## Using the EngFlow RBE To access the EngFlow RBE, a developer needs to be granted access to our project container repository. Once that has been done, then any bazel command can be run remotely by using `--config=remote`. For example: `bazel build --config=remote grid` or `bazel test --config=remote java/test/...` When you run a remote build, one of the first lines of output from Bazel will include a link to the EngFlow UI so you can track the progress of the build and gather information about the efficiency of the build. selenium-selenium-4.18.1/MANIFEST.in0000644000175000017500000000150214564764517016704 0ustar carstencarstenprune * recursive-include selenium/webdriver *.py recursive-include selenium/webdriver/common *.py recursive-include selenium/webdriver/common/actions *.py recursive-include selenium/webdriver/common/html5 *.py recursive-include selenium/common *.py recursive-include selenium/webdriver/chromium *.py recursive-include selenium/webdriver/chrome *.py recursive-include selenium/webdriver/phantomjs *.py recursive-include selenium/webdriver/firefox *.py *.xpi *.json recursive-include selenium/webdriver/ie *.py recursive-include selenium/webdriver/edge *.py recursive-include selenium/webdriver/remote *.py *.js recursive-include selenium/webdriver/support *.py include selenium/selenium.py include selenium/__init__.py include selenium/py.typed include CHANGES include README.rst include LICENSE recursive-include selenium.egg-info * selenium-selenium-4.18.1/.skipped-tests0000644000175000017500000000415114564764517017751 0ustar carstencarsten-//dotnet/test/common:DevTools/DevToolsNetworkTest-chrome -//dotnet/test/common:Interactions/BasicMouseInterfaceTest-chrome -//dotnet/test/common:Interactions/BasicMouseInterfaceTest-firefox -//dotnet/test/common:JavascriptEnabledBrowserTest-chrome -//dotnet/test/common:NetworkInterceptionTests-chrome -//dotnet/test/common:TakesScreenshotTest-chrome -//dotnet/test/common:TakesScreenshotTest-firefox -//dotnet/test/common:VirtualAuthn/VirtualAuthenticatorTest-chrome -//dotnet/test/support/UI:SelectBrowserTests-firefox -//dotnet/test/support/UI:SelectTests -//java/test/org/openqa/selenium/bidi/browsingcontext:BrowsingContextTest -//java/test/org/openqa/selenium/bidi/browsingcontext:BrowsingContextTest-remote -//java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest -//java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest-remote -//java/test/org/openqa/selenium/federatedcredentialmanagement:FederatedCredentialManagementTest -//java/test/org/openqa/selenium/firefox:FirefoxDriverBuilderTest -//java/test/org/openqa/selenium/grid/gridui:OverallGridTest -//java/test/org/openqa/selenium/grid/router:RemoteWebDriverDownloadTest -//java/test/org/openqa/selenium/grid/router:RemoteWebDriverDownloadTest-chrome -//java/test/org/openqa/selenium/grid/router:RemoteWebDriverDownloadTest-chrome-remote -//java/test/org/openqa/selenium/grid/router:RemoteWebDriverDownloadTest-remote -//java/test/org/openqa/selenium/interactions:DefaultMouseTest -//java/test/org/openqa/selenium/interactions:DefaultMouseTest-remote -//java/test/org/openqa/selenium/remote:RemoteWebDriverBuilderTest -//java/test/org/openqa/selenium/remote:RemoteWebDriverScreenshotTest-remote -//javascript/atoms:test-chrome -//javascript/atoms:test-firefox-beta -//javascript/atoms:test-firefox-dev -//py:common-chrome-test/selenium/webdriver/common/virtual_authenticator_tests.py -//py:test-chrome-test/selenium/webdriver/chrome/chrome_launcher_tests.py -//py:test-chrome-test/selenium/webdriver/chrome/chrome_service_tests.py -//py:test-chrome-test/selenium/webdriver/chrome/proxy_tests.py -//py:unit-test/unit/selenium/webdriver/common/cdp_module_fallback_tests.py selenium-selenium-4.18.1/requirements.txt0000644000175000017500000000115214564764517020433 0ustar carstencarstenasync-generator==1.10 attrs==23.1.0 certifi==2023.7.22 cffi==1.16.0 cryptography==41.0.4 dataclasses==0.6 debugpy==1.8.0 h11==0.14.0 idna==3.4 importlib-metadata==6.8.0 inflection==0.5.1 iniconfig==2.0.0 more-itertools==10.1.0 multidict==6.0.2 outcome==1.3.0 packaging==23.2 pluggy==1.3.0 py==1.11.0 pycparser==2.21 pyOpenSSL==22.0.0 pyparsing==3.1.1 PySocks==1.7.1 pytest==7.4.2 pytest-instafail==0.5.0 pytest-mock==3.12.0 pytest-trio==0.8.0 sniffio==1.3.0 sortedcontainers==2.4.0 toml==0.10.2 trio>=0.20.2 trio-websocket==0.9.2 twine==4.0.2 typing_extensions==4.9.0 urllib3[socks]==2.0.7 wsproto==1.2.0 zipp==3.17.0 selenium-selenium-4.18.1/test/0000755000175000017500000000000014564764517016127 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/0000755000175000017500000000000014564764517017106 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/__init__.py0000644000175000017500000000142314564764517021217 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/unit/selenium/0000755000175000017500000000000014564764517020727 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/selenium/__init__.py0000644000175000017500000000142314564764517023040 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/unit/selenium/webdriver/0000755000175000017500000000000014564764517022720 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/selenium/webdriver/common/0000755000175000017500000000000014564764517024210 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/selenium/webdriver/common/common_options_tests.py0000644000175000017500000000506614564764517031056 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver import Proxy from selenium.webdriver.common.options import ArgOptions from selenium.webdriver.common.proxy import ProxyType @pytest.fixture def options(): return ArgOptions() def test_add_arguments(options): options.add_argument("foo") assert "foo" in options._arguments def test_get_arguments(options): options._arguments = ["foo"] assert "foo" in options.arguments def test_enables_mobile(options): options.enable_mobile(android_package="cheese") assert options.mobile_options["androidPackage"] == "cheese" assert not hasattr(options.mobile_options, "androidActivity") assert not hasattr(options.mobile_options, "androidDeviceSerial") def test_enable_mobile_errors_without_package(options): with pytest.raises(AttributeError): options.enable_mobile() def test_enable_mobile_with_activity(options): options.enable_mobile(android_package="sausages", android_activity="eating") assert options.mobile_options["androidActivity"] == "eating" def test_enable_mobile_with_device_serial(options): options.enable_mobile(android_package="cheese", android_activity="crackers", device_serial="1234") options.mobile_options["androidDeviceSerial"] == "1234" def test_missing_capabilities_return_false_rather_than_none(): options = ArgOptions() assert options.strict_file_interactability is False assert options.set_window_rect is False assert options.accept_insecure_certs is False def test_add_proxy(): options = ArgOptions() proxy = Proxy({"proxyType": ProxyType.MANUAL}) proxy.http_proxy = "http://user:password@http_proxy.com:8080" options.proxy = proxy caps = options.to_capabilities() assert options.proxy == proxy assert caps.get("proxy") == proxy.to_capabilities() selenium-selenium-4.18.1/test/unit/selenium/webdriver/common/cdp_module_fallback_tests.py0000644000175000017500000000237314564764517031743 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import logging import re import types from selenium.webdriver.common.bidi.cdp import import_devtools def test_missing_cdp_devtools_version_falls_back(caplog): with caplog.at_level(logging.DEBUG, logger="selenium"): assert isinstance(import_devtools("will_never_exist"), types.ModuleType) # assert the fallback occurred successfully offered up a v{n} option. assert re.match(r"Falling back to loading `devtools`: v\d+", caplog.records[-1].getMessage()) is not None selenium-selenium-4.18.1/test/unit/selenium/webdriver/common/print_page_options_tests.py0000644000175000017500000000622514564764517031714 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.print_page_options import PrintOptions @pytest.fixture def print_options(): return PrintOptions() def test_set_orientation(print_options): print_options.orientation = "portrait" assert print_options.orientation == "portrait" def test_raises_exception_if_orientation_is_invalid(print_options): with pytest.raises(ValueError): print_options.orientation = "foobar" def test_set_scale(print_options): print_options.scale = 1 assert print_options.scale == 1 def test_raises_exception_if_scale_is_outside_range(print_options): with pytest.raises(ValueError): print_options.scale = 3 def test_raises_exception_if_scale_is_not_an_integer(print_options): with pytest.raises(ValueError): print_options.scale = "1" def test_set_background(print_options): print_options.background = True assert print_options.background is True def test_unset_value_to_be_none(print_options): assert print_options.page_width is None def test_set_width(print_options): print_options.page_width = 3 assert print_options.page_width == 3 def test_raises_exception_if_set_invalid_width(print_options): with pytest.raises(ValueError): print_options.page_width = -1 def test_raises_exception_if_set_with_not_int(print_options): with pytest.raises(ValueError): print_options.page_width = "2" def test_set_height(print_options): print_options.page_height = 2 assert print_options.page_height == 2 def test_set_shrink_to_fit(print_options): print_options.shrink_to_fit = True assert print_options.shrink_to_fit is True def test_raises_exception_if_set_shrink_to_fit_non_bool(print_options): with pytest.raises(ValueError): print_options.shrink_to_fit = "True" def test_set_page_ranges(print_options): print_options.page_ranges = ["1-2"] assert print_options.page_ranges == ["1-2"] def test_raises_exception_if_page_ranges_not_list(print_options): with pytest.raises(ValueError): print_options.page_ranges = "foobar" def test_margin_height(print_options): print_options.margin_top = 2 assert print_options.margin_top == 2 def test_raises_exception_if_margin_is_invalid(print_options): with pytest.raises(ValueError): print_options.margin_top = -1 with pytest.raises(ValueError): print_options.margin_top = "2" selenium-selenium-4.18.1/test/unit/selenium/webdriver/virtual_authenticator/0000755000175000017500000000000014564764517027340 5ustar carstencarsten././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootselenium-selenium-4.18.1/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_options_tests.pyselenium-selenium-4.18.1/test/unit/selenium/webdriver/virtual_authenticator/virtual_authenticator_op0000644000175000017500000000364714564764517034413 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.virtual_authenticator import VirtualAuthenticatorOptions @pytest.fixture def options(): return VirtualAuthenticatorOptions() def test_bespoke_options_for_virtual_authenticator(): assert VirtualAuthenticatorOptions( protocol="ctap1/u2f", transport="ble", has_resident_key=True, has_user_verification=True, is_user_consenting=False, is_user_verified=True, ).to_dict() == { "protocol": "ctap1/u2f", "transport": "ble", "hasResidentKey": True, "hasUserVerification": True, "isUserConsenting": False, "isUserVerified": True, } def test_to_dict_with_defaults(options): default_options = options.to_dict() assert default_options["transport"] == VirtualAuthenticatorOptions.Transport.USB.value assert default_options["protocol"] == VirtualAuthenticatorOptions.Protocol.CTAP2.value assert default_options["hasResidentKey"] is False assert default_options["hasUserVerification"] is False assert default_options["isUserConsenting"] is True assert default_options["isUserVerified"] is False selenium-selenium-4.18.1/test/unit/selenium/webdriver/virtual_authenticator/credentials_test.py0000644000175000017500000001303214564764517033245 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from base64 import urlsafe_b64decode from base64 import urlsafe_b64encode from typing import Tuple import pytest from selenium.webdriver.common.virtual_authenticator import Credential BASE64__ENCODED_PK = """ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDbBOu5Lhs4vpowbCnmCyLUpIE7JM9sm9QXzye2G+jr+Kr MsinWohEce47BFPJlTaDzHSvOW2eeunBO89ZcvvVc8RLz4qyQ8rO98xS1jtgqi1NcBPETDrtzthODu/gd0sjB2Tk3TLuBGV oPXt54a+Oo4JbBJ6h3s0+5eAfGplCbSNq6hN3Jh9YOTw5ZA6GCEy5l8zBaOgjXytd2v2OdSVoEDNiNQRkjJd2rmS2oi9AyQ FR3B7BrPSiDlCcITZFOWgLF5C31Wp/PSHwQhlnh7/6YhnE2y9tzsUvzx0wJXrBADW13+oMxrneDK3WGbxTNYgIi1PvSqXlq GjHtCK+R2QkXAgMBAAECggEAVc6bu7VAnP6v0gDOeX4razv4FX/adCao9ZsHZ+WPX8PQxtmWYqykH5CY4TSfsuizAgyPuQ0 +j4Vjssr9VODLqFoanspT6YXsvaKanncUYbasNgUJnfnLnw3an2XpU2XdmXTNYckCPRX9nsAAURWT3/n9ljc/XYY22ecYxM 8sDWnHu2uKZ1B7M3X60bQYL5T/lVXkKdD6xgSNLeP4AkRx0H4egaop68hoW8FIwmDPVWYVAvo8etzWCtibRXz5FcNld9MgD /Ai7ycKy4Q1KhX5GBFI79MVVaHkSQfxPHpr7/XcmpQOEAr+BMPon4s4vnKqAGdGB3j/E3d/+4F2swykoQKBgQD8hCsp6FIQ 5umJlk9/j/nGsMl85LgLaNVYpWlPRKPc54YNumtvj5vx1BG+zMbT7qIE3nmUPTCHP7qb5ERZG4CdMCS6S64/qzZEqijLCqe pwj6j4fV5SyPWEcpxf6ehNdmcfgzVB3Wolfwh1ydhx/96L1jHJcTKchdJJzlfTvq8wwKBgQDeCnKws1t5GapfE1rmC/h4ol L2qZTth9oQmbrXYohVnoqNFslDa43ePZwL9Jmd9kYb0axOTNMmyrP0NTj41uCfgDS0cJnNTc63ojKjegxHIyYDKRZNVUR/d xAYB/vPfBYZUS7M89pO6LLsHhzS3qpu3/hppo/Uc/AM/r8PSflNHQKBgDnWgBh6OQncChPUlOLv9FMZPR1ZOfqLCYrjYEqi uzGm6iKM13zXFO4AGAxu1P/IAd5BovFcTpg79Z8tWqZaUUwvscnl+cRlj+mMXAmdqCeO8VASOmqM1ml667axeZDIR867ZG8 K5V029Wg+4qtX5uFypNAAi6GfHkxIKrD04yOHAoGACdh4wXESi0oiDdkz3KOHPwIjn6BhZC7z8mx+pnJODU3cYukxv3WTct lUhAsyjJiQ/0bK1yX87ulqFVgO0Knmh+wNajrb9wiONAJTMICG7tiWJOm7fW5cfTJwWkBwYADmkfTRmHDvqzQSSvoC2S7aa 9QulbC3C/qgGFNrcWgcT9kCgYAZTa1P9bFCDU7hJc2mHwJwAW7/FQKEJg8SL33KINpLwcR8fqaYOdAHWWz636osVEqosRrH zJOGpf9x2RSWzQJ+dq8+6fACgfFZOVpN644+sAHfNPAI/gnNKU5OfUv+eav8fBnzlf1A3y3GIkyMyzFN3DE7e0n/lyqxE4H BYGpI8g== """ @pytest.fixture() def data() -> Tuple: _id = bytearray({1, 2, 3, 4}) rp_id = "localhost" user_handle = bytearray({1}) privatekey = urlsafe_b64decode(BASE64__ENCODED_PK) sign_count = 0 return (_id, rp_id, user_handle, privatekey, sign_count) def test_rk_enabled_credential(data): _id, rp_id, user_handle, privatekey, sign_count = data credential = Credential.create_resident_credential(_id, rp_id, user_handle, privatekey, sign_count) assert credential.id == urlsafe_b64encode(bytearray({1, 2, 3, 4})).decode() if credential.is_resident_credential is True: assert True assert credential.rp_id == "localhost" assert credential.user_handle == urlsafe_b64encode(bytearray({1})).decode() assert credential.private_key == urlsafe_b64encode(privatekey).decode() assert credential.sign_count == 0 def test_rk_disabled_credentials(data): _id, rp_id, user_handle, privatekey, sign_count = data credential = Credential.create_non_resident_credential(_id, rp_id, privatekey, sign_count) assert credential.id == urlsafe_b64encode(bytearray({1, 2, 3, 4})).decode() assert credential.private_key == urlsafe_b64encode(privatekey).decode() assert credential.sign_count == 0 assert credential.rp_id == "localhost" if credential.is_resident_credential is False: assert True else: assert False if credential.user_handle is None: assert True else: assert False def test_to_dict(data): _id, rp_id, user_handle, privatekey, sign_count = data credential = Credential.create_resident_credential(_id, rp_id, user_handle, privatekey, sign_count) credential_dict = credential.to_dict() assert credential_dict["credentialId"] == urlsafe_b64encode(bytearray({1, 2, 3, 4})).decode() if credential_dict["isResidentCredential"] is True: assert True else: assert False assert credential_dict["rpId"] == "localhost" assert credential_dict["userHandle"] == urlsafe_b64encode(bytearray({1})).decode() assert credential_dict["privateKey"] == urlsafe_b64encode(privatekey).decode() assert credential_dict["signCount"] == 0 def test_from_dict(): data = { "credentialId": urlsafe_b64encode(bytearray({1, 2, 3, 4})).decode(), "isResidentCredential": True, "rpId": "localhost", "userHandle": urlsafe_b64encode(bytearray({1})).decode(), "privateKey": BASE64__ENCODED_PK, "signCount": 0, } credential = Credential.from_dict(data) key = urlsafe_b64decode(BASE64__ENCODED_PK) assert credential.id == urlsafe_b64encode(bytearray({1, 2, 3, 4})).decode() if credential.is_resident_credential is True: assert True else: assert False assert credential.rp_id == "localhost" assert credential.user_handle == urlsafe_b64encode(bytearray({1})).decode() assert credential.private_key == urlsafe_b64encode(key).decode() assert credential.sign_count == 0 selenium-selenium-4.18.1/test/unit/selenium/webdriver/virtual_authenticator/__init__.py0000644000175000017500000000142314564764517031451 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/unit/selenium/webdriver/webkitgtk/0000755000175000017500000000000014564764517024713 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/selenium/webdriver/webkitgtk/webkitgtk_options_tests.py0000644000175000017500000000440714564764517032262 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.webkitgtk.options import Options @pytest.fixture def options(): return Options() def test_set_binary_location(options): options.binary_location = "/foo/bar" assert options._binary_location == "/foo/bar" def test_get_binary_location(options): options._binary_location = "/foo/bar" assert options.binary_location == "/foo/bar" def test_set_overlay_scrollbars_enabled(options): options.overlay_scrollbars_enabled = False assert options._overlay_scrollbars_enabled is False def test_get_overlay_scrollbars_enabled(options): options._overlay_scrollbars_enabled = True assert options.overlay_scrollbars_enabled is True def test_creates_capabilities(options): options._arguments = ["foo"] options._binary_location = "/bar" options._overlay_scrollbars_enabled = True caps = options.to_capabilities() opts = caps.get(Options.KEY) assert opts assert "foo" in opts["args"] assert opts["binary"] == "/bar" assert opts["useOverlayScrollbars"] is True def test_starts_with_default_capabilities(options): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.WEBKITGTK.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert options._caps == caps def test_is_a_baseoptions(options): from selenium.webdriver.common.options import BaseOptions assert isinstance(options, BaseOptions) selenium-selenium-4.18.1/test/unit/selenium/webdriver/__init__.py0000644000175000017500000000142314564764517025031 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/unit/selenium/webdriver/support/0000755000175000017500000000000014564764517024434 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/selenium/webdriver/support/color_tests.py0000644000175000017500000000712714564764517027355 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.support.color import Color def test_color_can_be_subclassed(): class MyColor(Color): pass assert isinstance(MyColor.from_string("rgb(1, 2, 3)"), MyColor) def test_rgb_to_rgb(): rgb = "rgb(1, 2, 3)" assert Color.from_string(rgb).rgb == rgb def test_rgb_to_rgba(): rgb = "rgb(1, 2, 3)" assert Color.from_string(rgb).rgba == "rgba(1, 2, 3, 1)" def test_rgb_pct_to_rgba(): rgb = "rgb(10%, 20%, 30%)" assert Color.from_string(rgb).rgba == "rgba(25, 51, 76, 1)" def test_rgb_allows_whitespace(): rgb = "rgb(\t1, 2 , 3)" assert Color.from_string(rgb).rgb == "rgb(1, 2, 3)" def test_rgba_to_rgba(): rgba = "rgba(1, 2, 3, 0.5)" assert Color.from_string(rgba).rgba == rgba def test_rgba_pct_to_rgba(): rgba = "rgba(10%, 20%, 30%, 0.5)" assert Color.from_string(rgba).rgba == "rgba(25, 51, 76, 0.5)" def test_hex_to_hex(): hex_ = "#ff00a0" assert Color.from_string(hex_).hex == hex_ def test_hex_to_rgb(): hex_ = "#01Ff03" rgb = "rgb(1, 255, 3)" assert Color.from_string(hex_).rgb == rgb def test_hex_to_rgba(): hex_ = "#01Ff03" rgba = "rgba(1, 255, 3, 1)" assert Color.from_string(hex_).rgba == rgba hex_ = "#00ff33" rgba = "rgba(0, 255, 51, 1)" assert Color.from_string(hex_).rgba == rgba def test_rgb_to_hex(): assert Color.from_string("rgb(1, 255, 3)").hex == "#01ff03" def test_hex3_to_rgba(): assert Color.from_string("#0f3").rgba == "rgba(0, 255, 51, 1)" def test_hsl_to_rgba(): hsl = "hsl(120, 100%, 25%)" rgba = "rgba(0, 128, 0, 1)" assert Color.from_string(hsl).rgba == rgba hsl = "hsl(100, 0%, 50%)" rgba = "rgba(128, 128, 128, 1)" assert Color.from_string(hsl).rgba == rgba def test_hsla_to_rgba(): hsla = "hsla(120, 100%, 25%, 1)" rgba = "rgba(0, 128, 0, 1)" assert Color.from_string(hsla).rgba == rgba hsla = "hsla(100, 0%, 50%, 0.5)" rgba = "rgba(128, 128, 128, 0.5)" assert Color.from_string(hsla).rgba == rgba def test_named_color(): assert Color.from_string("green").rgba == "rgba(0, 128, 0, 1)" assert Color.from_string("gray").rgba == "rgba(128, 128, 128, 1)" assert Color.from_string("aqua").hex == "#00ffff" assert Color.from_string("transparent").rgba == "rgba(0, 0, 0, 0)" def test_equals(): assert Color.from_string("#f00") == Color.from_string("rgb(255, 0, 0)") assert Color.from_string("rgba(30, 30, 30, 0.2)") != Color.from_string("rgba(30, 30, 30, 1)") def test_hash(): hash1 = hash(Color.from_string("#f00")) hash2 = hash(Color.from_string("rgb(255, 0, 0)")) assert hash1 == hash2 def test_string_representations(): hex_ = "#01Ff03" assert str(Color.from_string(hex_)) == "Color: rgba(1, 255, 3, 1)" assert repr(Color.from_string(hex_)) == "Color(red=1, green=255, blue=3, alpha=1)" selenium-selenium-4.18.1/test/unit/selenium/webdriver/ie/0000755000175000017500000000000014564764517023315 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/selenium/webdriver/ie/__init__.py0000644000175000017500000000142314564764517025426 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/unit/selenium/webdriver/ie/test_ie_options.py0000644000175000017500000001453614564764517027107 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.ie.options import ElementScrollBehavior from selenium.webdriver.ie.options import Options TIMEOUT = 30 @pytest.fixture def opts(): yield Options() def test_arguments(opts): arg1 = "-k" arg2 = "-private" opts.add_argument(arg1) opts.add_argument(arg2) assert arg1 in opts.arguments assert arg2 in opts.arguments def test_browser_attach_timeout(opts): opts.browser_attach_timeout = TIMEOUT assert opts.browser_attach_timeout == TIMEOUT assert opts.options.get(Options.BROWSER_ATTACH_TIMEOUT) == TIMEOUT def test_raises_exception_for_invalid_browser_attach_timeout(opts): with pytest.raises(ValueError): opts.browser_attach_timeout = "foo" def test_element_scroll_behavior(opts): opts.element_scroll_behavior = ElementScrollBehavior.BOTTOM assert opts.element_scroll_behavior == ElementScrollBehavior.BOTTOM assert opts.options.get(Options.ELEMENT_SCROLL_BEHAVIOR) == ElementScrollBehavior.BOTTOM def test_ensure_clean_session(opts): opts.ensure_clean_session = True assert opts.ensure_clean_session is True assert opts.options.get(Options.ENSURE_CLEAN_SESSION) is True def test_file_upload_dialog_timeout(opts): opts.file_upload_dialog_timeout = TIMEOUT assert opts.file_upload_dialog_timeout is TIMEOUT assert opts.options.get(Options.FILE_UPLOAD_DIALOG_TIMEOUT) is TIMEOUT def test_raises_exception_for_file_upload_dialog_timeout(opts): with pytest.raises(ValueError): opts.file_upload_dialog_timeout = "foo" def test_force_create_process_api(opts): opts.force_create_process_api = True assert opts.force_create_process_api is True assert opts.options.get(Options.FORCE_CREATE_PROCESS_API) is True def test_force_shell_windows_api(opts): opts.force_shell_windows_api = True assert opts.force_shell_windows_api is True assert opts.options.get(Options.FORCE_SHELL_WINDOWS_API) is True def test_full_page_screenshot(opts): opts.full_page_screenshot = True assert opts.full_page_screenshot is True assert opts.options.get(Options.FULL_PAGE_SCREENSHOT) is True def test_ignore_protected_mode_settings(opts): opts.ignore_protected_mode_settings = True assert opts.ignore_protected_mode_settings is True assert opts.options.get(Options.IGNORE_PROTECTED_MODE_SETTINGS) is True def test_ignore_zoom_level(opts): opts.ignore_zoom_level = True assert opts.ignore_zoom_level is True assert opts.options.get(Options.IGNORE_ZOOM_LEVEL) is True def test_initial_browser_url(opts): url = "http://www.selenium.dev" opts.initial_browser_url = url assert opts.initial_browser_url == url assert opts.options.get(Options.INITIAL_BROWSER_URL) == url def test_native_events(opts): opts.native_events = True assert opts.native_events is True assert opts.options.get(Options.NATIVE_EVENTS) is True def test_persistent_hover(opts): opts.persistent_hover = True assert opts.persistent_hover is True assert opts.options.get(Options.PERSISTENT_HOVER) is True def test_require_window_focus(opts): opts.require_window_focus = True assert opts.require_window_focus is True assert opts.options.get(Options.REQUIRE_WINDOW_FOCUS) is True def test_use_per_process_proxy(opts): opts.use_per_process_proxy = True assert opts.use_per_process_proxy is True assert opts.options.get(Options.USE_PER_PROCESS_PROXY) is True def test_use_legacy_file_upload_dialog_handling(opts): opts.use_legacy_file_upload_dialog_handling = True assert opts.use_legacy_file_upload_dialog_handling is True assert opts.options.get(Options.USE_LEGACY_FILE_UPLOAD_DIALOG_HANDLING) is True def test_attach_to_edge_chrome(opts): opts.attach_to_edge_chrome = True assert opts.attach_to_edge_chrome is True assert opts.options.get(Options.ATTACH_TO_EDGE_CHROME) is True def test_edge_executable_path(opts): path = "/path/to/edge" opts.edge_executable_path = path assert opts.edge_executable_path == path assert opts.options.get(Options.EDGE_EXECUTABLE_PATH) == path def test_additional_options(opts): opts.add_additional_option("foo", "bar") assert opts.additional_options.get("foo") == "bar" def test_to_capabilities(opts): opts._options["foo"] = "bar" assert Options.KEY in opts.to_capabilities() assert opts.to_capabilities().get(Options.KEY) == opts._options def test_to_capabilities_arguments(opts): arg = "-k" opts.add_argument(arg) caps_opts = opts.to_capabilities().get(Options.KEY) assert caps_opts.get(Options.SWITCHES) == arg def test_to_capabilities_additional_options(opts): name = "foo" value = "bar" opts.add_additional_option(name, value) caps_opts = opts.to_capabilities().get(Options.KEY) assert caps_opts.get(name) == value def test_to_capabilities_should_not_modify_set_options(opts): opts._options["foo"] = "bar" arg = "-k" opts.add_argument(arg) opts.add_additional_option("baz", "qux") opts.to_capabilities().get(Options.KEY) assert opts.options.get("foo") == "bar" assert opts.arguments[0] == arg assert opts.additional_options.get("baz") == "qux" def test_starts_with_default_capabilities(opts): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.INTERNETEXPLORER.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert opts._caps == caps def test_is_a_baseoptions(opts): from selenium.webdriver.common.options import BaseOptions assert isinstance(opts, BaseOptions) selenium-selenium-4.18.1/test/unit/selenium/webdriver/edge/0000755000175000017500000000000014564764517023624 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/selenium/webdriver/edge/edge_options_tests.py0000644000175000017500000000431314564764517030100 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.edge.options import Options @pytest.fixture def options(): return Options() def test_raises_exception_with_invalid_page_load_strategy(options): with pytest.raises(ValueError): options.page_load_strategy = "never" def test_set_page_load_strategy(options): options.page_load_strategy = PageLoadStrategy.normal caps = options.to_capabilities() assert caps["pageLoadStrategy"] == PageLoadStrategy.normal def test_get_page_load_strategy(options): options._caps["pageLoadStrategy"] = PageLoadStrategy.normal assert options.page_load_strategy == PageLoadStrategy.normal def test_creates_capabilities(options): options.page_load_strategy = PageLoadStrategy.eager caps = options.to_capabilities() assert caps["pageLoadStrategy"] == PageLoadStrategy.eager def test_starts_with_default_capabilities(options): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.EDGE.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert options._caps == caps def test_is_a_baseoptions(options): from selenium.webdriver.common.options import BaseOptions assert isinstance(options, BaseOptions) def test_use_webview(): options = Options() options.use_webview = True caps = options.to_capabilities() assert caps["browserName"] == "webview2" selenium-selenium-4.18.1/test/unit/selenium/webdriver/firefox/0000755000175000017500000000000014564764517024362 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/selenium/webdriver/firefox/firefox_options_tests.py0000644000175000017500000001275614564764517031406 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import InvalidArgumentException from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.common.proxy import Proxy from selenium.webdriver.common.proxy import ProxyType from selenium.webdriver.firefox.firefox_binary import FirefoxBinary from selenium.webdriver.firefox.firefox_profile import FirefoxProfile from selenium.webdriver.firefox.options import Options @pytest.fixture def options(): return Options() def test_set_binary_with_firefox_binary(options): binary = FirefoxBinary("foo") options.binary = binary assert options.binary_location == "foo" def test_set_binary_with_path(options): options.binary = "/foo" assert options.binary_location == "/foo" def test_get_binary(options): options.binary = "/foo" assert options.binary._start_cmd == "/foo" def test_set_binary_location(options): options.binary_location = "/foo" assert options.binary_location == "/foo" def test_get_binary_location(options): options._binary_location = "/foo" assert options.binary_location == "/foo" def test_set_preference(options): options.set_preference("foo", "bar") assert options._preferences["foo"] == "bar" def test_get_preferences(options): options._preferences = {"foo": "bar"} assert options.preferences["foo"] == "bar" def test_set_proxy(options): proxy = Proxy({"proxyType": ProxyType.MANUAL}) options.proxy = proxy assert options._proxy == proxy def test_set_proxy_isnt_in_moz_prefix(options): proxy = Proxy({"proxyType": ProxyType.MANUAL}) options.proxy = proxy caps = options.to_capabilities() assert caps["proxy"]["proxyType"] == "manual" assert caps.get("moz:firefoxOptions") is None def test_raises_exception_if_proxy_is_not_proxy_object(options): with pytest.raises(InvalidArgumentException): options.proxy = "foo" def test_get_proxy(options): options._proxy = "foo" assert options.proxy == "foo" def test_set_profile_with_firefox_profile(options): profile = FirefoxProfile() options.profile = profile assert options._profile == profile def test_set_profile_with_path(options): options.profile = None assert isinstance(options._profile, FirefoxProfile) def test_get_profile(options): options._profile = "foo" assert options.profile == "foo" def test_add_arguments(options): options.add_argument("foo") assert "foo" in options._arguments def test_get_arguments(options): options._arguments = ["foo"] assert "foo" in options.arguments def test_raises_exception_if_argument_is_falsy(options): with pytest.raises(ValueError): options.add_argument(None) def test_set_log_level(options): options.log.level = "debug" assert options.log.level == "debug" def test_creates_capabilities(options): profile = FirefoxProfile() options._arguments = ["foo"] options._binary_location = "/bar" options._preferences = {"foo": "bar"} options.proxy = Proxy({"proxyType": ProxyType.MANUAL}) options._profile = profile options.log.level = "debug" caps = options.to_capabilities() opts = caps.get(Options.KEY) assert opts assert "foo" in opts["args"] assert opts["binary"] == "/bar" assert opts["prefs"]["foo"] == "bar" assert isinstance(opts["profile"], str) and opts["profile"] assert caps["proxy"]["proxyType"] == "manual" assert opts["log"]["level"] == "debug" def test_starts_with_default_capabilities(options): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.FIREFOX.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert options._caps == caps def test_is_a_baseoptions(options): from selenium.webdriver.common.options import BaseOptions assert isinstance(options, BaseOptions) def test_raises_exception_with_invalid_page_load_strategy(options): with pytest.raises(ValueError): options.page_load_strategy = "never" def test_set_page_load_strategy(options): options.page_load_strategy = PageLoadStrategy.normal assert options._caps["pageLoadStrategy"] == PageLoadStrategy.normal def test_get_page_load_strategy(options): options._page_load_strategy = PageLoadStrategy.normal assert options._caps["pageLoadStrategy"] == PageLoadStrategy.normal def test_creates_capabilities_with_page_load_strategy(options): options.page_load_strategy = PageLoadStrategy.eager caps = options.to_capabilities() assert caps["pageLoadStrategy"] == PageLoadStrategy.eager def test_enables_firefox_mobile(options): options.enable_mobile() result_caps = options.to_capabilities() assert result_caps["moz:firefoxOptions"]["androidPackage"] == "org.mozilla.firefox" selenium-selenium-4.18.1/test/unit/selenium/webdriver/remote/0000755000175000017500000000000014564764517024213 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/selenium/webdriver/remote/remote_connection_tests.py0000644000175000017500000002235514564764517031530 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from urllib import parse import pytest import urllib3 from selenium import __version__ from selenium.webdriver.remote.remote_connection import RemoteConnection def test_get_remote_connection_headers_defaults(): url = "http://remote" headers = RemoteConnection.get_remote_connection_headers(parse.urlparse(url)) assert "Authorization" not in headers assert "Connection" not in headers assert headers.get("Accept") == "application/json" assert headers.get("Content-Type") == "application/json;charset=UTF-8" assert headers.get("User-Agent").startswith(f"selenium/{__version__} (python ") assert headers.get("User-Agent").split(" ")[-1] in {"windows)", "mac)", "linux)"} def test_get_remote_connection_headers_adds_auth_header_if_pass(): url = "http://user:pass@remote" headers = RemoteConnection.get_remote_connection_headers(parse.urlparse(url)) assert headers.get("Authorization") == "Basic dXNlcjpwYXNz" def test_get_remote_connection_headers_adds_keep_alive_if_requested(): url = "http://remote" headers = RemoteConnection.get_remote_connection_headers(parse.urlparse(url), keep_alive=True) assert headers.get("Connection") == "keep-alive" def test_get_proxy_url_http(mock_proxy_settings): proxy = "http://http_proxy.com:8080" remote_connection = RemoteConnection("http://remote", keep_alive=False) proxy_url = remote_connection._get_proxy_url() assert proxy_url == proxy def test_get_proxy_url_https(mock_proxy_settings): proxy = "http://https_proxy.com:8080" remote_connection = RemoteConnection("https://remote", keep_alive=False) proxy_url = remote_connection._get_proxy_url() assert proxy_url == proxy def test_get_proxy_url_none(mock_proxy_settings_missing): remote_connection = RemoteConnection("https://remote", keep_alive=False) proxy_url = remote_connection._get_proxy_url() assert proxy_url is None def test_get_proxy_url_http_auth(mock_proxy_auth_settings): remote_connection = RemoteConnection("http://remote", keep_alive=False) proxy_url = remote_connection._get_proxy_url() raw_proxy_url, basic_auth_string = remote_connection._separate_http_proxy_auth() assert proxy_url == "http://user:password@http_proxy.com:8080" assert raw_proxy_url == "http://http_proxy.com:8080" assert basic_auth_string == "user:password" def test_get_proxy_url_https_auth(mock_proxy_auth_settings): remote_connection = RemoteConnection("https://remote", keep_alive=False) proxy_url = remote_connection._get_proxy_url() raw_proxy_url, basic_auth_string = remote_connection._separate_http_proxy_auth() assert proxy_url == "https://user:password@https_proxy.com:8080" assert raw_proxy_url == "https://https_proxy.com:8080" assert basic_auth_string == "user:password" def test_get_connection_manager_without_proxy(mock_proxy_settings_missing): remote_connection = RemoteConnection("http://remote", keep_alive=False) conn = remote_connection._get_connection_manager() assert isinstance(conn, urllib3.PoolManager) def test_get_connection_manager_for_certs_and_timeout(monkeypatch): monkeypatch.setattr(RemoteConnection, "get_timeout", lambda _: 10) # Class state; leaks into subsequent tests. remote_connection = RemoteConnection("http://remote", keep_alive=False) conn = remote_connection._get_connection_manager() assert conn.connection_pool_kw["timeout"] == 10 assert conn.connection_pool_kw["cert_reqs"] == "CERT_REQUIRED" assert "certifi/cacert.pem" in conn.connection_pool_kw["ca_certs"] def test_default_socket_timeout_is_correct(): remote_connection = RemoteConnection("http://remote", keep_alive=True) conn = remote_connection._get_connection_manager() assert conn.connection_pool_kw["timeout"] is None def test_get_connection_manager_with_proxy(mock_proxy_settings): remote_connection = RemoteConnection("http://remote", keep_alive=False) conn = remote_connection._get_connection_manager() assert isinstance(conn, urllib3.ProxyManager) assert conn.proxy.scheme == "http" assert conn.proxy.host == "http_proxy.com" assert conn.proxy.port == 8080 remote_connection_https = RemoteConnection("https://remote", keep_alive=False) conn = remote_connection_https._get_connection_manager() assert isinstance(conn, urllib3.ProxyManager) assert conn.proxy.scheme == "http" assert conn.proxy.host == "https_proxy.com" assert conn.proxy.port == 8080 def test_get_connection_manager_with_auth_proxy(mock_proxy_auth_settings): proxy_auth_header = urllib3.make_headers(proxy_basic_auth="user:password") remote_connection = RemoteConnection("http://remote", keep_alive=False) conn = remote_connection._get_connection_manager() assert isinstance(conn, urllib3.ProxyManager) assert conn.proxy.scheme == "http" assert conn.proxy.host == "http_proxy.com" assert conn.proxy.port == 8080 assert conn.proxy_headers == proxy_auth_header remote_connection_https = RemoteConnection("https://remote", keep_alive=False) conn = remote_connection_https._get_connection_manager() assert isinstance(conn, urllib3.ProxyManager) assert conn.proxy.scheme == "https" assert conn.proxy.host == "https_proxy.com" assert conn.proxy.port == 8080 assert conn.proxy_headers == proxy_auth_header @pytest.mark.parametrize( "url", [ "*", ".localhost", "localhost:80", "locahost", "127.0.0.1", "LOCALHOST", "LOCALHOST:80", "http://localhost", "https://localhost", "test.localhost", " localhost", "::1", "127.0.0.2", ], ) def test_get_connection_manager_when_no_proxy_set(mock_no_proxy_settings, url): remote_connection = RemoteConnection(url) conn = remote_connection._get_connection_manager() assert isinstance(conn, urllib3.PoolManager) def test_ignore_proxy_env_vars(mock_proxy_settings): remote_connection = RemoteConnection("http://remote", ignore_proxy=True) conn = remote_connection._get_connection_manager() assert isinstance(conn, urllib3.PoolManager) def test_get_socks_proxy_when_set(mock_socks_proxy_settings): remote_connection = RemoteConnection("http://127.0.0.1:4444/wd/hub") conn = remote_connection._get_connection_manager() from urllib3.contrib.socks import SOCKSProxyManager assert isinstance(conn, SOCKSProxyManager) class MockResponse: code = 200 headers = [] def read(self): return b"{}" def close(self): pass def getheader(self, *args, **kwargs): pass @pytest.fixture(scope="function") def mock_proxy_settings_missing(monkeypatch): monkeypatch.delenv("HTTPS_PROXY", raising=False) monkeypatch.delenv("HTTP_PROXY", raising=False) monkeypatch.delenv("https_proxy", raising=False) monkeypatch.delenv("http_proxy", raising=False) @pytest.fixture(scope="function") def mock_socks_proxy_settings(monkeypatch): http_proxy = "SOCKS5://http_proxy.com:8080" https_proxy = "SOCKS5://https_proxy.com:8080" monkeypatch.setenv("HTTPS_PROXY", https_proxy) monkeypatch.setenv("HTTP_PROXY", http_proxy) monkeypatch.setenv("https_proxy", https_proxy) monkeypatch.setenv("http_proxy", http_proxy) @pytest.fixture(scope="function") def mock_proxy_settings(monkeypatch): http_proxy = "http://http_proxy.com:8080" https_proxy = "http://https_proxy.com:8080" monkeypatch.setenv("HTTPS_PROXY", https_proxy) monkeypatch.setenv("HTTP_PROXY", http_proxy) monkeypatch.setenv("https_proxy", https_proxy) monkeypatch.setenv("http_proxy", http_proxy) @pytest.fixture(scope="function") def mock_proxy_auth_settings(monkeypatch): http_proxy = "http://user:password@http_proxy.com:8080" https_proxy = "https://user:password@https_proxy.com:8080" monkeypatch.setenv("HTTPS_PROXY", https_proxy) monkeypatch.setenv("HTTP_PROXY", http_proxy) monkeypatch.setenv("https_proxy", https_proxy) monkeypatch.setenv("http_proxy", http_proxy) @pytest.fixture(scope="function") def mock_no_proxy_settings(monkeypatch): http_proxy = "http://http_proxy.com:8080" https_proxy = "http://https_proxy.com:8080" monkeypatch.setenv("HTTPS_PROXY", https_proxy) monkeypatch.setenv("HTTP_PROXY", http_proxy) monkeypatch.setenv("https_proxy", https_proxy) monkeypatch.setenv("http_proxy", http_proxy) monkeypatch.setenv("no_proxy", "65.253.214.253,localhost,127.0.0.1,*zyz.xx,::1") monkeypatch.setenv("NO_PROXY", "65.253.214.253,localhost,127.0.0.1,*zyz.xx,::1,127.0.0.0/8") selenium-selenium-4.18.1/test/unit/selenium/webdriver/remote/__init__.py0000644000175000017500000000142314564764517026324 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/unit/selenium/webdriver/remote/error_handler_tests.py0000644000175000017500000002674414564764517030652 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common import exceptions from selenium.webdriver.remote.errorhandler import ErrorCode from selenium.webdriver.remote.errorhandler import ErrorHandler @pytest.fixture def handler(): yield ErrorHandler() def test_does_not_raise_exception_on_success(handler): assert handler.check_response({"status": ErrorCode.SUCCESS}) is None assert handler.check_response({}) is None @pytest.mark.parametrize("code", ErrorCode.NO_SUCH_ELEMENT) def test_raises_exception_for_no_such_element(handler, code): with pytest.raises(exceptions.NoSuchElementException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.NO_SUCH_FRAME) def test_raises_exception_for_no_such_frame(handler, code): with pytest.raises(exceptions.NoSuchFrameException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.UNKNOWN_COMMAND) def test_raises_exception_for_unknown_command(handler, code): with pytest.raises(exceptions.WebDriverException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.STALE_ELEMENT_REFERENCE) def test_raises_exception_for_stale_element_reference(handler, code): with pytest.raises(exceptions.StaleElementReferenceException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.ELEMENT_NOT_VISIBLE) def test_raises_exception_for_element_not_visible(handler, code): with pytest.raises(exceptions.ElementNotVisibleException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_ELEMENT_STATE) def test_raises_exception_for_invalid_element_state(handler, code): with pytest.raises(exceptions.InvalidElementStateException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.UNKNOWN_ERROR) def test_raises_exception_for_unknown_error(handler, code): with pytest.raises(exceptions.WebDriverException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.ELEMENT_IS_NOT_SELECTABLE) def test_raises_exception_for_element_not_selectable(handler, code): with pytest.raises(exceptions.ElementNotSelectableException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.JAVASCRIPT_ERROR) def test_raises_exception_for_javascript_error(handler, code): with pytest.raises(exceptions.JavascriptException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.XPATH_LOOKUP_ERROR) def test_raises_exception_for_xpath_lookup_error(handler, code): with pytest.raises(exceptions.WebDriverException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.TIMEOUT) def test_raises_exception_for_timeout(handler, code): with pytest.raises(exceptions.TimeoutException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.NO_SUCH_WINDOW) def test_raises_exception_for_no_such_window(handler, code): with pytest.raises(exceptions.NoSuchWindowException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_COOKIE_DOMAIN) def test_raises_exception_for_invalid_cookie_domain(handler, code): with pytest.raises(exceptions.InvalidCookieDomainException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.UNABLE_TO_SET_COOKIE) def test_raises_exception_for_unable_to_set_cookie(handler, code): with pytest.raises(exceptions.UnableToSetCookieException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.UNEXPECTED_ALERT_OPEN) def test_raises_exception_for_unexpected_alert_open(handler, code): with pytest.raises(exceptions.UnexpectedAlertPresentException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.NO_ALERT_OPEN) def test_raises_exception_for_no_alert_open(handler, code): with pytest.raises(exceptions.NoAlertPresentException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.SCRIPT_TIMEOUT) def test_raises_exception_for_script_timeout(handler, code): with pytest.raises(exceptions.TimeoutException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_ELEMENT_COORDINATES) def test_raises_exception_for_invalid_element_coordinates(handler, code): with pytest.raises(exceptions.WebDriverException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.IME_NOT_AVAILABLE) def test_raises_exception_for_ime_not_available(handler, code): with pytest.raises(exceptions.ImeNotAvailableException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.IME_ENGINE_ACTIVATION_FAILED) def test_raises_exception_for_ime_activation_failed(handler, code): with pytest.raises(exceptions.ImeActivationFailedException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_SELECTOR) def test_raises_exception_for_invalid_selector(handler, code): with pytest.raises(exceptions.InvalidSelectorException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.SESSION_NOT_CREATED) def test_raises_exception_for_session_not_created(handler, code): with pytest.raises(exceptions.SessionNotCreatedException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS) def test_raises_exception_for_move_target_out_of_bounds(handler, code): with pytest.raises(exceptions.MoveTargetOutOfBoundsException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_XPATH_SELECTOR) def test_raises_exception_for_invalid_xpath_selector(handler, code): with pytest.raises(exceptions.InvalidSelectorException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER) def test_raises_exception_for_invalid_xpath_selector_return_typer(handler, code): with pytest.raises(exceptions.InvalidSelectorException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.ELEMENT_NOT_INTERACTABLE) def test_raises_exception_for_element_not_interactable(handler, code): with pytest.raises(exceptions.ElementNotInteractableException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INSECURE_CERTIFICATE) def test_raises_exception_for_insecure_certificate(handler, code): with pytest.raises(exceptions.InsecureCertificateException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_ARGUMENT) def test_raises_exception_for_invalid_argument(handler, code): with pytest.raises(exceptions.InvalidArgumentException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_COORDINATES) def test_raises_exception_for_invalid_coordinates(handler, code): with pytest.raises(exceptions.InvalidCoordinatesException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.INVALID_SESSION_ID) def test_raises_exception_for_invalid_session_id(handler, code): with pytest.raises(exceptions.InvalidSessionIdException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.NO_SUCH_COOKIE) def test_raises_exception_for_no_such_cookie(handler, code): with pytest.raises(exceptions.NoSuchCookieException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.UNABLE_TO_CAPTURE_SCREEN) def test_raises_exception_for_unable_to_capture_screen_exception(handler, code): with pytest.raises(exceptions.ScreenshotException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.ELEMENT_CLICK_INTERCEPTED) def test_raises_exception_for_element_click_intercepted(handler, code): with pytest.raises(exceptions.ElementClickInterceptedException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.UNKNOWN_METHOD) def test_raises_exception_for_unknown_method(handler, code): with pytest.raises(exceptions.UnknownMethodException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("code", ErrorCode.METHOD_NOT_ALLOWED) def test_raises_exception_for_method_not_allowed(handler, code): with pytest.raises(exceptions.WebDriverException): handler.check_response({"status": code, "value": "foo"}) @pytest.mark.parametrize("key", ["stackTrace", "stacktrace"]) def test_relays_exception_stacktrace(handler, key): import json stacktrace = {"lineNumber": 100, "fileName": "egg", "methodName": "ham", "className": "Spam"} value = {key: [stacktrace], "message": "very bad", "error": ErrorCode.UNKNOWN_METHOD[0]} response = {"status": 400, "value": json.dumps({"value": value})} with pytest.raises(exceptions.UnknownMethodException) as e: handler.check_response(response) assert "Spam.ham" in e.value.stacktrace[0] def test_handle_errors_better(handler): import json response = { "status": 500, "value": json.dumps( { "value": { "message": "Could not start a new session. No Node supports the required capabilities: Capabilities {browserName: chrome, goog:chromeOptions: {args: [headless, silent], extensions: [], w3c: false}}, Capabilities {browserName: chrome, goog:chromeOptions: {args: [headless, silent], extensions: [], w3c: false}, version: }\nBuild info: version: '4.0.0-beta-3', revision: '5d108f9a67'\nSystem info: host: '9315f0a993d2', ip: '172.17.0.8', os.name: 'Linux', os.arch: 'amd64', os.version: '5.8.0-44-generic', java.version: '1.8.0_282'\nDriver info: driver.version: unknown" } } ), } with pytest.raises(exceptions.WebDriverException) as e: handler.check_response(response) assert "Could not start a new session." in e.value.msg selenium-selenium-4.18.1/test/unit/selenium/webdriver/remote/new_session_tests.py0000644000175000017500000001041114564764517030340 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from importlib import import_module import pytest from selenium.webdriver.chrome.options import Options as ChromeOptions from selenium.webdriver.common.options import ArgOptions from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.common.proxy import Proxy from selenium.webdriver.common.proxy import ProxyType from selenium.webdriver.remote import webdriver from selenium.webdriver.remote.command import Command from selenium.webdriver.remote.webdriver import WebDriver def test_converts_proxy_type_value_to_lowercase_for_w3c(mocker): mock = mocker.patch("selenium.webdriver.remote.webdriver.WebDriver.execute") w3c_caps = {"pageLoadStrategy": "normal", "proxy": {"proxyType": "manual", "httpProxy": "foo"}} options = ArgOptions() proxy = Proxy({"proxyType": ProxyType.MANUAL, "httpProxy": "foo"}) options.proxy = proxy WebDriver(options=options) expected_params = {"capabilities": {"firstMatch": [{}], "alwaysMatch": w3c_caps}} mock.assert_called_with(Command.NEW_SESSION, expected_params) def test_works_as_context_manager(mocker): mocker.patch("selenium.webdriver.remote.webdriver.WebDriver.execute") quit_ = mocker.patch("selenium.webdriver.remote.webdriver.WebDriver.quit") with WebDriver(options=ChromeOptions()) as driver: assert isinstance(driver, WebDriver) assert quit_.call_count == 1 @pytest.mark.parametrize("browser_name", ["firefox", "chrome", "ie"]) def test_accepts_options_to_remote_driver(mocker, browser_name): options = import_module(f"selenium.webdriver.{browser_name}.options") mock = mocker.patch("selenium.webdriver.remote.webdriver.WebDriver.start_session") opts = options.Options() opts.add_argument("foo") WebDriver(options=opts) expected_caps = opts.to_capabilities() mock.assert_called_with(expected_caps) def test_always_match_if_2_of_the_same_options(): from selenium.webdriver.chrome.options import Options as ChromeOptions from selenium.webdriver.chrome.options import Options as ChromeOptions2 co1 = ChromeOptions() co1.add_argument("foo") co2 = ChromeOptions2() co2.add_argument("bar") expected = { "capabilities": { "alwaysMatch": { "browserName": "chrome", "pageLoadStrategy": PageLoadStrategy.normal, }, "firstMatch": [ {"goog:chromeOptions": {"args": ["foo"], "extensions": []}}, {"goog:chromeOptions": {"args": ["bar"], "extensions": []}}, ], } } result = webdriver.create_matches([co1, co2]) assert expected == result def test_first_match_when_2_different_option_types(): from selenium.webdriver.chrome.options import Options as ChromeOptions from selenium.webdriver.firefox.options import Options as FirefoxOptions expected = { "capabilities": { "alwaysMatch": {"pageLoadStrategy": PageLoadStrategy.normal}, "firstMatch": [ {"browserName": "chrome", "goog:chromeOptions": {"extensions": [], "args": []}}, { "browserName": "firefox", "acceptInsecureCerts": True, "moz:debuggerAddress": True, "moz:firefoxOptions": {"args": ["foo"]}, }, ], } } firefox_options = FirefoxOptions() firefox_options.add_argument("foo") result = webdriver.create_matches([ChromeOptions(), firefox_options]) assert expected == result selenium-selenium-4.18.1/test/unit/selenium/webdriver/remote/subtyping_tests.py0000644000175000017500000000417514564764517030042 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.remote.webdriver import WebDriver from selenium.webdriver.remote.webdriver import WebElement def test_web_element_not_subclassed(): """A registered subtype of WebElement should work with isinstance checks.""" class MyWebElement: def __init__(self, parent, id, _w3c=True): self.parent = parent self.id = id self._w3c = _w3c # Test that non registered class instance is not instance of Remote WebElement my_web_element = MyWebElement("parent", "1") assert not isinstance(my_web_element, WebElement) # Register the class as a subtype of WebElement WebElement.register(MyWebElement) my_registered_web_element = MyWebElement("parent", "2") assert isinstance(my_registered_web_element, WebElement) def test_webdriver_not_subclassed(): """A registered subtype of WebDriver should work with isinstance checks.""" class MyWebDriver: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Test that non registered class instance is not instance of Remote WebDriver my_driver = MyWebDriver() assert not isinstance(my_driver, WebDriver) # Register the class as a subtype of WebDriver WebDriver.register(MyWebDriver) my_registered_driver = MyWebDriver() assert isinstance(my_registered_driver, MyWebDriver) selenium-selenium-4.18.1/test/unit/selenium/webdriver/chrome/0000755000175000017500000000000014564764517024175 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/selenium/webdriver/chrome/chrome_options_tests.py0000644000175000017500000001102514564764517031020 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import platform from os import path import pytest from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.options import PageLoadStrategy @pytest.fixture def options(): return Options() def test_set_binary_location(options): options.binary_location = "/foo/bar" assert options._binary_location == "/foo/bar" def test_get_binary_location(options): options._binary_location = "/foo/bar" assert options.binary_location == "/foo/bar" def test_set_debugger_address(options): options.debugger_address = "/foo/bar" assert options._debugger_address == "/foo/bar" def test_get_debugger_address(options): options._debugger_address = "/foo/bar" assert options.debugger_address == "/foo/bar" def test_add_arguments(options): options.add_argument("foo") assert "foo" in options._arguments def test_get_arguments(options): options._arguments = ["foo"] assert "foo" in options.arguments def test_raises_exception_if_argument_is_falsy(options): with pytest.raises(ValueError): options.add_argument(None) def test_raises_exception_if_extension_is_falsy(options): with pytest.raises(ValueError): options.add_extension(None) def test_raises_exception_if_extension_does_not_exist(options): with pytest.raises(IOError): options.add_extension(path.join(path.abspath(path.curdir), "fakepath")) def test_add_extension(options, mocker): pth = path.abspath(path.expanduser("/foo/bar")) mocker.patch("os.path.exists").return_value = True options.add_extension(pth) assert pth in options._extension_files def test_raises_exception_if_encoded_extension_is_falsy(options): with pytest.raises(ValueError): options.add_encoded_extension(None) def test_add_encoded_extension(options): options.add_encoded_extension("/foo/bar") assert "/foo/bar" in options._extensions def test_get_extensions_from_extension_files(options, mocker): null = "NUL" if platform.system().lower() == "windows" else "/dev/null" mocker.patch("selenium.webdriver.chromium.options.open").return_value = open(null) mocker.patch("base64.b64encode").return_value = b"foo" options._extension_files = ["foo"] assert "foo" in options.extensions def test_get_extensions_from_encoded_extensions(options, mocker): options._extensions = ["foo"] assert "foo" in options.extensions def test_add_experimental_options(options): options.add_experimental_option("foo", "bar") assert options._experimental_options["foo"] == "bar" def test_get_experimental_options(options): options._experimental_options = {"foo": "bar"} assert options.experimental_options["foo"] == "bar" def test_creates_capabilities(options): options._arguments = ["foo"] options._binary_location = "/bar" options._extensions = ["baz"] options._debugger_address = "/foo/bar" options._experimental_options = {"foo": "bar"} caps = options.to_capabilities() opts = caps.get(Options.KEY) assert opts assert "foo" in opts["args"] assert opts["binary"] == "/bar" assert "baz" in opts["extensions"] assert opts["debuggerAddress"] == "/foo/bar" assert opts["foo"] == "bar" def test_starts_with_default_capabilities(options): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.CHROME.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert options._caps == caps def test_is_a_baseoptions(options): from selenium.webdriver.common.options import BaseOptions assert isinstance(options, BaseOptions) def test_enables_chrome_mobile(options): options.enable_mobile() result_caps = options.to_capabilities() assert result_caps["goog:chromeOptions"]["androidPackage"] == "com.android.chrome" selenium-selenium-4.18.1/test/unit/selenium/webdriver/wpewebkit/0000755000175000017500000000000014564764517024721 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/selenium/webdriver/wpewebkit/wpewebkit_options_tests.py0000644000175000017500000000356414564764517032301 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.wpewebkit.options import Options @pytest.fixture def options(): return Options() def test_starts_with_default_capabilities(options): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.WPEWEBKIT.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert options._caps == caps def test_set_binary_location(options): options.binary_location = "/foo/bar" assert options._binary_location == "/foo/bar" def test_get_binary_location(options): options._binary_location = "/foo/bar" assert options.binary_location == "/foo/bar" def test_creates_capabilities(options): options._arguments = ["foo"] options._binary_location = "/bar" caps = options.to_capabilities() opts = caps.get(Options.KEY) assert opts assert "foo" in opts["args"] assert opts["binary"] == "/bar" def test_is_a_baseoptions(options): from selenium.webdriver.common.options import BaseOptions assert isinstance(options, BaseOptions) selenium-selenium-4.18.1/test/unit/selenium/webdriver/safari/0000755000175000017500000000000014564764517024165 5ustar carstencarstenselenium-selenium-4.18.1/test/unit/selenium/webdriver/safari/safari_options_tests.py0000644000175000017500000000433514564764517031006 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.safari.options import Options @pytest.fixture def options(): return Options() def test_starts_with_default_capabilities(options): from selenium.webdriver import DesiredCapabilities caps = DesiredCapabilities.SAFARI.copy() caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert options._caps == caps def test_is_a_baseoptions(options): from selenium.webdriver.common.options import BaseOptions assert isinstance(options, BaseOptions) def test_can_set_automatic_inspection(options): options.automatic_inspection = True assert options.automatic_inspection is True assert options._caps.get(Options.AUTOMATIC_INSPECTION) is True def test_can_set_automatic_profiling(options): options.automatic_profiling = True assert options.automatic_profiling is True assert options._caps.get(Options.AUTOMATIC_PROFILING) is True def test_setting_technology_preview_changes_browser_name(options): from selenium.webdriver import DesiredCapabilities BROWSER_NAME = "browserName" assert options._caps.get(BROWSER_NAME) == DesiredCapabilities.SAFARI[BROWSER_NAME] options.use_technology_preview = True assert options._caps.get(BROWSER_NAME) == options.SAFARI_TECH_PREVIEW options.use_technology_preview = False assert options._caps.get(BROWSER_NAME) == DesiredCapabilities.SAFARI[BROWSER_NAME] selenium-selenium-4.18.1/test/__init__.py0000644000175000017500000000142314564764517020240 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/runner/0000755000175000017500000000000014564764517017440 5ustar carstencarstenselenium-selenium-4.18.1/test/runner/run_pytest.py0000644000175000017500000000205114564764517022224 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest with open("pytest.ini", "w", encoding="utf-8") as ini_file: ini_file.write("[pytest]\n") ini_file.write("addopts = -r=a\n") ini_file.write("rootdir = py\n") ini_file.write("python_files = test_*.py *_tests.py\n") raise SystemExit(pytest.main()) selenium-selenium-4.18.1/test/selenium/0000755000175000017500000000000014564764517017750 5ustar carstencarstenselenium-selenium-4.18.1/test/selenium/__init__.py0000644000175000017500000000142314564764517022061 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/selenium/webdriver/0000755000175000017500000000000014564764517021741 5ustar carstencarstenselenium-selenium-4.18.1/test/selenium/webdriver/common/0000755000175000017500000000000014564764517023231 5ustar carstencarstenselenium-selenium-4.18.1/test/selenium/webdriver/common/virtual_authenticator_tests.py0000644000175000017500000003225114564764517031450 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from base64 import b64decode from base64 import urlsafe_b64decode from typing import List import pytest from selenium.common.exceptions import InvalidArgumentException from selenium.webdriver.common.virtual_authenticator import Credential from selenium.webdriver.common.virtual_authenticator import VirtualAuthenticatorOptions from selenium.webdriver.remote.webdriver import WebDriver # working Key BASE64__ENCODED_PK = """ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDbBOu5Lhs4vpowbCnmCyLUpIE7JM9sm9QXzye2G+jr+Kr MsinWohEce47BFPJlTaDzHSvOW2eeunBO89ZcvvVc8RLz4qyQ8rO98xS1jtgqi1NcBPETDrtzthODu/gd0sjB2Tk3TLuBGV oPXt54a+Oo4JbBJ6h3s0+5eAfGplCbSNq6hN3Jh9YOTw5ZA6GCEy5l8zBaOgjXytd2v2OdSVoEDNiNQRkjJd2rmS2oi9AyQ FR3B7BrPSiDlCcITZFOWgLF5C31Wp/PSHwQhlnh7/6YhnE2y9tzsUvzx0wJXrBADW13+oMxrneDK3WGbxTNYgIi1PvSqXlq GjHtCK+R2QkXAgMBAAECggEAVc6bu7VAnP6v0gDOeX4razv4FX/adCao9ZsHZ+WPX8PQxtmWYqykH5CY4TSfsuizAgyPuQ0 +j4Vjssr9VODLqFoanspT6YXsvaKanncUYbasNgUJnfnLnw3an2XpU2XdmXTNYckCPRX9nsAAURWT3/n9ljc/XYY22ecYxM 8sDWnHu2uKZ1B7M3X60bQYL5T/lVXkKdD6xgSNLeP4AkRx0H4egaop68hoW8FIwmDPVWYVAvo8etzWCtibRXz5FcNld9MgD /Ai7ycKy4Q1KhX5GBFI79MVVaHkSQfxPHpr7/XcmpQOEAr+BMPon4s4vnKqAGdGB3j/E3d/+4F2swykoQKBgQD8hCsp6FIQ 5umJlk9/j/nGsMl85LgLaNVYpWlPRKPc54YNumtvj5vx1BG+zMbT7qIE3nmUPTCHP7qb5ERZG4CdMCS6S64/qzZEqijLCqe pwj6j4fV5SyPWEcpxf6ehNdmcfgzVB3Wolfwh1ydhx/96L1jHJcTKchdJJzlfTvq8wwKBgQDeCnKws1t5GapfE1rmC/h4ol L2qZTth9oQmbrXYohVnoqNFslDa43ePZwL9Jmd9kYb0axOTNMmyrP0NTj41uCfgDS0cJnNTc63ojKjegxHIyYDKRZNVUR/d xAYB/vPfBYZUS7M89pO6LLsHhzS3qpu3/hppo/Uc/AM/r8PSflNHQKBgDnWgBh6OQncChPUlOLv9FMZPR1ZOfqLCYrjYEqi uzGm6iKM13zXFO4AGAxu1P/IAd5BovFcTpg79Z8tWqZaUUwvscnl+cRlj+mMXAmdqCeO8VASOmqM1ml667axeZDIR867ZG8 K5V029Wg+4qtX5uFypNAAi6GfHkxIKrD04yOHAoGACdh4wXESi0oiDdkz3KOHPwIjn6BhZC7z8mx+pnJODU3cYukxv3WTct lUhAsyjJiQ/0bK1yX87ulqFVgO0Knmh+wNajrb9wiONAJTMICG7tiWJOm7fW5cfTJwWkBwYADmkfTRmHDvqzQSSvoC2S7aa 9QulbC3C/qgGFNrcWgcT9kCgYAZTa1P9bFCDU7hJc2mHwJwAW7/FQKEJg8SL33KINpLwcR8fqaYOdAHWWz636osVEqosRrH zJOGpf9x2RSWzQJ+dq8+6fACgfFZOVpN644+sAHfNPAI/gnNKU5OfUv+eav8fBnzlf1A3y3GIkyMyzFN3DE7e0n/lyqxE4H BYGpI8g== """ REGISTER_CREDENTIAL = "registerCredential().then(arguments[arguments.length - 1]);" GET_CREDENTIAL = """getCredential([{ "type": "public-key", "id": Int8Array.from(arguments[0]), }]).then(arguments[arguments.length - 1]);""" def create_rk_enabled_u2f_authenticator(driver) -> WebDriver: options = VirtualAuthenticatorOptions() options.protocol = VirtualAuthenticatorOptions.Protocol.U2F options.has_resident_key = True driver.add_virtual_authenticator(options) return driver def create_rk_disabled_u2f_authenticator(driver) -> WebDriver: options = VirtualAuthenticatorOptions() options.protocol = VirtualAuthenticatorOptions.Protocol.U2F options.has_resident_key = False driver.add_virtual_authenticator(options) return driver def create_rk_enabled_ctap2_authenticator(driver) -> WebDriver: options = VirtualAuthenticatorOptions() options.protocol = VirtualAuthenticatorOptions.Protocol.CTAP2 options.has_resident_key = True options.has_user_verification = True options.is_user_verified = True driver.add_virtual_authenticator(options) return driver def create_rk_disabled_ctap2_authenticator(driver) -> WebDriver: options = VirtualAuthenticatorOptions() options.protocol = VirtualAuthenticatorOptions.Protocol.CTAP2 options.transport = VirtualAuthenticatorOptions.Transport.USB options.has_resident_key = False options.has_user_verification = True options.is_user_verified = True driver.add_virtual_authenticator(options) return driver def get_assertion_for(webdriver: WebDriver, credential_id: List[int]): return webdriver.execute_async_script(GET_CREDENTIAL, credential_id) def extract_id(response): return response.get("credential", {}).get("id", "") def extract_raw_id(response): return response.get("credential", {}).get("rawId", "") def not_allowed_error_in(response) -> bool: return response.get("status", "").startswith("NotAllowedError") # ---------------- TESTS ------------------------------------ @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_add_and_remove_virtual_authenticator(driver, pages): driver = create_rk_disabled_ctap2_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) result = driver.execute_async_script(REGISTER_CREDENTIAL) assert result.get("status", "") == "OK" assert get_assertion_for(driver, result["credential"]["rawId"]).get("status", "") == "OK" assert driver.virtual_authenticator_id is not None driver.remove_virtual_authenticator() assert driver.virtual_authenticator_id is None @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_add_and_remove_non_resident_credentials(driver, pages): driver = create_rk_disabled_ctap2_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) assert driver.virtual_authenticator_id is not None credential = Credential.create_non_resident_credential( bytearray({1, 2, 3, 4}), "localhost", b64decode(BASE64__ENCODED_PK), 0, ) driver.add_credential(credential) assert get_assertion_for(driver, [1, 2, 3, 4]).get("status", "") == "OK" driver.remove_virtual_authenticator() assert driver.virtual_authenticator_id is None @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_add_non_resident_credential_when_authenticator_uses_u2f_protocol(driver, pages): driver = create_rk_disabled_u2f_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) base64_pk = """ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB """ credential = Credential.create_non_resident_credential( bytearray({1, 2, 3, 4}), "localhost", urlsafe_b64decode(base64_pk), 0, ) driver.add_credential(credential) assert get_assertion_for(driver, [1, 2, 3, 4]).get("status", "") == "OK" driver.remove_virtual_authenticator() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_add_resident_credential_not_supported_when_authenticator_uses_u2f_protocol(driver, pages): driver = create_rk_enabled_u2f_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) base64_pk = """ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB """ credential = Credential.create_resident_credential( bytearray({1, 2, 3, 4}), "localhost", bytearray({1}), urlsafe_b64decode(base64_pk), 0, ) with pytest.raises(InvalidArgumentException): driver.add_credential(credential) driver.remove_virtual_authenticator() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_get_credentials(driver, pages): driver = create_rk_enabled_ctap2_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) # Register a Resident Credential response1 = driver.execute_async_script( """ registerCredential({authenticatorSelection: {requireResidentKey: true}}) .then(arguments[arguments.length - 1]); """ ) assert response1.get("status", "") == "OK" # Register a Non-Resident Credential response2 = driver.execute_async_script(REGISTER_CREDENTIAL) assert response2.get("status", "") == "OK" assert extract_id(response1) != extract_id(response2) # Retrieve the two credentials credentials = driver.get_credentials() assert len(credentials) == 2 credential1, credential2 = None, None for credential in credentials: # Using startswith because there can be padding difference '==' or '=' in the end if credential.id.startswith(extract_id(response1)): credential1: Credential = credential elif credential.id.startswith(extract_id(response2)): credential2: Credential = credential else: assert False, "Unknown credential" assert credential1.is_resident_credential, "Credential1 should be resident credential" assert credential1.private_key is not None, "Credential1 should have private key" assert credential2.is_resident_credential is False, "Credential2 should not be resident credential" assert credential2.private_key is not None, "Credential2 should have private key" assert credential2.sign_count == 1 driver.remove_virtual_authenticator() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_remove_credential_by_raw_Id(driver, pages): driver = create_rk_disabled_u2f_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) # register a credential response = driver.execute_async_script(REGISTER_CREDENTIAL) assert response.get("status", "") == "OK" # remove the credential using array of bytes: rawId raw_id = extract_raw_id(response) driver.remove_credential(bytearray(raw_id)) # Trying to get the assertion should fail response = get_assertion_for(driver, raw_id) assert not_allowed_error_in(response), "Should have thrown a NotAllowedError" driver.remove_virtual_authenticator() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_remove_credential_by_b64_urlId(driver, pages): driver = create_rk_disabled_u2f_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) # register a credential response = driver.execute_async_script(REGISTER_CREDENTIAL) assert response.get("status", "") == "OK" # remove the credential using array of bytes: rawId raw_id = extract_raw_id(response) credential_id = extract_id(response) driver.remove_credential(credential_id) # Trying to get the assertion should fail response = get_assertion_for(driver, raw_id) assert not_allowed_error_in(response), "Should have thrown a NotAllowedError" driver.remove_virtual_authenticator() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_remove_all_credentials(driver, pages): driver = create_rk_disabled_u2f_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) # Register 2 credentials response1 = driver.execute_async_script(REGISTER_CREDENTIAL) raw_id1 = response1["credential"]["rawId"] response2 = driver.execute_async_script(REGISTER_CREDENTIAL) raw_id2 = response2["credential"]["rawId"] driver.remove_all_credentials() response = driver.execute_async_script( """ getCredential([{ "type": "public-key", "id": Int8Array.from(arguments[0]), }, { "type": "public-key", "id": Int8Array.from(arguments[1]), }]).then(arguments[arguments.length - 1]); """, raw_id1, raw_id2, ) assert not_allowed_error_in(response), "Should have thrown a NotAllowedError" driver.remove_virtual_authenticator() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_set_user_verified(driver, pages): driver = create_rk_enabled_ctap2_authenticator(driver) driver.get(pages.url("virtual-authenticator.html", localhost=True)) # Register a credential requiring UV. response = driver.execute_async_script( "registerCredential({authenticatorSelection: {userVerification: 'required'}}).then(arguments[arguments.length - 1]);" ) assert response.get("status", "") == "OK" raw_id = response["credential"]["rawId"] # Getting an assertion requiring user verification should succeed. response = driver.execute_async_script(GET_CREDENTIAL, raw_id) assert response.get("status", "") == "OK" # Disable user verified. driver.set_user_verified(False) # Getting an assertion requiring user verification should fail. response = driver.execute_async_script(GET_CREDENTIAL, raw_id) assert not_allowed_error_in(response), "Should have thrown a NotAllowedError" driver.remove_virtual_authenticator() selenium-selenium-4.18.1/test/selenium/webdriver/common/executing_javascript_tests.py0000644000175000017500000002422414564764517031252 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement try: str = unicode except NameError: pass def test_should_be_able_to_execute_simple_javascript_and_return_astring(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return document.title") assert isinstance(result, str), "The type of the result is %s" % type(result) assert "XHTML Test Page" == result def test_should_be_able_to_execute_simple_javascript_and_return_an_integer(driver, pages): pages.load("nestedElements.html") result = driver.execute_script("return document.getElementsByName('checky').length") assert isinstance(result, int) assert int(result) > 1 def test_should_be_able_to_execute_simple_javascript_and_return_aweb_element(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return document.getElementById('id1')") assert result is not None assert isinstance(result, WebElement) assert "a" == result.tag_name.lower() def test_should_be_able_to_execute_simple_javascript_and_return_alist_of_web_elements(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return document.querySelectorAll('div.navigation a')") assert result is not None assert isinstance(result, list) assert all(isinstance(item, WebElement) for item in result) assert all("a" == item.tag_name.lower() for item in result) def test_should_be_able_to_execute_simple_javascript_and_return_web_elements_inside_alist(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return [document.body]") assert result is not None assert isinstance(result, list) assert isinstance(result[0], WebElement) def test_should_be_able_to_execute_simple_javascript_and_return_web_elements_inside_anested_list(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return [document.body, [document.getElementById('id1')]]") assert result is not None assert isinstance(result, list) assert isinstance(result[0], WebElement) assert isinstance(result[1][0], WebElement) def test_should_be_able_to_execute_simple_javascript_and_return_web_elements_inside_adict(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return {el1: document.body}") assert result is not None assert isinstance(result, dict) assert isinstance(result.get("el1"), WebElement) def test_should_be_able_to_execute_simple_javascript_and_return_web_elements_inside_anested_dict(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return {el1: document.body, " "nested: {el2: document.getElementById('id1')}}") assert result is not None assert isinstance(result, dict) assert isinstance(result.get("el1"), WebElement) assert isinstance(result.get("nested").get("el2"), WebElement) def test_should_be_able_to_execute_simple_javascript_and_return_web_elements_inside_alist_inside_adict(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return {el1: [document.body]}") assert result is not None assert isinstance(result, dict) assert isinstance(result.get("el1"), list) assert isinstance(result.get("el1")[0], WebElement) def test_should_be_able_to_execute_simple_javascript_and_return_aboolean(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return true") assert result is not None assert isinstance(result, bool) assert bool(result) def test_should_be_able_to_execute_simple_javascript_and_astrings_array(driver, pages): pages.load("javascriptPage.html") expectedResult = [] expectedResult.append("zero") expectedResult.append("one") expectedResult.append("two") result = driver.execute_script("return ['zero', 'one', 'two']") assert expectedResult == result def test_should_be_able_to_execute_simple_javascript_and_return_an_array(driver, pages): pages.load("javascriptPage.html") expectedResult = [] expectedResult.append("zero") subList = [] subList.append(True) subList.append(False) expectedResult.append(subList) result = driver.execute_script("return ['zero', [true, false]]") assert result is not None assert isinstance(result, list) assert expectedResult == result def test_passing_and_returning_an_int_should_return_awhole_number(driver, pages): pages.load("javascriptPage.html") expectedResult = 1 result = driver.execute_script("return arguments[0]", expectedResult) assert isinstance(result, int) assert expectedResult == result def test_passing_and_returning_adouble_should_return_adecimal(driver, pages): pages.load("javascriptPage.html") expectedResult = 1.2 result = driver.execute_script("return arguments[0]", expectedResult) assert isinstance(result, float) assert expectedResult == result def test_should_throw_an_exception_when_the_javascript_is_bad(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(WebDriverException): driver.execute_script("return squiggle()") def test_should_be_able_to_call_functions_defined_on_the_page(driver, pages): pages.load("javascriptPage.html") driver.execute_script("displayMessage('I like cheese')") text = driver.find_element(By.ID, "result").text assert "I like cheese" == text.strip() def test_should_be_able_to_pass_astring_an_as_argument(driver, pages): pages.load("javascriptPage.html") value = driver.execute_script("return arguments[0] == 'fish' ? 'fish' : 'not fish'", "fish") assert "fish" == value def test_should_be_able_to_pass_aboolean_an_as_argument(driver, pages): pages.load("javascriptPage.html") value = bool(driver.execute_script("return arguments[0] == true", True)) assert value def test_should_be_able_to_pass_anumber_an_as_argument(driver, pages): pages.load("javascriptPage.html") value = bool(driver.execute_script("return arguments[0] == 1 ? true : false", 1)) assert value def test_should_be_able_to_pass_aweb_element_as_argument(driver, pages): pages.load("javascriptPage.html") button = driver.find_element(By.ID, "plainButton") value = driver.execute_script( "arguments[0]['flibble'] = arguments[0].getAttribute('id'); return arguments[0]['flibble']", button ) assert "plainButton" == value def test_should_be_able_to_pass_an_array_as_argument(driver, pages): pages.load("javascriptPage.html") array = ["zero", 1, True, 3.14159] length = int(driver.execute_script("return arguments[0].length", array)) assert len(array) == length def test_should_be_able_to_pass_acollection_as_argument(driver, pages): pages.load("javascriptPage.html") collection = [] collection.append("Cheddar") collection.append("Brie") collection.append(7) length = int(driver.execute_script("return arguments[0].length", collection)) assert len(collection) == length collection = [] collection.append("Gouda") collection.append("Stilton") collection.append("Stilton") collection.append(True) length = int(driver.execute_script("return arguments[0].length", collection)) assert len(collection) == length def test_should_throw_an_exception_if_an_argument_is_not_valid(driver, pages): pages.load("javascriptPage.html") with pytest.raises(Exception): driver.execute_script("return arguments[0]", driver) def test_should_be_able_to_pass_in_more_than_one_argument(driver, pages): pages.load("javascriptPage.html") result = driver.execute_script("return arguments[0] + arguments[1]", "one", "two") assert "onetwo" == result def test_javascript_string_handling_should_work_as_expected(driver, pages): pages.load("javascriptPage.html") value = driver.execute_script("return ''") assert "" == value value = driver.execute_script("return undefined") assert value is None value = driver.execute_script("return ' '") assert " " == value def test_should_be_able_to_create_apersistent_value(driver, pages): pages.load("formPage.html") driver.execute_script("document.alerts = []") driver.execute_script("document.alerts.push('hello world')") text = driver.execute_script("return document.alerts.shift()") assert "hello world" == text def test_can_pass_adictionary_as_aparameter(driver, pages): pages.load("simpleTest.html") nums = [1, 2] args = {"bar": "test", "foo": nums} res = driver.execute_script("return arguments[0]['foo'][1]", args) assert 2 == res def test_can_pass_anone(driver, pages): pages.load("simpleTest.html") res = driver.execute_script("return arguments[0] === null", None) assert res def test_can_return_a_const(driver, pages): pages.load("simpleTest.html") res = driver.execute_script("const cheese='cheese'; return cheese") assert res == "cheese" def test_can_return_a_const_in_a_page(driver, pages): pages.load("const_js.html") res = driver.execute_script("return makeMeA('sandwich');") assert res == "cheese sandwich" @pytest.mark.xfail_remote @pytest.mark.xfail_firefox def test_can_return_global_const(driver, pages): pages.load("const_js.html") # cheese is a variable with "cheese" in it res = driver.execute_script("return cheese") assert res == "cheese" selenium-selenium-4.18.1/test/selenium/webdriver/common/utils.py0000644000175000017500000000202114564764517024736 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. def convert_cookie_to_json(cookie): cookie_dict = {} for key, value in cookie.items(): if key == "expires": cookie_dict["expiry"] = int(value) * 1000 else: cookie_dict[key] = value return cookie_dict selenium-selenium-4.18.1/test/selenium/webdriver/common/stale_reference_tests.py0000644000175000017500000000351714564764517030161 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import StaleElementReferenceException from selenium.webdriver.common.by import By def test_old_page(driver, pages): pages.load("simpleTest.html") elem = driver.find_element(by=By.ID, value="links") pages.load("xhtmlTest.html") msg = r"\/errors#stale-element-reference-exception" with pytest.raises(StaleElementReferenceException, match=msg): elem.click() @pytest.mark.xfail_safari def test_should_not_crash_when_calling_get_size_on_an_obsolete_element(driver, pages): pages.load("simpleTest.html") elem = driver.find_element(by=By.ID, value="links") pages.load("xhtmlTest.html") with pytest.raises(StaleElementReferenceException): elem.size @pytest.mark.xfail_safari def test_should_not_crash_when_querying_the_attribute_of_astale_element(driver, pages): pages.load("xhtmlTest.html") heading = driver.find_element(by=By.XPATH, value="//h1") pages.load("simpleTest.html") with pytest.raises(StaleElementReferenceException): heading.get_attribute("class") selenium-selenium-4.18.1/test/selenium/webdriver/common/timeout_tests.py0000644000175000017500000000436214564764517026520 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.timeouts import Timeouts def test_should_create_timeouts_object(): implicit_wait = 10 page_load = 10 script = 10 timeouts = Timeouts(implicit_wait=implicit_wait, page_load=page_load, script=script) assert implicit_wait == timeouts.implicit_wait assert page_load == timeouts.page_load assert script == timeouts.script def test_should_error_if_implicit_wait_isnt_a_number(): with pytest.raises(TypeError): Timeouts(implicit_wait="abc") timeout = Timeouts(implicit_wait=0) with pytest.raises(TypeError): timeout.implicit_wait = "abc" def test_should_error_if_page_load_isnt_a_number(): with pytest.raises(TypeError): Timeouts(page_load="abc") timeout = Timeouts(page_load=0) with pytest.raises(TypeError): timeout.page_load = "abc" def test_should_error_if_script_isnt_a_number(): with pytest.raises(TypeError): Timeouts(script="abc") timeout = Timeouts(script=0) with pytest.raises(TypeError): timeout.script = "abc" def test_should_get_timeouts_without_setting_them(driver): results = driver.timeouts assert results.implicit_wait == 0 assert results.page_load == 300 assert results.script == 30 def test_should_set_and_get_timeouts_on_remote_end(driver): timeout = Timeouts(implicit_wait=10) driver.timeouts = timeout result = driver.timeouts assert result.implicit_wait == timeout.implicit_wait selenium-selenium-4.18.1/test/selenium/webdriver/common/select_element_handling_tests.py0000644000175000017500000000674514564764517031675 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.common.by import By def test_should_be_possible_to_deselect_asingle_option_from_aselect_which_allows_multiple_choice(driver, pages): pages.load("formPage.html") multiSelect = driver.find_element(By.ID, "multi") options = multiSelect.find_elements(By.TAG_NAME, "option") option = options[0] assert option.is_selected() is True option.click() assert option.is_selected() is False option.click() assert option.is_selected() is True option = options[2] assert option.is_selected() is True def test_should_be_able_to_change_the_selected_option_in_aselec(driver, pages): pages.load("formPage.html") selectBox = driver.find_element(By.XPATH, "//select[@name='selectomatic']") options = selectBox.find_elements(By.TAG_NAME, "option") one = options[0] two = options[1] assert one.is_selected() is True assert two.is_selected() is False two.click() assert one.is_selected() is False assert two.is_selected() is True def test_should_be_able_to_select_more_than_one_option_from_aselect_which_allows_multiple_choice(driver, pages): pages.load("formPage.html") multiSelect = driver.find_element(By.ID, "multi") options = multiSelect.find_elements(By.TAG_NAME, "option") for option in options: if not option.is_selected(): option.click() for i in range(len(options)): option = options[i] assert option.is_selected() is True def test_should_select_first_option_if_none_is_selected(driver, pages): pages.load("formPage.html") selectBox = driver.find_element(By.XPATH, "//select[@name='select-default']") options = selectBox.find_elements(By.TAG_NAME, "option") one = options[0] two = options[1] assert one.is_selected() is True assert two.is_selected() is False two.click() assert one.is_selected() is False assert two.is_selected() is True def test_can_select_elements_in_opt_group(driver, pages): pages.load("selectPage.html") element = driver.find_element(By.ID, "two-in-group") element.click() assert element.is_selected() is True def test_can_get_value_from_option_via_attribute_when_attribute_doesnt_exist(driver, pages): pages.load("formPage.html") element = driver.find_element(By.CSS_SELECTOR, "select[name='select-default'] option") assert element.get_attribute("value") == "One" element = driver.find_element(By.ID, "blankOption") assert element.get_attribute("value") == "" def test_can_get_value_from_option_via_attribute_when_attribute_is_empty_string(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "optionEmptyValueSet") assert element.get_attribute("value") == "" selenium-selenium-4.18.1/test/selenium/webdriver/common/repr_tests.py0000644000175000017500000000304214564764517025774 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait def test_should_implement_repr_for_web_driver(driver): driver_repr = repr(driver) assert type(driver).__name__ in driver_repr assert driver.session_id in driver_repr def test_should_implement_repr_for_web_element(driver, pages): pages.load("simpleTest.html") elem = driver.find_element(By.ID, "validImgTag") elem_repr = repr(elem) assert type(elem).__name__ in elem_repr assert driver.session_id in elem_repr assert elem._id in elem_repr def test_should_implement_repr_for_wait(driver): wait = WebDriverWait(driver, 30) wait_repr = repr(wait) assert type(wait).__name__ in wait_repr assert driver.session_id in wait_repr selenium-selenium-4.18.1/test/selenium/webdriver/common/test_file2.txt0000644000175000017500000000003314564764517026026 0ustar carstencarstenlorem ipsum dolor sit amet selenium-selenium-4.18.1/test/selenium/webdriver/common/webdriverwait_tests.py0000644000175000017500000003721714564764517027715 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import time import pytest from selenium.common.exceptions import InvalidElementStateException from selenium.common.exceptions import InvalidSelectorException from selenium.common.exceptions import StaleElementReferenceException from selenium.common.exceptions import TimeoutException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait def throw_sere(driver): raise StaleElementReferenceException("test") def test_should_fail_with_invalid_selector_exception(driver, pages): pages.load("dynamic.html") with pytest.raises(InvalidSelectorException): WebDriverWait(driver, 0.7).until(EC.presence_of_element_located((By.XPATH, "//*[contains(@id,'something'"))) def test_should_explicitly_wait_for_a_single_element(driver, pages): pages.load("dynamic.html") add = driver.find_element(By.ID, "adder") add.click() WebDriverWait(driver, 3).until( EC.presence_of_element_located((By.ID, "box0")) ) # All is well if this doesn't throw. def test_should_still_fail_to_find_an_element_with_explicit_wait(driver, pages): pages.load("dynamic.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.presence_of_element_located((By.ID, "box0"))) def test_should_explicitly_wait_until_at_least_one_element_is_found_when_searching_for_many(driver, pages): pages.load("dynamic.html") add = driver.find_element(By.ID, "adder") add.click() add.click() elements = WebDriverWait(driver, 3).until(EC.presence_of_all_elements_located((By.CLASS_NAME, "redbox"))) assert len(elements) >= 1 def test_should_fail_to_find_elements_when_explicit_waiting(driver, pages): pages.load("dynamic.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.presence_of_all_elements_located((By.CLASS_NAME, "redbox"))) def test_should_wait_until_at_least_one_visible_elements_is_found_when_searching_for_many(driver, pages): pages.load("hidden_partially.html") add_visible = driver.find_element(By.ID, "addVisible") add_hidden = driver.find_element(By.ID, "addHidden") add_visible.click() add_visible.click() add_hidden.click() class wait_for_two_elements: def __init__(self, locator): self.locator = locator def __call__(self, driver): elements = [element for element in driver.find_elements(*self.locator) if EC._element_if_visible(element)] return elements if len(elements) == 2 else False elements = WebDriverWait(driver, 3).until(wait_for_two_elements((By.CLASS_NAME, "redbox"))) assert len(elements) == 2 def test_should_fail_to_find_visible_elements_when_explicit_waiting(driver, pages): pages.load("hidden_partially.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.visibility_of_any_elements_located((By.CLASS_NAME, "redbox"))) def test_should_wait_until_all_visible_elements_are_found_when_searching_for_many(driver, pages): pages.load("hidden_partially.html") add_visible = driver.find_element(By.ID, "addVisible") add_visible.click() add_visible.click() elements = WebDriverWait(driver, 3).until(EC.visibility_of_all_elements_located((By.CLASS_NAME, "redbox"))) assert len(elements) == 2 def test_should_fail_if_not_all_elements_are_visible(driver, pages): pages.load("hidden_partially.html") add_visible = driver.find_element(By.ID, "addVisible") add_hidden = driver.find_element(By.ID, "addHidden") add_visible.click() add_hidden.click() with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.visibility_of_all_elements_located((By.CLASS_NAME, "redbox"))) def test_should_wait_only_as_long_as_timeout_specified_when_implicit_waits_are_set(driver, pages): pages.load("dynamic.html") driver.implicitly_wait(0.5) start = time.time() with pytest.raises(TimeoutException): WebDriverWait(driver, 1).until(EC.presence_of_element_located((By.ID, "box0"))) assert time.time() - start < 1.5 def test_should_wait_at_least_once(driver, pages): pages.load("simpleTest.html") elements = WebDriverWait(driver, 0).until(lambda d: d.find_elements(By.TAG_NAME, "h1")) assert len(elements) >= 1 def test_wait_until_not_returns_if_evaluates_to_false(driver, pages): assert WebDriverWait(driver, 1).until_not(lambda d: False) is False def test_wait_should_still_fail_if_produce_ignored_exception(driver, pages): ignored = (InvalidElementStateException, StaleElementReferenceException) with pytest.raises(TimeoutException): WebDriverWait(driver, 1, 0.7, ignored_exceptions=ignored).until(throw_sere) def test_wait_should_still_fail_if_produce_child_of_ignored_exception(driver, pages): ignored = WebDriverException with pytest.raises(TimeoutException): WebDriverWait(driver, 1, 0.7, ignored_exceptions=ignored).until(throw_sere) def test_wait_until_not_should_not_fail_if_produce_ignored_exception(driver, pages): ignored = (InvalidElementStateException, StaleElementReferenceException) assert WebDriverWait(driver, 1, 0.7, ignored_exceptions=ignored).until_not(throw_sere) def test_expected_condition_title_is(driver, pages): pages.load("blank.html") WebDriverWait(driver, 1).until(EC.title_is("blank")) driver.execute_script("setTimeout(function(){document.title='not blank'}, 200)") WebDriverWait(driver, 2).until(EC.title_is("not blank")) assert driver.title == "not blank" with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.title_is("blank")) def test_expected_condition_title_contains(driver, pages): pages.load("blank.html") driver.execute_script("setTimeout(function(){document.title='not blank'}, 200)") WebDriverWait(driver, 2).until(EC.title_contains("not")) assert driver.title == "not blank" with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.title_contains("blanket")) @pytest.mark.xfail_safari def test_expected_condition_visibility_of_element_located(driver, pages): pages.load("javascriptPage.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.visibility_of_element_located((By.ID, "clickToHide"))) driver.find_element(By.ID, "clickToShow").click() element = WebDriverWait(driver, 5).until(EC.visibility_of_element_located((By.ID, "clickToHide"))) assert element.is_displayed() is True @pytest.mark.xfail_safari def test_expected_condition_visibility_of(driver, pages): pages.load("javascriptPage.html") hidden = driver.find_element(By.ID, "clickToHide") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.visibility_of(hidden)) driver.find_element(By.ID, "clickToShow").click() element = WebDriverWait(driver, 5).until(EC.visibility_of(hidden)) assert element.is_displayed() is True def test_expected_condition_text_to_be_present_in_element(driver, pages): pages.load("booleanAttributes.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.text_to_be_present_in_element((By.ID, "unwrappable"), "Expected")) driver.execute_script( "setTimeout(function(){var el = document.getElementById('unwrappable'); el.textContent = el.innerText = 'Unwrappable Expected text'}, 200)" ) WebDriverWait(driver, 2).until(EC.text_to_be_present_in_element((By.ID, "unwrappable"), "Expected")) assert "Unwrappable Expected text" == driver.find_element(By.ID, "unwrappable").text def test_expected_condition_text_to_be_present_in_element_value(driver, pages): pages.load("booleanAttributes.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 1).until(EC.text_to_be_present_in_element_value((By.ID, "inputRequired"), "Expected")) driver.execute_script( "setTimeout(function(){document.getElementById('inputRequired').value = 'Example Expected text'}, 200)" ) WebDriverWait(driver, 2).until(EC.text_to_be_present_in_element_value((By.ID, "inputRequired"), "Expected")) assert "Example Expected text" == driver.find_element(By.ID, "inputRequired").get_attribute("value") def test_expected_condition_text_to_be_present_in_element_attribute(driver, pages): pages.load("booleanAttributes.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 1).until( EC.text_to_be_present_in_element_attribute((By.ID, "inputRequired"), "value", "Expected") ) driver.execute_script( "setTimeout(function(){document.getElementById('inputRequired').value = 'Example Expected text'}, 200)" ) WebDriverWait(driver, 2).until( EC.text_to_be_present_in_element_attribute((By.ID, "inputRequired"), "value", "Expected") ) assert "Example Expected text" == driver.find_element(By.ID, "inputRequired").get_attribute("value") def test_expected_condition_frame_to_be_available_and_switch_to_it_by_locator(driver, pages): pages.load("blank.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 1).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "myFrame"))) driver.execute_script( "setTimeout(function(){var f = document.createElement('iframe'); f.id='myFrame'; f.src = '" + pages.url("iframeWithAlert.html") + "'; document.body.appendChild(f)}, 200)" ) WebDriverWait(driver, 2).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "myFrame"))) assert "click me" == driver.find_element(By.ID, "alertInFrame").text def test_expected_condition_invisiblity_of_element(driver, pages): pages.load("javascriptPage.html") target = driver.find_element(By.ID, "clickToHide") driver.execute_script("delayedShowHide(0, true)") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.invisibility_of_element(target)) driver.execute_script("delayedShowHide(200, false)") element = WebDriverWait(driver, 2).until(EC.invisibility_of_element(target)) assert element.is_displayed() is False assert target == element def test_expected_condition_invisiblity_of_element_located(driver, pages): pages.load("javascriptPage.html") driver.execute_script("delayedShowHide(0, true)") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.invisibility_of_element_located((By.ID, "clickToHide"))) driver.execute_script("delayedShowHide(200, false)") element = WebDriverWait(driver, 2).until(EC.invisibility_of_element_located((By.ID, "clickToHide"))) assert element.is_displayed() is False @pytest.mark.xfail_safari def test_expected_condition_element_to_be_clickable(driver, pages): pages.load("javascriptPage.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.element_to_be_clickable((By.ID, "clickToHide"))) driver.execute_script("delayedShowHide(200, true)") WebDriverWait(driver, 2).until(EC.element_to_be_clickable((By.ID, "clickToHide"))) element = driver.find_element(By.ID, "clickToHide") element.click() WebDriverWait(driver, 4.5).until(EC.invisibility_of_element_located((By.ID, "clickToHide"))) assert element.is_displayed() is False def test_expected_condition_staleness_of(driver, pages): pages.load("dynamicallyModifiedPage.html") element = driver.find_element(By.ID, "element-to-remove") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.staleness_of(element)) driver.find_element(By.ID, "buttonDelete").click() assert "element" == element.text WebDriverWait(driver, 2).until(EC.staleness_of(element)) with pytest.raises(StaleElementReferenceException): element.text def test_expected_condition_element_to_be_selected(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "checky") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.element_to_be_selected(element)) driver.execute_script("setTimeout(function(){document.getElementById('checky').checked = true}, 200)") WebDriverWait(driver, 2).until(EC.element_to_be_selected(element)) assert element.is_selected() is True def test_expected_condition_element_located_to_be_selected(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "checky") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.element_located_to_be_selected((By.ID, "checky"))) driver.execute_script("setTimeout(function(){document.getElementById('checky').checked = true}, 200)") WebDriverWait(driver, 2).until(EC.element_located_to_be_selected((By.ID, "checky"))) assert element.is_selected() is True def test_expected_condition_element_selection_state_to_be(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "checky") WebDriverWait(driver, 0.7).until(EC.element_selection_state_to_be(element, False)) assert element.is_selected() is False with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.element_selection_state_to_be(element, True)) driver.execute_script("setTimeout(function(){document.getElementById('checky').checked = true}, 200)") WebDriverWait(driver, 2).until(EC.element_selection_state_to_be(element, True)) assert element.is_selected() is True def test_expected_condition_element_located_selection_state_to_be(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "checky") WebDriverWait(driver, 0.7).until(EC.element_located_selection_state_to_be((By.ID, "checky"), False)) assert element.is_selected() is False with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.element_located_selection_state_to_be((By.ID, "checky"), True)) driver.execute_script("setTimeout(function(){document.getElementById('checky').checked = true}, 200)") WebDriverWait(driver, 2).until(EC.element_located_selection_state_to_be((By.ID, "checky"), True)) assert element.is_selected() is True def test_expected_condition_alert_is_present(driver, pages): pages.load("blank.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.7).until(EC.alert_is_present()) driver.execute_script("setTimeout(function(){alert('alerty')}, 200)") WebDriverWait(driver, 2).until(EC.alert_is_present()) alert = driver.switch_to.alert assert "alerty" == alert.text alert.dismiss() def test_expected_condition_attribute_to_be_include_in_element(driver, pages): pages.load("booleanAttributes.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 1).until(EC.element_attribute_to_include((By.ID, "inputRequired"), "test")) value = WebDriverWait(driver, 2).until(EC.element_attribute_to_include((By.ID, "inputRequired"), "value")) assert value is not None selenium-selenium-4.18.1/test/selenium/webdriver/common/w3c_interaction_tests.py0000644000175000017500000003126614564764517030130 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.actions import interaction from selenium.webdriver.common.actions.action_builder import ActionBuilder from selenium.webdriver.common.actions.pointer_input import PointerInput from selenium.webdriver.common.actions.wheel_input import WheelInput from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait def test_should_be_able_to_get_pointer_and_keyboard_inputs(driver, pages): actions = ActionBuilder(driver) pointers = actions.pointer_inputs keyboards = actions.key_inputs assert pointers is not None assert keyboards is not None @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_sending_keys_to_active_element_with_modifier(driver, pages): pages.load("formPage.html") e = driver.find_element(By.ID, "working") e.click() actions = ActionBuilder(driver) key_action = actions.key_action key_action.key_down(Keys.SHIFT).send_keys("abc").key_up(Keys.SHIFT) actions.perform() assert "ABC" == e.get_attribute("value") @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_create_pause_action_on_keyboard(driver, pages): # If we don't get an error and takes less than 3 seconds to run, we are good import datetime start = datetime.datetime.now() actions1 = ActionBuilder(driver) key_actions = actions1.key_action key_actions.pause(1) actions1.perform() finish = datetime.datetime.now() assert (finish - start).seconds <= 3 # Add a filler step actions2 = ActionBuilder(driver) key_action = actions2.key_action key_action.pause() actions2.perform() def test_can_create_pause_action_on_pointer(driver, pages): # If we don't get an error and takes less than 3 seconds to run, we are good import datetime start = datetime.datetime.now() actions1 = ActionBuilder(driver) key_actions = actions1.pointer_action key_actions.pause(1) actions1.perform() finish = datetime.datetime.now() assert (finish - start).seconds <= 3 # Add a filler step actions2 = ActionBuilder(driver) key_action = actions2.pointer_action key_action.pause() actions2.perform() def test_can_clear_actions(driver, pages): actions = ActionBuilder(driver) actions.clear_actions() def test_move_and_click(driver, pages): pages.load("javascriptPage.html") toClick = driver.find_element(By.ID, "clickField") actions = ActionBuilder(driver) pointer = actions.pointer_action pointer.move_to(toClick).click() actions.perform() assert "Clicked" == toClick.get_attribute("value") def test_drag_and_drop(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" element_available_timeout = 15 wait = WebDriverWait(driver, element_available_timeout) pages.load("droppableItems.html") wait.until(lambda dr: _is_element_available(driver, "draggable")) if not _is_element_available(driver, "draggable"): raise AssertionError("Could not find draggable element after 15 seconds.") toDrag = driver.find_element(By.ID, "draggable") dropInto = driver.find_element(By.ID, "droppable") actions = ActionBuilder(driver) pointer = actions.pointer_action pointer.click_and_hold(toDrag).move_to(dropInto).release() actions.perform() dropInto = driver.find_element(By.ID, "droppable") text = dropInto.find_element(By.TAG_NAME, "p").text assert "Dropped!" == text def test_context_click(driver, pages): pages.load("javascriptPage.html") toContextClick = driver.find_element(By.ID, "doubleClickField") actions = ActionBuilder(driver) pointer = actions.pointer_action pointer.context_click(toContextClick) actions.perform() assert "ContextClicked" == toContextClick.get_attribute("value") @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote(reason="Fails on Travis") @pytest.mark.xfail_chrome(reason="Fails on Travis") def test_double_click(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toDoubleClick = driver.find_element(By.ID, "doubleClickField") actions = ActionBuilder(driver) pointer = actions.pointer_action pointer.double_click(toDoubleClick) actions.perform() assert "DoubleClicked" == toDoubleClick.get_attribute("value") def test_dragging_element_with_mouse_moves_it_to_another_list(driver, pages): _perform_drag_and_drop_with_mouse(driver, pages) dragInto = driver.find_element(By.ID, "sortable1") assert 6 == len(dragInto.find_elements(By.TAG_NAME, "li")) def test_dragging_element_with_mouse_fires_events(driver, pages): _perform_drag_and_drop_with_mouse(driver, pages) dragReporter = driver.find_element(By.ID, "dragging_reports") assert "Nothing happened. DragOut DropIn RightItem 3" == dragReporter.text @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_pen_pointer_properties(driver, pages): pages.load("pointerActionsPage.html") pointerArea = driver.find_element(By.CSS_SELECTOR, "#pointerArea") pointer_input = PointerInput(interaction.POINTER_PEN, "pen") actions = ActionBuilder(driver, mouse=pointer_input) center = _get_inview_center(pointerArea.rect, _get_viewport_rect(driver)) actions.pointer_action.move_to(pointerArea).pointer_down(pressure=0.36, tilt_x=-72, tilt_y=9, twist=86).move_to( pointerArea, x=5, y=10 ).pointer_up().move_to(pointerArea, x=5, y=10) actions.perform() events = _get_events(driver) assert events[3]["type"] == "pointerdown" assert events[3]["pageX"] == pytest.approx(center["x"], abs=1.0) assert events[3]["pageY"] == pytest.approx(center["y"], abs=1.0) assert events[3]["target"] == "pointerArea" assert events[3]["pointerType"] == "pen" # The default value of width and height for mouse and pen inputs is 1 assert round(events[3]["width"], 2) == 1 assert round(events[3]["height"], 2) == 1 assert round(events[3]["pressure"], 2) == 0.36 assert events[3]["tiltX"] == -72 assert events[3]["tiltY"] == 9 assert events[3]["twist"] == 86 assert events[6]["type"] == "pointermove" assert events[6]["target"] == "pointerArea" assert events[6]["pointerType"] == "pen" assert round(events[6]["width"], 2) == 1 assert round(events[6]["height"], 2) == 1 # The default value of pressure for all inputs is 0.5, other properties are 0 assert round(events[6]["pressure"], 2) == 0.5 assert events[6]["tiltX"] == 0 assert events[6]["tiltY"] == 0 assert events[6]["twist"] == 0 @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_touch_pointer_properties(driver, pages): pages.load("pointerActionsPage.html") pointerArea = driver.find_element(By.CSS_SELECTOR, "#pointerArea") center = _get_inview_center(pointerArea.rect, _get_viewport_rect(driver)) touch_input = PointerInput(interaction.POINTER_TOUCH, "touch") touch_chain = ActionBuilder(driver, mouse=touch_input) touch_chain.pointer_action.move_to(pointerArea).pointer_down( width=23, height=31, pressure=0.78, tilt_x=21, tilt_y=-8, twist=355 ).move_to( pointerArea, x=10, y=10, width=39, height=35, pressure=0.91, tilt_x=-19, tilt_y=62, twist=345 ).pointer_up().move_to( pointerArea, x=15, y=15 ) touch_chain.perform() events = _get_events(driver) assert len(events) == 7 event_types = [e["type"] for e in events] assert [ "pointerover", "pointerenter", "pointerdown", "pointermove", "pointerup", "pointerout", "pointerleave", ] == event_types assert events[2]["type"] == "pointerdown" assert events[2]["pageX"] == pytest.approx(center["x"], abs=1.0) assert events[2]["pageY"] == pytest.approx(center["y"], abs=1.0) assert events[2]["target"] == "pointerArea" assert events[2]["pointerType"] == "touch" assert round(events[2]["width"], 2) == 23 assert round(events[2]["height"], 2) == 31 assert round(events[2]["pressure"], 2) == 0.78 assert events[2]["tiltX"] == 21 assert events[2]["tiltY"] == -8 assert events[2]["twist"] == 355 assert events[3]["type"] == "pointermove" assert events[3]["pageX"] == pytest.approx(center["x"] + 10, abs=1.0) assert events[3]["pageY"] == pytest.approx(center["y"] + 10, abs=1.0) assert events[3]["target"] == "pointerArea" assert events[3]["pointerType"] == "touch" assert round(events[3]["width"], 2) == 39 assert round(events[3]["height"], 2) == 35 assert round(events[3]["pressure"], 2) == 0.91 assert events[3]["tiltX"] == -19 assert events[3]["tiltY"] == 62 assert events[3]["twist"] == 345 @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_mouse_wheel(driver, pages): pages.load("scrollingPage.html") driver.execute_script("document.scrollingElement.scrollTop = 0") scrollable = driver.find_element(By.CSS_SELECTOR, "#scrollable") wheel_input = WheelInput("wheel") actions = ActionBuilder(driver, wheel=wheel_input) actions.wheel_action.scroll(0, 0, 5, 10, 0, scrollable) actions.perform() events = _get_events(driver) assert len(events) == 1 assert events[0]["type"] == "wheel" assert events[0]["deltaX"] >= 5 assert events[0]["deltaY"] >= 10 assert events[0]["deltaZ"] == 0 assert events[0]["target"] == "scrollContent" def _perform_drag_and_drop_with_mouse(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("draggableLists.html") dragReporter = driver.find_element(By.ID, "dragging_reports") toDrag = driver.find_element(By.ID, "rightitem-3") dragInto = driver.find_element(By.ID, "sortable1") actions = ActionBuilder(driver) pointer = actions.pointer_action pointer.click_and_hold(toDrag).move_to(driver.find_element(By.ID, "leftitem-4")).move_to(dragInto).release() assert "Nothing happened." == dragReporter.text actions.perform() assert "Nothing happened. DragOut" in dragReporter.text def _is_element_available(driver, id): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" try: driver.find_element(By.ID, id) return True except Exception: return False def _get_events(driver): """Return list of key events recorded in the test_keys_page fixture.""" events = driver.execute_script("return allEvents.events;") or [] # `key` values in `allEvents` may be escaped (see `escapeSurrogateHalf` in # test_keys_wdspec.html), so this converts them back into unicode literals. for e in events: # example: turn "U+d83d" (6 chars) into u"\ud83d" (1 char) if "key" in e and e["key"].startswith("U+"): key = e["key"] hex_suffix = key[key.index("+") + 1 :] e["key"] = chr(int(hex_suffix, 16)) # WebKit sets code as 'Unidentified' for unidentified key codes, but # tests expect ''. if "code" in e and e["code"] == "Unidentified": e["code"] = "" return events def _get_inview_center(elem_rect, viewport_rect): x = { "left": max(0, min(elem_rect["x"], elem_rect["x"] + elem_rect["width"])), "right": min(viewport_rect["width"], max(elem_rect["x"], elem_rect["x"] + elem_rect["width"])), } y = { "top": max(0, min(elem_rect["y"], elem_rect["y"] + elem_rect["height"])), "bottom": min(viewport_rect["height"], max(elem_rect["y"], elem_rect["y"] + elem_rect["height"])), } return { "x": (x["left"] + x["right"]) / 2, "y": (y["top"] + y["bottom"]) / 2, } def _get_viewport_rect(driver): return driver.execute_script( """ return { height: window.innerHeight || document.documentElement.clientHeight, width: window.innerWidth || document.documentElement.clientWidth, }; """ ) selenium-selenium-4.18.1/test/selenium/webdriver/common/click_scrolling_tests.py0000644000175000017500000001573514564764517030201 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import MoveTargetOutOfBoundsException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait def test_clicking_on_anchor_scrolls_page(driver, pages): scrollScript = """var pageY; if (typeof(window.pageYOffset) == 'number') { pageY = window.pageYOffset; } else { pageY = document.documentElement.scrollTop; } return pageY;""" pages.load("macbeth.html") driver.find_element(By.PARTIAL_LINK_TEXT, "last speech").click() yOffset = driver.execute_script(scrollScript) # Focusing on to click, but not actually following, # the link will scroll it in to view, which is a few pixels further than 0 assert yOffset > 300 def test_should_scroll_to_click_on_an_element_hidden_by_overflow(driver, pages): pages.load("click_out_of_bounds_overflow.html") link = driver.find_element(By.ID, "link") try: link.click() except MoveTargetOutOfBoundsException as e: AssertionError("Should not be out of bounds: %s" % e.msg) def test_should_be_able_to_click_on_an_element_hidden_by_overflow(driver, pages): pages.load("scroll.html") link = driver.find_element(By.ID, "line8") # This used to throw a MoveTargetOutOfBoundsException - we don't expect it to link.click() assert "line8" == driver.find_element(By.ID, "clicked").text @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_should_be_able_to_click_on_an_element_hidden_by_double_overflow(driver, pages): pages.load("scrolling_tests/page_with_double_overflow_auto.html") driver.find_element(By.ID, "link").click() WebDriverWait(driver, 3).until(EC.title_is("Clicked Successfully!")) def test_should_be_able_to_click_on_an_element_hidden_by_yoverflow(driver, pages): pages.load("scrolling_tests/page_with_y_overflow_auto.html") driver.find_element(By.ID, "link").click() WebDriverWait(driver, 3).until(EC.title_is("Clicked Successfully!")) def test_should_not_scroll_overflow_elements_which_are_visible(driver, pages): pages.load("scroll2.html") list = driver.find_element(By.TAG_NAME, "ul") item = list.find_element(By.ID, "desired") item.click() yOffset = driver.execute_script("return arguments[0].scrollTop", list) assert 0 == yOffset, "Should not have scrolled" @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_should_not_scroll_if_already_scrolled_and_element_is_in_view(driver, pages): pages.load("scroll3.html") driver.find_element(By.ID, "button2").click() scrollTop = get_scroll_top(driver) driver.find_element(By.ID, "button1").click() assert scrollTop == get_scroll_top(driver) def test_should_be_able_to_click_radio_button_scrolled_into_view(driver, pages): pages.load("scroll4.html") driver.find_element(By.ID, "radio").click() # If we don't throw, we're good @pytest.mark.xfail_safari def test_should_scroll_overflow_elements_if_click_point_is_out_of_view_but_element_is_in_view(driver, pages): pages.load("scroll5.html") driver.find_element(By.ID, "inner").click() assert "clicked" == driver.find_element(By.ID, "clicked").text @pytest.mark.xfail_firefox(reason="https://github.com/w3c/webdriver/issues/408") @pytest.mark.xfail_remote(reason="https://github.com/w3c/webdriver/issues/408") @pytest.mark.xfail_safari def test_should_be_able_to_click_element_in_aframe_that_is_out_of_view(driver, pages): pages.load("scrolling_tests/page_with_frame_out_of_view.html") driver.switch_to.frame(driver.find_element(By.NAME, "frame")) element = driver.find_element(By.NAME, "checkbox") element.click() assert element.is_selected() def test_should_be_able_to_click_element_that_is_out_of_view_in_aframe(driver, pages): pages.load("scrolling_tests/page_with_scrolling_frame.html") driver.switch_to.frame(driver.find_element(By.NAME, "scrolling_frame")) element = driver.find_element(By.NAME, "scroll_checkbox") element.click() assert element.is_selected() def test_should_not_be_able_to_click_element_that_is_out_of_view_in_anon_scrollable_frame(driver, pages): pages.load("scrolling_tests/page_with_non_scrolling_frame.html") driver.switch_to.frame("scrolling_frame") element = driver.find_element(By.NAME, "scroll_checkbox") element.click() # TODO we should assert that the click was unsuccessful @pytest.mark.xfail_safari def test_should_be_able_to_click_element_that_is_out_of_view_in_aframe_that_is_out_of_view(driver, pages): pages.load("scrolling_tests/page_with_scrolling_frame_out_of_view.html") driver.switch_to.frame(driver.find_element(By.NAME, "scrolling_frame")) element = driver.find_element(By.NAME, "scroll_checkbox") element.click() assert element.is_selected() @pytest.mark.xfail_firefox @pytest.mark.xfail_chrome @pytest.mark.xfail_remote def test_should_be_able_to_click_element_that_is_out_of_view_in_anested_frame(driver, pages): pages.load("scrolling_tests/page_with_nested_scrolling_frames.html") driver.switch_to.frame(driver.find_element(By.NAME, "scrolling_frame")) driver.switch_to.frame(driver.find_element(By.NAME, "nested_scrolling_frame")) element = driver.find_element(By.NAME, "scroll_checkbox") element.click() assert element.is_selected() @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_chrome @pytest.mark.xfail_remote def test_should_be_able_to_click_element_that_is_out_of_view_in_anested_frame_that_is_out_of_view(driver, pages): pages.load("scrolling_tests/page_with_nested_scrolling_frames_out_of_view.html") driver.switch_to.frame(driver.find_element(By.NAME, "scrolling_frame")) driver.switch_to.frame(driver.find_element(By.NAME, "nested_scrolling_frame")) element = driver.find_element(By.NAME, "scroll_checkbox") element.click() assert element.is_selected() def test_should_not_scroll_when_getting_element_size(driver, pages): pages.load("scroll3.html") scrollTop = get_scroll_top(driver) driver.find_element(By.ID, "button1").size assert scrollTop == get_scroll_top(driver) def get_scroll_top(driver): return driver.execute_script("return document.body.scrollTop") selenium-selenium-4.18.1/test/selenium/webdriver/common/element_aria_label_tests.py0000644000175000017500000000217214564764517030613 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_should_return_accessible_name(driver): driver.get("data:text/html,

Level 1 Header

") header1 = driver.find_element(By.CSS_SELECTOR, "h1") assert header1.accessible_name == "Level 1 Header" selenium-selenium-4.18.1/test/selenium/webdriver/common/quit_tests.py0000644000175000017500000000167714564764517026022 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest @pytest.mark.no_driver_after_test def test_quit(driver, pages): driver.quit() with pytest.raises(Exception): pages.load("simpleTest.html") selenium-selenium-4.18.1/test/selenium/webdriver/common/interactions_tests.py0000644000175000017500000003212414564764517027531 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """Tests for advanced user interactions.""" import pytest from selenium.common.exceptions import MoveTargetOutOfBoundsException from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.actions import interaction from selenium.webdriver.common.actions.wheel_input import ScrollOrigin from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait def perform_drag_and_drop_with_mouse(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("draggableLists.html") dragReporter = driver.find_element(By.ID, "dragging_reports") toDrag = driver.find_element(By.ID, "rightitem-3") dragInto = driver.find_element(By.ID, "sortable1") holdItem = ActionChains(driver).click_and_hold(toDrag) moveToSpecificItem = ActionChains(driver).move_to_element(driver.find_element(By.ID, "leftitem-4")) moveToOtherList = ActionChains(driver).move_to_element(dragInto) drop = ActionChains(driver).release(dragInto) assert "Nothing happened." == dragReporter.text holdItem.perform() moveToSpecificItem.perform() moveToOtherList.perform() assert "Nothing happened. DragOut" == dragReporter.text drop.perform() @pytest.mark.xfail_safari def test_dragging_element_with_mouse_moves_it_to_another_list(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" perform_drag_and_drop_with_mouse(driver, pages) dragInto = driver.find_element(By.ID, "sortable1") assert 6 == len(dragInto.find_elements(By.TAG_NAME, "li")) @pytest.mark.xfail_safari def test_dragging_element_with_mouse_fires_events(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" perform_drag_and_drop_with_mouse(driver, pages) dragReporter = driver.find_element(By.ID, "dragging_reports") assert "Nothing happened. DragOut DropIn RightItem 3" == dragReporter.text def _is_element_available(driver, id): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" try: driver.find_element(By.ID, id) return True except Exception: return False @pytest.mark.xfail_safari def test_drag_and_drop(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" element_available_timeout = 15 wait = WebDriverWait(driver, element_available_timeout) pages.load("droppableItems.html") wait.until(lambda dr: _is_element_available(driver, "draggable")) if not _is_element_available(driver, "draggable"): raise AssertionError("Could not find draggable element after 15 seconds.") toDrag = driver.find_element(By.ID, "draggable") dropInto = driver.find_element(By.ID, "droppable") holdDrag = ActionChains(driver).click_and_hold(toDrag) move = ActionChains(driver).move_to_element(dropInto) drop = ActionChains(driver).release(dropInto) holdDrag.perform() move.perform() drop.perform() dropInto = driver.find_element(By.ID, "droppable") text = dropInto.find_element(By.TAG_NAME, "p").text assert "Dropped!" == text @pytest.mark.xfail_safari def test_double_click(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toDoubleClick = driver.find_element(By.ID, "doubleClickField") dblClick = ActionChains(driver).double_click(toDoubleClick) dblClick.perform() assert "DoubleClicked" == toDoubleClick.get_attribute("value") def test_context_click(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toContextClick = driver.find_element(By.ID, "doubleClickField") contextClick = ActionChains(driver).context_click(toContextClick) contextClick.perform() assert "ContextClicked" == toContextClick.get_attribute("value") def test_move_and_click(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toClick = driver.find_element(By.ID, "clickField") click = ActionChains(driver).move_to_element(toClick).click() click.perform() assert "Clicked" == toClick.get_attribute("value") def test_cannot_move_to_anull_locator(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") with pytest.raises(AttributeError): move = ActionChains(driver).move_to_element(None) move.perform() @pytest.mark.xfail_safari def test_clicking_on_form_elements(driver, pages): """Copied from org.openqa.selenium.interactions.CombinedInputActionsTest.""" pages.load("formSelectionPage.html") options = driver.find_elements(By.TAG_NAME, "option") selectThreeOptions = ( ActionChains(driver).click(options[1]).key_down(Keys.SHIFT).click(options[3]).key_up(Keys.SHIFT) ) selectThreeOptions.perform() showButton = driver.find_element(By.NAME, "showselected") showButton.click() resultElement = driver.find_element(By.ID, "result") assert "roquefort parmigiano cheddar" == resultElement.text @pytest.mark.xfail_firefox @pytest.mark.xfail_safari def test_selecting_multiple_items(driver, pages): """Copied from org.openqa.selenium.interactions.CombinedInputActionsTest.""" pages.load("selectableItems.html") reportingElement = driver.find_element(By.ID, "infodiv") assert "no info" == reportingElement.text listItems = driver.find_elements(By.TAG_NAME, "li") selectThreeItems = ( ActionChains(driver) .key_down(Keys.CONTROL) .click(listItems[1]) .click(listItems[3]) .click(listItems[5]) .key_up(Keys.CONTROL) ) selectThreeItems.perform() assert "#item2 #item4 #item6" == reportingElement.text # Now click on another element, make sure that's the only one selected. actionsBuilder = ActionChains(driver) actionsBuilder.click(listItems[6]).perform() assert "#item7" == reportingElement.text @pytest.mark.xfail_safari def test_sending_keys_to_active_element_with_modifier(driver, pages): pages.load("formPage.html") e = driver.find_element(By.ID, "working") e.click() ActionChains(driver).key_down(Keys.SHIFT).send_keys("abc").key_up(Keys.SHIFT).perform() assert "ABC" == e.get_attribute("value") def test_sending_keys_to_element(driver, pages): pages.load("formPage.html") e = driver.find_element(By.ID, "working") ActionChains(driver).send_keys_to_element(e, "abc").perform() assert "abc" == e.get_attribute("value") def test_can_send_keys_between_clicks(driver, pages): """ For W3C, ensures that the correct number of pauses are given to the other input device. """ pages.load("javascriptPage.html") keyup = driver.find_element(By.ID, "keyUp") keydown = driver.find_element(By.ID, "keyDown") ActionChains(driver).click(keyup).send_keys("foobar").click(keydown).perform() assert "foobar" == keyup.get_attribute("value") def test_can_reset_interactions(driver): actions = ActionChains(driver) actions.click() actions.key_down("A") assert all(len(device.actions) > 0 for device in actions.w3c_actions.devices if device.type != interaction.WHEEL) actions.reset_actions() assert all(len(device.actions) == 0 for device in actions.w3c_actions.devices) def test_can_pause(driver, pages): from time import time pages.load("javascriptPage.html") pause_time = 2 toClick = driver.find_element(By.ID, "clickField") toDoubleClick = driver.find_element(By.ID, "doubleClickField") pause = ActionChains(driver).click(toClick).pause(pause_time).click(toDoubleClick) start = time() pause.perform() end = time() assert pause_time < end - start assert "Clicked" == toClick.get_attribute("value") assert "Clicked" == toDoubleClick.get_attribute("value") @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_to_element(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") iframe = driver.find_element(By.TAG_NAME, "iframe") assert not _in_viewport(driver, iframe) ActionChains(driver).scroll_to_element(iframe).perform() assert _in_viewport(driver, iframe) @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_from_element_by_amount(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") iframe = driver.find_element(By.TAG_NAME, "iframe") scroll_origin = ScrollOrigin.from_element(iframe) ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() driver.switch_to.frame(iframe) checkbox = driver.find_element(By.NAME, "scroll_checkbox") assert _in_viewport(driver, checkbox) @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_from_element_with_offset_by_amount(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") footer = driver.find_element(By.TAG_NAME, "footer") scroll_origin = ScrollOrigin.from_element(footer, 0, -50) ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() iframe = driver.find_element(By.TAG_NAME, "iframe") driver.switch_to.frame(iframe) checkbox = driver.find_element(By.NAME, "scroll_checkbox") assert _in_viewport(driver, checkbox) def test_errors_when_element_offset_not_in_viewport(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") footer = driver.find_element(By.TAG_NAME, "footer") scroll_origin = ScrollOrigin.from_element(footer, 0, 50) with pytest.raises(MoveTargetOutOfBoundsException): ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_from_viewport_by_amount(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") footer = driver.find_element(By.TAG_NAME, "footer") delta_y = footer.rect["y"] ActionChains(driver).scroll_by_amount(0, delta_y).pause(0.2).perform() assert _in_viewport(driver, footer) def test_can_scroll_from_viewport_with_offset_by_amount(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame.html") scroll_origin = ScrollOrigin.from_viewport(10, 10) ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() iframe = driver.find_element(By.TAG_NAME, "iframe") driver.switch_to.frame(iframe) checkbox = driver.find_element(By.NAME, "scroll_checkbox") assert _in_viewport(driver, checkbox) def test_errors_when_origin_offset_not_in_viewport(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame.html") scroll_origin = ScrollOrigin.from_viewport(-10, -10) with pytest.raises(MoveTargetOutOfBoundsException): ActionChains(driver).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() def _get_events(driver): """Return list of key events recorded in the test_keys_page fixture.""" events = driver.execute_script("return allEvents.events;") or [] # `key` values in `allEvents` may be escaped (see `escapeSurrogateHalf` in # test_keys_wdspec.html), so this converts them back into unicode literals. for e in events: # example: turn "U+d83d" (6 chars) into u"\ud83d" (1 char) if "key" in e and e["key"].startswith("U+"): key = e["key"] hex_suffix = key[key.index("+") + 1 :] e["key"] = chr(int(hex_suffix, 16)) # WebKit sets code as 'Unidentified' for unidentified key codes, but # tests expect ''. if "code" in e and e["code"] == "Unidentified": e["code"] = "" return events def _in_viewport(driver, element): script = ( "for(var e=arguments[0],f=e.offsetTop,t=e.offsetLeft,o=e.offsetWidth,n=e.offsetHeight;\n" "e.offsetParent;)f+=(e=e.offsetParent).offsetTop,t+=e.offsetLeft;\n" "return f\n" "window.pageYOffset&&t+o>window.pageXOffset" ) return driver.execute_script(script, element) selenium-selenium-4.18.1/test/selenium/webdriver/common/executing_async_javascript_tests.py0000644000175000017500000002077614564764517032457 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import TimeoutException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement @pytest.fixture(autouse=True) def reset_timeouts(driver): driver.set_script_timeout(5) yield driver.set_script_timeout(30) def test_should_not_timeout_if_callback_invoked_immediately(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script("arguments[arguments.length - 1](123);") assert isinstance(result, int) assert 123 == result def test_should_be_able_to_return_javascript_primitives_from_async_scripts_neither_none_nor_undefined(driver, pages): pages.load("ajaxy_page.html") assert 123 == driver.execute_async_script("arguments[arguments.length - 1](123);") assert "abc" == driver.execute_async_script("arguments[arguments.length - 1]('abc');") assert not bool(driver.execute_async_script("arguments[arguments.length - 1](false);")) assert bool(driver.execute_async_script("arguments[arguments.length - 1](true);")) def test_should_be_able_to_return_javascript_primitives_from_async_scripts_null_and_undefined(driver, pages): pages.load("ajaxy_page.html") assert driver.execute_async_script("arguments[arguments.length - 1](null)") is None assert driver.execute_async_script("arguments[arguments.length - 1]()") is None def test_should_be_able_to_return_an_array_literal_from_an_async_script(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script("arguments[arguments.length - 1]([]);") assert "Expected not to be null!", result is not None assert isinstance(result, list) assert len(result) == 0 def test_should_be_able_to_return_an_array_object_from_an_async_script(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script("arguments[arguments.length - 1](new Array());") assert "Expected not to be null!", result is not None assert isinstance(result, list) assert len(result) == 0 def test_should_be_able_to_return_arrays_of_primitives_from_async_scripts(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script("arguments[arguments.length - 1]([null, 123, 'abc', true, false]);") assert result is not None assert isinstance(result, list) assert not bool(result.pop()) assert bool(result.pop()) assert "abc" == result.pop() assert 123 == result.pop() assert result.pop() is None assert len(result) == 0 def test_should_be_able_to_return_web_elements_from_async_scripts(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script("arguments[arguments.length - 1](document.body);") assert isinstance(result, WebElement) assert "body" == result.tag_name.lower() @pytest.mark.xfail_safari @pytest.mark.xfail_chrome(reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=4525") def test_should_be_able_to_return_arrays_of_web_elements_from_async_scripts(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script("arguments[arguments.length - 1]([document.body, document.body]);") assert result is not None assert isinstance(result, list) list_ = result assert 2 == len(list_) assert isinstance(list_[0], WebElement) assert isinstance(list_[1], WebElement) assert "body" == list_[0].tag_name # assert list_[0] == list_[1] def test_should_timeout_if_script_does_not_invoke_callback(driver, pages): pages.load("ajaxy_page.html") with pytest.raises(TimeoutException): # Script is expected to be async and explicitly callback, so this should timeout. driver.execute_async_script("return 1 + 2;") def test_should_timeout_if_script_does_not_invoke_callback_with_azero_timeout(driver, pages): pages.load("ajaxy_page.html") with pytest.raises(TimeoutException): driver.execute_async_script("window.setTimeout(function() {}, 0);") def test_should_not_timeout_if_script_callsback_inside_azero_timeout(driver, pages): pages.load("ajaxy_page.html") driver.execute_async_script( """var callback = arguments[arguments.length - 1]; window.setTimeout(function() { callback(123); }, 0)""" ) def test_should_timeout_if_script_does_not_invoke_callback_with_long_timeout(driver, pages): driver.set_script_timeout(0.5) pages.load("ajaxy_page.html") with pytest.raises(TimeoutException): driver.execute_async_script( """var callback = arguments[arguments.length - 1]; window.setTimeout(callback, 1500);""" ) def test_should_detect_page_loads_while_waiting_on_an_async_script_and_return_an_error(driver, pages): pages.load("ajaxy_page.html") driver.set_script_timeout(0.1) with pytest.raises(WebDriverException): url = pages.url("dynamic.html") driver.execute_async_script(f"window.location = '{url}';") def test_should_catch_errors_when_executing_initial_script(driver, pages): pages.load("ajaxy_page.html") with pytest.raises(WebDriverException): driver.execute_async_script("throw Error('you should catch this!');") def test_should_be_able_to_execute_asynchronous_scripts(driver, pages): pages.load("ajaxy_page.html") typer = driver.find_element(by=By.NAME, value="typer") typer.send_keys("bob") assert "bob" == typer.get_attribute("value") driver.find_element(by=By.ID, value="red").click() driver.find_element(by=By.NAME, value="submit").click() assert 1 == len( driver.find_elements(by=By.TAG_NAME, value="div") ), "There should only be 1 DIV at this point, which is used for the butter message" driver.set_script_timeout(10) text = driver.execute_async_script( """var callback = arguments[arguments.length - 1]; window.registerListener(arguments[arguments.length - 1]);""" ) assert "bob" == text assert "" == typer.get_attribute("value") assert 2 == len( driver.find_elements(by=By.TAG_NAME, value="div") ), "There should be 1 DIV (for the butter message) + 1 DIV (for the new label)" def test_should_be_able_to_pass_multiple_arguments_to_async_scripts(driver, pages): pages.load("ajaxy_page.html") result = driver.execute_async_script( """ arguments[arguments.length - 1](arguments[0] + arguments[1]);""", 1, 2, ) assert 3 == result # TODO DavidBurns Disabled till Java WebServer is used # def test_should_be_able_to_make_xmlhttp_requests_and_wait_for_the_response(driver, pages): # script = """ # var url = arguments[0]; # var callback = arguments[arguments.length - 1]; # // Adapted from http://www.quirksmode.org/js/xmlhttp.html # var XMLHttpFactories = [ # function () return new XMLHttpRequest(), # function () return new ActiveXObject('Msxml2.XMLHTTP'), # function () return new ActiveXObject('Msxml3.XMLHTTP'), # function () return new ActiveXObject('Microsoft.XMLHTTP') # ]; # var xhr = false; # while (!xhr && XMLHttpFactories.length) # try{ # xhr = XMLHttpFactories.shift().call(); # }catch (e) # # if (!xhr) throw Error('unable to create XHR object'); # xhr.open('GET', url, true); # xhr.onreadystatechange = function() # if (xhr.readyState == 4) callback(xhr.responseText); # # xhr.send('');""" # empty string to stop firefox 3 from choking # # pages.load("ajaxy_page.html") # driver.set_script_timeout(3) # response = driver.execute_async_script(script, pages.sleepingPage + "?time=2") # htm = "DoneSlept for 2s" # assert response.strip() == htm selenium-selenium-4.18.1/test/selenium/webdriver/common/window_switching_tests.py0000644000175000017500000001647614564764517030431 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchWindowException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.common.window import WindowTypes from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait @pytest.fixture(autouse=True) def close_windows(driver): main_windows_handle = driver.current_window_handle yield from urllib import request as url_request URLError = url_request.URLError try: window_handles = driver.window_handles except URLError: return for handle in window_handles: if handle != main_windows_handle: driver.switch_to.window(handle) driver.close() driver.switch_to.window(main_windows_handle) def test_should_switch_focus_to_anew_window_when_it_is_opened_and_not_stop_future_operations(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle driver.find_element(By.LINK_TEXT, "Open new window").click() assert driver.title == "XHTML Test Page" handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) assert driver.title == "We Arrive Here" pages.load("iframes.html") handle = driver.current_window_handle driver.find_element(By.ID, "iframe_page_heading") driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) assert driver.current_window_handle == handle def test_can_switch_to_window_by_name(driver, pages): pages.load("xhtmlTest.html") handles = driver.window_handles driver.find_element(By.LINK_TEXT, "Open new window").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) driver.switch_to.window("result") assert driver.title == "We Arrive Here" def test_should_throw_no_such_window_exception(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchWindowException): driver.switch_to.window("invalid name") @pytest.mark.xfail_safari def test_should_throw_no_such_window_exception_on_an_attempt_to_get_its_handle(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle handles = driver.window_handles driver.find_element(By.LINK_TEXT, "Open new window").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) driver.close() with pytest.raises(NoSuchWindowException): driver.current_window_handle @pytest.mark.xfail_ie def test_should_throw_no_such_window_exception_on_any_operation_if_awindow_is_closed(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle handles = driver.window_handles driver.find_element(By.LINK_TEXT, "Open new window").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) driver.close() with pytest.raises(NoSuchWindowException): driver.title with pytest.raises(NoSuchWindowException): driver.find_element(By.TAG_NAME, "body") @pytest.mark.xfail_ie @pytest.mark.xfail_safari def test_should_throw_no_such_window_exception_on_any_element_operation_if_awindow_is_closed(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle handles = driver.window_handles driver.find_element(By.LINK_TEXT, "Open new window").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) element = driver.find_element(By.TAG_NAME, "body") driver.close() with pytest.raises(NoSuchWindowException): element.text def test_clicking_on_abutton_that_closes_an_open_window_does_not_cause_the_browser_to_hang(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle handles = driver.window_handles driver.find_element(By.NAME, "windowThree").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) driver.find_element(By.ID, "close").click() driver.switch_to.window(current) driver.find_element(By.ID, "linkId") @pytest.mark.xfail_safari def test_can_call_get_window_handles_after_closing_awindow(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle handles = driver.window_handles driver.find_element(By.NAME, "windowThree").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) driver.find_element(By.ID, "close").click() WebDriverWait(driver, 3).until(EC.number_of_windows_to_be(1)) def test_can_obtain_awindow_handle(driver, pages): pages.load("xhtmlTest.html") currentHandle = driver.current_window_handle assert currentHandle is not None def test_failing_to_switch_to_awindow_leaves_the_current_window_as_is(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle with pytest.raises(NoSuchWindowException): driver.switch_to.window("I will never exist") new_handle = driver.current_window_handle assert current == new_handle @pytest.mark.xfail_safari def test_that_accessing_finding_an_element_after_window_is_closed_and_haventswitched_doesnt_crash(driver, pages): pages.load("xhtmlTest.html") current = driver.current_window_handle handles = driver.window_handles driver.find_element(By.NAME, "windowThree").click() WebDriverWait(driver, 3).until(EC.new_window_is_opened(handles)) handles = driver.window_handles handles.remove(current) driver.switch_to.window(handles[0]) with pytest.raises(WebDriverException): driver.find_element(By.ID, "close").click() all_handles = driver.window_handles assert 1 == len(all_handles) driver.find_element(By.ID, "close") driver.switch_to.window(current) @pytest.mark.xfail_ie def test_should_be_able_to_create_anew_window(driver, pages): original_handle = driver.current_window_handle driver.switch_to.new_window(WindowTypes.TAB) new_handle = driver.current_window_handle driver.close() driver.switch_to.window(original_handle) assert new_handle != original_handle selenium-selenium-4.18.1/test/selenium/webdriver/common/selenium_manager_tests.py0000644000175000017500000000664314564764517030351 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from unittest.mock import Mock import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.proxy import Proxy from selenium.webdriver.common.selenium_manager import SeleniumManager def test_browser_version_is_used_for_sm(mocker): import subprocess mock_run = mocker.patch("subprocess.run") mocked_result = Mock() mocked_result.configure_mock( **{ "stdout.decode.return_value": '{"result": {"driver_path": "driver", "browser_path": "browser"}, "logs": []}', "returncode": 0, } ) mock_run.return_value = mocked_result options = Options() options.capabilities["browserName"] = "chrome" options.browser_version = "110" _ = SeleniumManager().driver_location(options) args, kwargs = subprocess.run.call_args assert "--browser-version" in args[0] assert "110" in args[0] def test_browser_path_is_used_for_sm(mocker): import subprocess mock_run = mocker.patch("subprocess.run") mocked_result = Mock() mocked_result.configure_mock( **{ "stdout.decode.return_value": '{"result": {"driver_path": "driver", "browser_path": "browser"}, "logs": []}', "returncode": 0, } ) mock_run.return_value = mocked_result options = Options() options.capabilities["browserName"] = "chrome" options.binary_location = "/opt/bin/browser-bin" _ = SeleniumManager().driver_location(options) args, kwargs = subprocess.run.call_args assert "--browser-path" in args[0] assert "/opt/bin/browser-bin" in args[0] def test_proxy_is_used_for_sm(mocker): import subprocess mock_run = mocker.patch("subprocess.run") mocked_result = Mock() mocked_result.configure_mock( **{ "stdout.decode.return_value": '{"result": {"driver_path": "driver", "browser_path": "browser"}, "logs": []}', "returncode": 0, } ) mock_run.return_value = mocked_result options = Options() options.capabilities["browserName"] = "chrome" proxy = Proxy() proxy.http_proxy = "http-proxy" options.proxy = proxy _ = SeleniumManager().driver_location(options) args, kwargs = subprocess.run.call_args assert "--proxy" in args[0] assert "http-proxy" in args[0] def test_stderr_is_propagated_to_exception_messages(): msg = r"Unsuccessful command executed:.*\n.* 'Invalid browser name: foo'.*" with pytest.raises(WebDriverException, match=msg): manager = SeleniumManager() binary = manager.get_binary() _ = manager.run([str(binary), "--browser", "foo"]) selenium-selenium-4.18.1/test/selenium/webdriver/common/page_load_timeout_tests.py0000644000175000017500000000265214564764517030513 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By @pytest.fixture(autouse=True) def reset_timeouts(driver): yield driver.set_page_load_timeout(300) def test_should_timeout_on_page_load_taking_too_long(driver, pages): driver.set_page_load_timeout(0.01) with pytest.raises(TimeoutException): pages.load("simpleTest.html") @pytest.mark.xfail_safari def test_click_should_timeout(driver, pages): pages.load("simpleTest.html") driver.set_page_load_timeout(0.01) with pytest.raises(TimeoutException): driver.find_element(By.ID, "multilinelink").click() selenium-selenium-4.18.1/test/selenium/webdriver/common/script_pinning_tests.py0000644000175000017500000000512314564764517030054 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import re import pytest from selenium.common.exceptions import JavascriptException from selenium.webdriver.remote.script_key import ScriptKey def test_should_allow_script_pinning(driver, pages): pages.load("simpleTest.html") driver.pinned_scripts = {} script_key = driver.pin_script("return 'i like cheese';") result = driver.execute_script(script_key) assert result == "i like cheese" def test_should_allow_pinned_scripts_to_take_arguments(driver, pages): pages.load("simpleTest.html") driver.pinned_scripts = {} hello = driver.pin_script("return arguments[0]") result = driver.execute_script(hello, "cheese") assert result == "cheese" def test_should_list_all_pinned_scripts(driver, pages): pages.load("simpleTest.html") driver.pinned_scripts = {} expected = [] expected.append(driver.pin_script("return arguments[0];").id) expected.append(driver.pin_script("return 'cheese';").id) expected.append(driver.pin_script("return 42;").id) result = driver.get_pinned_scripts() assert expected == result def test_should_allow_scripts_to_be_unpinned(driver, pages): pages.load("simpleTest.html") driver.pinned_scripts = {} cheese = driver.pin_script("return 'cheese';") driver.unpin(cheese) results = driver.get_pinned_scripts() assert cheese not in results def test_calling_unpinned_script_causes_error(driver, pages): pages.load("simpleTest.html") cheese = driver.pin_script("return 'brie';") driver.unpin(cheese) with pytest.raises(JavascriptException): driver.execute_script(cheese) def test_unpinning_non_existing_script_raises(driver, pages): pages.load("simpleTest.html") with pytest.raises(KeyError, match=re.escape(r"No script with key: ScriptKey(id=1) existed in {}")): driver.unpin(ScriptKey(1)) selenium-selenium-4.18.1/test/selenium/webdriver/common/__init__.py0000644000175000017500000000142314564764517025342 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/selenium/webdriver/common/conftest.py0000644000175000017500000000173514564764517025436 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. def pytest_generate_tests(metafunc): if "driver" in metafunc.fixturenames and metafunc.config.option.drivers: metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True) selenium-selenium-4.18.1/test/selenium/webdriver/common/takes_screenshots_tests.py0000644000175000017500000000300114564764517030546 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import base64 import imghdr import pytest from selenium.webdriver.common.by import By def test_get_screenshot_as_base64(driver, pages): pages.load("simpleTest.html") result = base64.b64decode(driver.get_screenshot_as_base64()) assert imghdr.what("", result) == "png" def test_get_screenshot_as_png(driver, pages): pages.load("simpleTest.html") result = driver.get_screenshot_as_png() assert imghdr.what("", result) == "png" @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_get_element_screenshot(driver, pages): pages.load("simpleTest.html") element = driver.find_element(By.ID, "multiline") result = base64.b64decode(element.screenshot_as_base64) assert imghdr.what("", result) == "png" selenium-selenium-4.18.1/test/selenium/webdriver/common/proxy_tests.py0000644000175000017500000001112414564764517026205 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.options import ArgOptions from selenium.webdriver.common.proxy import Proxy from selenium.webdriver.common.proxy import ProxyType MANUAL_PROXY = { "httpProxy": "some.url:1234", "ftpProxy": "ftp.proxy", "noProxy": "localhost, foo.localhost", "sslProxy": "ssl.proxy:1234", "socksProxy": "socks.proxy:65555", "socksUsername": "test", "socksPassword": "test", "socksVersion": 5, } PAC_PROXY = { "proxyAutoconfigUrl": "http://pac.url:1234", } AUTODETECT_PROXY = { "autodetect": True, } def test_can_add_manual_proxy_to_options(): proxy = Proxy() proxy.http_proxy = MANUAL_PROXY["httpProxy"] proxy.ftp_proxy = MANUAL_PROXY["ftpProxy"] proxy.no_proxy = MANUAL_PROXY["noProxy"] proxy.sslProxy = MANUAL_PROXY["sslProxy"] proxy.socksProxy = MANUAL_PROXY["socksProxy"] proxy.socksUsername = MANUAL_PROXY["socksUsername"] proxy.socksPassword = MANUAL_PROXY["socksPassword"] proxy.socksVersion = MANUAL_PROXY["socksVersion"] options = ArgOptions() options.proxy = proxy proxy_capabilities = MANUAL_PROXY.copy() proxy_capabilities["proxyType"] = "manual" assert proxy_capabilities == options.to_capabilities().get("proxy") def test_can_add_autodetect_proxy_to_options(): proxy = Proxy() proxy.auto_detect = AUTODETECT_PROXY["autodetect"] options = ArgOptions() options.proxy = proxy proxy_capabilities = AUTODETECT_PROXY.copy() proxy_capabilities["proxyType"] = "autodetect" assert proxy_capabilities == options.to_capabilities().get("proxy") def test_can_add_pacproxy_to_options(): proxy = Proxy() proxy.proxy_autoconfig_url = PAC_PROXY["proxyAutoconfigUrl"] options = ArgOptions() options.proxy = proxy proxy_capabilities = PAC_PROXY.copy() proxy_capabilities["proxyType"] = "pac" assert proxy_capabilities == options.to_capabilities().get("proxy") def test_can_not_change_initialized_proxy_type(): proxy = Proxy(raw={"proxyType": "direct"}) with pytest.raises(Exception): proxy.proxy_type = ProxyType.SYSTEM proxy = Proxy(raw={"proxyType": ProxyType.DIRECT}) with pytest.raises(Exception): proxy.proxy_type = ProxyType.SYSTEM def test_can_init_manual_proxy(): proxy = Proxy(raw=MANUAL_PROXY) assert ProxyType.MANUAL == proxy.proxy_type assert MANUAL_PROXY["httpProxy"] == proxy.http_proxy assert MANUAL_PROXY["ftpProxy"] == proxy.ftp_proxy assert MANUAL_PROXY["noProxy"] == proxy.no_proxy assert MANUAL_PROXY["sslProxy"] == proxy.sslProxy assert MANUAL_PROXY["socksProxy"] == proxy.socksProxy assert MANUAL_PROXY["socksUsername"] == proxy.socksUsername assert MANUAL_PROXY["socksPassword"] == proxy.socksPassword assert MANUAL_PROXY["socksVersion"] == proxy.socksVersion def test_can_init_autodetect_proxy(): proxy = Proxy(raw=AUTODETECT_PROXY) assert ProxyType.AUTODETECT == proxy.proxy_type assert AUTODETECT_PROXY["autodetect"] == proxy.auto_detect def test_can_init_pacproxy(): proxy = Proxy(raw=PAC_PROXY) assert ProxyType.PAC == proxy.proxy_type assert PAC_PROXY["proxyAutoconfigUrl"] == proxy.proxy_autoconfig_url def test_can_init_empty_proxy(): proxy = Proxy() assert ProxyType.UNSPECIFIED == proxy.proxy_type assert "" == proxy.http_proxy assert "" == proxy.ftp_proxy assert "" == proxy.no_proxy assert "" == proxy.sslProxy assert "" == proxy.socksProxy assert "" == proxy.socksUsername assert "" == proxy.socksPassword assert proxy.auto_detect is False assert "" == proxy.proxy_autoconfig_url assert proxy.socks_version is None options = ArgOptions() options.proxy = proxy proxy_capabilities = {} proxy_capabilities["proxyType"] = "unspecified" assert proxy_capabilities == options.to_capabilities().get("proxy") selenium-selenium-4.18.1/test/selenium/webdriver/common/click_tests.py0000644000175000017500000000264114564764517026115 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait @pytest.fixture(autouse=True) def loadPage(pages): pages.load("clicks.html") def test_can_click_on_alink_that_overflows_and_follow_it(driver): driver.find_element(By.ID, "overflowLink").click() WebDriverWait(driver, 3).until(EC.title_is("XHTML Test Page")) def test_clicking_alink_made_up_of_numbers_is_handled_correctly(driver): driver.find_element(By.LINK_TEXT, "333333").click() WebDriverWait(driver, 3).until(EC.title_is("XHTML Test Page")) selenium-selenium-4.18.1/test/selenium/webdriver/common/implicit_waits_tests.py0000644000175000017500000000514414564764517030052 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By def test_should_implicitly_wait_for_asingle_element(driver, pages): pages.load("dynamic.html") add = driver.find_element(By.ID, "adder") driver.implicitly_wait(3) add.click() driver.find_element(By.ID, "box0") # All is well if this doesn't throw. def test_should_still_fail_to_find_an_element_when_implicit_waits_are_enabled(driver, pages): pages.load("dynamic.html") driver.implicitly_wait(0.5) with pytest.raises(NoSuchElementException): driver.find_element(By.ID, "box0") def test_should_return_after_first_attempt_to_find_one_after_disabling_implicit_waits(driver, pages): pages.load("dynamic.html") driver.implicitly_wait(3) driver.implicitly_wait(0) with pytest.raises(NoSuchElementException): driver.find_element(By.ID, "box0") def test_should_implicitly_wait_until_at_least_one_element_is_found_when_searching_for_many(driver, pages): pages.load("dynamic.html") add = driver.find_element(By.ID, "adder") driver.implicitly_wait(2) add.click() add.click() elements = driver.find_elements(By.CLASS_NAME, "redbox") assert len(elements) >= 1 def test_should_still_fail_to_find_an_elemenst_when_implicit_waits_are_enabled(driver, pages): pages.load("dynamic.html") driver.implicitly_wait(0.5) elements = driver.find_elements(By.CLASS_NAME, "redbox") assert 0 == len(elements) def test_should_return_after_first_attempt_to_find_many_after_disabling_implicit_waits(driver, pages): pages.load("dynamic.html") add = driver.find_element(By.ID, "adder") driver.implicitly_wait(1.1) driver.implicitly_wait(0) add.click() elements = driver.find_elements(By.CLASS_NAME, "redbox") assert 0 == len(elements) selenium-selenium-4.18.1/test/selenium/webdriver/common/api_example_tests.py0000644000175000017500000002256614564764517027324 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait def test_get_title(driver, pages): pages.load("simpleTest.html") title = driver.title assert "Hello WebDriver" == title def test_get_current_url(driver, pages, webserver): pages.load("simpleTest.html") url = driver.current_url assert webserver.where_is("simpleTest.html") == url def test_find_element_by_xpath(driver, pages): pages.load("simpleTest.html") elem = driver.find_element(By.XPATH, "//h1") assert "Heading" == elem.text def test_find_element_by_xpath_throw_no_such_element_exception(driver, pages): pages.load("simpleTest.html") with pytest.raises(NoSuchElementException): driver.find_element(By.XPATH, "//h4") def test_find_elements_by_xpath(driver, pages): pages.load("nestedElements.html") elems = driver.find_elements(By.XPATH, "//option") assert 48 == len(elems) assert "One" == elems[0].get_attribute("value") def test_find_elements_by_name(driver, pages): pages.load("xhtmlTest.html") elem = driver.find_element(By.NAME, "windowOne") assert "Open new window" == elem.text def test_find_elements_by_name_in_element_context(driver, pages): pages.load("nestedElements.html") elem = driver.find_element(By.NAME, "form2") sub_elem = elem.find_element(By.NAME, "selectomatic") assert "2" == sub_elem.get_attribute("id") def test_find_elements_by_link_text_in_element_context(driver, pages): pages.load("nestedElements.html") elem = driver.find_element(By.NAME, "div1") sub_elem = elem.find_element(By.LINK_TEXT, "hello world") assert "link1" == sub_elem.get_attribute("name") def test_find_element_by_id_in_element_context(driver, pages): pages.load("nestedElements.html") elem = driver.find_element(By.NAME, "form2") sub_elem = elem.find_element(By.ID, "2") assert "selectomatic" == sub_elem.get_attribute("name") def test_find_element_by_xpath_in_element_context(driver, pages): pages.load("nestedElements.html") elem = driver.find_element(By.NAME, "form2") sub_elem = elem.find_element(By.XPATH, "select") assert "2" == sub_elem.get_attribute("id") def test_find_element_by_xpath_in_element_context_not_found(driver, pages): pages.load("nestedElements.html") elem = driver.find_element(By.NAME, "form2") with pytest.raises(NoSuchElementException): elem.find_element(By.XPATH, "div") def test_should_be_able_to_enter_data_into_form_fields(driver, pages): pages.load("xhtmlTest.html") elem = driver.find_element(By.XPATH, "//form[@name='someForm']/input[@id='username']") elem.clear() elem.send_keys("some text") elem = driver.find_element(By.XPATH, "//form[@name='someForm']/input[@id='username']") assert "some text" == elem.get_attribute("value") def test_find_element_by_tag_name(driver, pages): pages.load("simpleTest.html") elems = driver.find_elements(By.TAG_NAME, "div") num_by_xpath = len(driver.find_elements(By.XPATH, "//div")) assert num_by_xpath == len(elems) elems = driver.find_elements(By.TAG_NAME, "iframe") assert 0 == len(elems) def test_find_element_by_tag_name_within_element(driver, pages): pages.load("simpleTest.html") div = driver.find_element(By.ID, "multiline") elems = div.find_elements(By.TAG_NAME, "p") assert len(elems) == 1 def test_switch_frame_by_name(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.NAME, "third")) checkbox = driver.find_element(By.ID, "checky") checkbox.click() checkbox.submit() def test_is_enabled(driver, pages): pages.load("formPage.html") elem = driver.find_element(By.XPATH, "//input[@id='working']") assert elem.is_enabled() elem = driver.find_element(By.XPATH, "//input[@id='notWorking']") assert not elem.is_enabled() def test_is_selected_and_toggle(driver, pages): pages.load("formPage.html") elem = driver.find_element(By.ID, "multi") option_elems = elem.find_elements(By.XPATH, "option") assert option_elems[0].is_selected() option_elems[0].click() assert not option_elems[0].is_selected() option_elems[0].click() assert option_elems[0].is_selected() assert option_elems[2].is_selected() def test_navigate(driver, pages): pages.load("formPage.html") driver.find_element(By.ID, "imageButton").submit() WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) driver.back() assert "We Leave From Here" == driver.title driver.forward() assert "We Arrive Here" == driver.title def test_get_attribute(driver, pages): url = pages.url("xhtmlTest.html") driver.get(url) elem = driver.find_element(By.ID, "id1") attr = elem.get_attribute("href") assert f"{url}#" == attr def test_get_implicit_attribute(driver, pages): pages.load("nestedElements.html") elems = driver.find_elements(By.XPATH, "//option") assert len(elems) >= 3 for i, elem in enumerate(elems[:3]): assert i == int(elem.get_attribute("index")) def test_get_dom_attribute(driver, pages): url = pages.url("formPage.html") driver.get(url) elem = driver.find_element(By.ID, "vsearchGadget") attr = elem.get_dom_attribute("accesskey") assert "4" == attr def test_get_property(driver, pages): url = pages.url("formPage.html") driver.get(url) elem = driver.find_element(By.ID, "withText") prop = elem.get_property("value") assert "Example text" == prop def test_execute_simple_script(driver, pages): pages.load("xhtmlTest.html") title = driver.execute_script("return document.title;") assert "XHTML Test Page" == title def test_execute_script_and_return_element(driver, pages): pages.load("xhtmlTest.html") elem = driver.execute_script("return document.getElementById('id1');") assert "WebElement" in str(type(elem)) def test_execute_script_with_args(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return arguments[0] == 'fish' ? 'fish' : 'not fish';", "fish") assert "fish" == result def test_execute_script_with_multiple_args(driver, pages): pages.load("xhtmlTest.html") result = driver.execute_script("return arguments[0] + arguments[1]", 1, 2) assert 3 == result def test_execute_script_with_element_args(driver, pages): pages.load("javascriptPage.html") button = driver.find_element(By.ID, "plainButton") result = driver.execute_script( "arguments[0]['flibble'] = arguments[0].getAttribute('id'); return arguments[0]['flibble'];", button ) assert "plainButton" == result def test_find_elements_by_partial_link_text(driver, pages): pages.load("xhtmlTest.html") elem = driver.find_element(By.PARTIAL_LINK_TEXT, "new window") elem.click() def test_is_element_displayed(driver, pages): pages.load("javascriptPage.html") visible = driver.find_element(By.ID, "displayed").is_displayed() not_visible = driver.find_element(By.ID, "hidden").is_displayed() assert visible assert not not_visible @pytest.mark.xfail_chrome def test_move_window_position(driver, pages): pages.load("blank.html") loc = driver.get_window_position() # note can't test 0,0 since some OS's dont allow that location # because of system toolbars new_x = 50 new_y = 50 if loc["x"] == new_x: new_x += 10 if loc["y"] == new_y: new_y += 10 driver.set_window_position(new_x, new_y) loc = driver.get_window_position() assert loc["x"] == new_x assert loc["y"] == new_y def test_change_window_size(driver, pages): pages.load("blank.html") size = driver.get_window_size() newSize = [600, 600] if size["width"] == 600: newSize[0] = 500 if size["height"] == 600: newSize[1] = 500 driver.set_window_size(newSize[0], newSize[1]) size = driver.get_window_size() assert size["width"] == newSize[0] assert size["height"] == newSize[1] @pytest.mark.xfail_firefox(raises=WebDriverException) @pytest.mark.xfail_remote @pytest.mark.xfail_safari def test_get_log_types(driver, pages): pages.load("blank.html") assert isinstance(driver.log_types, list) @pytest.mark.xfail_firefox(raises=WebDriverException) @pytest.mark.xfail_remote @pytest.mark.xfail_safari def test_get_log(driver, pages): pages.load("blank.html") for log_type in driver.log_types: log = driver.get_log(log_type) assert isinstance(log, list) selenium-selenium-4.18.1/test/selenium/webdriver/common/clear_tests.py0000644000175000017500000000504014564764517026112 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import InvalidElementStateException from selenium.webdriver.common.by import By def test_writable_text_input_should_clear(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "writableTextInput") element.clear() assert "" == element.get_attribute("value") def test_text_input_should_not_clear_when_disabled(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "textInputNotEnabled") assert not element.is_enabled() with pytest.raises(InvalidElementStateException): element.clear() def test_text_input_should_not_clear_when_read_only(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "readOnlyTextInput") with pytest.raises(InvalidElementStateException): element.clear() def test_writable_text_area_should_clear(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "writableTextArea") element.clear() assert "" == element.get_attribute("value") def test_text_area_should_not_clear_when_disabled(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "textAreaNotEnabled") with pytest.raises(InvalidElementStateException): element.clear() def test_text_area_should_not_clear_when_read_only(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "textAreaReadOnly") with pytest.raises(InvalidElementStateException): element.clear() def test_content_editable_area_should_clear(driver, pages): pages.load("readOnlyPage.html") element = driver.find_element(By.ID, "content-editable") element.clear() assert "" == element.text selenium-selenium-4.18.1/test/selenium/webdriver/common/driver_element_finding_tests.py0000644000175000017500000006201314564764517031531 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import InvalidSelectorException from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By # By.id positive def test_should_be_able_to_find_asingle_element_by_id(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.ID, "linkId") assert element.get_attribute("id") == "linkId" def test_should_be_able_to_find_asingle_element_by_numeric_id(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.ID, "2") assert element.get_attribute("id") == "2" def test_should_be_able_to_find_an_element_with_css_escape(driver, pages): pages.load("idElements.html") element = driver.find_element(By.ID, "with.dots") assert element.get_attribute("id") == "with.dots" def test_should_be_able_to_find_multiple_elements_by_id(driver, pages): pages.load("nestedElements.html") elements = driver.find_elements(By.ID, "test_id") assert len(elements) == 2 def test_should_be_able_to_find_multiple_elements_by_numeric_id(driver, pages): pages.load("nestedElements.html") elements = driver.find_elements(By.ID, "2") assert len(elements) == 8 # By.id negative def test_should_not_be_able_to_locate_by_id_asingle_element_that_does_not_exist(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.ID, "non_Existent_Button") def test_should_not_be_able_to_locate_by_id_multiple_elements_that_do_not_exist(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.ID, "non_Existent_Button") assert len(elements) == 0 def test_finding_asingle_element_by_empty_id_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.ID, "") def test_finding_multiple_elements_by_empty_id_should_return_empty_list(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.ID, "") assert len(elements) == 0 def test_finding_asingle_element_by_id_with_space_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.ID, "nonexistent button") def test_finding_multiple_elements_by_id_with_space_should_return_empty_list(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.ID, "nonexistent button") assert len(elements) == 0 def test_no_such_element_error(driver, pages): pages.load("formPage.html") msg = r"\/errors#no-such-element-exception" with pytest.raises(NoSuchElementException, match=msg): driver.find_element(By.ID, "non_Existent_Button") # By.name positive def test_should_be_able_to_find_asingle_element_by_name(driver, pages): pages.load("formPage.html") element = driver.find_element(By.NAME, "checky") assert element.get_attribute("value") == "furrfu" def test_should_be_able_to_find_multiple_elements_by_name(driver, pages): pages.load("nestedElements.html") elements = driver.find_elements(By.NAME, "checky") assert len(elements) > 1 def test_should_be_able_to_find_an_element_that_does_not_support_the_name_property(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "div1") assert element.get_attribute("name") == "div1" # By.name negative def test_should_not_be_able_to_locate_by_name_asingle_element_that_does_not_exist(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.NAME, "non_Existent_Button") def test_should_not_be_able_to_locate_by_name_multiple_elements_that_do_not_exist(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.NAME, "non_Existent_Button") assert len(elements) == 0 def test_finding_asingle_element_by_empty_name_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.NAME, "") def test_finding_multiple_elements_by_empty_name_should_return_empty_list(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.NAME, "") assert len(elements) == 0 def test_finding_asingle_element_by_name_with_space_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.NAME, "nonexistent button") def test_finding_multiple_elements_by_name_with_space_should_return_empty_list(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.NAME, "nonexistent button") assert len(elements) == 0 # By.tag_Name positive def test_should_be_able_to_find_asingle_element_by_tag_name(driver, pages): pages.load("formPage.html") element = driver.find_element(By.TAG_NAME, "input") assert element.tag_name.lower() == "input" def test_should_be_able_to_find_multiple_elements_by_tag_name(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.TAG_NAME, "input") assert len(elements) > 1 # By.tag_Name negative def test_should_not_be_able_to_locate_by_tag_name_asingle_element_that_does_not_exist(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.TAG_NAME, "non_Existent_Button") def test_should_not_be_able_to_locate_by_tag_name_multiple_elements_that_do_not_exist(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.TAG_NAME, "non_Existent_Button") assert len(elements) == 0 @pytest.mark.xfail_firefox(reason="https://github.com/mozilla/geckodriver/issues/2007") @pytest.mark.xfail_remote(reason="https://github.com/mozilla/geckodriver/issues/2007") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises NoSuchElementException") def test_finding_asingle_element_by_empty_tag_name_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(InvalidSelectorException): driver.find_element(By.TAG_NAME, "") @pytest.mark.xfail_firefox(reason="https://github.com/mozilla/geckodriver/issues/2007") @pytest.mark.xfail_remote(reason="https://github.com/mozilla/geckodriver/issues/2007") @pytest.mark.xfail_safari(reason="unlike chrome, safari returns an empty list") def test_finding_multiple_elements_by_empty_tag_name_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.TAG_NAME, "") def test_finding_asingle_element_by_tag_name_with_space_should_throw(driver, pages): pages.load("formPage.html") with pytest.raises(NoSuchElementException): driver.find_element(By.TAG_NAME, "nonexistent button") def test_finding_multiple_elements_by_tag_name_with_space_should_return_empty_list(driver, pages): pages.load("formPage.html") elements = driver.find_elements(By.TAG_NAME, "nonexistent button") assert len(elements) == 0 # By.class_Name positive def test_should_be_able_to_find_asingle_element_by_class(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CLASS_NAME, "extraDiv") assert "Another div starts here." in element.text def test_should_be_able_to_find_multiple_elements_by_class_name(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.CLASS_NAME, "nameC") assert len(elements) > 1 def test_should_find_element_by_class_when_it_is_the_first_name_among_many(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CLASS_NAME, "nameA") assert element.text == "An H2 title" def test_should_find_element_by_class_when_it_is_the_last_name_among_many(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CLASS_NAME, "nameC") assert element.text == "An H2 title" def test_should_find_element_by_class_when_it_is_in_the_middle_among_many(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CLASS_NAME, "nameBnoise") assert element.text == "An H2 title" def test_should_find_element_by_class_when_its_name_is_surrounded_by_whitespace(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CLASS_NAME, "spaceAround") assert element.text == "Spaced out" def test_should_find_elements_by_class_when_its_name_is_surrounded_by_whitespace(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.CLASS_NAME, "spaceAround") assert len(elements) == 1 assert elements[0].text == "Spaced out" # By.class_Name negative def test_should_not_find_element_by_class_when_the_name_queried_is_shorter_than_candidate_name(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchElementException): driver.find_element(By.CLASS_NAME, "name_B") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_finding_asingle_element_by_empty_class_name_should_throw(driver, pages): pages.load("xhtmlTest.html") msg = r"\/errors#invalid-selector-exception" with pytest.raises(InvalidSelectorException, match=msg): driver.find_element(By.CLASS_NAME, "") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_finding_multiple_elements_by_empty_class_name_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.CLASS_NAME, "") def test_finding_asingle_element_by_compound_class_name_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchElementException): driver.find_element(By.CLASS_NAME, "a b") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_finding_asingle_element_by_invalid_class_name_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_element(By.CLASS_NAME, "!@#$%^&*") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_finding_multiple_elements_by_invalid_class_name_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.CLASS_NAME, "!@#$%^&*") # By.xpath positive def test_should_be_able_to_find_asingle_element_by_xpath(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.XPATH, "//h1") assert element.text == "XHTML Might Be The Future" def test_should_be_able_to_find_multiple_elements_by_xpath(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.XPATH, "//div") assert len(elements) == 13 def test_should_be_able_to_find_many_elements_repeatedly_by_xpath(driver, pages): pages.load("xhtmlTest.html") xpath = "//node()[contains(@id,'id')]" assert len(driver.find_elements(By.XPATH, xpath)) == 3 xpath = "//node()[contains(@id,'nope')]" assert len(driver.find_elements(By.XPATH, xpath)) == 0 def test_should_be_able_to_identify_elements_by_class(driver, pages): pages.load("xhtmlTest.html") header = driver.find_element(By.XPATH, "//h1[@class='header']") assert header.text == "XHTML Might Be The Future" def test_should_be_able_to_find_an_element_by_xpath_with_multiple_attributes(driver, pages): pages.load("formPage.html") element = driver.find_element(By.XPATH, "//form[@name='optional']/input[@type='submit' and @value='Click!']") assert element.tag_name.lower() == "input" assert element.get_attribute("value") == "Click!" def test_finding_alink_by_xpath_should_locate_an_element_with_the_given_text(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.XPATH, "//a[text()='click me']") assert element.text == "click me" def test_finding_alink_by_xpath_using_contains_keyword_should_work(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.XPATH, "//a[contains(.,'hello world')]") assert "hello world" in element.text # @pytest.mark.xfail_chrome(raises=InvalidSelectorException) # @pytest.mark.xfail_chromiumedge(raises=InvalidSelectorException) # @pytest.mark.xfail_firefox(raises=InvalidSelectorException) # @pytest.mark.xfail_remote(raises=InvalidSelectorException) # @pytest.mark.xfail_safari(raises=NoSuchElementException) # @pytest.mark.xfail_webkitgtk(raises=InvalidSelectorException) # def test_Should_Be_Able_To_Find_Element_By_XPath_With_Namespace(driver, pages): # pages.load("svgPage.html") # element = driver.find_element(By.XPATH, "//svg:svg//svg:text") # assert element.text == "Test Chart" def test_should_be_able_to_find_element_by_xpath_in_xml_document(driver, pages): pages.load("simple.xml") element = driver.find_element(By.XPATH, "//foo") assert "baz" in element.text # By.xpath negative def test_should_throw_an_exception_when_there_is_no_link_to_click(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchElementException): driver.find_element(By.XPATH, "//a[@id='Not here']") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_should_throw_invalid_selector_exception_when_xpath_is_syntactically_invalid_in_driver_find_element( driver, pages ): pages.load("formPage.html") with pytest.raises(InvalidSelectorException): driver.find_element(By.XPATH, "this][isnot][valid") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_should_throw_invalid_selector_exception_when_xpath_is_syntactically_invalid_in_driver_find_elements( driver, pages ): pages.load("formPage.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.XPATH, "this][isnot][valid") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_should_throw_invalid_selector_exception_when_xpath_is_syntactically_invalid_in_element_find_element( driver, pages ): pages.load("formPage.html") body = driver.find_element(By.TAG_NAME, "body") with pytest.raises(InvalidSelectorException): body.find_element(By.XPATH, "this][isnot][valid") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_should_throw_invalid_selector_exception_when_xpath_is_syntactically_invalid_in_element_find_elements( driver, pages ): pages.load("formPage.html") body = driver.find_element(By.TAG_NAME, "body") with pytest.raises(InvalidSelectorException): body.find_elements(By.XPATH, "this][isnot][valid") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_should_throw_invalid_selector_exception_when_xpath_returns_wrong_type_in_driver_find_element(driver, pages): pages.load("formPage.html") with pytest.raises(InvalidSelectorException): driver.find_element(By.XPATH, "count(//input)") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_should_throw_invalid_selector_exception_when_xpath_returns_wrong_type_in_driver_find_elements(driver, pages): pages.load("formPage.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.XPATH, "count(//input)") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_should_throw_invalid_selector_exception_when_xpath_returns_wrong_type_in_element_find_element(driver, pages): pages.load("formPage.html") body = driver.find_element(By.TAG_NAME, "body") with pytest.raises(InvalidSelectorException): body.find_element(By.XPATH, "count(//input)") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_should_throw_invalid_selector_exception_when_xpath_returns_wrong_type_in_element_find_elements(driver, pages): pages.load("formPage.html") body = driver.find_element(By.TAG_NAME, "body") with pytest.raises(InvalidSelectorException): body.find_elements(By.XPATH, "count(//input)") # By.css_Selector positive def test_should_be_able_to_find_asingle_element_by_css_selector(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CSS_SELECTOR, "div.content") assert element.tag_name.lower() == "div" assert element.get_attribute("class") == "content" def test_should_be_able_to_find_multiple_elements_by_css_selector(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.CSS_SELECTOR, "p") assert len(elements) > 1 def test_should_be_able_to_find_asingle_element_by_compound_css_selector(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.CSS_SELECTOR, "div.extraDiv, div.content") assert element.tag_name.lower() == "div" assert element.get_attribute("class") == "content" def test_should_be_able_to_find_multiple_elements_by_compound_css_selector(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.CSS_SELECTOR, "div.extraDiv, div.content") assert len(elements) > 1 assert elements[0].get_attribute("class") == "content" assert elements[1].get_attribute("class") == "extraDiv" def test_should_be_able_to_find_an_element_by_boolean_attribute_using_css_selector(driver, pages): pages.load("locators_tests/boolean_attribute_selected.html") element = driver.find_element(By.CSS_SELECTOR, "option[selected='selected']") assert element.get_attribute("value") == "two" def test_should_be_able_to_find_an_element_by_boolean_attribute_using_short_css_selector(driver, pages): pages.load("locators_tests/boolean_attribute_selected.html") element = driver.find_element(By.CSS_SELECTOR, "option[selected]") assert element.get_attribute("value") == "two" def test_should_be_able_to_find_an_element_by_boolean_attribute_using_short_css_selector_on_html_4_page(driver, pages): pages.load("locators_tests/boolean_attribute_selected_html4.html") element = driver.find_element(By.CSS_SELECTOR, "option[selected]") assert element.get_attribute("value") == "two" # By.css_Selector negative def test_should_not_find_element_by_css_selector_when_there_is_no_such_element(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchElementException): driver.find_element(By.CSS_SELECTOR, ".there-is-no-such-class") def test_should_not_find_elements_by_css_selector_when_there_is_no_such_element(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.CSS_SELECTOR, ".there-is-no-such-class") assert len(elements) == 0 @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_finding_asingle_element_by_empty_css_selector_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_element(By.CSS_SELECTOR, "") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_finding_multiple_elements_by_empty_css_selector_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.CSS_SELECTOR, "") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_finding_asingle_element_by_invalid_css_selector_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_element(By.CSS_SELECTOR, "//a/b/c[@id='1']") @pytest.mark.xfail_safari(reason="unlike chrome, safari raises TimeoutException") def test_finding_multiple_elements_by_invalid_css_selector_should_throw(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(InvalidSelectorException): driver.find_elements(By.CSS_SELECTOR, "//a/b/c[@id='1']") # By.link_Text positive def test_should_be_able_to_find_alink_by_text(driver, pages): pages.load("xhtmlTest.html") link = driver.find_element(By.LINK_TEXT, "click me") assert link.text == "click me" def test_should_be_able_to_find_multiple_links_by_text(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.LINK_TEXT, "click me") assert len(elements) == 2 def test_should_find_element_by_link_text_containing_equals_sign(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.LINK_TEXT, "Link=equalssign") assert element.get_attribute("id") == "linkWithEqualsSign" def test_should_find_multiple_elements_by_link_text_containing_equals_sign(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.LINK_TEXT, "Link=equalssign") assert 1 == len(elements) assert elements[0].get_attribute("id") == "linkWithEqualsSign" def test_finds_by_link_text_on_xhtml_page(driver, pages): pages.load("actualXhtmlPage.xhtml") link_Text = "Foo" element = driver.find_element(By.LINK_TEXT, link_Text) assert element.text == link_Text def test_link_with_formatting_tags(driver, pages): pages.load("simpleTest.html") elem = driver.find_element(By.ID, "links") res = elem.find_element(By.PARTIAL_LINK_TEXT, "link with formatting tags") assert res.text == "link with formatting tags" @pytest.mark.xfail_safari def test_driver_can_get_link_by_link_test_ignoring_trailing_whitespace(driver, pages): pages.load("simpleTest.html") link = driver.find_element(By.LINK_TEXT, "link with trailing space") assert link.get_attribute("id") == "linkWithTrailingSpace" assert link.text == "link with trailing space" # By.link_Text negative def test_should_not_be_able_to_locate_by_link_text_asingle_element_that_does_not_exist(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchElementException): driver.find_element(By.LINK_TEXT, "Not here either") def test_should_not_be_able_to_locate_by_link_text_multiple_elements_that_do_not_exist(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.LINK_TEXT, "Not here either") assert len(elements) == 0 # By.partial_Link_Text positive def test_should_be_able_to_find_multiple_elements_by_partial_link_text(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.PARTIAL_LINK_TEXT, "ick me") assert len(elements) == 2 def test_should_be_able_to_find_asingle_element_by_partial_link_text(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.PARTIAL_LINK_TEXT, "anon") assert "anon" in element.text def test_should_find_element_by_partial_link_text_containing_equals_sign(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.PARTIAL_LINK_TEXT, "Link=") assert element.get_attribute("id") == "linkWithEqualsSign" def test_should_find_multiple_elements_by_partial_link_text_containing_equals_sign(driver, pages): pages.load("xhtmlTest.html") elements = driver.find_elements(By.PARTIAL_LINK_TEXT, "Link=") assert len(elements) == 1 assert elements[0].get_attribute("id") == "linkWithEqualsSign" # Misc tests def test_driver_should_be_able_to_find_elements_after_loading_more_than_one_page_at_atime(driver, pages): pages.load("formPage.html") pages.load("xhtmlTest.html") link = driver.find_element(By.LINK_TEXT, "click me") assert link.text == "click me" # You don't want to ask why this is here def test_when_finding_by_name_should_not_return_by_id(driver, pages): pages.load("formPage.html") element = driver.find_element(By.NAME, "id-name1") assert element.get_attribute("value") == "name" element = driver.find_element(By.ID, "id-name1") assert element.get_attribute("value") == "id" element = driver.find_element(By.NAME, "id-name2") assert element.get_attribute("value") == "name" element = driver.find_element(By.ID, "id-name2") assert element.get_attribute("value") == "id" def test_should_be_able_to_find_ahidden_elements_by_name(driver, pages): pages.load("formPage.html") element = driver.find_element(By.NAME, "hidden") assert element.get_attribute("name") == "hidden" def test_should_not_be_able_to_find_an_element_on_a_blank_page(driver, pages): driver.get("about:blank") with pytest.raises(NoSuchElementException): driver.find_element(By.TAG_NAME, "a") selenium-selenium-4.18.1/test/selenium/webdriver/common/rendered_webelement_tests.py0000644000175000017500000000470114564764517031026 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.support.color import Color def test_should_pick_up_style_of_an_element(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="green-parent") backgroundColour = Color.from_string(element.value_of_css_property("background-color")) assert Color.from_string("rgba(0, 128, 0, 1)") == backgroundColour element = driver.find_element(by=By.ID, value="red-item") backgroundColour = Color.from_string(element.value_of_css_property("background-color")) assert Color.from_string("rgba(255, 0, 0, 1)") == backgroundColour def test_should_allow_inherited_styles_to_be_used(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="green-item") backgroundColour = Color.from_string(element.value_of_css_property("background-color")) assert backgroundColour == Color.from_string("transparent") def test_should_correctly_identify_that_an_element_has_width(driver, pages): pages.load("xhtmlTest.html") shrinko = driver.find_element(by=By.ID, value="linkId") size = shrinko.size assert size["width"] > 0 assert size["height"] > 0 @pytest.mark.xfail_safari(reason="Get Element Rect command not implemented", raises=WebDriverException) def test_should_be_able_to_determine_the_rect_of_an_element(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.ID, "username") rect = element.rect assert rect["x"] > 0 assert rect["y"] > 0 assert rect["width"] > 0 assert rect["height"] > 0 selenium-selenium-4.18.1/test/selenium/webdriver/common/upload_tests.py0000644000175000017500000000550514564764517026316 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import pytest from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement @pytest.fixture def get_local_path(): current_dir = os.path.dirname(os.path.realpath(__file__)) def wrapped(filename): return os.path.join(current_dir, filename) return wrapped def test_can_upload_file(driver, pages, get_local_path): pages.load("upload.html") driver.find_element(By.ID, "upload").send_keys(get_local_path("test_file.txt")) driver.find_element(By.ID, "go").click() driver.switch_to.frame(driver.find_element(By.ID, "upload_target")) body = driver.find_element(By.CSS_SELECTOR, "body").text assert "test_file.txt" in body def test_can_upload_two_files(driver, pages, get_local_path): pages.load("upload.html") two_file_paths = get_local_path("test_file.txt") + "\n" + get_local_path("test_file2.txt") driver.find_element(By.ID, "upload").send_keys(two_file_paths) driver.find_element(By.ID, "go").click() driver.switch_to.frame(driver.find_element(By.ID, "upload_target")) body = driver.find_element(By.CSS_SELECTOR, "body").text assert "test_file.txt" in body assert "test_file2.txt" in body @pytest.mark.xfail_firefox @pytest.mark.xfail_chrome @pytest.mark.xfail_safari def test_file_is_uploaded_to_remote_machine_on_select(driver, pages, get_local_path): uploaded_files = [] original_upload_func = WebElement._upload def mocked_upload_func(self, filename): uploaded_files.append(filename) return original_upload_func(self, filename) WebElement._upload = mocked_upload_func try: pages.load("upload.html") two_file_paths = get_local_path("test_file.txt") + "\n" + get_local_path("test_file2.txt") driver.find_element(By.ID, "upload").send_keys(two_file_paths) assert len(uploaded_files) == 2 assert uploaded_files[0] == get_local_path("test_file.txt") assert uploaded_files[1] == get_local_path("test_file2.txt") finally: WebElement._upload = original_upload_func selenium-selenium-4.18.1/test/selenium/webdriver/common/frame_switching_tests.py0000644000175000017500000004422414564764517030204 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import NoSuchFrameException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait # ---------------------------------------------------------------------------------------------- # # Tests that WebDriver doesn't do anything fishy when it navigates to a page with frames. # # ---------------------------------------------------------------------------------------------- @pytest.fixture(autouse=True) def restore_default_context(driver): yield driver.switch_to.default_content() def test_should_always_focus_on_the_top_most_frame_after_anavigation_event(driver, pages): pages.load("frameset.html") driver.find_element(By.TAG_NAME, "frameset") # Test passes if this does not throw. def test_should_not_automatically_switch_focus_to_an_iframe_when_apage_containing_them_is_loaded(driver, pages): pages.load("iframes.html") driver.find_element(By.ID, "iframe_page_heading") def test_should_open_page_with_broken_frameset(driver, pages): pages.load("framesetPage3.html") frame1 = driver.find_element(By.ID, "first") driver.switch_to.frame(frame1) driver.switch_to.default_content() frame2 = driver.find_element(By.ID, "second") driver.switch_to.frame(frame2) # IE9 can not switch to this broken frame - it has no window. # ---------------------------------------------------------------------------------------------- # # Tests that WebDriver can switch to frames as expected. # # ---------------------------------------------------------------------------------------------- def test_should_be_able_to_switch_to_aframe_by_its_index(driver, pages): pages.load("frameset.html") driver.switch_to.frame(1) assert driver.find_element(By.ID, "pageNumber").text == "2" def test_should_be_able_to_switch_to_an_iframe_by_its_index(driver, pages): pages.load("iframes.html") driver.switch_to.frame(0) assert driver.find_element(By.NAME, "id-name1").get_attribute("value") == "name" def test_should_be_able_to_switch_to_aframe_by_its_name(driver, pages): pages.load("frameset.html") driver.switch_to.frame("fourth") assert driver.find_element(By.TAG_NAME, "frame").get_attribute("name") == "child1" def test_should_be_able_to_switch_to_an_iframe_by_its_name(driver, pages): pages.load("iframes.html") driver.switch_to.frame("iframe1-name") assert driver.find_element(By.NAME, "id-name1").get_attribute("value") == "name" def test_should_be_able_to_switch_to_aframe_by_its_id(driver, pages): pages.load("frameset.html") driver.switch_to.frame("fifth") assert driver.find_element(By.NAME, "windowOne").text == "Open new window" def test_should_be_able_to_switch_to_an_iframe_by_its_id(driver, pages): pages.load("iframes.html") driver.switch_to.frame("iframe1") assert driver.find_element(By.NAME, "id-name1").get_attribute("value") == "name" def test_should_be_able_to_switch_to_frame_with_name_containing_dot(driver, pages): pages.load("frameset.html") driver.switch_to.frame("sixth.iframe1") assert "Page number 3" in driver.find_element(By.TAG_NAME, "body").text def test_should_be_able_to_switch_to_aframe_using_apreviously_located_web_element(driver, pages): pages.load("frameset.html") frame = driver.find_element(By.TAG_NAME, "frame") driver.switch_to.frame(frame) assert driver.find_element(By.ID, "pageNumber").text == "1" def test_should_be_able_to_switch_to_an_iframe_using_apreviously_located_web_element(driver, pages): pages.load("iframes.html") frame = driver.find_element(By.TAG_NAME, "iframe") driver.switch_to.frame(frame) element = driver.find_element(By.NAME, "id-name1") assert element.get_attribute("value") == "name" def test_should_ensure_element_is_aframe_before_switching(driver, pages): pages.load("frameset.html") frame = driver.find_element(By.TAG_NAME, "frameset") with pytest.raises(NoSuchFrameException): driver.switch_to.frame(frame) def test_frame_searches_should_be_relative_to_the_currently_selected_frame(driver, pages): pages.load("frameset.html") driver.switch_to.frame("second") assert driver.find_element(By.ID, "pageNumber").text == "2" with pytest.raises(NoSuchElementException): driver.switch_to.frame(driver.find_element(By.NAME, "third")) driver.switch_to.default_content() driver.switch_to.frame(driver.find_element(By.NAME, "third")) with pytest.raises(NoSuchFrameException): driver.switch_to.frame("second") driver.switch_to.default_content() driver.switch_to.frame(driver.find_element(By.NAME, "second")) assert driver.find_element(By.ID, "pageNumber").text == "2" def test_should_select_child_frames_by_chained_calls(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.NAME, "fourth")) driver.switch_to.frame(driver.find_element(By.NAME, "child2")) assert driver.find_element(By.ID, "pageNumber").text == "11" def test_should_throw_frame_not_found_exception_looking_up_sub_frames_with_super_frame_names(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.NAME, "fourth")) with pytest.raises(NoSuchElementException): driver.switch_to.frame(driver.find_element(By.NAME, "second")) def test_should_throw_an_exception_when_aframe_cannot_be_found(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchElementException): driver.switch_to.frame(driver.find_element(By.NAME, "Nothing here")) def test_should_throw_an_exception_when_aframe_cannot_be_found_by_index(driver, pages): pages.load("xhtmlTest.html") with pytest.raises(NoSuchFrameException): driver.switch_to.frame(27) def test_should_be_able_to_switch_to_parent_frame(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.NAME, "fourth")) driver.switch_to.parent_frame() driver.switch_to.frame(driver.find_element(By.NAME, "first")) assert driver.find_element(By.ID, "pageNumber").text == "1" @pytest.mark.xfail_safari def test_should_be_able_to_switch_to_parent_frame_from_asecond_level_frame(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.NAME, "fourth")) driver.switch_to.frame(driver.find_element(By.NAME, "child1")) driver.switch_to.parent_frame() driver.switch_to.frame(driver.find_element(By.NAME, "child2")) assert driver.find_element(By.ID, "pageNumber").text == "11" def test_switching_to_parent_frame_from_default_context_is_no_op(driver, pages): pages.load("xhtmlTest.html") driver.switch_to.parent_frame() assert driver.title == "XHTML Test Page" def test_should_be_able_to_switch_to_parent_from_an_iframe(driver, pages): pages.load("iframes.html") driver.switch_to.frame(0) driver.switch_to.parent_frame() driver.find_element(By.ID, "iframe_page_heading") # ---------------------------------------------------------------------------------------------- # # General frame handling behavior tests # # ---------------------------------------------------------------------------------------------- def test_should_continue_to_refer_to_the_same_frame_once_it_has_been_selected(driver, pages): pages.load("frameset.html") driver.switch_to.frame(2) checkbox = driver.find_element(By.XPATH, "//input[@name='checky']") checkbox.click() checkbox.submit() # TODO(simon): this should not be needed, and is only here because IE's submit returns too # soon. WebDriverWait(driver, 3).until(EC.text_to_be_present_in_element((By.XPATH, "//p"), "Success!")) @pytest.mark.xfail_firefox(raises=WebDriverException, reason="https://github.com/mozilla/geckodriver/issues/610") @pytest.mark.xfail_remote(raises=WebDriverException, reason="https://github.com/mozilla/geckodriver/issues/610") @pytest.mark.xfail_safari @pytest.mark.xfail_chrome def test_should_focus_on_the_replacement_when_aframe_follows_alink_to_a_top_targeted_page(driver, pages): pages.load("frameset.html") driver.switch_to.frame(0) driver.find_element(By.LINK_TEXT, "top").click() expectedTitle = "XHTML Test Page" WebDriverWait(driver, 3).until(EC.title_is(expectedTitle)) WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "only-exists-on-xhtmltest"))) def test_should_allow_auser_to_switch_from_an_iframe_back_to_the_main_content_of_the_page(driver, pages): pages.load("iframes.html") driver.switch_to.frame(0) driver.switch_to.default_content() driver.find_element(By.ID, "iframe_page_heading") def test_should_allow_the_user_to_switch_to_an_iframe_and_remain_focused_on_it(driver, pages): pages.load("iframes.html") driver.switch_to.frame(0) driver.find_element(By.ID, "submitButton").click() assert get_text_of_greeting_element(driver) == "Success!" def get_text_of_greeting_element(driver): return WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "greeting"))).text def test_should_be_able_to_click_in_aframe(driver, pages): pages.load("frameset.html") driver.switch_to.frame("third") # This should replace frame "third" ... driver.find_element(By.ID, "submitButton").click() # driver should still be focused on frame "third" ... assert get_text_of_greeting_element(driver) == "Success!" # Make sure it was really frame "third" which was replaced ... driver.switch_to.default_content() driver.switch_to.frame("third") assert get_text_of_greeting_element(driver) == "Success!" def test_should_be_able_to_click_in_aframe_that_rewrites_top_window_location(driver, pages): pages.load("click_tests/issue5237.html") driver.switch_to.frame(driver.find_element(By.ID, "search")) driver.find_element(By.ID, "submit").click() driver.switch_to.default_content() WebDriverWait(driver, 3).until(EC.title_is("Target page for issue 5237")) def test_should_be_able_to_click_in_asub_frame(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.ID, "sixth")) driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) # This should replace frame "iframe1" inside frame "sixth" ... driver.find_element(By.ID, "submitButton").click() # driver should still be focused on frame "iframe1" inside frame "sixth" ... assert get_text_of_greeting_element(driver), "Success!" # Make sure it was really frame "iframe1" inside frame "sixth" which was replaced ... driver.switch_to.default_content() driver.switch_to.frame(driver.find_element(By.ID, "sixth")) driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) assert driver.find_element(By.ID, "greeting").text == "Success!" def test_should_be_able_to_find_elements_in_iframes_by_xpath(driver, pages): pages.load("iframes.html") driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) element = driver.find_element(By.XPATH, "//*[@id = 'changeme']") assert element is not None def test_get_current_url_returns_top_level_browsing_context_url(driver, pages): pages.load("frameset.html") assert "frameset.html" in driver.current_url driver.switch_to.frame(driver.find_element(By.NAME, "second")) assert "frameset.html" in driver.current_url def test_get_current_url_returns_top_level_browsing_context_url_for_iframes(driver, pages): pages.load("iframes.html") assert "iframes.html" in driver.current_url driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) assert "iframes.html" in driver.current_url def test_should_be_able_to_switch_to_the_top_if_the_frame_is_deleted_from_under_us(driver, pages): pages.load("frame_switching_tests/deletingFrame.html") driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) killIframe = driver.find_element(By.ID, "killIframe") killIframe.click() driver.switch_to.default_content() WebDriverWait(driver, 3).until_not(EC.presence_of_element_located((By.ID, "iframe1"))) addIFrame = driver.find_element(By.ID, "addBackFrame") addIFrame.click() WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "iframe1"))) driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "success"))) def test_should_be_able_to_switch_to_the_top_if_the_frame_is_deleted_from_under_us_with_frame_index(driver, pages): pages.load("frame_switching_tests/deletingFrame.html") iframe = 0 WebDriverWait(driver, 3).until(EC.frame_to_be_available_and_switch_to_it(iframe)) # we should be in the frame now killIframe = driver.find_element(By.ID, "killIframe") killIframe.click() driver.switch_to.default_content() addIFrame = driver.find_element(By.ID, "addBackFrame") addIFrame.click() WebDriverWait(driver, 3).until(EC.frame_to_be_available_and_switch_to_it(iframe)) WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "success"))) def test_frame_to_be_available_and_switch_to_it_using_string_inputs(driver, pages): # Similar to above test, but using `iframe = "iframe1"` instead of `iframe = 0` pages.load("frame_switching_tests/deletingFrame.html") iframe = "iframe1" WebDriverWait(driver, 3).until(EC.frame_to_be_available_and_switch_to_it(iframe)) # we should be in the frame now killIframe = driver.find_element(By.ID, "killIframe") killIframe.click() driver.switch_to.default_content() addIFrame = driver.find_element(By.ID, "addBackFrame") addIFrame.click() WebDriverWait(driver, 3).until(EC.frame_to_be_available_and_switch_to_it(iframe)) WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "success"))) def test_should_be_able_to_switch_to_the_top_if_the_frame_is_deleted_from_under_us_with_webelement(driver, pages): pages.load("frame_switching_tests/deletingFrame.html") iframe = driver.find_element(By.ID, "iframe1") WebDriverWait(driver, 3).until(EC.frame_to_be_available_and_switch_to_it(iframe)) # we should be in the frame now killIframe = driver.find_element(By.ID, "killIframe") killIframe.click() driver.switch_to.default_content() addIFrame = driver.find_element(By.ID, "addBackFrame") addIFrame.click() iframe = driver.find_element(By.ID, "iframe1") WebDriverWait(driver, 3).until(EC.frame_to_be_available_and_switch_to_it(iframe)) WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "success"))) # @pytest.mark.xfail_chrome(raises=NoSuchElementException) # @pytest.mark.xfail_chromiumedge(raises=NoSuchElementException) # @pytest.mark.xfail_firefox(raises=WebDriverException, # reason='https://github.com/mozilla/geckodriver/issues/614') # @pytest.mark.xfail_remote(raises=WebDriverException, # reason='https://github.com/mozilla/geckodriver/issues/614') # @pytest.mark.xfail_webkitgtk(raises=NoSuchElementException) # @pytest.mark.xfail_safari # def test_should_not_be_able_to_do_anything_the_frame_is_deleted_from_under_us(driver, pages): # pages.load("frame_switching_tests/deletingFrame.html") # driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) # killIframe = driver.find_element(By.ID, "killIframe") # killIframe.click() # with pytest.raises(NoSuchFrameException): # driver.find_element(By.ID, "killIframe").click() def test_should_return_window_title_in_aframeset(driver, pages): pages.load("frameset.html") driver.switch_to.frame(driver.find_element(By.NAME, "third")) assert "Unique title" == driver.title def test_java_script_should_execute_in_the_context_of_the_current_frame(driver, pages): pages.load("frameset.html") assert driver.execute_script("return window == window.top") driver.switch_to.frame(driver.find_element(By.NAME, "third")) assert driver.execute_script("return window != window.top") @pytest.mark.xfail_chrome(reason="Fails on Travis") @pytest.mark.xfail_safari def test_should_not_switch_magically_to_the_top_window(driver, pages): pages.load("frame_switching_tests/bug4876.html") driver.switch_to.frame(0) WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "inputText"))) for i in range(20): try: input = WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "inputText"))) submit = WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "submitButton"))) input.clear() import random input.send_keys("rand%s" % int(random.random())) submit.click() finally: url = driver.execute_script("return window.location.href") # IE6 and Chrome add "?"-symbol to the end of the URL if url.endswith("?"): url = url[: len(url) - 1] assert pages.url("frame_switching_tests/bug4876_iframe.html") == url def test_get_should_switch_to_default_context(driver, pages): pages.load("iframes.html") driver.find_element(By.ID, "iframe1") driver.switch_to.frame(driver.find_element(By.ID, "iframe1")) driver.find_element(By.ID, "cheese") # Found on formPage.html but not on iframes.html. pages.load("iframes.html") # This must effectively switch_to.default_content(), too. driver.find_element(By.ID, "iframe1") selenium-selenium-4.18.1/test/selenium/webdriver/common/form_handling_tests.py0000644000175000017500000001754314564764517027646 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait def test_should_click_on_submit_input_elements(driver, pages): pages.load("formPage.html") driver.find_element(By.ID, "submitButton").click() WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) def test_clicking_on_unclickable_elements_does_nothing(driver, pages): pages.load("formPage.html") driver.find_element(By.XPATH, "//body").click() def test_should_be_able_to_click_image_buttons(driver, pages): pages.load("formPage.html") driver.find_element(By.ID, "imageButton").click() WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) def test_should_submit_input_in_form(driver, pages): pages.load("formPage.html") driver.find_element(By.NAME, "login").submit() WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) def test_should_submit_any_input_element_within_form(driver, pages): pages.load("formPage.html") driver.find_element(By.ID, "checky").submit() WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) def test_should_submit_any_element_within_form(driver, pages): pages.load("formPage.html") driver.find_element(By.XPATH, "//form/p").submit() WebDriverWait(driver, 5).until(EC.title_is("We Arrive Here")) def test_should_submit_element_with_id_submit(driver, pages): pages.load("formPage.html") driver.find_element(By.ID, "submit").submit() WebDriverWait(driver, 5).until(EC.title_is("We Arrive Here")) def test_should_submit_element_with_name_submit(driver, pages): pages.load("formPage.html") driver.find_element(By.NAME, "submit").submit() WebDriverWait(driver, 5).until(EC.title_is("We Arrive Here")) def test_should_not_submit_button_outside_form(driver, pages): pages.load("formPage.html") with pytest.raises(WebDriverException): driver.find_element(By.NAME, "SearchableText").submit() def test_should_be_able_to_enter_text_into_atext_area_by_setting_its_value(driver, pages): pages.load("javascriptPage.html") textarea = driver.find_element(By.ID, "keyUpArea") cheesey = "Brie and cheddar" textarea.send_keys(cheesey) assert textarea.get_attribute("value") == cheesey def test_should_enter_data_into_form_fields(driver, pages): pages.load("xhtmlTest.html") element = driver.find_element(By.XPATH, "//form[@name='someForm']/input[@id='username']") originalValue = element.get_attribute("value") assert originalValue == "change" element.clear() element.send_keys("some text") element = driver.find_element(By.XPATH, "//form[@name='someForm']/input[@id='username']") newFormValue = element.get_attribute("value") assert newFormValue == "some text" def test_should_be_able_to_select_acheck_box(driver, pages): pages.load("formPage.html") checkbox = driver.find_element(By.ID, "checky") assert checkbox.is_selected() is False checkbox.click() assert checkbox.is_selected() is True checkbox.click() assert checkbox.is_selected() is False def test_should_toggle_the_checked_state_of_acheckbox(driver, pages): pages.load("formPage.html") checkbox = driver.find_element(By.ID, "checky") assert checkbox.is_selected() is False checkbox.click() assert checkbox.is_selected() is True checkbox.click() assert checkbox.is_selected() is False def test_toggling_acheckbox_should_return_its_current_state(driver, pages): pages.load("formPage.html") checkbox = driver.find_element(By.ID, "checky") assert checkbox.is_selected() is False checkbox.click() assert checkbox.is_selected() is True checkbox.click() assert checkbox.is_selected() is False def test_should_be_able_to_select_aradio_button(driver, pages): pages.load("formPage.html") radioButton = driver.find_element(By.ID, "peas") assert radioButton.is_selected() is False radioButton.click() assert radioButton.is_selected() is True def test_should_be_able_to_select_aradio_button_by_clicking_on_it(driver, pages): pages.load("formPage.html") radioButton = driver.find_element(By.ID, "peas") assert radioButton.is_selected() is False radioButton.click() assert radioButton.is_selected() is True def test_should_return_state_of_radio_buttons_before_interaction(driver, pages): pages.load("formPage.html") radioButton = driver.find_element(By.ID, "cheese_and_peas") assert radioButton.is_selected() is True radioButton = driver.find_element(By.ID, "cheese") assert radioButton.is_selected() is False def test_toggling_an_option_should_toggle_options_in_amulti_select(driver, pages): pages.load("formPage.html") select = driver.find_element(By.NAME, "multi") option = select.find_elements(By.TAG_NAME, "option")[0] selected = option.is_selected() option.click() assert not selected == option.is_selected() option.click() assert selected == option.is_selected() def test_should_throw_an_exception_when_selecting_an_unselectable_element(driver, pages): pages.load("formPage.html") element = driver.find_element(By.XPATH, "//title") with pytest.raises(WebDriverException): element.click() def test_sending_keyboard_events_should_append_text_in_inputs(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "working") element.send_keys("Some") value = element.get_attribute("value") assert value == "Some" element.send_keys(" text") value = element.get_attribute("value") assert value == "Some text" def test_should_be_able_to_clear_text_from_input_elements(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "working") element.send_keys("Some text") value = element.get_attribute("value") assert len(value) > 0 element.clear() value = element.get_attribute("value") assert len(value) == 0 def test_empty_text_boxes_should_return_an_empty_string_not_null(driver, pages): pages.load("formPage.html") emptyTextBox = driver.find_element(By.ID, "working") assert emptyTextBox.get_attribute("value") == "" emptyTextArea = driver.find_element(By.ID, "emptyTextArea") assert emptyTextArea.get_attribute("value") == "" def test_should_be_able_to_clear_text_from_text_areas(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "withText") element.send_keys("Some text") value = element.get_attribute("value") assert len(value) > 0 element.clear() value = element.get_attribute("value") assert len(value) == 0 def test_radio_should_not_be_selected_after_selecting_sibling(driver, pages): pages.load("formPage.html") cheese = driver.find_element(By.ID, "cheese") peas = driver.find_element(By.ID, "peas") cheese.click() assert cheese.is_selected() is True assert peas.is_selected() is False peas.click() assert cheese.is_selected() is False assert peas.is_selected() is True selenium-selenium-4.18.1/test/selenium/webdriver/common/cookie_tests.py0000644000175000017500000001177514564764517026311 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import calendar import random import time import pytest @pytest.fixture def cookie(webserver): cookie = {"name": "foo", "value": "bar", "domain": webserver.host, "path": "/", "secure": False} return cookie @pytest.fixture def same_site_cookie_strict(webserver): same_site_cookie_strict = { "name": "foo", "value": "bar", "path": "/", "domain": webserver.host, "sameSite": "Strict", "secure": False, } return same_site_cookie_strict @pytest.fixture def same_site_cookie_lax(webserver): same_site_cookie_lax = { "name": "foo", "value": "bar", "path": "/", "domain": webserver.host, "sameSite": "Lax", "secure": False, } return same_site_cookie_lax @pytest.fixture def same_site_cookie_none(webserver): same_site_cookie_none = { "name": "foo", "value": "bar", "path": "/", "domain": webserver.host, "sameSite": "None", "secure": True, } return same_site_cookie_none @pytest.fixture(autouse=True) def pages(request, driver, pages): pages.load("simpleTest.html") yield pages driver.delete_all_cookies() def test_add_cookie(cookie, driver): driver.add_cookie(cookie) returned = driver.execute_script("return document.cookie") assert cookie["name"] in returned @pytest.mark.xfail_firefox(reason="sameSite cookie attribute not implemented") @pytest.mark.xfail_remote(reason="sameSite cookie attribute not implemented") @pytest.mark.xfail_safari def test_add_cookie_same_site_strict(same_site_cookie_strict, driver): driver.add_cookie(same_site_cookie_strict) returned = driver.get_cookie("foo") assert "sameSite" in returned and returned["sameSite"] == "Strict" @pytest.mark.xfail_firefox(reason="sameSite cookie attribute not implemented") @pytest.mark.xfail_remote(reason="sameSite cookie attribute not implemented") @pytest.mark.xfail_safari def test_add_cookie_same_site_lax(same_site_cookie_lax, driver): driver.add_cookie(same_site_cookie_lax) returned = driver.get_cookie("foo") assert "sameSite" in returned and returned["sameSite"] == "Lax" @pytest.mark.xfail_firefox(reason="sameSite cookie attribute not implemented") @pytest.mark.xfail_remote(reason="sameSite cookie attribute not implemented") @pytest.mark.xfail_safari def test_add_cookie_same_site_none(same_site_cookie_none, driver): driver.add_cookie(same_site_cookie_none) # Note that insecure sites (http:) can't set cookies with the Secure directive. # driver.get_cookie would return None @pytest.mark.xfail_ie @pytest.mark.xfail_safari def test_adding_acookie_that_expired_in_the_past(cookie, driver): expired = cookie.copy() expired["expiry"] = calendar.timegm(time.gmtime()) - 1 driver.add_cookie(expired) assert 0 == len(driver.get_cookies()) def test_delete_all_cookie(cookie, driver): driver.add_cookie(cookie) driver.delete_all_cookies() assert not driver.get_cookies() def test_delete_cookie(cookie, driver): driver.add_cookie(cookie) driver.delete_cookie("foo") assert not driver.get_cookies() def test_should_get_cookie_by_name(driver): key = f"key_{int(random.random() * 10000000)}" driver.execute_script("document.cookie = arguments[0] + '=set';", key) cookie = driver.get_cookie(key) assert "set" == cookie["value"] def test_should_return_none_when_cookie_does_not_exist(driver): key = f"key_{int(random.random() * 10000000)}" cookie = driver.get_cookie(key) assert cookie is None def test_get_all_cookies(cookie, driver, pages, webserver): cookies = driver.get_cookies() count = len(cookies) for i in range(2): cookie["name"] = f"key_{int(random.random() * 10000000)}" driver.add_cookie(cookie) pages.load("simpleTest.html") assert count + 2 == len(driver.get_cookies()) def test_should_not_delete_cookies_with_asimilar_name(cookie, driver, webserver): cookie2 = cookie.copy() cookie2["name"] = "{}x".format(cookie["name"]) driver.add_cookie(cookie) driver.add_cookie(cookie2) driver.delete_cookie(cookie["name"]) cookies = driver.get_cookies() assert cookie["name"] != cookies[0]["name"] assert cookie2["name"] == cookies[0]["name"] selenium-selenium-4.18.1/test/selenium/webdriver/common/page_loader.py0000644000175000017500000000257414564764517026055 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """This module contains some decorators that can be used to support the page models. For example for an action that needs a page to be fully loaded, the @require_loaded decorator will make sure the page is loaded before the call is invoked. This pattern is also useful for waiting for certain asynchronous events to happen before executing certain actions.""" def require_loaded(func): def load_page(page, *params, **kwds): if not page.is_loaded(): page.load() assert page.is_loaded(), "page should be loaded by now" return func(page, *params, **kwds) return load_page selenium-selenium-4.18.1/test/selenium/webdriver/common/page_loading_tests.py0000644000175000017500000001157714564764517027451 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import pytest # # from selenium.common.exceptions import WebDriverException # from selenium.webdriver.common.by import By # from selenium.webdriver.support.wait import WebDriverWait # from selenium.webdriver.support import expected_conditions as EC def test_should_wait_for_document_to_be_loaded(driver, pages): pages.load("simpleTest.html") assert driver.title == "Hello WebDriver" # Disabled till Java WebServer is used # def test_should_follow_redirects_sent_in_the_http_response_headers(driver, pages): # pages.load("redirect.html") # assert driver.title == "We Arrive Here" # Disabled till the Java WebServer is used # def test_should_follow_meta_redirects(driver, pages): # pages.load("metaRedirect.html") # assert driver.title == "We Arrive Here" # def test_should_be_able_to_get_afragment_on_the_current_page(driver, pages): # pages.load("xhtmlTest.html") # location = driver.current_url # driver.get(location + "#text") # driver.find_element(by=By.ID, value="id1") # @pytest.mark.xfail_firefox(raises=WebDriverException) # @pytest.mark.xfail_remote(raises=WebDriverException) # def test_should_return_when_getting_aurl_that_does_not_resolve(driver): # # Of course, we're up the creek if this ever does get registered # driver.get("http://www.thisurldoesnotexist.comx/") # @pytest.mark.xfail_firefox(raises=WebDriverException) # @pytest.mark.xfail_remote(raises=WebDriverException) # def test_should_return_when_getting_aurl_that_does_not_connect(driver): # # Here's hoping that there's nothing here. There shouldn't be # driver.get("http://localhost:3001") # def test_should_be_able_to_load_apage_with_framesets_and_wait_until_all_frames_are_loaded() { # driver.get(pages.framesetPage) # # driver.switchTo().frame(0) # WebElement pageNumber = driver.findElement(By.xpath("#span[@id='pageNumber']")) # self.assertEqual((pageNumber.getText().trim(), equalTo("1")) # # driver.switchTo().defaultContent().switchTo().frame(1) # pageNumber = driver.findElement(By.xpath("#span[@id='pageNumber']")) # self.assertEqual((pageNumber.getText().trim(), equalTo("2")) # Need to implement this decorator # @NeedsFreshDriver # def test_sould_do_nothing_if_there_is_nothing_to_go_back_to() { # originalTitle = driver.getTitle(); # driver.get(pages.formPage); # driver.back(); # # We may have returned to the browser's home page # self.assertEqual(driver.title, anyOf(equalTo(originalTitle), equalTo("We Leave From Here"))); # @pytest.mark.xfail_safari # def test_should_be_able_to_navigate_back_in_the_browser_history(driver, pages): # pages.load("formPage.html") # driver.find_element(by=By.ID, value="imageButton").submit() # WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) # driver.back() # assert driver.title == "We Leave From Here" # @pytest.mark.xfail_safari # def test_should_be_able_to_navigate_back_in_the_browser_history_in_presence_of_iframes(driver, pages): # pages.load("xhtmlTest.html") # driver.find_element(by=By.NAME, value="sameWindow").click() # assert driver.title == "This page has iframes" # driver.back() # assert driver.title == "XHTML Test Page" # def test_should_be_able_to_navigate_forwards_in_the_browser_history(driver, pages): # pages.load("formPage.html") # driver.find_element(by=By.ID, value="imageButton").submit() # WebDriverWait(driver, 3).until(EC.title_is("We Arrive Here")) # driver.back() # assert driver.title == "We Leave From Here" # driver.forward() # assert driver.title == "We Arrive Here" # @pytest.mark.xfail_ie # @pytest.mark.xfail_firefox(run=False) # @pytest.mark.xfail_remote(run=False) # @pytest.mark.xfail_chrome(run=False) # @pytest.mark.xfail_chromiumedge(run=False) # def test_should_not_hang_if_document_open_call_is_never_followed_by_document_close_call(driver, pages): # pages.load("document_write_in_onload.html") # driver.find_element(By.XPATH, "//body") # def test_should_be_able_to_refresh_apage(driver, pages): # pages.load("xhtmlTest.html") # driver.refresh() # assert driver.title == "XHTML Test Page" selenium-selenium-4.18.1/test/selenium/webdriver/common/children_finding_tests.py0000644000175000017500000001531214564764517030315 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By def test_should_find_element_by_xpath(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") child = element.find_element(By.XPATH, "select") assert child.get_attribute("id") == "2" def test_should_not_find_element_by_xpath(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") with pytest.raises(NoSuchElementException): element.find_element(By.XPATH, "select/x") def test_finding_dot_slash_elements_on_element_by_xpath_should_find_not_top_level_elements(driver, pages): pages.load("simpleTest.html") parent = driver.find_element(By.ID, "multiline") children = parent.find_elements(By.XPATH, "./p") assert 1 == len(children) assert "A div containing" == children[0].text def test_should_find_elements_by_xpath(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") children = element.find_elements(By.XPATH, "select/option") assert len(children) == 8 assert children[0].text == "One" assert children[1].text == "Two" def test_should_not_find_elements_by_xpath(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") children = element.find_elements(By.XPATH, "select/x") assert len(children) == 0 def test_finding_elements_on_element_by_xpath_should_find_top_level_elements(driver, pages): pages.load("simpleTest.html") parent = driver.find_element(By.ID, "multiline") all_para_elements = driver.find_elements(By.XPATH, "//p") children = parent.find_elements(By.XPATH, "//p") assert len(all_para_elements) == len(children) def test_should_find_element_by_name(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") child = element.find_element(By.NAME, "selectomatic") assert child.get_attribute("id") == "2" def test_should_find_elements_by_name(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") children = element.find_elements(By.NAME, "selectomatic") assert len(children) == 2 def test_should_find_element_by_id(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") child = element.find_element(By.ID, "2") assert child.get_attribute("name") == "selectomatic" def test_should_find_elements_by_id(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") child = element.find_elements(By.ID, "2") assert len(child) == 2 def test_should_find_element_by_id_when_multiple_matches_exist(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.ID, "test_id_div") child = element.find_element(By.ID, "test_id") assert child.text == "inside" def test_should_find_element_by_id_when_no_match_in_context(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.ID, "test_id_div") with pytest.raises(NoSuchElementException): element.find_element(By.ID, "test_id_out") def test_should_find_element_by_link_text(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "div1") child = element.find_element(By.LINK_TEXT, "hello world") assert child.get_attribute("name") == "link1" def test_should_find_elements_by_link_text(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "div1") children = element.find_elements(By.LINK_TEXT, "hello world") assert len(children) == 2 assert "link1" == children[0].get_attribute("name") assert "link2" == children[1].get_attribute("name") def test_should_find_element_by_class_name(driver, pages): pages.load("nestedElements.html") parent = driver.find_element(By.NAME, "classes") element = parent.find_element(By.CLASS_NAME, "one") assert "Find me" == element.text def test_should_find_elements_by_class_name(driver, pages): pages.load("nestedElements.html") parent = driver.find_element(By.NAME, "classes") elements = parent.find_elements(By.CLASS_NAME, "one") assert 2 == len(elements) def test_should_find_element_by_tag_name(driver, pages): pages.load("nestedElements.html") parent = driver.find_element(By.NAME, "div1") element = parent.find_element(By.TAG_NAME, "a") assert "link1" == element.get_attribute("name") def test_should_find_elements_by_tag_name(driver, pages): pages.load("nestedElements.html") parent = driver.find_element(By.NAME, "div1") elements = parent.find_elements(By.TAG_NAME, "a") assert 2 == len(elements) def test_should_be_able_to_find_an_element_by_css_selector(driver, pages): pages.load("nestedElements.html") parent = driver.find_element(By.NAME, "form2") element = parent.find_element(By.CSS_SELECTOR, '*[name="selectomatic"]') assert "2" == element.get_attribute("id") def test_should_be_able_to_find_multiple_elements_by_css_selector(driver, pages): pages.load("nestedElements.html") parent = driver.find_element(By.NAME, "form2") elements = parent.find_elements(By.CSS_SELECTOR, '*[name="selectomatic"]') assert 2 == len(elements) def test_should_throw_an_error_if_user_passes_in_invalid_by(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") with pytest.raises(WebDriverException): element.find_element("foo", "bar") def test_should_throw_an_error_if_user_passes_in_invalid_by_when_find_elements(driver, pages): pages.load("nestedElements.html") element = driver.find_element(By.NAME, "form2") with pytest.raises(WebDriverException): element.find_elements("foo", "bar") selenium-selenium-4.18.1/test/selenium/webdriver/common/correct_event_firing_tests.py0000644000175000017500000001151114564764517031224 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By @pytest.mark.xfail_safari def test_should_fire_click_event_when_clicking(driver, pages): pages.load("javascriptPage.html") _click_on_element_which_records_events(driver) _assert_event_fired(driver, "click") @pytest.mark.xfail_safari def test_should_fire_mouse_down_event_when_clicking(driver, pages): pages.load("javascriptPage.html") _click_on_element_which_records_events(driver) _assert_event_fired(driver, "mousedown") @pytest.mark.xfail_safari def test_should_fire_mouse_up_event_when_clicking(driver, pages): pages.load("javascriptPage.html") _click_on_element_which_records_events(driver) _assert_event_fired(driver, "mouseup") @pytest.mark.xfail_safari def test_should_issue_mouse_down_events(driver, pages): pages.load("javascriptPage.html") driver.find_element(By.ID, "mousedown").click() result = driver.find_element(By.ID, "result").text assert result == "mouse down" @pytest.mark.xfail_safari def test_should_issue_click_events(driver, pages): pages.load("javascriptPage.html") driver.find_element(By.ID, "mouseclick").click() result = driver.find_element(By.ID, "result").text assert result == "mouse click" @pytest.mark.xfail_safari def test_should_issue_mouse_up_events(driver, pages): pages.load("javascriptPage.html") driver.find_element(By.ID, "mouseup").click() result = driver.find_element(By.ID, "result").text assert result == "mouse up" @pytest.mark.xfail_safari def test_mouse_events_should_bubble_up_to_containing_elements(driver, pages): pages.load("javascriptPage.html") driver.find_element(By.ID, "child").click() result = driver.find_element(By.ID, "result").text assert result == "mouse down" @pytest.mark.xfail_safari def test_should_emit_on_change_events_when_selecting_elements(driver, pages): pages.load("javascriptPage.html") select = driver.find_element(By.ID, "selector") options = select.find_elements(By.TAG_NAME, "option") initialTextValue = driver.find_element(By.ID, "result").text select.click() assert driver.find_element(By.ID, "result").text == initialTextValue options[1].click() assert driver.find_element(By.ID, "result").text == "bar" @pytest.mark.xfail_safari def test_should_emit_on_change_events_when_changing_the_state_of_acheckbox(driver, pages): pages.load("javascriptPage.html") checkbox = driver.find_element(By.ID, "checkbox") checkbox.click() assert driver.find_element(By.ID, "result").text == "checkbox thing" def test_should_emit_click_event_when_clicking_on_atext_input_element(driver, pages): pages.load("javascriptPage.html") clicker = driver.find_element(By.ID, "clickField") clicker.click() assert clicker.get_attribute("value") == "Clicked" @pytest.mark.xfail_safari def test_clearing_an_element_should_cause_the_on_change_handler_to_fire(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(By.ID, "clearMe") element.clear() result = driver.find_element(By.ID, "result") assert result.text == "Cleared" # TODO Currently Failing and needs fixing # def test_sending_keys_to_another_element_should_cause_the_blur_event_to_fire(driver, pages): # pages.load("javascriptPage.html") # element = driver.find_element(By.ID, "theworks") # element.send_keys("foo") # element2 = driver.find_element(By.ID, "changeable") # element2.send_keys("bar") # _assertEventFired(driver, "blur") # TODO Currently Failing and needs fixing # def test_sending_keys_to_an_element_should_cause_the_focus_event_to_fire(driver, pages): # pages.load("javascriptPage.html") # element = driver.find_element(By.ID, "theworks") # element.send_keys("foo") # _assertEventFired(driver, "focus") def _click_on_element_which_records_events(driver): driver.find_element(By.ID, "plainButton").click() def _assert_event_fired(driver, eventName): result = driver.find_element(By.ID, "result") text = result.text assert eventName in text, "No " + eventName + " fired: " + text selenium-selenium-4.18.1/test/selenium/webdriver/common/select_class_tests.py0000644000175000017500000003144514564764517027500 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import UnexpectedTagNameException from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import Select disabledSelect = {"name": "no-select", "values": ["Foo"]} disabledSingleSelect = {"name": "single_disabled", "values": ["Enabled", "Disabled"]} disabledMultiSelect = {"name": "multi_disabled", "values": ["Enabled", "Disabled"]} singleSelectValues1 = { "name": "selectomatic", "values": ["One", "Two", "Four", "Still learning how to count, apparently"], } singleSelectValues2 = {"name": "redirect", "values": ["One", "Two"]} singleSelectValuesWithSpaces = { "name": "select_with_spaces", "values": ["One", "Two", "Four", "Still learning how to count, apparently"], } multiSelectValues1 = {"name": "multi", "values": ["Eggs", "Ham", "Sausages", "Onion gravy"]} multiSelectValues2 = {"name": "select_empty_multiple", "values": ["select_1", "select_2", "select_3", "select_4"]} def test_select_by_index_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1]: sel = Select(driver.find_element(By.NAME, select["name"])) for x in range(len(select["values"])): sel.select_by_index(x) assert sel.first_selected_option.text == select["values"][x] @pytest.mark.xfail_safari(reason="options incorrectly reported as enabled") def test_raises_exception_select_by_index_single_disabled(driver, pages): pages.load("formPage.html") sel = Select(driver.find_element(By.NAME, disabledSingleSelect["name"])) with pytest.raises(NotImplementedError): sel.select_by_index(1) def test_select_by_value_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1]: sel = Select(driver.find_element(By.NAME, select["name"])) for x in range(len(select["values"])): sel.select_by_value(select["values"][x].lower()) assert sel.first_selected_option.text == select["values"][x] @pytest.mark.xfail_safari(reason="options incorrectly reported as enabled") def test_raises_exception_select_by_value_single_disabled(driver, pages): pages.load("formPage.html") sel = Select(driver.find_element(By.NAME, disabledSingleSelect["name"])) with pytest.raises(NotImplementedError): sel.select_by_value(disabledSingleSelect["values"][1].lower()) def test_select_by_visible_text_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1]: sel = Select(driver.find_element(By.NAME, select["name"])) for x in range(len(select["values"])): print(select["values"][x]) sel.select_by_visible_text(select["values"][x]) assert sel.first_selected_option.text == select["values"][x] @pytest.mark.xfail_safari(reason="options incorrectly reported as enabled") def test_raises_exception_select_by_text_single_disabled(driver, pages): pages.load("formPage.html") sel = Select(driver.find_element(By.NAME, disabledSingleSelect["name"])) with pytest.raises(NotImplementedError): sel.select_by_visible_text(disabledSingleSelect["values"][1]) def test_select_by_index_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() for x in range(len(select["values"])): sel.select_by_index(x) selected = sel.all_selected_options assert len(selected) == x + 1 for j in range(len(selected)): assert selected[j].text == select["values"][j] @pytest.mark.xfail_safari(reason="options incorrectly reported as enabled") def test_raises_exception_select_by_index_multiple_disabled(driver, pages): pages.load("formPage.html") sel = Select(driver.find_element(By.NAME, disabledMultiSelect["name"])) with pytest.raises(NotImplementedError): sel.select_by_index(1) def test_select_by_value_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() for x in range(len(select["values"])): sel.select_by_value(select["values"][x].lower()) selected = sel.all_selected_options assert len(selected) == x + 1 for j in range(len(selected)): assert selected[j].text == select["values"][j] @pytest.mark.xfail_safari(reason="options incorrectly reported as enabled") def test_raises_exception_select_by_value_multiple_disabled(driver, pages): pages.load("formPage.html") sel = Select(driver.find_element(By.NAME, disabledMultiSelect["name"])) with pytest.raises(NotImplementedError): sel.select_by_value(disabledMultiSelect["values"][1].lower()) def test_select_by_visible_text_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() for x in range(len(select["values"])): sel.select_by_visible_text(select["values"][x]) selected = sel.all_selected_options assert len(selected) == x + 1 for j in range(len(selected)): assert selected[j].text == select["values"][j] @pytest.mark.xfail_safari(reason="options incorrectly reported as enabled") def test_raises_exception_select_by_text_multiple_disabled(driver, pages): pages.load("formPage.html") sel = Select(driver.find_element(By.NAME, disabledMultiSelect["name"])) with pytest.raises(NotImplementedError): sel.select_by_visible_text(disabledMultiSelect["values"][1]) def test_deselect_all_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2]: with pytest.raises(NotImplementedError): Select(driver.find_element(By.NAME, select["name"])).deselect_all() def test_deselect_all_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() assert len(sel.all_selected_options) == 0 def test_deselect_by_index_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2]: with pytest.raises(NotImplementedError): Select(driver.find_element(By.NAME, select["name"])).deselect_by_index(0) def test_deselect_by_value_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2]: with pytest.raises(NotImplementedError): Select(driver.find_element(By.NAME, select["name"])).deselect_by_value(select["values"][0].lower()) def test_deselect_by_visible_text_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2]: with pytest.raises(NotImplementedError): Select(driver.find_element(By.NAME, select["name"])).deselect_by_visible_text(select["values"][0]) def test_deselect_by_index_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() sel.select_by_index(0) sel.select_by_index(1) sel.select_by_index(2) sel.select_by_index(3) sel.deselect_by_index(1) sel.deselect_by_index(3) selected = sel.all_selected_options assert len(selected) == 2 assert selected[0].text == select["values"][0] assert selected[1].text == select["values"][2] def test_deselect_by_value_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() sel.select_by_index(0) sel.select_by_index(1) sel.select_by_index(2) sel.select_by_index(3) sel.deselect_by_value(select["values"][1].lower()) sel.deselect_by_value(select["values"][3].lower()) selected = sel.all_selected_options assert len(selected) == 2 assert selected[0].text == select["values"][0] assert selected[1].text == select["values"][2] def test_deselect_by_visible_text_multiple(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: sel = Select(driver.find_element(By.NAME, select["name"])) sel.deselect_all() sel.select_by_index(0) sel.select_by_index(1) sel.select_by_index(2) sel.select_by_index(3) sel.deselect_by_visible_text(select["values"][1]) sel.deselect_by_visible_text(select["values"][3]) selected = sel.all_selected_options assert len(selected) == 2 assert selected[0].text == select["values"][0] assert selected[1].text == select["values"][2] def test_get_options(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2, multiSelectValues1, multiSelectValues2]: opts = Select(driver.find_element(By.NAME, select["name"])).options assert len(opts) == len(select["values"]) for i in range(len(opts)): assert opts[i].text == select["values"][i] def test_get_all_selected_options_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2, disabledSelect]: opts = Select(driver.find_element(By.NAME, select["name"])).all_selected_options assert len(opts) == 1 assert opts[0].text == select["values"][0] def test_get_all_selected_options_multiple(driver, pages): pages.load("formPage.html") opts = Select(driver.find_element(By.NAME, multiSelectValues1["name"])).all_selected_options assert len(opts) == 2 assert opts[0].text, multiSelectValues1["values"][0] assert opts[1].text, multiSelectValues1["values"][2] opts = Select(driver.find_element(By.NAME, multiSelectValues2["name"])).all_selected_options assert len(opts) == 0 def test_get_first_selected_option_single(driver, pages): pages.load("formPage.html") for select in [singleSelectValues1, singleSelectValues2]: opt = Select(driver.find_element(By.NAME, select["name"])).first_selected_option assert opt.text == select["values"][0] def test_get_first_selected_option_multiple(driver, pages): pages.load("formPage.html") opt = Select(driver.find_element(By.NAME, multiSelectValues1["name"])).first_selected_option assert opt.text == multiSelectValues1["values"][0] opt = Select(driver.find_element(By.NAME, multiSelectValues2["name"])).all_selected_options assert len(opt) == 0 def test_raises_exception_for_invalid_tag_name(driver, pages): pages.load("formPage.html") with pytest.raises(UnexpectedTagNameException): Select(driver.find_element(By.TAG_NAME, "div")) def test_deselect_by_index_non_existent(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: with pytest.raises(NoSuchElementException): Select(driver.find_element(By.NAME, select["name"])).deselect_by_index(10) def test_deselect_by_value_non_existent(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: with pytest.raises(NoSuchElementException): Select(driver.find_element(By.NAME, select["name"])).deselect_by_value("not there") def test_deselect_by_text_non_existent(driver, pages): pages.load("formPage.html") for select in [multiSelectValues1, multiSelectValues2]: with pytest.raises(NoSuchElementException): Select(driver.find_element(By.NAME, select["name"])).deselect_by_visible_text("not there") selenium-selenium-4.18.1/test/selenium/webdriver/common/network.py0000644000175000017500000000407614564764517025303 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # module for getting the lan ip address of the computer import os import socket if os.name != "nt": import fcntl import struct def get_interface_ip(ifname): def _bytes(value, encoding): try: return bytes(value, encoding) # Python 3 except TypeError: return value # Python 2 sckt = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return socket.inet_ntoa( fcntl.ioctl(sckt.fileno(), 0x8915, struct.pack("256s", _bytes(ifname[:15], "utf-8")))[20:24] # SIOCGIFADDR ) def get_lan_ip(): if os.environ.get("CI") == "true": return "0.0.0.0" try: ip = socket.gethostbyname(socket.gethostname()) except Exception: return "0.0.0.0" if ip.startswith("127.") and os.name != "nt": interfaces = [ "eth0", "eth1", "eth2", "en0", "en1", "en2", "en3", "en4", "wlan0", "wlan1", "wifi0", "ath0", "ath1", "ppp0", ] for ifname in interfaces: try: ip = get_interface_ip(ifname) break except OSError: pass return ip selenium-selenium-4.18.1/test/selenium/webdriver/common/element_attribute_tests.py0000644000175000017500000002601214564764517030542 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By def test_should_return_null_when_getting_the_value_of_an_attribute_that_is_not_listed(driver, pages): pages.load("simpleTest.html") head = driver.find_element(By.XPATH, "/html") attribute = head.get_attribute("cheese") assert attribute is None def test_should_return_null_when_getting_src_attribute_of_invalid_img_tag(driver, pages): pages.load("simpleTest.html") img = driver.find_element(By.ID, "invalidImgTag") img_attr = img.get_attribute("src") assert img_attr is None def test_should_return_an_absolute_url_when_getting_src_attribute_of_avalid_img_tag(driver, pages): pages.load("simpleTest.html") img = driver.find_element(By.ID, "validImgTag") img_attr = img.get_attribute("src") assert "icon.gif" in img_attr def test_should_return_an_absolute_url_when_getting_href_attribute_of_avalid_anchor_tag(driver, pages): pages.load("simpleTest.html") img = driver.find_element(By.ID, "validAnchorTag") img_attr = img.get_attribute("href") assert "icon.gif" in img_attr def test_should_return_empty_attribute_values_when_present_and_the_value_is_actually_empty(driver, pages): pages.load("simpleTest.html") body = driver.find_element(By.XPATH, "//body") assert "" == body.get_attribute("style") def test_should_return_the_value_of_the_disabled_attribute_as_false_if_not_set(driver, pages): pages.load("formPage.html") inputElement = driver.find_element(By.XPATH, "//input[@id='working']") assert inputElement.get_attribute("disabled") is None assert inputElement.is_enabled() pElement = driver.find_element(By.ID, "peas") assert pElement.get_attribute("disabled") is None assert pElement.is_enabled() def test_should_return_the_value_of_the_index_attribute_even_if_it_is_missing(driver, pages): pages.load("formPage.html") multiSelect = driver.find_element(By.ID, "multi") options = multiSelect.find_elements(By.TAG_NAME, "option") assert "1" == options[1].get_attribute("index") def test_should_indicate_the_elements_that_are_disabled_are_not_is_enabled(driver, pages): pages.load("formPage.html") inputElement = driver.find_element(By.XPATH, "//input[@id='notWorking']") assert not inputElement.is_enabled() inputElement = driver.find_element(By.XPATH, "//input[@id='working']") assert inputElement.is_enabled() def test_elements_should_be_disabled_if_they_are_disabled_using_random_disabled_strings(driver, pages): pages.load("formPage.html") disabledTextElement1 = driver.find_element(By.ID, "disabledTextElement1") assert not disabledTextElement1.is_enabled() disabledTextElement2 = driver.find_element(By.ID, "disabledTextElement2") assert not disabledTextElement2.is_enabled() disabledSubmitElement = driver.find_element(By.ID, "disabledSubmitElement") assert not disabledSubmitElement.is_enabled() def test_should_indicate_when_atext_area_is_disabled(driver, pages): pages.load("formPage.html") textArea = driver.find_element(By.XPATH, "//textarea[@id='notWorkingArea']") assert not textArea.is_enabled() @pytest.mark.xfail_safari def test_should_throw_exception_if_sending_keys_to_element_disabled_using_random_disabled_strings(driver, pages): pages.load("formPage.html") disabledTextElement1 = driver.find_element(By.ID, "disabledTextElement1") with pytest.raises(WebDriverException): disabledTextElement1.send_keys("foo") assert "" == disabledTextElement1.text disabledTextElement2 = driver.find_element(By.ID, "disabledTextElement2") with pytest.raises(WebDriverException): disabledTextElement2.send_keys("bar") assert "" == disabledTextElement2.text def test_should_indicate_when_aselect_is_disabled(driver, pages): pages.load("formPage.html") enabled = driver.find_element(By.NAME, "selectomatic") disabled = driver.find_element(By.NAME, "no-select") assert enabled.is_enabled() assert not disabled.is_enabled() def test_should_return_the_value_of_checked_for_acheckbox_even_if_it_lacks_that_attribute(driver, pages): pages.load("formPage.html") checkbox = driver.find_element(By.XPATH, "//input[@id='checky']") assert checkbox.get_attribute("checked") is None checkbox.click() assert "true" == checkbox.get_attribute("checked") def test_should_return_the_value_of_selected_for_radio_buttons_even_if_they_lack_that_attribute(driver, pages): pages.load("formPage.html") neverSelected = driver.find_element(By.ID, "cheese") initiallyNotSelected = driver.find_element(By.ID, "peas") initiallySelected = driver.find_element(By.ID, "cheese_and_peas") assert neverSelected.get_attribute("checked") is None assert initiallyNotSelected.get_attribute("checked") is None assert "true" == initiallySelected.get_attribute("checked") initiallyNotSelected.click() assert neverSelected.get_attribute("selected") is None assert "true" == initiallyNotSelected.get_attribute("checked") assert initiallySelected.get_attribute("checked") is None def test_should_return_the_value_of_selected_for_options_in_selects_even_if_they_lack_that_attribute(driver, pages): pages.load("formPage.html") selectBox = driver.find_element(By.XPATH, "//select[@name='selectomatic']") options = selectBox.find_elements(By.TAG_NAME, "option") one = options[0] two = options[1] assert one.is_selected() assert not two.is_selected() assert "true" == one.get_attribute("selected") assert two.get_attribute("selected") is None def test_should_return_value_of_class_attribute_of_an_element(driver, pages): pages.load("xhtmlTest.html") heading = driver.find_element(By.XPATH, "//h1") classname = heading.get_attribute("class") assert "header" == classname # Disabled due to issues with Frames # def test_should_return_value_of_class_attribute_of_an_element_after_switching_iframe(driver, pages): # pages.load("iframes.html") # driver.switch_to.frame("iframe1") # # wallace = driver.find_element(By.XPATH, "//div[@id='wallace']") # classname = wallace.get_attribute("class") # assert "gromit" == classname def test_should_return_the_contents_of_atext_area_as_its_value(driver, pages): pages.load("formPage.html") value = driver.find_element(By.ID, "withText").get_attribute("value") assert "Example text" == value def test_should_return_the_contents_of_atext_area_as_its_value_when_set_to_non_norminal_true(driver, pages): pages.load("formPage.html") e = driver.find_element(By.ID, "withText") driver.execute_script("arguments[0].value = 'tRuE'", e) value = e.get_attribute("value") assert "tRuE" == value def test_should_treat_readonly_as_avalue(driver, pages): pages.load("formPage.html") element = driver.find_element(By.NAME, "readonly") readOnlyAttribute = element.get_attribute("readonly") textInput = driver.find_element(By.NAME, "x") notReadOnly = textInput.get_attribute("readonly") assert readOnlyAttribute != notReadOnly def test_should_get_numeric_attribute(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "withText") assert "5" == element.get_attribute("rows") def test_can_return_atext_approximation_of_the_style_attribute(driver, pages): pages.load("javascriptPage.html") style = driver.find_element(By.ID, "red-item").get_attribute("style") assert "background-color" in style.lower() def test_should_correctly_report_value_of_colspan(driver, pages): pages.load("tables.html") th1 = driver.find_element(By.ID, "th1") td2 = driver.find_element(By.ID, "td2") assert "th1" == th1.get_attribute("id") assert "3" == th1.get_attribute("colspan") assert "td2" == td2.get_attribute("id") assert "2" == td2.get_attribute("colspan") def test_can_retrieve_the_current_value_of_atext_form_field_text_input(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "working") assert "" == element.get_attribute("value") element.send_keys("hello world") assert "hello world" == element.get_attribute("value") def test_can_retrieve_the_current_value_of_atext_form_field_email_input(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "email") assert "" == element.get_attribute("value") element.send_keys("hello@example.com") assert "hello@example.com" == element.get_attribute("value") def test_can_retrieve_the_current_value_of_atext_form_field_text_area(driver, pages): pages.load("formPage.html") element = driver.find_element(By.ID, "emptyTextArea") assert "" == element.get_attribute("value") element.send_keys("hello world") assert "hello world" == element.get_attribute("value") def test_should_return_null_for_non_present_boolean_attributes(driver, pages): pages.load("booleanAttributes.html") element1 = driver.find_element(By.ID, "working") assert element1.get_attribute("required") is None @pytest.mark.xfail_ie def test_should_return_true_for_present_boolean_attributes(driver, pages): pages.load("booleanAttributes.html") element1 = driver.find_element(By.ID, "emailRequired") assert "true" == element1.get_attribute("required") element2 = driver.find_element(By.ID, "emptyTextAreaRequired") assert "true" == element2.get_attribute("required") element3 = driver.find_element(By.ID, "inputRequired") assert "true" == element3.get_attribute("required") element4 = driver.find_element(By.ID, "textAreaRequired") assert "true" == element4.get_attribute("required") @pytest.mark.xfail_chrome @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_should_get_unicode_chars_from_attribute(driver, pages): pages.load("formPage.html") title = driver.find_element(By.ID, "vsearchGadget").get_attribute("title") assert "Hvad s\xf8ger du?" == title @pytest.mark.xfail_chrome @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_should_get_values_and_not_miss_items(driver, pages): pages.load("attributes.html") expected = "4b273a33fbbd29013nN93dy4F1A~" result = driver.find_element(By.CSS_SELECTOR, "li").get_attribute("value") assert expected == result selenium-selenium-4.18.1/test/selenium/webdriver/common/web_components_tests.py0000644000175000017500000000552714564764517030060 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchShadowRootException from selenium.webdriver.common.by import By from selenium.webdriver.remote.shadowroot import ShadowRoot from selenium.webdriver.remote.webelement import WebElement @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_can_get_the_shadow_root_of_an_element(driver, pages): pages.load("webComponents.html") shadow_root = driver.find_element(By.CSS_SELECTOR, "custom-checkbox-element").shadow_root assert isinstance(shadow_root, ShadowRoot) @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_no_such_shadow_root_thrown_when_no_shadow_root(driver, pages): with pytest.raises(NoSuchShadowRootException): pages.load("simpleTest.html") driver.find_element(By.CSS_SELECTOR, "div").shadow_root @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_returns_shadow_root_via_execute_script(driver, pages): pages.load("webComponents.html") custom_element = driver.find_element(By.CSS_SELECTOR, "custom-checkbox-element") shadow_root = custom_element.shadow_root execute_shadow_root = driver.execute_script("return arguments[0].shadowRoot", custom_element) assert shadow_root == execute_shadow_root @pytest.mark.xfail_safari @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_find_element_in_a_shadowroot(driver, pages): pages.load("webComponents.html") custom_element = driver.find_element(By.CSS_SELECTOR, "custom-checkbox-element") shadow_root = custom_element.shadow_root element = shadow_root.find_element(By.CSS_SELECTOR, "input") assert isinstance(element, WebElement) @pytest.mark.xfail_safari @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_find_elements_in_a_shadow_root(driver, pages): pages.load("webComponents.html") custom_element = driver.find_element(By.CSS_SELECTOR, "custom-checkbox-element") shadow_root = custom_element.shadow_root elements = shadow_root.find_elements(By.CSS_SELECTOR, "input") assert len(elements) == 1 assert isinstance(elements[0], WebElement) selenium-selenium-4.18.1/test/selenium/webdriver/common/element_aria_tests.py0000644000175000017500000000341514564764517027455 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_should_return_explicitly_specified_role(driver): driver.get("data:text/html,
Level 1 Header
") header1 = driver.find_element(By.CSS_SELECTOR, "div") assert header1.aria_role == "heading" @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_should_return_implicit_role_defined_by_tag_name(driver): driver.get("data:text/html,

Level 1 Header

") header1 = driver.find_element(By.CSS_SELECTOR, "h1") assert header1.aria_role == "heading" @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote def test_should_return_explicit_role_even_if_it_contradicts_tag_name(driver): driver.get("data:text/html,

Level 1 Header

") header1 = driver.find_element(By.CSS_SELECTOR, "h1") assert header1.aria_role == "alert" selenium-selenium-4.18.1/test/selenium/webdriver/common/example2.py0000644000175000017500000000223414564764517025321 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from google_one_box import GoogleOneBox def test_search(driver): """This example shows how to use the page object pattern. For more information about this pattern, see: https://github.com/SeleniumHQ/selenium/wiki/PageObjects""" google = GoogleOneBox(driver, "http://www.google.com") res = google.search_for("cheese") assert res.link_contains_match_for("Wikipedia") selenium-selenium-4.18.1/test/selenium/webdriver/common/results_page.py0000644000175000017500000000265014564764517026303 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.common.by import By class ResultsPage: """This class models a google search result page.""" def __init__(self, driver): self._driver = driver def is_loaded(self): return "/search" in self._driver.get_current_url() def load(self): raise Exception("This page shouldn't be loaded directly") def link_contains_match_for(self, term): result_section = self._driver.find_element(By.ID, "res") elements = result_section.find_elements(By.XPATH, ".//*[@class='l']") for e in elements: if term in e.get_text(): return True return False selenium-selenium-4.18.1/test/selenium/webdriver/common/typing_tests.py0000644000175000017500000003242714564764517026347 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys def test_should_fire_key_press_events(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("a") result = driver.find_element(by=By.ID, value="result") assert "press:" in result.text def test_should_fire_key_down_events(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("I") result = driver.find_element(by=By.ID, value="result") assert "down" in result.text def test_should_fire_key_up_events(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("a") result = driver.find_element(by=By.ID, value="result") assert "up:" in result.text def test_should_type_lower_case_letters(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("abc def") assert keyReporter.get_attribute("value") == "abc def" def test_should_be_able_to_type_capital_letters(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("ABC DEF") assert keyReporter.get_attribute("value") == "ABC DEF" def test_should_be_able_to_type_quote_marks(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys('"') assert keyReporter.get_attribute("value") == '"' def test_should_be_able_to_type_the_at_character(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("@") assert keyReporter.get_attribute("value") == "@" def test_should_be_able_to_mix_upper_and_lower_case_letters(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("me@eXample.com") assert keyReporter.get_attribute("value") == "me@eXample.com" def test_arrow_keys_should_not_be_printable(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys(Keys.ARROW_LEFT) assert keyReporter.get_attribute("value") == "" def test_list_of_arrow_keys_should_not_be_printable(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys([Keys.ARROW_LEFT]) assert keyReporter.get_attribute("value") == "" def test_should_be_able_to_use_arrow_keys(driver, pages): pages.load("javascriptPage.html") keyReporter = driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("Tet", Keys.ARROW_LEFT, "s") assert keyReporter.get_attribute("value") == "Test" @pytest.mark.xfail_safari def test_will_simulate_akey_up_when_entering_text_into_input_elements(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyUp") element.send_keys("I like cheese") result = driver.find_element(by=By.ID, value="result") assert result.text == "I like cheese" @pytest.mark.xfail_safari def test_will_simulate_akey_down_when_entering_text_into_input_elements(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyDown") element.send_keys("I like cheese") result = driver.find_element(by=By.ID, value="result") # Because the key down gets the result before the input element is # filled, we're a letter short here assert result.text == "I like chees" @pytest.mark.xfail_safari def test_will_simulate_akey_press_when_entering_text_into_input_elements(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyPress") element.send_keys("I like cheese") result = driver.find_element(by=By.ID, value="result") # Because the key down gets the result before the input element is # filled, we're a letter short here assert result.text == "I like chees" @pytest.mark.xfail_safari def test_will_simulate_akey_up_when_entering_text_into_text_areas(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyUpArea") element.send_keys("I like cheese") result = driver.find_element(by=By.ID, value="result") assert result.text == "I like cheese" @pytest.mark.xfail_safari def test_will_simulate_akey_down_when_entering_text_into_text_areas(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyDownArea") element.send_keys("I like cheese") result = driver.find_element(by=By.ID, value="result") # Because the key down gets the result before the input element is # filled, we're a letter short here assert result.text == "I like chees" @pytest.mark.xfail_safari def test_will_simulate_akey_press_when_entering_text_into_text_areas(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyPressArea") element.send_keys("I like cheese") result = driver.find_element(by=By.ID, value="result") # Because the key down gets the result before the input element is # filled, we're a letter short here assert result.text == "I like chees" def test_should_report_key_code_of_arrow_keys_up_down_events(driver, pages): pages.load("javascriptPage.html") result = driver.find_element(by=By.ID, value="result") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys(Keys.ARROW_DOWN) assert "down: 40" in result.text.strip() assert "up: 40" in result.text.strip() element.send_keys(Keys.ARROW_UP) assert "down: 38" in result.text.strip() assert "up: 38" in result.text.strip() element.send_keys(Keys.ARROW_LEFT) assert "down: 37" in result.text.strip() assert "up: 37" in result.text.strip() element.send_keys(Keys.ARROW_RIGHT) assert "down: 39" in result.text.strip() assert "up: 39" in result.text.strip() # And leave no rubbish/printable keys in the "keyReporter" assert element.get_attribute("value") == "" def test_numeric_non_shift_keys(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") numericLineCharsNonShifted = "`1234567890-=[]\\,.'/42" element.send_keys(numericLineCharsNonShifted) assert element.get_attribute("value") == numericLineCharsNonShifted @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") def test_numeric_shift_keys(driver, pages): pages.load("javascriptPage.html") result = driver.find_element(by=By.ID, value="result") element = driver.find_element(by=By.ID, value="keyReporter") numericShiftsEtc = '~!@#$%^&*()_+{}:i"<>?|END~' element.send_keys(numericShiftsEtc) assert element.get_attribute("value") == numericShiftsEtc assert "up: 16" in result.text.strip() def test_lower_case_alpha_keys(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") lowerAlphas = "abcdefghijklmnopqrstuvwxyz" element.send_keys(lowerAlphas) assert element.get_attribute("value") == lowerAlphas @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") def test_uppercase_alpha_keys(driver, pages): pages.load("javascriptPage.html") result = driver.find_element(by=By.ID, value="result") element = driver.find_element(by=By.ID, value="keyReporter") upperAlphas = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" element.send_keys(upperAlphas) assert element.get_attribute("value") == upperAlphas assert "up: 16" in result.text.strip() @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") def test_all_printable_keys(driver, pages): pages.load("javascriptPage.html") result = driver.find_element(by=By.ID, value="result") element = driver.find_element(by=By.ID, value="keyReporter") allPrintable = "!\"#$%&'()*+,-./0123456789:<=>?@ ABCDEFGHIJKLMNOPQRSTUVWXYZ [\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" element.send_keys(allPrintable) assert element.get_attribute("value") == allPrintable assert "up: 16" in result.text.strip() def test_arrow_keys_and_page_up_and_down(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys(f"a{Keys.LEFT}b{Keys.RIGHT}{Keys.UP}{Keys.DOWN}{Keys.PAGE_UP}{Keys.PAGE_DOWN}1") assert element.get_attribute("value") == "ba1" # def test_home_and_end_and_page_up_and_page_down_keys(driver, pages): # // FIXME: macs don't have HOME keys, would PGUP work? # if (Platform.getCurrent().is(Platform.MAC)) { # return # } # pages.load("javascriptPage.html") # element = driver.find_element(by=By.ID, value="keyReporter") # element.send_keys("abc" + Keys.HOME + "0" + Keys.LEFT + Keys.RIGHT + # Keys.PAGE_UP + Keys.PAGE_DOWN + Keys.END + "1" + Keys.HOME + # "0" + Keys.PAGE_UP + Keys.END + "111" + Keys.HOME + "00") # assert element.get_attribute("value") == "0000abc1111" def test_delete_and_backspace_keys(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys("abcdefghi") assert element.get_attribute("value") == "abcdefghi" element.send_keys(Keys.LEFT, Keys.LEFT, Keys.DELETE) assert element.get_attribute("value") == "abcdefgi" element.send_keys(Keys.LEFT, Keys.LEFT, Keys.BACK_SPACE) assert element.get_attribute("value") == "abcdfgi" @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") def test_special_space_keys(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys("abcd" + Keys.SPACE + "fgh" + Keys.SPACE + "ij") assert element.get_attribute("value") == "abcd fgh ij" @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1255258") @pytest.mark.xfail_safari def test_numberpad_and_function_keys(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys( "abcd{}{}{}{}{}{}{}{}{}{}{}{}abcd".format( Keys.MULTIPLY, Keys.SUBTRACT, Keys.ADD, Keys.DECIMAL, Keys.SEPARATOR, Keys.NUMPAD0, Keys.NUMPAD9, Keys.ADD, Keys.SEMICOLON, Keys.EQUALS, Keys.DIVIDE, Keys.NUMPAD3, ) ) assert element.get_attribute("value") == "abcd*-+.,09+;=/3abcd" element.clear() element.send_keys("FUNCTION" + Keys.F2 + "-KEYS" + Keys.F2) element.send_keys("" + Keys.F2 + "-TOO" + Keys.F2) assert element.get_attribute("value") == "FUNCTION-KEYS-TOO" @pytest.mark.xfail_safari def test_shift_selection_deletes(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys("abcd efgh") assert element.get_attribute("value") == "abcd efgh" element.send_keys(Keys.SHIFT, Keys.LEFT, Keys.LEFT, Keys.LEFT) element.send_keys(Keys.DELETE) assert element.get_attribute("value") == "abcd e" def test_should_type_into_input_elements_that_have_no_type_attribute(driver, pages): pages.load("formPage.html") element = driver.find_element(by=By.ID, value="no-type") element.send_keys("Should Say Cheese") assert element.get_attribute("value") == "Should Say Cheese" def test_should_type_an_integer(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="keyReporter") element.send_keys(1234) assert element.get_attribute("value") == "1234" selenium-selenium-4.18.1/test/selenium/webdriver/common/bidi_tests.py0000644000175000017500000000666714564764517025753 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By from selenium.webdriver.common.log import Log from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1819965") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1819965") @pytest.mark.xfail_safari async def test_check_console_messages(driver, pages): async with driver.bidi_connection() as session: log = Log(driver, session) pages.load("javascriptPage.html") from selenium.webdriver.common.bidi.console import Console async with log.add_listener(Console.LOG) as messages: driver.execute_script("console.log('I love cheese')") assert messages["message"] == "I love cheese" @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1819965") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1819965") @pytest.mark.xfail_safari async def test_check_error_console_messages(driver, pages): async with driver.bidi_connection() as session: log = Log(driver, session) pages.load("javascriptPage.html") from selenium.webdriver.common.bidi.console import Console async with log.add_listener(Console.ERROR) as messages: driver.execute_script('console.error("I don\'t cheese")') driver.execute_script("console.log('I love cheese')") assert messages["message"] == "I don't cheese" @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote async def test_collect_js_exceptions(driver, pages): async with driver.bidi_connection() as session: log = Log(driver, session) pages.load("javascriptPage.html") async with log.add_js_error_listener() as exceptions: driver.find_element(By.ID, "throwing-mouseover").click() assert exceptions is not None assert exceptions.exception_details.stack_trace.call_frames[0].function_name == "onmouseover" @pytest.mark.xfail_firefox @pytest.mark.xfail_safari @pytest.mark.xfail_remote async def test_collect_log_mutations(driver, pages): async with driver.bidi_connection() as session: log = Log(driver, session) async with log.mutation_events() as event: pages.load("dynamic.html") driver.find_element(By.ID, "reveal").click() WebDriverWait(driver, 5).until(EC.visibility_of(driver.find_element(By.ID, "revealed"))) assert event["attribute_name"] == "style" assert event["current_value"] == "" assert event["old_value"] == "display:none;" selenium-selenium-4.18.1/test/selenium/webdriver/common/position_and_size_tests.py0000644000175000017500000001105514564764517030547 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By def test_should_be_able_to_determine_the_location_of_an_element(driver, pages): pages.load("xhtmlTest.html") location = driver.find_element(By.ID, "username").location_once_scrolled_into_view assert location["x"] > 0 assert location["y"] > 0 @pytest.mark.parametrize( "page", ( "coordinates_tests/simple_page.html", "coordinates_tests/page_with_empty_element.html", "coordinates_tests/page_with_transparent_element.html", "coordinates_tests/page_with_hidden_element.html", ), ids=("basic", "empty", "transparent", "hidden"), ) @pytest.mark.xfail_safari def test_should_get_coordinates_of_an_element(page, driver, pages): pages.load(page) element = driver.find_element(By.ID, "box") _check_location(element.location_once_scrolled_into_view, x=10, y=10) _check_location(element.location, x=10, y=10) @pytest.mark.xfail_safari def test_should_get_coordinates_of_an_invisible_element(driver, pages): pages.load("coordinates_tests/page_with_invisible_element.html") element = driver.find_element(By.ID, "box") _check_location(element.location_once_scrolled_into_view, x=0, y=0) _check_location(element.location, x=0, y=0) def test_should_scroll_page_and_get_coordinates_of_an_element_that_is_out_of_view_port(driver, pages): pages.load("coordinates_tests/page_with_element_out_of_view.html") element = driver.find_element(By.ID, "box") windowHeight = driver.get_window_size()["height"] _check_location(element.location_once_scrolled_into_view, x=10) assert 0 <= element.location_once_scrolled_into_view["y"] <= (windowHeight - 100) _check_location(element.location, x=10, y=5010) @pytest.mark.xfail_chrome @pytest.mark.xfail_chromiumedge @pytest.mark.xfail_firefox @pytest.mark.xfail_remote @pytest.mark.xfail_safari def test_should_get_coordinates_of_an_element_in_aframe(driver, pages): pages.load("coordinates_tests/element_in_frame.html") driver.switch_to.frame(driver.find_element(By.NAME, "ifr")) element = driver.find_element(By.ID, "box") _check_location(element.location_once_scrolled_into_view, x=25, y=25) _check_location(element.location, x=10, y=10) @pytest.mark.xfail_chrome @pytest.mark.xfail_chromiumedge @pytest.mark.xfail_firefox @pytest.mark.xfail_remote @pytest.mark.xfail_safari def test_should_get_coordinates_of_an_element_in_anested_frame(driver, pages): pages.load("coordinates_tests/element_in_nested_frame.html") driver.switch_to.frame(driver.find_element(By.NAME, "ifr")) driver.switch_to.frame(driver.find_element(By.NAME, "ifr")) element = driver.find_element(By.ID, "box") _check_location(element.location_once_scrolled_into_view, x=40, y=40) _check_location(element.location, x=10, y=10) def test_should_get_coordinates_of_an_element_with_fixed_position(driver, pages): pages.load("coordinates_tests/page_with_fixed_element.html") element = driver.find_element(By.ID, "fixed") _check_location(element.location_once_scrolled_into_view, y=0) _check_location(element.location, y=0) driver.find_element(By.ID, "bottom").click() _check_location(element.location_once_scrolled_into_view, y=0) assert element.location["y"] > 0 def test_should_correctly_identify_that_an_element_has_width_and_height(driver, pages): pages.load("xhtmlTest.html") shrinko = driver.find_element(By.ID, "linkId") size = shrinko.size assert size["width"] > 0 assert size["height"] > 0 def _check_location(location, **kwargs): try: # python 2.x expected = kwargs.viewitems() actual = location.viewitems() except AttributeError: # python 3.x expected = kwargs.items() actual = location.items() assert expected <= actual selenium-selenium-4.18.1/test/selenium/webdriver/common/opacity_tests.py0000644000175000017500000000337714564764517026507 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By @pytest.mark.xfail_ie def test_should_be_able_to_click_on_elements_with_opacity_zero(driver, pages): pages.load("click_jacker.html") element = driver.find_element(By.ID, "clickJacker") assert "0" == element.value_of_css_property("opacity"), ( "Precondition failed: clickJacker should be transparent.\ Value was %s" % element.value_of_css_property("opacity") ) element.click() assert "1" == element.value_of_css_property("opacity") @pytest.mark.xfail_ie def test_should_be_able_to_select_options_from_an_invisible_select(driver, pages): pages.load("formPage.html") select = driver.find_element(By.ID, "invisi_select") options = select.find_elements(By.TAG_NAME, "option") apples = options[0] oranges = options[1] assert apples.is_selected() assert not oranges.is_selected() oranges.click() assert not apples.is_selected() assert oranges.is_selected() selenium-selenium-4.18.1/test/selenium/webdriver/common/webserver.py0000644000175000017500000001522714564764517025616 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """A simple web server for testing purpose. It serves the testing html pages that are needed by the webdriver unit tests.""" import contextlib import logging import os import re import threading try: from urllib import request as urllib_request except ImportError: import urllib as urllib_request try: from http.server import BaseHTTPRequestHandler from http.server import HTTPServer from socketserver import ThreadingMixIn except ImportError: from BaseHTTPServer import BaseHTTPRequestHandler from BaseHTTPServer import HTTPServer from SocketServer import ThreadingMixIn def updir(): dirname = os.path.dirname return dirname(dirname(__file__)) LOGGER = logging.getLogger(__name__) WEBDRIVER = os.environ.get("WEBDRIVER", updir()) HTML_ROOT = os.path.join(WEBDRIVER, "../../../../common/src/web") if not os.path.isdir(HTML_ROOT): message = ( "Can't find 'common_web' directory, try setting WEBDRIVER" " environment variable WEBDRIVER:" + WEBDRIVER + " HTML_ROOT:" + HTML_ROOT ) LOGGER.error(message) assert 0, message DEFAULT_HOST = "localhost" DEFAULT_HOST_IP = "127.0.0.1" DEFAULT_PORT = 8000 class HtmlOnlyHandler(BaseHTTPRequestHandler): """Http handler.""" def do_GET(self): """GET method handler.""" try: path = self.path[1:].split("?")[0] if path[:5] == "page/": html = """Page{page_number} Page number {page_number}

top """.format( page_number=path[5:] ) html = html.encode("utf-8") else: with open(os.path.join(HTML_ROOT, path), encoding="latin-1") as f: html = f.read().encode("utf-8") self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() self.wfile.write(html) except OSError: self.send_error(404, f"File Not Found: {path}") def do_POST(self): """POST method handler.""" try: remaining_bytes = int(self.headers["content-length"]) contents = "" line = self.rfile.readline() contents += line.decode("utf-8") remaining_bytes -= len(line) line = self.rfile.readline() contents += line.decode("utf-8") remaining_bytes -= len(line) fn = re.findall(r'Content-Disposition.*name="upload"; filename="(.*)"', line.decode("utf-8")) if not fn: self.send_error(500, f"File not found. {contents}") return line = self.rfile.readline() remaining_bytes -= len(line) contents += line.decode("utf-8") line = self.rfile.readline() remaining_bytes -= len(line) contents += line.decode("utf-8") preline = self.rfile.readline() remaining_bytes -= len(preline) while remaining_bytes > 0: line = self.rfile.readline() remaining_bytes -= len(line) contents += line.decode("utf-8") self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() self.wfile.write( f""" {contents} """.encode() ) except Exception as e: self.send_error(500, f"Error found: {e}") def log_message(self, format, *args): """Override default to avoid trashing stderr""" pass class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): pass class SimpleWebServer: """A very basic web server.""" def __init__(self, host=DEFAULT_HOST_IP, port=DEFAULT_PORT): self.stop_serving = False host = host port = port while True: try: self.server = ThreadedHTTPServer((host, port), HtmlOnlyHandler) self.host = host self.port = port break except OSError: LOGGER.debug(f"port {port} is in use, trying to next one") port += 1 self.thread = threading.Thread(target=self._run_web_server) def _run_web_server(self): """Runs the server loop.""" LOGGER.debug("web server started") while not self.stop_serving: self.server.handle_request() self.server.server_close() def start(self): """Starts the server.""" self.thread.start() def stop(self): """Stops the server.""" self.stop_serving = True with contextlib.suppress(IOError): _ = urllib_request.urlopen(f"http://{self.host}:{self.port}") def where_is(self, path, localhost=False) -> str: # True force serve the page from localhost if localhost: return f"http://{DEFAULT_HOST}:{self.port}/{path}" return f"http://{self.host}:{self.port}/{path}" def main(argv=None): from optparse import OptionParser from time import sleep if argv is None: import sys argv = sys.argv parser = OptionParser("%prog [options]") parser.add_option( "-p", "--port", dest="port", type="int", help=f"port to listen (default: {DEFAULT_PORT})", default=DEFAULT_PORT ) opts, args = parser.parse_args(argv[1:]) if args: parser.error("wrong number of arguments") # Will exit server = SimpleWebServer(port=opts.port) server.start() print(f"Server started on port {opts.port}, hit CTRL-C to quit") try: while 1: sleep(0.1) except KeyboardInterrupt: pass if __name__ == "__main__": main() selenium-selenium-4.18.1/test/selenium/webdriver/common/print_pdf_tests.py0000644000175000017500000000456114564764517027020 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.print_page_options import PrintOptions START_INDEX = 0 END_INDEX = 5 PDF_MAGIC_NUMBER = "JVBER" @pytest.mark.xfail_safari(reason="no endpoint for print in safari") def test_pdf_with_2_pages(driver, pages): print_options = PrintOptions() print_options.page_ranges = ["1-2"] pages.load("printPage.html") base64code = driver.print_page(print_options) assert base64code[START_INDEX:END_INDEX] == PDF_MAGIC_NUMBER @pytest.mark.xfail_safari(reason="no endpoint for print in safari") def test_pdf_with_all_pages(driver, pages): pages.load("printPage.html") base64code = driver.print_page() assert base64code[START_INDEX:END_INDEX] == PDF_MAGIC_NUMBER @pytest.mark.xfail_safari(reason="no endpoint for print in safari") def test_valid_params(driver, pages): print_options = PrintOptions() print_options.page_ranges = ["1-2"] print_options.orientation = "landscape" print_options.width = 30 pages.load("printPage.html") base64code = driver.print_page(print_options) assert base64code[START_INDEX:END_INDEX] == PDF_MAGIC_NUMBER @pytest.mark.xfail_safari(reason="no endpoint for print in safari") def test_session_id_is_not_preserved_after_page_is_printed(driver, pages): print_options = PrintOptions() print_options.margin_bottom = print_options.margin_top = print_options.margin_left = print_options.margin_right = 0 assert "sessionId" not in print_options.to_dict() pages.load("printPage.html") driver.print_page(print_options=print_options) assert "sessionId" not in print_options.to_dict() selenium-selenium-4.18.1/test/selenium/webdriver/common/test_file.txt0000644000175000017500000000003314564764517025744 0ustar carstencarstenlorem ipsum dolor sit amet selenium-selenium-4.18.1/test/selenium/webdriver/common/text_handling_tests.py0000644000175000017500000001610214564764517027655 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By newLine = "\n" def test_should_return_the_text_content_of_asingle_element_with_no_children(driver, pages): pages.load("simpleTest.html") selectText = driver.find_element(by=By.ID, value="oneline").text assert selectText == "A single line of text" getText = driver.find_element(by=By.ID, value="oneline").text assert getText == "A single line of text" def test_should_return_the_entire_text_content_of_child_elements(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="multiline").text assert "A div containing" in text assert "More than one line of text" in text assert "and block level elements" in text @pytest.mark.xfail_safari def test_should_ignore_script_elements(driver, pages): pages.load("javascriptEnhancedForm.html") labelForUsername = driver.find_element(by=By.ID, value="labelforusername") text = labelForUsername.text assert len(labelForUsername.find_elements(by=By.TAG_NAME, value="script")) == 1 assert "document.getElementById" not in text assert text == "Username:" @pytest.mark.xfail_safari def test_should_represent_ablock_level_element_as_anewline(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="multiline").text assert text.startswith("A div containing" + newLine) assert "More than one line of text" + newLine in text assert text.endswith("and block level elements") @pytest.mark.xfail_safari def test_should_collapse_multiple_whitespace_characters_into_asingle_space(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="lotsofspaces").text assert text == "This line has lots of spaces." @pytest.mark.xfail_safari def test_should_trim_text(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="multiline").text assert text.startswith("A div containing") assert text.endswith("block level elements") @pytest.mark.xfail_safari def test_should_convert_anon_breaking_space_into_anormal_space_character(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="nbsp").text assert text == "This line has a non-breaking space" @pytest.mark.xfail_safari def test_should_treat_anon_breaking_space_as_any_other_whitespace_character_when_collapsing_whitespace(driver, pages): pages.load("simpleTest.html") element = driver.find_element(by=By.ID, value="nbspandspaces") text = element.text assert text == "This line has a non-breaking space and spaces" @pytest.mark.xfail_safari def test_having_inline_elements_should_not_affect_how_text_is_returned(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="inline").text assert text == "This line has text within elements that are meant to be displayed inline" @pytest.mark.xfail_safari def test_should_return_the_entire_text_of_inline_elements(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="span").text assert text == "An inline element" def test_should_be_able_to_set_more_than_one_line_of_text_in_atext_area(driver, pages): pages.load("formPage.html") textarea = driver.find_element(by=By.ID, value="withText") textarea.clear() expectedText = "I like cheese" + newLine + newLine + "It's really nice" textarea.send_keys(expectedText) seenText = textarea.get_attribute("value") assert seenText == expectedText def test_should_be_able_to_enter_dates_after_filling_in_other_values_first(driver, pages): pages.load("formPage.html") input_ = driver.find_element(by=By.ID, value="working") expectedValue = "10/03/2007 to 30/07/1993" input_.send_keys(expectedValue) seenValue = input_.get_attribute("value") assert seenValue == expectedValue @pytest.mark.xfail_safari def test_should_return_empty_string_when_text_is_only_spaces(driver, pages): pages.load("xhtmlTest.html") text = driver.find_element(by=By.ID, value="spaces").text assert text == "" def test_should_return_empty_string_when_text_is_empty(driver, pages): pages.load("xhtmlTest.html") text = driver.find_element(by=By.ID, value="empty").text assert text == "" @pytest.mark.xfail def test_should_return_empty_string_when_tag_is_self_closing(driver, pages): pages.load("xhtmlFormPage.xhtml") text = driver.find_element(by=By.ID, value="self-closed").text assert text == "" @pytest.mark.xfail_safari def test_should_handle_sibling_block_level_elements(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="twoblocks").text assert text == "Some text" + newLine + "Some more text" @pytest.mark.xfail_safari def test_should_handle_whitespace_in_inline_elements(driver, pages): pages.load("simpleTest.html") text = driver.find_element(by=By.ID, value="inlinespan").text assert text == "line has text" def test_read_alarge_amount_of_data(driver, pages): pages.load("macbeth.html") source = driver.page_source.strip().lower() assert source.endswith("") @pytest.mark.xfail_safari def test_should_only_include_visible_text(driver, pages): pages.load("javascriptPage.html") empty = driver.find_element(by=By.ID, value="suppressedParagraph").text explicit = driver.find_element(by=By.ID, value="outer").text assert "" == empty assert "sub-element that is explicitly visible" == explicit @pytest.mark.xfail_safari def test_should_get_text_from_table_cells(driver, pages): pages.load("tables.html") tr = driver.find_element(by=By.ID, value="hidden_text") text = tr.text assert "some text" in text assert "some more text" not in text def test_should_get_text_which_is_avalid_jsonobject(driver, pages): pages.load("simpleTest.html") element = driver.find_element(by=By.ID, value="simpleJsonText") assert '{a="b", c=1, d=true}' == element.text # assert "{a=\"b\", \"c\"=d, e=true, f=\\123\\\\g\\\\\"\"\"\\\'}", element.text) def test_should_get_text_which_is_avalid_complex_jsonobject(driver, pages): pages.load("simpleTest.html") element = driver.find_element(by=By.ID, value="complexJsonText") assert """{a=\"\\\\b\\\\\\\"\'\\\'\"}""" == element.text selenium-selenium-4.18.1/test/selenium/webdriver/common/visibility_tests.py0000644000175000017500000001315414564764517027220 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import ElementNotInteractableException from selenium.common.exceptions import ElementNotVisibleException from selenium.webdriver.common.by import By def test_should_allow_the_user_to_tell_if_an_element_is_displayed_or_not(driver, pages): pages.load("javascriptPage.html") assert driver.find_element(by=By.ID, value="displayed").is_displayed() is True assert driver.find_element(by=By.ID, value="none").is_displayed() is False assert driver.find_element(by=By.ID, value="suppressedParagraph").is_displayed() is False assert driver.find_element(by=By.ID, value="hidden").is_displayed() is False def test_visibility_should_take_into_account_parent_visibility(driver, pages): pages.load("javascriptPage.html") childDiv = driver.find_element(by=By.ID, value="hiddenchild") hiddenLink = driver.find_element(by=By.ID, value="hiddenlink") assert childDiv.is_displayed() is False assert hiddenLink.is_displayed() is False def test_should_count_elements_as_visible_if_style_property_has_been_set(driver, pages): pages.load("javascriptPage.html") shown = driver.find_element(by=By.ID, value="visibleSubElement") assert shown.is_displayed() is True @pytest.mark.xfail_safari def test_should_modify_the_visibility_of_an_element_dynamically(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="hideMe") assert element.is_displayed() is True element.click() assert element.is_displayed() is False def test_hidden_input_elements_are_never_visible(driver, pages): pages.load("javascriptPage.html") shown = driver.find_element(by=By.NAME, value="hidden") assert shown.is_displayed() is False def test_should_not_be_able_to_click_on_an_element_that_is_not_displayed(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="unclickable") try: element.click() assert 1 == 0, "should have thrown an exception" except (ElementNotVisibleException, ElementNotInteractableException): pass def test_should_not_be_able_to_toggle_an_element_that_is_not_displayed(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="untogglable") try: element.click() assert 1 == 0, "should have thrown an exception" except (ElementNotVisibleException, ElementNotInteractableException): pass def test_should_not_be_able_to_select_an_element_that_is_not_displayed(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="untogglable") try: element.click() assert 1 == 0, "should have thrown an exception" except (ElementNotVisibleException, ElementNotInteractableException): pass def test_should_not_be_able_to_type_an_element_that_is_not_displayed(driver, pages): pages.load("javascriptPage.html") element = driver.find_element(by=By.ID, value="unclickable") try: element.send_keys("You don't see me") assert 1 == 0, "should have thrown an exception" except (ElementNotVisibleException, ElementNotInteractableException): pass assert element.get_attribute("value") != "You don't see me" def test_should_say_elements_with_negative_transform_are_not_displayed(driver, pages): pages.load("cssTransform.html") elementX = driver.find_element(By.ID, value="parentX") assert elementX.is_displayed() is False elementY = driver.find_element(By.ID, value="parentY") assert elementY.is_displayed() is False def test_should_say_elements_with_parent_with_negative_transform_are_not_displayed(driver, pages): pages.load("cssTransform.html") elementX = driver.find_element(By.ID, value="childX") assert elementX.is_displayed() is False elementY = driver.find_element(By.ID, value="childY") assert elementY.is_displayed() is False def test_should_say_element_with_zero_transform_is_visible(driver, pages): pages.load("cssTransform.html") zero_tranform = driver.find_element(By.ID, "zero-tranform") assert zero_tranform.is_displayed() is True def test_should_say_element_is_visible_when_it_has_negative_transform_but_elementisnt_in_anegative_space(driver, pages): pages.load("cssTransform2.html") zero_tranform = driver.find_element(By.ID, "negative-percentage-transformY") assert zero_tranform.is_displayed() is True def test_should_show_element_not_visible_with_hidden_attribute(driver, pages): pages.load("hidden.html") singleHidden = driver.find_element(By.ID, "singleHidden") assert singleHidden.is_displayed() is False def test_should_show_element_not_visible_when_parent_element_has_hidden_attribute(driver, pages): pages.load("hidden.html") child = driver.find_element(By.ID, "child") assert child.is_displayed() is False selenium-selenium-4.18.1/test/selenium/webdriver/common/alerts_tests.py0000644000175000017500000002345614564764517026331 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import sys import pytest from selenium.common.exceptions import InvalidElementStateException from selenium.common.exceptions import NoAlertPresentException from selenium.common.exceptions import UnexpectedAlertPresentException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait @pytest.fixture(autouse=True) def close_alert(driver): yield try: driver.switch_to.alert.dismiss() except Exception: pass def test_should_be_able_to_override_the_window_alert_method(driver, pages): pages.load("alerts.html") driver.execute_script("window.alert = function(msg) { document.getElementById('text').innerHTML = msg; }") driver.find_element(by=By.ID, value="alert").click() try: assert driver.find_element(By.ID, "text").text == "cheese" except Exception as e: # if we're here, likely the alert is displayed # not dismissing it will affect other tests try: _wait_for_alert(driver).dismiss() except Exception: pass raise e def test_should_allow_users_to_accept_an_alert_manually(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="alert").click() alert = _wait_for_alert(driver) alert.accept() # If we can perform any action, we're good to go assert "Testing Alerts" == driver.title def test_should_allow_users_to_accept_an_alert_with_no_text_manually(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "empty-alert").click() alert = _wait_for_alert(driver) alert.accept() # If we can perform any action, we're good to go assert "Testing Alerts" == driver.title def test_should_get_text_of_alert_opened_in_set_timeout(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "slow-alert").click() # DO NOT WAIT OR SLEEP HERE # This is a regression test for a bug where only the first switchTo call would throw, # and only if it happens before the alert actually loads. alert = _wait_for_alert(driver) try: assert "Slow" == alert.text finally: alert.accept() def test_should_allow_users_to_dismiss_an_alert_manually(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="alert").click() alert = _wait_for_alert(driver) alert.dismiss() # If we can perform any action, we're good to go assert "Testing Alerts" == driver.title def test_should_allow_auser_to_accept_aprompt(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="prompt").click() alert = _wait_for_alert(driver) alert.accept() # If we can perform any action, we're good to go assert "Testing Alerts" == driver.title def test_should_allow_auser_to_dismiss_aprompt(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="prompt").click() alert = _wait_for_alert(driver) alert.dismiss() # If we can perform any action, we're good to go assert "Testing Alerts" == driver.title def test_should_allow_auser_to_set_the_value_of_aprompt(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="prompt").click() alert = _wait_for_alert(driver) alert.send_keys("cheese") alert.accept() result = driver.find_element(by=By.ID, value="text").text assert "cheese" == result @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_setting_the_value_of_an_alert_throws(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "alert").click() alert = _wait_for_alert(driver) with pytest.raises(InvalidElementStateException): alert.send_keys("cheese") alert.accept() @pytest.mark.xfail_chrome( condition=sys.platform == "darwin", reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=26", run=False ) @pytest.mark.xfail_chromiumedge( condition=sys.platform == "darwin", reason="https://bugs.chromium.org/p/chromedriver/issues/detail?id=26", run=False ) def test_alert_should_not_allow_additional_commands_if_dimissed(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "alert").click() alert = _wait_for_alert(driver) alert.dismiss() with pytest.raises(NoAlertPresentException): alert.text @pytest.mark.xfail_firefox(reason="Fails on travis") @pytest.mark.xfail_remote(reason="Fails on travis") @pytest.mark.xfail_safari def test_should_allow_users_to_accept_an_alert_in_aframe(driver, pages): pages.load("alerts.html") driver.switch_to.frame(driver.find_element(By.NAME, "iframeWithAlert")) driver.find_element(By.ID, "alertInFrame").click() alert = _wait_for_alert(driver) alert.accept() assert "Testing Alerts" == driver.title @pytest.mark.xfail_firefox(reason="Fails on travis") @pytest.mark.xfail_remote(reason="Fails on travis") @pytest.mark.xfail_safari def test_should_allow_users_to_accept_an_alert_in_anested_frame(driver, pages): pages.load("alerts.html") driver.switch_to.frame(driver.find_element(By.NAME, "iframeWithIframe")) driver.switch_to.frame(driver.find_element(By.NAME, "iframeWithAlert")) driver.find_element(By.ID, "alertInFrame").click() alert = _wait_for_alert(driver) alert.accept() assert "Testing Alerts" == driver.title def test_should_throw_an_exception_if_an_alert_has_not_been_dealt_with_and_dismiss_the_alert(): pass # //TODO(David) Complete this test def test_prompt_should_use_default_value_if_no_keys_sent(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "prompt-with-default").click() alert = _wait_for_alert(driver) alert.accept() txt = driver.find_element(By.ID, "text").text assert "This is a default value" == txt def test_prompt_should_have_null_value_if_dismissed(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "prompt-with-default").click() alert = _wait_for_alert(driver) alert.dismiss() assert "null" == driver.find_element(By.ID, "text").text def test_handles_two_alerts_from_one_interaction(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "double-prompt").click() alert1 = _wait_for_alert(driver) alert1.send_keys("brie") alert1.accept() alert2 = _wait_for_alert(driver) alert2.send_keys("cheddar") alert2.accept() assert driver.find_element(By.ID, "text1").text == "brie" assert driver.find_element(By.ID, "text2").text == "cheddar" @pytest.mark.xfail_safari def test_should_handle_alert_on_page_load(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "open-page-with-onload-alert").click() alert = _wait_for_alert(driver) value = alert.text alert.accept() assert "onload" == value def test_should_handle_alert_on_page_load_using_get(driver, pages): pages.load("pageWithOnLoad.html") alert = _wait_for_alert(driver) value = alert.text alert.accept() assert "onload" == value WebDriverWait(driver, 3).until( EC.text_to_be_present_in_element((By.TAG_NAME, "p"), "Page with onload event handler") ) @pytest.mark.xfail_chrome(reason="Non W3C conformant") @pytest.mark.xfail_chromiumedge(reason="Non W3C conformant") def test_should_handle_alert_on_page_before_unload(driver, pages): pages.load("pageWithOnBeforeUnloadMessage.html") element = driver.find_element(By.ID, "navigate") element.click() WebDriverWait(driver, 3).until(EC.title_is("Testing Alerts")) def test_should_allow_the_user_to_get_the_text_of_an_alert(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="alert").click() alert = _wait_for_alert(driver) value = alert.text alert.accept() assert "cheese" == value def test_should_allow_the_user_to_get_the_text_of_aprompt(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "prompt").click() alert = _wait_for_alert(driver) value = alert.text alert.accept() assert "Enter something" == value def test_alert_should_not_allow_additional_commands_if_dismissed(driver, pages): pages.load("alerts.html") driver.find_element(By.ID, "alert").click() alert = _wait_for_alert(driver) alert.accept() with pytest.raises(NoAlertPresentException): alert.text @pytest.mark.xfail_firefox(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1279211") @pytest.mark.xfail_remote(reason="https://bugzilla.mozilla.org/show_bug.cgi?id=1279211") @pytest.mark.xfail_chrome def test_unexpected_alert_present_exception_contains_alert_text(driver, pages): pages.load("alerts.html") driver.find_element(by=By.ID, value="alert").click() alert = _wait_for_alert(driver) value = alert.text with pytest.raises(UnexpectedAlertPresentException) as e: pages.load("simpleTest.html") assert value == e.value.alert_text assert f"Alert Text: {value}" in str(e) def _wait_for_alert(driver): return WebDriverWait(driver, 3).until(EC.alert_is_present()) selenium-selenium-4.18.1/test/selenium/webdriver/common/window_tests.py0000644000175000017500000001413214564764517026335 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.support.wait import WebDriverWait # @pytest.mark.xfail_ie # @pytest.mark.xfail_chromiumedge(reason="Fails on Travis") # @pytest.mark.xfail_firefox(reason="Fails on Travis") # @pytest.mark.xfail_remote(reason="Fails on Travis") # def test_should_maximize_the_window(driver): # resize_timeout = 5 # wait = WebDriverWait(driver, resize_timeout) # old_size = driver.get_window_size() # driver.set_window_size(200, 200) # wait.until( # lambda dr: dr.get_window_size() != old_size if old_size["width"] != 200 and old_size["height"] != 200 else True) # size = driver.get_window_size() # driver.maximize_window() # wait.until(lambda dr: dr.get_window_size() != size) # new_size = driver.get_window_size() # assert new_size["width"] > size["width"] # assert new_size["height"] > size["height"] def test_should_get_the_size_of_the_current_window(driver): size = driver.get_window_size() assert size.get("width") > 0 assert size.get("height") > 0 def test_should_set_the_size_of_the_current_window(driver): size = driver.get_window_size() target_width = size.get("width") - 20 target_height = size.get("height") - 20 driver.set_window_size(width=target_width, height=target_height) new_size = driver.get_window_size() assert new_size.get("width") == target_width assert new_size.get("height") == target_height @pytest.mark.xfail_chrome def test_should_get_the_position_of_the_current_window(driver): position = driver.get_window_position() assert position.get("x") >= 0 assert position.get("y") >= 0 def test_should_set_the_position_of_the_current_window(driver): position = driver.get_window_position() target_x = position.get("x") + 10 target_y = position.get("y") + 10 driver.set_window_position(x=target_x, y=target_y) WebDriverWait(driver, 2).until( lambda d: d.get_window_position()["x"] != position["x"] and d.get_window_position()["y"] != position["y"] ) new_position = driver.get_window_position() assert new_position.get("x") == target_x assert new_position.get("y") == target_y @pytest.mark.xfail_safari(raises=WebDriverException, reason="Get Window Rect command not implemented") @pytest.mark.xfail_chrome def test_should_get_the_rect_of_the_current_window(driver): rect = driver.get_window_rect() assert rect.get("x") >= 0 assert rect.get("y") >= 0 assert rect.get("width") >= 0 assert rect.get("height") >= 0 @pytest.mark.xfail_safari(raises=WebDriverException, reason="Get Window Rect command not implemented") def test_should_set_the_rect_of_the_current_window(driver): rect = driver.get_window_rect() target_x = rect.get("x") + 10 target_y = rect.get("y") + 10 target_width = rect.get("width") + 10 target_height = rect.get("height") + 10 driver.set_window_rect(x=target_x, y=target_y, width=target_width, height=target_height) WebDriverWait(driver, 2).until( lambda d: d.get_window_position()["x"] != rect["x"] and d.get_window_position()["y"] != rect["y"] ) new_rect = driver.get_window_rect() assert new_rect.get("x") == target_x assert new_rect.get("y") == target_y assert new_rect.get("width") == target_width assert new_rect.get("height") == target_height def test_set_window_rect_should_accept_0_as_x_and_y(driver): from selenium.common.exceptions import InvalidArgumentException try: driver.set_window_rect(x=0, y=0) except InvalidArgumentException: pytest.fail("Should not have thrown InvalidArgumentException") def test_set_window_rect_throws_when_height_and_width_are_0(driver): from selenium.common.exceptions import InvalidArgumentException with pytest.raises(InvalidArgumentException): driver.set_window_rect(height=0, width=0) # @pytest.mark.xfail_safari(raises=WebDriverException, # reason='Fullscreen command not implemented') # @pytest.mark.skipif(os.environ.get('TRAVIS') == 'true', # reason='Fullscreen command causes Travis to hang') # @pytest.mark.no_driver_after_test # def test_should_fullscreen_the_current_window(driver): # start_width = driver.execute_script('return window.innerWidth;') # start_height = driver.execute_script('return window.innerHeight;') # driver.fullscreen_window() # WebDriverWait(driver, 2)\ # .until(lambda d: driver.execute_script('return window.innerWidth;') > start_width) # end_width = driver.execute_script('return window.innerWidth;') # end_height = driver.execute_script('return window.innerHeight;') # driver.quit() # Kill driver so we aren't running fullscreen after # assert end_width > start_width # assert end_height > start_height # @pytest.mark.xfail_safari(raises=WebDriverException, # reason='Minimize command not implemented') # @pytest.mark.skipif(os.environ.get('TRAVIS') == 'true', # reason='Minimize command causes Travis to hang') # @pytest.mark.no_driver_after_test # def test_should_minimize_the_current_window(driver): # driver.minimize_window() # minimized = driver.execute_script('return document.hidden;') # driver.quit() # Kill driver so we aren't running minimized after # assert minimized is True selenium-selenium-4.18.1/test/selenium/webdriver/common/interactions_with_device_tests.py0000644000175000017500000003306314564764517032106 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """Tests for advanced user interactions.""" import pytest from selenium.common.exceptions import MoveTargetOutOfBoundsException from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.actions import interaction from selenium.webdriver.common.actions.key_input import KeyInput from selenium.webdriver.common.actions.pointer_input import PointerInput from selenium.webdriver.common.actions.wheel_input import ScrollOrigin from selenium.webdriver.common.actions.wheel_input import WheelInput from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait def _is_element_available(driver, id): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" try: driver.find_element(By.ID, id) return True except Exception: return False @pytest.mark.xfail_safari @pytest.mark.xfail_chrome def test_drag_and_drop_with_pointer(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" element_available_timeout = 15 wait = WebDriverWait(driver, element_available_timeout) pages.load("droppableItems.html") wait.until(lambda dr: _is_element_available(driver, "draggable")) if not _is_element_available(driver, "draggable"): raise AssertionError("Could not find draggable element after 15 seconds.") toDrag = driver.find_element(By.ID, "draggable") dropInto = driver.find_element(By.ID, "droppable") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") holdDrag = ActionChains(driver, devices=[mouse]).click_and_hold(toDrag) move = ActionChains(driver, devices=[mouse]).move_to_element(dropInto) drop = ActionChains(driver, devices=[mouse]).release(dropInto) holdDrag.perform() move.perform() drop.perform() dropInto = driver.find_element(By.ID, "droppable") text = dropInto.find_element(By.TAG_NAME, "p").text assert "Dropped!" == text @pytest.mark.xfail_safari def test_double_click_with_pointer(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toDoubleClick = driver.find_element(By.ID, "doubleClickField") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") dblClick = ActionChains(driver, devices=[mouse]).double_click(toDoubleClick) dblClick.perform() assert "DoubleClicked" == toDoubleClick.get_attribute("value") def test_context_click_with_pointer(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toContextClick = driver.find_element(By.ID, "doubleClickField") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") contextClick = ActionChains(driver, devices=[mouse]).context_click(toContextClick) contextClick.perform() assert "ContextClicked" == toContextClick.get_attribute("value") def test_move_and_click_with_pointer(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") toClick = driver.find_element(By.ID, "clickField") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") click = ActionChains(driver, devices=[mouse]).move_to_element(toClick).click() click.perform() assert "Clicked" == toClick.get_attribute("value") def test_cannot_move_to_anull_locator_with_pointer(driver, pages): """Copied from org.openqa.selenium.interactions.TestBasicMouseInterface.""" pages.load("javascriptPage.html") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") with pytest.raises(AttributeError): move = ActionChains(driver, devices=[mouse]).move_to_element(None) move.perform() @pytest.mark.xfail_safari def test_clicking_on_form_elements_with_pointer(driver, pages): """Copied from org.openqa.selenium.interactions.CombinedInputActionsTest.""" pages.load("formSelectionPage.html") options = driver.find_elements(By.TAG_NAME, "option") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") selectThreeOptions = ( ActionChains(driver, devices=[mouse]) .click(options[1]) .key_down(Keys.SHIFT) .click(options[3]) .key_up(Keys.SHIFT) ) selectThreeOptions.perform() showButton = driver.find_element(By.NAME, "showselected") showButton.click() resultElement = driver.find_element(By.ID, "result") assert "roquefort parmigiano cheddar" == resultElement.text @pytest.mark.xfail_firefox @pytest.mark.xfail_safari def test_selecting_multiple_items_with_devices(driver, pages): """Copied from org.openqa.selenium.interactions.CombinedInputActionsTest.""" pages.load("selectableItems.html") reportingElement = driver.find_element(By.ID, "infodiv") assert "no info" == reportingElement.text mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") key_board = KeyInput("test keyboard") listItems = driver.find_elements(By.TAG_NAME, "li") selectThreeItems = ( ActionChains(driver, devices=[mouse, key_board]) .key_down(Keys.CONTROL) .click(listItems[1]) .click(listItems[3]) .click(listItems[5]) .key_up(Keys.CONTROL) ) selectThreeItems.perform() assert "#item2 #item4 #item6" == reportingElement.text # Now click on another element, make sure that's the only one selected. actionsBuilder = ActionChains(driver) actionsBuilder.click(listItems[6]).perform() assert "#item7" == reportingElement.text @pytest.mark.xfail_safari def test_sending_keys_to_active_element_with_modifier_with_keyboard(driver, pages): pages.load("formPage.html") e = driver.find_element(By.ID, "working") e.click() key_board = KeyInput("test keyboard") ActionChains(driver, devices=[key_board]).key_down(Keys.SHIFT).send_keys("abc").key_up(Keys.SHIFT).perform() assert "ABC" == e.get_attribute("value") def test_sending_keys_to_element_with_keyboard(driver, pages): pages.load("formPage.html") e = driver.find_element(By.ID, "working") key_board = KeyInput("test keyboard") ActionChains(driver, devices=[key_board]).send_keys_to_element(e, "abc").perform() assert "abc" == e.get_attribute("value") def test_can_send_keys_between_clicks_with_keyboard(driver, pages): """ For W3C, ensures that the correct number of pauses are given to the other input device. """ pages.load("javascriptPage.html") keyup = driver.find_element(By.ID, "keyUp") keydown = driver.find_element(By.ID, "keyDown") key_board = KeyInput("test keyboard") ActionChains(driver, devices=[key_board]).click(keyup).send_keys("foobar").click(keydown).perform() assert "foobar" == keyup.get_attribute("value") def test_can_reset_interactions_with_devices(driver): mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") key_board = KeyInput("test keyboard") actions = ActionChains(driver, devices=[mouse, key_board]) actions.click() actions.key_down("A") assert all(len(device.actions) >= 0 for device in actions.w3c_actions.devices if device.type != interaction.WHEEL) actions.reset_actions() assert all(len(device.actions) == 0 for device in actions.w3c_actions.devices) def test_can_pause_with_pointer(driver, pages): from time import time pages.load("javascriptPage.html") pause_time = 2 toClick = driver.find_element(By.ID, "clickField") toDoubleClick = driver.find_element(By.ID, "doubleClickField") mouse = PointerInput(interaction.POINTER_MOUSE, "test mouse") pause = ActionChains(driver, devices=[mouse]).click(toClick).pause(pause_time).click(toDoubleClick) start = time() pause.perform() end = time() assert pause_time < end - start assert "Clicked" == toClick.get_attribute("value") assert "Clicked" == toDoubleClick.get_attribute("value") @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_to_element_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") iframe = driver.find_element(By.TAG_NAME, "iframe") assert not _in_viewport(driver, iframe) wheel = WheelInput("test wheel") ActionChains(driver, devices=[wheel]).scroll_to_element(iframe).perform() assert _in_viewport(driver, iframe) @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_from_element_by_amount_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") iframe = driver.find_element(By.TAG_NAME, "iframe") scroll_origin = ScrollOrigin.from_element(iframe) wheel = WheelInput("test wheel") ActionChains(driver, devices=[wheel]).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() driver.switch_to.frame(iframe) checkbox = driver.find_element(By.NAME, "scroll_checkbox") assert _in_viewport(driver, checkbox) @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_from_element_with_offset_by_amount_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") footer = driver.find_element(By.TAG_NAME, "footer") scroll_origin = ScrollOrigin.from_element(footer, 0, -50) wheel = WheelInput("test wheel") ActionChains(driver, devices=[wheel]).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() iframe = driver.find_element(By.TAG_NAME, "iframe") driver.switch_to.frame(iframe) checkbox = driver.find_element(By.NAME, "scroll_checkbox") assert _in_viewport(driver, checkbox) @pytest.mark.xfail_firefox def test_errors_when_element_offset_not_in_viewport_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") footer = driver.find_element(By.TAG_NAME, "footer") scroll_origin = ScrollOrigin.from_element(footer, 0, 50) wheel = WheelInput("test wheel") with pytest.raises(MoveTargetOutOfBoundsException): ActionChains(driver, devices=[wheel]).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() @pytest.mark.xfail_firefox @pytest.mark.xfail_remote def test_can_scroll_from_viewport_by_amount_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame_out_of_view.html") footer = driver.find_element(By.TAG_NAME, "footer") delta_y = footer.rect["y"] wheel = WheelInput("test wheel") ActionChains(driver, devices=[wheel]).scroll_by_amount(0, delta_y).pause(0.2).perform() assert _in_viewport(driver, footer) @pytest.mark.xfail_firefox def test_can_scroll_from_viewport_with_offset_by_amount_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame.html") scroll_origin = ScrollOrigin.from_viewport(10, 10) wheel = WheelInput("test wheel") ActionChains(driver, devices=[wheel]).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() iframe = driver.find_element(By.TAG_NAME, "iframe") driver.switch_to.frame(iframe) checkbox = driver.find_element(By.NAME, "scroll_checkbox") assert _in_viewport(driver, checkbox) @pytest.mark.xfail_firefox def test_errors_when_origin_offset_not_in_viewport_with_wheel(driver, pages): pages.load("scrolling_tests/frame_with_nested_scrolling_frame.html") scroll_origin = ScrollOrigin.from_viewport(-10, -10) wheel = WheelInput("test wheel") with pytest.raises(MoveTargetOutOfBoundsException): ActionChains(driver, devices=[wheel]).scroll_from_origin(scroll_origin, 0, 200).pause(0.2).perform() def _get_events(driver): """Return list of key events recorded in the test_keys_page fixture.""" events = driver.execute_script("return allEvents.events;") or [] # `key` values in `allEvents` may be escaped (see `escapeSurrogateHalf` in # test_keys_wdspec.html), so this converts them back into unicode literals. for e in events: # example: turn "U+d83d" (6 chars) into u"\ud83d" (1 char) if "key" in e and e["key"].startswith("U+"): key = e["key"] hex_suffix = key[key.index("+") + 1 :] e["key"] = chr(int(hex_suffix, 16)) # WebKit sets code as 'Unidentified' for unidentified key codes, but # tests expect ''. if "code" in e and e["code"] == "Unidentified": e["code"] = "" return events def _in_viewport(driver, element): script = ( "for(var e=arguments[0],f=e.offsetTop,t=e.offsetLeft,o=e.offsetWidth,n=e.offsetHeight;\n" "e.offsetParent;)f+=(e=e.offsetParent).offsetTop,t+=e.offsetLeft;\n" "return f\n" "window.pageYOffset&&t+o>window.pageXOffset" ) return driver.execute_script(script, element) selenium-selenium-4.18.1/test/selenium/webdriver/common/element_equality_tests.py0000644000175000017500000000307114564764517030374 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.common.by import By def test_same_element_looked_up_different_ways_should_be_equal(driver, pages): pages.load("simpleTest.html") body = driver.find_element(By.TAG_NAME, "body") xbody = driver.find_elements(By.XPATH, "//body")[0] assert body == xbody def test_different_elements_are_not_equal(driver, pages): pages.load("simpleTest.html") body = driver.find_element(By.TAG_NAME, "body") div = driver.find_element(By.TAG_NAME, "div") assert body != div def test_same_elements_found_different_ways_should_not_be_duplicated_in_aset(driver, pages): pages.load("simpleTest.html") body = driver.find_element(By.TAG_NAME, "body") xbody = driver.find_elements(By.XPATH, "//body") s = set(xbody) s.add(body) assert 1 == len(s) selenium-selenium-4.18.1/test/selenium/webdriver/__init__.py0000644000175000017500000000142314564764517024052 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/selenium/webdriver/marionette/0000755000175000017500000000000014564764517024110 5ustar carstencarstenselenium-selenium-4.18.1/test/selenium/webdriver/marionette/mn_options_tests.py0000644000175000017500000001132714564764517030075 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver.common.by import By from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.firefox.firefox_binary import FirefoxBinary from selenium.webdriver.firefox.firefox_profile import FirefoxProfile from selenium.webdriver.firefox.options import Log from selenium.webdriver.firefox.options import Options @pytest.fixture def driver_kwargs(driver_kwargs): driver_kwargs["options"] = Options() return driver_kwargs class TestIntegration: def test_we_can_pass_options(self, driver, pages): pages.load("formPage.html") driver.find_element(By.ID, "cheese") class TestUnit: def test_ctor(self): opts = Options() assert opts._binary is None assert not opts._preferences assert opts._profile is None assert not opts._arguments assert isinstance(opts.log, Log) def test_binary(self): opts = Options() assert opts.binary is None other_binary = FirefoxBinary() assert other_binary != opts.binary opts.binary = other_binary assert other_binary == opts.binary path = "/path/to/binary" opts.binary = path assert isinstance(opts.binary, FirefoxBinary) assert opts.binary._start_cmd == path def test_prefs(self): opts = Options() assert len(opts.preferences) == 0 assert isinstance(opts.preferences, dict) opts.set_preference("spam", "ham") assert len(opts.preferences) == 1 opts.set_preference("eggs", True) assert len(opts.preferences) == 2 opts.set_preference("spam", "spam") assert len(opts.preferences) == 2 assert opts.preferences == {"spam": "spam", "eggs": True} def test_profile(self, tmpdir_factory): opts = Options() assert opts.profile is None other_profile = FirefoxProfile() assert other_profile != opts.profile opts.profile = other_profile assert other_profile == opts.profile opts.profile = str(tmpdir_factory.mktemp("profile")) assert isinstance(opts.profile, FirefoxProfile) def test_arguments(self): opts = Options() assert len(opts.arguments) == 0 opts.add_argument("--foo") assert len(opts.arguments) == 1 opts.arguments.append("--bar") assert len(opts.arguments) == 2 assert opts.arguments == ["--foo", "--bar"] def test_to_capabilities(self): opts = Options() firefox_caps = DesiredCapabilities.FIREFOX.copy() firefox_caps.update({"pageLoadStrategy": PageLoadStrategy.normal}) assert opts.to_capabilities() == firefox_caps profile = FirefoxProfile() opts.profile = profile caps = opts.to_capabilities() assert "moz:firefoxOptions" in caps assert "profile" in caps["moz:firefoxOptions"] assert isinstance(caps["moz:firefoxOptions"]["profile"], str) assert caps["moz:firefoxOptions"]["profile"] == profile.encoded opts.add_argument("--foo") caps = opts.to_capabilities() assert "moz:firefoxOptions" in caps assert "args" in caps["moz:firefoxOptions"] assert caps["moz:firefoxOptions"]["args"] == ["--foo"] binary = FirefoxBinary() opts.binary = binary caps = opts.to_capabilities() assert "moz:firefoxOptions" in caps assert "binary" in caps["moz:firefoxOptions"] assert isinstance(caps["moz:firefoxOptions"]["binary"], str) assert caps["moz:firefoxOptions"]["binary"] == binary._start_cmd opts.set_preference("spam", "ham") caps = opts.to_capabilities() assert "moz:firefoxOptions" in caps assert "prefs" in caps["moz:firefoxOptions"] assert isinstance(caps["moz:firefoxOptions"]["prefs"], dict) assert caps["moz:firefoxOptions"]["prefs"]["spam"] == "ham" selenium-selenium-4.18.1/test/selenium/webdriver/marionette/mn_service_tests.py0000644000175000017500000000225114564764517030036 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.firefox.service import Service def test_command_line_args(): service = Service(service_args=["--log", "trace"]) found = False args = service.command_line_args() for idx in range(len(args) - 1): if args[idx] == "--log" and args[idx + 1] == "trace": found = True break assert found, "Provided arguments do not exist in array" selenium-selenium-4.18.1/test/selenium/webdriver/marionette/__init__.py0000644000175000017500000000142314564764517026221 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/selenium/webdriver/marionette/conftest.py0000644000175000017500000000236614564764517026316 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options as FirefoxOptions @pytest.fixture def options(): options = FirefoxOptions() return options @pytest.fixture def driver_class(): return Firefox @pytest.fixture def driver_kwargs(options): return {"options": options} @pytest.fixture def driver(driver_class, driver_kwargs): driver = driver_class(**driver_kwargs) yield driver driver.quit() selenium-selenium-4.18.1/test/selenium/webdriver/marionette/mn_set_context_tests.py0000644000175000017500000000166714564764517030747 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. def test_we_can_switch_context_to_chrome(driver): driver.set_context("chrome") assert 1 == driver.execute_script("var c = Components.classes; return 1;") selenium-selenium-4.18.1/test/selenium/webdriver/marionette/mn_context_tests.py0000644000175000017500000000215614564764517030066 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. def test_context_sets_correct_context_and_returns(driver): def get_context(): return driver.execute("GET_CONTEXT").pop("value") assert get_context() == driver.CONTEXT_CONTENT with driver.context(driver.CONTEXT_CHROME): assert get_context() == driver.CONTEXT_CHROME assert get_context() == driver.CONTEXT_CONTENT selenium-selenium-4.18.1/test/selenium/webdriver/support/0000755000175000017500000000000014564764517023455 5ustar carstencarstenselenium-selenium-4.18.1/test/selenium/webdriver/support/event_firing_webdriver_tests.py0000644000175000017500000002117714564764517032011 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from io import BytesIO import pytest from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.actions.action_builder import ActionBuilder from selenium.webdriver.common.by import By from selenium.webdriver.support.events import AbstractEventListener from selenium.webdriver.support.events import EventFiringWebDriver from selenium.webdriver.support.ui import WebDriverWait @pytest.fixture def log(): log = BytesIO() yield log log.close() def test_should_fire_navigation_events(driver, log, pages): class EventListener(AbstractEventListener): def before_navigate_to(self, url, driver): log.write(("before_navigate_to %s" % url.split("/")[-1]).encode()) def after_navigate_to(self, url, driver): log.write(("after_navigate_to %s" % url.split("/")[-1]).encode()) def before_navigate_back(self, driver): log.write(b"before_navigate_back") def after_navigate_back(self, driver): log.write(b"after_navigate_back") def before_navigate_forward(self, driver): log.write(b"before_navigate_forward") def after_navigate_forward(self, driver): log.write(b"after_navigate_forward") ef_driver = EventFiringWebDriver(driver, EventListener()) ef_driver.get(pages.url("formPage.html")) ef_driver.find_element(by=By.ID, value="imageButton").submit() WebDriverWait(ef_driver, 5).until(lambda d: d.title == "We Arrive Here") assert ef_driver.title == "We Arrive Here" ef_driver.back() assert ef_driver.title == "We Leave From Here" ef_driver.forward() assert ef_driver.title == "We Arrive Here" assert ( b"before_navigate_to formPage.html" b"after_navigate_to formPage.html" b"before_navigate_back" b"after_navigate_back" b"before_navigate_forward" b"after_navigate_forward" ) == log.getvalue() @pytest.mark.xfail_safari def test_should_fire_click_event(driver, log, pages): class EventListener(AbstractEventListener): def before_click(self, element, driver): log.write(b"before_click") def after_click(self, element, driver): log.write(b"after_click") ef_driver = EventFiringWebDriver(driver, EventListener()) ef_driver.get(pages.url("clicks.html")) ef_driver.find_element(By.ID, "overflowLink").click() assert ef_driver.title == "XHTML Test Page" assert b"before_click" + b"after_click" == log.getvalue() def test_should_fire_change_value_event(driver, log, pages): class EventListener(AbstractEventListener): def before_change_value_of(self, element, driver): log.write(b"before_change_value_of") def after_change_value_of(self, element, driver): log.write(b"after_change_value_of") ef_driver = EventFiringWebDriver(driver, EventListener()) ef_driver.get(pages.url("readOnlyPage.html")) element = ef_driver.find_element(By.ID, "writableTextInput") element.clear() assert "" == element.get_attribute("value") ef_driver.get(pages.url("javascriptPage.html")) keyReporter = ef_driver.find_element(by=By.ID, value="keyReporter") keyReporter.send_keys("abc def") assert keyReporter.get_attribute("value") == "abc def" assert ( b"before_change_value_of" b"after_change_value_of" b"before_change_value_of" b"after_change_value_of" ) == log.getvalue() def test_should_fire_find_event(driver, log, pages): class EventListener(AbstractEventListener): def before_find(self, by, value, driver): log.write((f"before_find by {by} {value}").encode()) def after_find(self, by, value, driver): log.write((f"after_find by {by} {value}").encode()) ef_driver = EventFiringWebDriver(driver, EventListener()) ef_driver.get(pages.url("simpleTest.html")) e = ef_driver.find_element(By.ID, "oneline") assert "A single line of text" == e.text e = ef_driver.find_element(By.XPATH, "/html/body/p[1]") assert "A single line of text" == e.text ef_driver.get(pages.url("frameset.html")) elements = ef_driver.find_elements(By.CSS_SELECTOR, "frame#sixth") assert 1 == len(elements) assert "frame" == elements[0].tag_name.lower() assert "sixth" == elements[0].get_attribute("id") assert ( b"before_find by id oneline" b"after_find by id oneline" b"before_find by xpath /html/body/p[1]" b"after_find by xpath /html/body/p[1]" b"before_find by css selector frame#sixth" b"after_find by css selector frame#sixth" ) == log.getvalue() def test_should_call_listener_when_an_exception_is_thrown(driver, log, pages): class EventListener(AbstractEventListener): def on_exception(self, exception, driver): if isinstance(exception, NoSuchElementException): log.write(b"NoSuchElementException is thrown") ef_driver = EventFiringWebDriver(driver, EventListener()) ef_driver.get(pages.url("simpleTest.html")) with pytest.raises(NoSuchElementException): ef_driver.find_element(By.ID, "foo") assert b"NoSuchElementException is thrown" == log.getvalue() def test_should_unwrap_element_args_when_calling_scripts(driver, log, pages): ef_driver = EventFiringWebDriver(driver, AbstractEventListener()) ef_driver.get(pages.url("javascriptPage.html")) button = ef_driver.find_element(By.ID, "plainButton") value = ef_driver.execute_script( "arguments[0]['flibble'] = arguments[0].getAttribute('id'); return arguments[0]['flibble']", button ) assert "plainButton" == value def test_should_unwrap_element_args_when_switching_frames(driver, log, pages): ef_driver = EventFiringWebDriver(driver, AbstractEventListener()) ef_driver.get(pages.url("iframes.html")) frame = ef_driver.find_element(By.ID, "iframe1") ef_driver.switch_to.frame(frame) assert "click me!" == ef_driver.find_element(By.ID, "imageButton").get_attribute("alt") def test_should_be_able_to_access_wrapped_instance_from_event_calls(driver): class EventListener(AbstractEventListener): def before_navigate_to(url, d): assert driver is d ef_driver = EventFiringWebDriver(driver, EventListener()) wrapped_driver = ef_driver.wrapped_driver assert driver is wrapped_driver def test_using_kwargs(driver, pages): ef_driver = EventFiringWebDriver(driver, AbstractEventListener()) ef_driver.get(pages.url("javascriptPage.html")) ef_driver.get_cookie(name="cookie_name") element = ef_driver.find_element(By.ID, "plainButton") element.get_attribute(name="id") def test_missing_attributes_raise_error(driver, pages): ef_driver = EventFiringWebDriver(driver, AbstractEventListener()) with pytest.raises(AttributeError): ef_driver.attribute_should_not_exist ef_driver.get(pages.url("readOnlyPage.html")) element = ef_driver.find_element(By.ID, "writableTextInput") with pytest.raises(AttributeError): element.attribute_should_not_exist def test_can_use_pointer_input_with_event_firing_webdriver(driver, pages): ef_driver = EventFiringWebDriver(driver, AbstractEventListener()) pages.load("javascriptPage.html") to_click = ef_driver.find_element(By.ID, "clickField") actions = ActionBuilder(ef_driver) pointer = actions.pointer_action pointer.move_to(to_click).click() actions.perform() assert to_click.get_attribute("value") == "Clicked" @pytest.mark.xfail_safari def test_can_use_key_input_with_event_firing_webdriver(driver, pages): ef_driver = EventFiringWebDriver(driver, AbstractEventListener()) pages.load("javascriptPage.html") ef_driver.find_element(By.ID, "keyUp").click() actions = ActionBuilder(ef_driver) key = actions.key_action key.send_keys("Success") actions.perform() result = ef_driver.find_element(By.ID, "result") assert result.text == "Success" selenium-selenium-4.18.1/test/selenium/webdriver/support/__init__.py0000644000175000017500000000142314564764517025566 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/selenium/webdriver/support/conftest.py0000644000175000017500000000173514564764517025662 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. def pytest_generate_tests(metafunc): if "driver" in metafunc.fixturenames and metafunc.config.option.drivers: metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True) selenium-selenium-4.18.1/test/selenium/webdriver/support/expected_conditions_tests.py0000644000175000017500000000657414564764517031317 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait def test_any_of_true(driver, pages): pages.load("simpleTest.html") WebDriverWait(driver, 0.1).until(EC.any_of(EC.title_is("Nope"), EC.title_is("Hello WebDriver"))) def test_any_of_false(driver, pages): pages.load("simpleTest.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.1).until(EC.any_of(EC.title_is("Nope"), EC.title_is("Still Nope"))) def test_all_of_true(driver, pages): pages.load("simpleTest.html") results = WebDriverWait(driver, 0.1).until( EC.all_of(EC.title_is("Hello WebDriver"), EC.visibility_of_element_located((By.ID, "oneline"))) ) assert results[0] is True assert isinstance(results[1], WebElement) def test_all_of_false(driver, pages): pages.load("simpleTest.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.1).until(EC.all_of(EC.title_is("Nope"), EC.title_is("Still Nope"))) def test_none_of_true(driver, pages): pages.load("simpleTest.html") WebDriverWait(driver, 0.1).until(EC.none_of(EC.title_is("Nope"), EC.title_is("Still Nope"))) def test_none_of_false(driver, pages): pages.load("simpleTest.html") with pytest.raises(TimeoutException): WebDriverWait(driver, 0.1).until(EC.none_of(EC.title_is("Nope"), EC.title_is("Hello WebDriver"))) def test_clickable_locator_true(driver, pages): pages.load("simpleTest.html") WebDriverWait(driver, 0.1).until(EC.element_to_be_clickable((By.ID, "multilinelink"))) def test_clickable_locator_false(driver, pages): pages.load("simpleTest.html") with pytest.raises(TimeoutException): # text element, should not be clickable WebDriverWait(driver, 0.1).until(EC.element_to_be_clickable((By.ID, "hiddenline"))) def test_clickable_element_true(driver, pages): pages.load("simpleTest.html") target = (By.ID, "multilinelink") element = driver.find_element(*target) # grab element at locator WebDriverWait(driver, 0.1).until(EC.element_to_be_clickable(element)) def test_clickable_element_false(driver, pages): pages.load("simpleTest.html") with pytest.raises(TimeoutException): target = (By.ID, "hiddenline") # text, should not be clickable element = driver.find_element(*target) # grab element at locator WebDriverWait(driver, 0.1).until(EC.element_to_be_clickable(element)) selenium-selenium-4.18.1/test/selenium/webdriver/support/relative_by_tests.py0000644000175000017500000000733014564764517027561 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By from selenium.webdriver.support.relative_locator import locate_with from selenium.webdriver.support.relative_locator import with_tag_name def test_should_be_able_to_find_first_one(driver, pages): pages.load("relative_locators.html") lowest = driver.find_element(By.ID, "below") el = driver.find_element(with_tag_name("p").above(lowest)) assert el.get_attribute("id") == "mid" def test_should_be_able_to_find_elements_above_another(driver, pages): pages.load("relative_locators.html") lowest = driver.find_element(By.ID, "below") elements = driver.find_elements(with_tag_name("p").above(lowest)) ids = [el.get_attribute("id") for el in elements] assert "above" in ids assert "mid" in ids def test_should_be_able_to_combine_filters(driver, pages): pages.load("relative_locators.html") elements = driver.find_elements( with_tag_name("td") .above(driver.find_element(By.ID, "center")) .to_right_of(driver.find_element(By.ID, "second")) ) ids = [el.get_attribute("id") for el in elements] assert "third" in ids def test_should_be_able_to_use_css_selectors(driver, pages): pages.load("relative_locators.html") elements = driver.find_elements( locate_with(By.CSS_SELECTOR, "td") .above(driver.find_element(By.ID, "center")) .to_right_of(driver.find_element(By.ID, "second")) ) ids = [el.get_attribute("id") for el in elements] assert "third" in ids def test_should_be_able_to_use_xpath(driver, pages): pages.load("relative_locators.html") elements = driver.find_elements( locate_with(By.XPATH, "//td[1]") .below(driver.find_element(By.ID, "second")) .above(driver.find_element(By.ID, "seventh")) ) ids = [el.get_attribute("id") for el in elements] assert "fourth" in ids def test_no_such_element_is_raised_rather_than_index_error(driver, pages): pages.load("relative_locators.html") with pytest.raises(NoSuchElementException) as exc: anchor = driver.find_element(By.ID, "second") driver.find_element(locate_with(By.ID, "nonexistentid").above(anchor)) assert "Cannot locate relative element with: {'id': 'nonexistentid'}" in exc.value.msg def test_near_locator_should_find_near_elements(driver, pages): pages.load("relative_locators.html") rect1 = driver.find_element(By.ID, "rect1") el = driver.find_element(locate_with(By.ID, "rect2").near(rect1)) assert el.get_attribute("id") == "rect2" def test_near_locator_should_not_find_far_elements(driver, pages): pages.load("relative_locators.html") rect3 = driver.find_element(By.ID, "rect3") with pytest.raises(NoSuchElementException) as exc: driver.find_element(locate_with(By.ID, "rect4").near(rect3)) assert "Cannot locate relative element with: {'id': 'rect4'}" in exc.value.msg selenium-selenium-4.18.1/test/selenium/webdriver/ie/0000755000175000017500000000000014564764517022336 5ustar carstencarstenselenium-selenium-4.18.1/test/selenium/webdriver/ie/__init__.py0000644000175000017500000000142314564764517024447 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/selenium/webdriver/ie/ie_launcher_tests.py0000644000175000017500000000322414564764517026411 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver import Ie from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.ie.options import Options def test_launch_and_close_browser(): driver = Ie() driver.quit() def test_we_can_launch_multiple_ie_instances(): driver1 = Ie() driver2 = Ie() driver3 = Ie() driver1.quit() driver2.quit() driver3.quit() def test_launch_ie_do_not_affect_default_capabilities(): expected = DesiredCapabilities.INTERNETEXPLORER.copy() driver = Ie() actual = DesiredCapabilities.INTERNETEXPLORER.copy() driver.quit() assert actual == expected def test_launch_ie_with_options(pages): opts = Options() expected = "clicks.html" opts.initial_browser_url = pages.url(expected) driver = Ie(options=opts) actual = driver.current_url driver.quit() assert expected in actual selenium-selenium-4.18.1/test/selenium/webdriver/firefox/0000755000175000017500000000000014564764517023403 5ustar carstencarstenselenium-selenium-4.18.1/test/selenium/webdriver/firefox/__init__.py0000644000175000017500000000142314564764517025514 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/selenium/webdriver/firefox/conftest.py0000644000175000017500000000164414564764517025607 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver import Firefox @pytest.fixture def driver(): driver = Firefox() yield driver driver.quit() selenium-selenium-4.18.1/test/selenium/webdriver/firefox/ff_installs_addons_tests.py0000644000175000017500000001060314564764517031033 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import zipfile from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait extensions = os.path.abspath("../../../../../../test/extensions/") def test_install_uninstall_signed_addon_xpi(driver, pages): extension = os.path.join(extensions, "webextensions-selenium-example.xpi") id = driver.install_addon(extension) assert id == "webextensions-selenium-example@example.com" pages.load("blank.html") injected = WebDriverWait(driver, timeout=2).until( lambda dr: dr.find_element(By.ID, "webextensions-selenium-example") ) assert injected.text == "Content injected by webextensions-selenium-example" driver.uninstall_addon(id) driver.refresh() assert len(driver.find_elements(By.ID, "webextensions-selenium-example")) == 0 def test_install_uninstall_signed_addon_zip(driver, pages): extension = os.path.join(extensions, "webextensions-selenium-example.zip") id = driver.install_addon(extension) assert id == "webextensions-selenium-example@example.com" pages.load("blank.html") injected = WebDriverWait(driver, timeout=2).until( lambda dr: dr.find_element(By.ID, "webextensions-selenium-example") ) assert injected.text == "Content injected by webextensions-selenium-example" driver.uninstall_addon(id) driver.refresh() assert len(driver.find_elements(By.ID, "webextensions-selenium-example")) == 0 def test_install_uninstall_unsigned_addon_zip(driver, pages): extension = os.path.join(extensions, "webextensions-selenium-example-unsigned.zip") id = driver.install_addon(extension, temporary=True) assert id == "webextensions-selenium-example@example.com" pages.load("blank.html") injected = WebDriverWait(driver, timeout=2).until( lambda dr: dr.find_element(By.ID, "webextensions-selenium-example") ) assert injected.text == "Content injected by webextensions-selenium-example" driver.uninstall_addon(id) driver.refresh() assert len(driver.find_elements(By.ID, "webextensions-selenium-example")) == 0 def test_install_uninstall_signed_addon_dir(driver, pages): zip = os.path.join(extensions, "webextensions-selenium-example.zip") target = os.path.join(extensions, "webextensions-selenium-example") with zipfile.ZipFile(zip, "r") as zip_ref: zip_ref.extractall(target) id = driver.install_addon(target) assert id == "webextensions-selenium-example@example.com" pages.load("blank.html") injected = WebDriverWait(driver, timeout=2).until( lambda dr: dr.find_element(By.ID, "webextensions-selenium-example") ) assert injected.text == "Content injected by webextensions-selenium-example" driver.uninstall_addon(id) driver.refresh() assert len(driver.find_elements(By.ID, "webextensions-selenium-example")) == 0 def test_install_uninstall_unsigned_addon_dir(driver, pages): zip = os.path.join(extensions, "webextensions-selenium-example-unsigned.zip") target = os.path.join(extensions, "webextensions-selenium-example-unsigned") with zipfile.ZipFile(zip, "r") as zip_ref: zip_ref.extractall(target) id = driver.install_addon(target, temporary=True) assert id == "webextensions-selenium-example@example.com" pages.load("blank.html") injected = WebDriverWait(driver, timeout=2).until( lambda dr: dr.find_element(By.ID, "webextensions-selenium-example") ) assert injected.text == "Content injected by webextensions-selenium-example" driver.uninstall_addon(id) driver.refresh() assert len(driver.find_elements(By.ID, "webextensions-selenium-example")) == 0 selenium-selenium-4.18.1/test/selenium/webdriver/firefox/ff_takes_full_page_screenshots_tests.py0000644000175000017500000000230614564764517033420 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import base64 import imghdr def test_get_full_page_screenshot_as_base64(driver, pages): pages.load("simpleTest.html") result = base64.b64decode(driver.get_full_page_screenshot_as_base64()) assert imghdr.what("", result) == "png" def test_get_full_page_screenshot_as_png(driver, pages): pages.load("simpleTest.html") result = driver.get_full_page_screenshot_as_png() assert imghdr.what("", result) == "png" selenium-selenium-4.18.1/test/selenium/webdriver/firefox/firefox_service_tests.py0000644000175000017500000000355214564764517030366 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import subprocess from selenium.webdriver import Firefox from selenium.webdriver.firefox.service import Service def test_log_output_as_filename() -> None: log_file = "geckodriver.log" service = Service(log_output=log_file) try: driver = Firefox(service=service) with open(log_file) as fp: assert "geckodriver\tINFO\tListening" in fp.readline() finally: driver.quit() os.remove(log_file) def test_log_output_as_file() -> None: log_name = "geckodriver.log" log_file = open(log_name, "w", encoding="utf-8") service = Service(log_output=log_file) try: driver = Firefox(service=service) with open(log_name) as fp: assert "geckodriver\tINFO\tListening" in fp.readline() finally: driver.quit() log_file.close() os.remove(log_name) def test_log_output_as_stdout(capfd) -> None: service = Service(log_output=subprocess.STDOUT) driver = Firefox(service=service) out, err = capfd.readouterr() assert "geckodriver\tINFO\tListening" in out driver.quit() selenium-selenium-4.18.1/test/selenium/webdriver/remote/0000755000175000017500000000000014564764517023234 5ustar carstencarstenselenium-selenium-4.18.1/test/selenium/webdriver/remote/remote_downloads_tests.py0000644000175000017500000000370414564764517030401 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import tempfile from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait def test_get_downloadable_files(driver, pages): _browser_downloads(driver, pages) file_names = driver.get_downloadable_files() assert "file_1.txt" in file_names assert "file_2.jpg" in file_names def test_download_file(driver, pages): _browser_downloads(driver, pages) file_name = driver.get_downloadable_files()[0] with tempfile.TemporaryDirectory() as target_directory: driver.download_file(file_name, target_directory) target_file = os.path.join(target_directory, file_name) with open(target_file, "r") as file: assert "Hello, World!" in file.read() def test_delete_downloadable_files(driver, pages): _browser_downloads(driver, pages) driver.delete_downloadable_files() assert not driver.get_downloadable_files() def _browser_downloads(driver, pages): pages.load("downloads/download.html") driver.find_element(By.ID, "file-1").click() driver.find_element(By.ID, "file-2").click() WebDriverWait(driver, 3).until(lambda d: "file_2.jpg" in d.get_downloadable_files()) selenium-selenium-4.18.1/test/selenium/webdriver/remote/remote_connection_tests.py0000644000175000017500000000203314564764517030540 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import base64 import imghdr def test_browser_specific_method(driver, pages): pages.load("simpleTest.html") screenshot = driver.execute("FULL_PAGE_SCREENSHOT")["value"] result = base64.b64decode(screenshot) assert imghdr.what("", result) == "png" selenium-selenium-4.18.1/test/selenium/webdriver/remote/remote_hub_connection.py0000644000175000017500000000222714564764517030161 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest import urllib3 from selenium import webdriver def test_command_executor_ssl_certificate_is_verified(): with pytest.raises(urllib3.exceptions.MaxRetryError) as excinfo: webdriver.Remote(command_executor="https://wrong.host.badssl.com/") assert isinstance(excinfo.value.reason, urllib3.exceptions.SSLError) assert "doesn't match" in str(excinfo.value) selenium-selenium-4.18.1/test/selenium/webdriver/remote/__init__.py0000644000175000017500000000142314564764517025345 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/selenium/webdriver/remote/remote_firefox_profile_tests.py0000644000175000017500000000231614564764517031567 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium import webdriver @pytest.fixture def driver(options): driver = webdriver.Remote(options=options) yield driver driver.quit() @pytest.fixture def options(): options = webdriver.FirefoxOptions() options.set_preference("browser.startup.homepage", "about:") return options def test_profile_is_used(driver): assert "about:blank" == driver.current_url or "about:" == driver.current_url selenium-selenium-4.18.1/test/selenium/webdriver/chrome/0000755000175000017500000000000014564764517023216 5ustar carstencarstenselenium-selenium-4.18.1/test/selenium/webdriver/chrome/chrome_service_tests.py0000644000175000017500000000633514564764517030016 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import subprocess import time import pytest from selenium.common.exceptions import WebDriverException from selenium.webdriver.chrome.service import Service @pytest.mark.xfail_chrome(raises=WebDriverException) @pytest.mark.no_driver_after_test def test_uses_chromedriver_logging(clean_driver, driver_executable) -> None: log_file = "chromedriver.log" service_args = ["--append-log"] service = Service( log_output=log_file, service_args=service_args, executable_path=driver_executable, ) driver2 = None try: driver1 = clean_driver(service=service) with open(log_file) as fp: lines = len(fp.readlines()) driver2 = clean_driver(service=service) with open(log_file) as fp: assert len(fp.readlines()) >= 2 * lines finally: driver1.quit() if driver2: driver2.quit() os.remove(log_file) @pytest.mark.no_driver_after_test def test_log_output_as_filename(clean_driver, driver_executable) -> None: log_file = "chromedriver.log" service = Service(log_output=log_file, executable_path=driver_executable) try: assert "--log-path=chromedriver.log" in service.service_args driver = clean_driver(service=service) with open(log_file) as fp: assert "Starting ChromeDriver" in fp.readline() finally: driver.quit() os.remove(log_file) @pytest.mark.no_driver_after_test def test_log_output_as_file(clean_driver, driver_executable) -> None: log_name = "chromedriver.log" log_file = open(log_name, "w", encoding="utf-8") service = Service(log_output=log_file, executable_path=driver_executable) try: driver = clean_driver(service=service) time.sleep(1) with open(log_name) as fp: assert "Starting ChromeDriver" in fp.readline() finally: driver.quit() log_file.close() os.remove(log_name) @pytest.mark.no_driver_after_test def test_log_output_as_stdout(clean_driver, capfd, driver_executable) -> None: service = Service(log_output=subprocess.STDOUT, executable_path=driver_executable) driver = clean_driver(service=service) out, err = capfd.readouterr() assert "Starting ChromeDriver" in out driver.quit() @pytest.mark.no_driver_after_test def test_log_output_null_default(driver, capfd) -> None: out, err = capfd.readouterr() assert "Starting ChromeDriver" not in out driver.quit() selenium-selenium-4.18.1/test/selenium/webdriver/chrome/__init__.py0000644000175000017500000000142314564764517025327 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/test/selenium/webdriver/chrome/conftest.py0000644000175000017500000000173514564764517025423 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. def pytest_generate_tests(metafunc): if "driver" in metafunc.fixturenames and metafunc.config.option.drivers: metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True) selenium-selenium-4.18.1/test/selenium/webdriver/chrome/proxy_tests.py0000644000175000017500000000310414564764517026171 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import pytest import urllib3 from selenium import webdriver @pytest.mark.no_driver_after_test def test_bad_proxy_doesnt_interfere(clean_driver, clean_service): # these values should be ignored if ignore_local_proxy_environment_variables() is called. os.environ["https_proxy"] = "bad" os.environ["http_proxy"] = "bad" options = webdriver.ChromeOptions() options.ignore_local_proxy_environment_variables() chrome_kwargs = {"options": options, "service": clean_service} driver = clean_driver(**chrome_kwargs) assert hasattr(driver, "command_executor") assert hasattr(driver.command_executor, "_proxy_url") assert isinstance(driver.command_executor._conn, urllib3.PoolManager) os.environ.pop("https_proxy") os.environ.pop("http_proxy") driver.quit() selenium-selenium-4.18.1/test/selenium/webdriver/chrome/chrome_launcher_tests.py0000644000175000017500000000241314564764517030150 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest @pytest.mark.no_driver_after_test def test_launch_and_close_browser(clean_driver, clean_service): driver = clean_driver(service=clean_service) driver.quit() @pytest.mark.no_driver_after_test def test_we_can_launch_multiple_chrome_instances(clean_driver, clean_service): driver1 = clean_driver(service=clean_service) driver2 = clean_driver(service=clean_service) driver3 = clean_driver(service=clean_service) driver1.quit() driver2.quit() driver3.quit() selenium-selenium-4.18.1/test/selenium/webdriver/chrome/chrome_network_emulation_tests.py0000644000175000017500000000257214564764517032123 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.common.exceptions import WebDriverException @pytest.mark.no_driver_after_test def test_network_conditions_emulation(driver): driver.set_network_conditions(offline=False, latency=56, throughput=789) # additional latency (ms) conditions = driver.get_network_conditions() assert conditions["offline"] is False assert conditions["latency"] == 56 assert conditions["download_throughput"] == 789 assert conditions["upload_throughput"] == 789 driver.delete_network_conditions() with pytest.raises(WebDriverException): driver.get_network_conditions() selenium-selenium-4.18.1/test/selenium/webdriver/safari/0000755000175000017500000000000014564764517023206 5ustar carstencarstenselenium-selenium-4.18.1/test/selenium/webdriver/safari/conftest.py0000644000175000017500000000207714564764517025413 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import pytest from selenium.webdriver import Safari @pytest.fixture def driver_class(): return Safari @pytest.fixture def driver_kwargs(): return {} @pytest.fixture def driver(driver_class, driver_kwargs): driver = driver_class(**driver_kwargs) yield driver driver.quit() selenium-selenium-4.18.1/test/selenium/webdriver/safari/launcher_tests.py0000644000175000017500000000471614564764517026613 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import pytest from selenium.common.exceptions import NoSuchDriverException from selenium.webdriver.safari.service import Service def test_launch(driver): assert driver.capabilities["browserName"] == "Safari" def test_launch_with_invalid_executable_path_raises_exception(driver_class): path = "/this/path/should/never/exist" assert not os.path.exists(path) service = Service(executable_path=path) with pytest.raises(NoSuchDriverException): driver_class(service=service) @pytest.mark.skipif( not os.path.exists("/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver"), reason="Preview not installed", ) class TestTechnologyPreview: @pytest.fixture def driver_kwargs(self): path = "/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver" assert os.path.exists( path ), "Safari Technology Preview required! Download it from https://developer.apple.com/safari/technology-preview/" return {"executable_path": path} def test_launch(self, driver): assert driver.capabilities["browserName"] == "safari" def test_launch_safari_with_legacy_flag(mocker, driver_class): import subprocess mocker.patch("subprocess.Popen") try: driver_class(service_args=["--legacy"]) except Exception: pass args, kwargs = subprocess.Popen.call_args assert "--legacy" in args[0] def test_launch_safari_without_legacy_flag(mocker, driver_class): import subprocess mocker.patch("subprocess.Popen") try: driver_class() except Exception: pass args, kwargs = subprocess.Popen.call_args assert "--legacy" not in args[0] selenium-selenium-4.18.1/tox.ini0000644000175000017500000000347714564764517016476 0ustar carstencarsten[tox] envlist = docs, flake8, isort [testenv:docs] skip_install = true deps = Jinja2==3.0.3 Sphinx==1.8.2 commands = sphinx-build -b html -d ../build/docs/doctrees docs/source ../build/docs/api/py {posargs} [testenv:mypy] skip_install = true deps = mypy==1.4.1 lxml==4.9.1 types-urllib3==1.26.25 types-certifi==2021.10.8.3 trio-typing==0.7.0 commands = mypy --install-types {posargs} [isort] ; isort is a common python tool for keeping imports nicely formatted. ; Automatically keep imports alphabetically sorted, on single lines in ; PEP recommended sections (https://peps.python.org/pep-0008/#imports) ; files or individual lines can be ignored via `# isort:skip|# isort:skip_file`. profile = black py_version=38 force_single_line = True [testenv:linting-ci] ; checks linting for CI with stricter exiting when failing. skip_install = true deps = isort==5.13.2 black==24.1.1 flake8==6.1.0 flake8-typing-imports==1.14.0 docformatter==1.7.5 commands = ; execute isort in check only mode. isort --check-only --diff selenium/ test/ conftest.py ; execute black in check only mode with diff. black --check --diff selenium/ test/ conftest.py -l 120 flake8 selenium/ test/ --min-python-version=3.8 docformatter --check -r selenium/ [testenv:linting] ; A consolidated linting based recipe, responsible for executing linting tools across the code base. ; This encompasses isort for imports, black for general formatting and flake8. ; IMPORTANT: black & isort rewrite files, flake8 merely alerts to the failure. skip_install = true deps = isort==5.13.2 black==24.1.1 flake8==6.1.0 flake8-typing-imports==1.14.0 docformatter==1.7.5 commands = isort selenium/ test/ conftest.py black selenium/ test/ conftest.py -l 120 flake8 selenium/ test/ --min-python-version=3.8 docformatter --in-place -r selenium/ selenium-selenium-4.18.1/generate.py0000644000175000017500000010465614564764517017330 0ustar carstencarsten# The MIT License(MIT) # # Copyright(c) 2018 Hyperion Gray # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # This is a copy of https://github.com/HyperionGray/python-chrome-devtools-protocol/blob/master/generator/generate.py # The license above is theirs and MUST be preserved. # flake8: noqa import builtins from dataclasses import dataclass from enum import Enum import itertools import json import logging import operator import os from pathlib import Path import re from textwrap import dedent, indent as tw_indent import typing import inflection # type: ignore log_level = getattr(logging, os.environ.get('LOG_LEVEL', 'warning').upper()) logging.basicConfig(level=log_level) logger = logging.getLogger('generate') SHARED_HEADER = '''# DO NOT EDIT THIS FILE! # # This file is generated from the CDP specification. If you need to make # changes, edit the generator and regenerate all of the modules.''' INIT_HEADER = '''{} '''.format(SHARED_HEADER) MODULE_HEADER = '''{} # # CDP domain: {{}}{{}} from __future__ import annotations from .util import event_class, T_JSON_DICT from dataclasses import dataclass import enum import typing '''.format(SHARED_HEADER) current_version = '' UTIL_PY = """ import typing T_JSON_DICT = typing.Dict[str, typing.Any] _event_parsers = dict() def event_class(method): ''' A decorator that registers a class as an event class. ''' def decorate(cls): _event_parsers[method] = cls return cls return decorate def parse_json_event(json: T_JSON_DICT) -> typing.Any: ''' Parse a JSON dictionary into a CDP event. ''' return _event_parsers[json['method']].from_json(json['params']) """ def indent(s, n): ''' A shortcut for ``textwrap.indent`` that always uses spaces. ''' return tw_indent(s, n * ' ') BACKTICK_RE = re.compile(r'`([^`]+)`(\w+)?') def escape_backticks(docstr): ''' Escape backticks in a docstring by doubling them up. This is a little tricky because RST requires a non-letter character after the closing backticks, but some CDPs docs have things like "`AxNodeId`s". If we double the backticks in that string, then it won't be valid RST. The fix is to insert an apostrophe if an "s" trails the backticks. ''' def replace_one(match): if match.group(2) == 's': return f"``{match.group(1)}``'s" if match.group(2): # This case (some trailer other than "s") doesn't currently exist # in the CDP definitions, but it's here just to be safe. return f'``{match.group(1)}`` {match.group(2)}' return f'``{match.group(1)}``' # Sometimes pipes are used where backticks should have been used. docstr = docstr.replace('|', '`') return BACKTICK_RE.sub(replace_one, docstr) def inline_doc(description): ''' Generate an inline doc, e.g. ``#: This type is a ...`` ''' if not description: return '' description = escape_backticks(description) lines = [f'#: {l}' for l in description.split('\n')] return '\n'.join(lines) def docstring(description): ''' Generate a docstring from a description. ''' if not description: return '' description = escape_backticks(description) return dedent("'''\n{}\n'''").format(description) def is_builtin(name): ''' Return True if ``name`` would shadow a builtin. ''' try: getattr(builtins, name) return True except AttributeError: return False def snake_case(name): ''' Convert a camel case name to snake case. If the name would shadow a Python builtin, then append an underscore. ''' name = inflection.underscore(name) if is_builtin(name): name += '_' return name def ref_to_python(ref): ''' Convert a CDP ``$ref`` to the name of a Python type. For a dotted ref, the part before the dot is snake cased. ''' if '.' in ref: domain, subtype = ref.split('.') ref = f'{snake_case(domain)}.{subtype}' return f"{ref}" class CdpPrimitiveType(Enum): ''' All of the CDP types that map directly to a Python type. ''' boolean = 'bool' integer = 'int' number = 'float' object = 'dict' string = 'str' @classmethod def get_annotation(cls, cdp_type): ''' Return a type annotation for the CDP type. ''' if cdp_type == 'any': return 'typing.Any' return cls[cdp_type].value @classmethod def get_constructor(cls, cdp_type, val): ''' Return the code to construct a value for a given CDP type. ''' if cdp_type == 'any': return val cons = cls[cdp_type].value return f'{cons}({val})' @dataclass class CdpItems: ''' Represents the type of a repeated item. ''' type: str ref: str @classmethod def from_json(cls, type): ''' Generate code to instantiate an item from a JSON object. ''' return cls(type.get('type'), type.get('$ref')) @dataclass class CdpProperty: ''' A property belonging to a non-primitive CDP type. ''' name: str description: typing.Optional[str] type: typing.Optional[str] ref: typing.Optional[str] enum: typing.List[str] items: typing.Optional[CdpItems] optional: bool experimental: bool deprecated: bool @property def py_name(self): ''' Get this property's Python name. ''' return snake_case(self.name) @property def py_annotation(self): ''' This property's Python type annotation. ''' if self.items: if self.items.ref: py_ref = ref_to_python(self.items.ref) ann = f"typing.List[{py_ref}]" else: ann = 'typing.List[{}]'.format( CdpPrimitiveType.get_annotation(self.items.type)) else: if self.ref: py_ref = ref_to_python(self.ref) ann = py_ref else: ann = CdpPrimitiveType.get_annotation( typing.cast(str, self.type)) if self.optional: ann = f'typing.Optional[{ann}]' return ann @classmethod def from_json(cls, property): ''' Instantiate a CDP property from a JSON object. ''' return cls( property['name'], property.get('description'), property.get('type'), property.get('$ref'), property.get('enum'), CdpItems.from_json(property['items']) if 'items' in property else None, property.get('optional', False), property.get('experimental', False), property.get('deprecated', False), ) def generate_decl(self): ''' Generate the code that declares this property. ''' code = inline_doc(self.description) if code: code += '\n' code += f'{self.py_name}: {self.py_annotation}' if self.optional: code += ' = None' return code def generate_to_json(self, dict_, use_self=True): ''' Generate the code that exports this property to the specified JSON dict. ''' self_ref = 'self.' if use_self else '' assign = f"{dict_}['{self.name}'] = " if self.items: if self.items.ref: assign += f"[i.to_json() for i in {self_ref}{self.py_name}]" else: assign += f"[i for i in {self_ref}{self.py_name}]" else: if self.ref: assign += f"{self_ref}{self.py_name}.to_json()" else: assign += f"{self_ref}{self.py_name}" if self.optional: code = dedent(f'''\ if {self_ref}{self.py_name} is not None: {assign}''') else: code = assign return code def generate_from_json(self, dict_): ''' Generate the code that creates an instance from a JSON dict named ``dict_``. ''' if self.items: if self.items.ref: py_ref = ref_to_python(self.items.ref) expr = f"[{py_ref}.from_json(i) for i in {dict_}['{self.name}']]" expr else: cons = CdpPrimitiveType.get_constructor(self.items.type, 'i') expr = f"[{cons} for i in {dict_}['{self.name}']]" else: if self.ref: py_ref = ref_to_python(self.ref) expr = f"{py_ref}.from_json({dict_}['{self.name}'])" else: expr = CdpPrimitiveType.get_constructor(self.type, f"{dict_}['{self.name}']") if self.optional: expr = f"{expr} if '{self.name}' in {dict_} else None" return expr @dataclass class CdpType: ''' A top-level CDP type. ''' id: str description: typing.Optional[str] type: str items: typing.Optional[CdpItems] enum: typing.List[str] properties: typing.List[CdpProperty] @classmethod def from_json(cls, type_): ''' Instantiate a CDP type from a JSON object. ''' return cls( type_['id'], type_.get('description'), type_['type'], CdpItems.from_json(type_['items']) if 'items' in type_ else None, type_.get('enum'), [CdpProperty.from_json(p) for p in type_.get('properties', [])], ) def generate_code(self): ''' Generate Python code for this type. ''' logger.debug('Generating type %s: %s', self.id, self.type) if self.enum: return self.generate_enum_code() if self.properties: return self.generate_class_code() return self.generate_primitive_code() def generate_primitive_code(self): ''' Generate code for a primitive type. ''' if self.items: if self.items.ref: nested_type = ref_to_python(self.items.ref) else: nested_type = CdpPrimitiveType.get_annotation(self.items.type) py_type = f'typing.List[{nested_type}]' superclass = 'list' else: # A primitive type cannot have a ref, so there is no branch here. py_type = CdpPrimitiveType.get_annotation(self.type) superclass = py_type code = f'class {self.id}({superclass}):\n' doc = docstring(self.description) if doc: code += indent(doc, 4) + '\n' def_to_json = dedent(f'''\ def to_json(self) -> {py_type}: return self''') code += indent(def_to_json, 4) def_from_json = dedent(f'''\ @classmethod def from_json(cls, json: {py_type}) -> {self.id}: return cls(json)''') code += '\n\n' + indent(def_from_json, 4) def_repr = dedent(f'''\ def __repr__(self): return '{self.id}({{}})'.format(super().__repr__())''') code += '\n\n' + indent(def_repr, 4) return code def generate_enum_code(self): ''' Generate an "enum" type. Enums are handled by making a python class that contains only class members. Each class member is upper snaked case, e.g. ``MyTypeClass.MY_ENUM_VALUE`` and is assigned a string value from the CDP metadata. ''' def_to_json = dedent('''\ def to_json(self): return self.value''') def_from_json = dedent('''\ @classmethod def from_json(cls, json): return cls(json)''') code = f'class {self.id}(enum.Enum):\n' doc = docstring(self.description) if doc: code += indent(doc, 4) + '\n' for enum_member in self.enum: snake_name = snake_case(enum_member).upper() enum_code = f'{snake_name} = "{enum_member}"\n' code += indent(enum_code, 4) code += '\n' + indent(def_to_json, 4) code += '\n\n' + indent(def_from_json, 4) return code def generate_class_code(self): ''' Generate a class type. Top-level types that are defined as a CDP ``object`` are turned into Python dataclasses. ''' # children = set() code = dedent(f'''\ @dataclass class {self.id}:\n''') doc = docstring(self.description) if doc: code += indent(doc, 4) + '\n' # Emit property declarations. These are sorted so that optional # properties come after required properties, which is required to make # the dataclass constructor work. props = list(self.properties) props.sort(key=operator.attrgetter('optional')) code += '\n\n'.join(indent(p.generate_decl(), 4) for p in props) code += '\n\n' # Emit to_json() method. The properties are sorted in the same order as # above for readability. def_to_json = dedent('''\ def to_json(self): json = dict() ''') assigns = (p.generate_to_json(dict_='json') for p in props) def_to_json += indent('\n'.join(assigns), 4) def_to_json += '\n' def_to_json += indent('return json', 4) code += indent(def_to_json, 4) + '\n\n' # Emit from_json() method. The properties are sorted in the same order # as above for readability. def_from_json = dedent('''\ @classmethod def from_json(cls, json): return cls( ''') from_jsons = [] for p in props: from_json = p.generate_from_json(dict_='json') from_jsons.append(f'{p.py_name}={from_json},') def_from_json += indent('\n'.join(from_jsons), 8) def_from_json += '\n' def_from_json += indent(')', 4) code += indent(def_from_json, 4) return code def get_refs(self): ''' Return all refs for this type. ''' refs = set() if self.enum: # Enum types don't have refs. pass elif self.properties: # Enumerate refs for a class type. for prop in self.properties: if prop.items and prop.items.ref: refs.add(prop.items.ref) elif prop.ref: refs.add(prop.ref) else: # A primitive type can't have a direct ref, but it can have an items # which contains a ref. if self.items and self.items.ref: refs.add(self.items.ref) return refs class CdpParameter(CdpProperty): ''' A parameter to a CDP command. ''' def generate_code(self): ''' Generate the code for a parameter in a function call. ''' if self.items: if self.items.ref: nested_type = ref_to_python(self.items.ref) py_type = f"typing.List[{nested_type}]" else: nested_type = CdpPrimitiveType.get_annotation(self.items.type) py_type = f'typing.List[{nested_type}]' else: if self.ref: py_type = f"{ref_to_python(self.ref)}" else: py_type = CdpPrimitiveType.get_annotation( typing.cast(str, self.type)) if self.optional: py_type = f'typing.Optional[{py_type}]' code = f"{self.py_name}: {py_type}" if self.optional: code += ' = None' return code def generate_decl(self): ''' Generate the declaration for this parameter. ''' if self.description: code = inline_doc(self.description) code += '\n' else: code = '' code += f'{self.py_name}: {self.py_annotation}' return code def generate_doc(self): ''' Generate the docstring for this parameter. ''' doc = f':param {self.py_name}:' if self.experimental: doc += ' **(EXPERIMENTAL)**' if self.optional: doc += ' *(Optional)*' if self.description: desc = self.description.replace('`', '``').replace('\n', ' ') doc += f' {desc}' return doc def generate_from_json(self, dict_): ''' Generate the code to instantiate this parameter from a JSON dict. ''' code = super().generate_from_json(dict_) return f'{self.py_name}={code}' class CdpReturn(CdpProperty): ''' A return value from a CDP command. ''' @property def py_annotation(self): ''' Return the Python type annotation for this return. ''' if self.items: if self.items.ref: py_ref = ref_to_python(self.items.ref) ann = f"typing.List[{py_ref}]" else: py_type = CdpPrimitiveType.get_annotation(self.items.type) ann = f'typing.List[{py_type}]' else: if self.ref: py_ref = ref_to_python(self.ref) ann = f"{py_ref}" else: ann = CdpPrimitiveType.get_annotation(self.type) if self.optional: ann = f'typing.Optional[{ann}]' return ann def generate_doc(self): ''' Generate the docstring for this return. ''' if self.description: doc = self.description.replace('\n', ' ') if self.optional: doc = f'*(Optional)* {doc}' else: doc = '' return doc def generate_return(self, dict_): ''' Generate code for returning this value. ''' return super().generate_from_json(dict_) @dataclass class CdpCommand: ''' A CDP command. ''' name: str description: str experimental: bool deprecated: bool parameters: typing.List[CdpParameter] returns: typing.List[CdpReturn] domain: str @property def py_name(self): ''' Get a Python name for this command. ''' return snake_case(self.name) @classmethod def from_json(cls, command, domain) -> 'CdpCommand': ''' Instantiate a CDP command from a JSON object. ''' parameters = command.get('parameters', []) returns = command.get('returns', []) return cls( command['name'], command.get('description'), command.get('experimental', False), command.get('deprecated', False), [typing.cast(CdpParameter, CdpParameter.from_json(p)) for p in parameters], [typing.cast(CdpReturn, CdpReturn.from_json(r)) for r in returns], domain, ) def generate_code(self): ''' Generate code for a CDP command. ''' global current_version # Generate the function header if len(self.returns) == 0: ret_type = 'None' elif len(self.returns) == 1: ret_type = self.returns[0].py_annotation else: nested_types = ', '.join(r.py_annotation for r in self.returns) ret_type = f'typing.Tuple[{nested_types}]' ret_type = f"typing.Generator[T_JSON_DICT,T_JSON_DICT,{ret_type}]" code = '' code += f'def {self.py_name}(' ret = f') -> {ret_type}:\n' if self.parameters: params = [p.generate_code() for p in self.parameters] optional = False clean_params = [] for para in params: if "= None" in para: optional = True if optional and "= None" not in para: para += ' = None' clean_params.append(para) code += '\n' code += indent( ',\n'.join(clean_params), 8) code += '\n' code += indent(ret, 4) else: code += ret # Generate the docstring doc = '' if self.description: doc = self.description if self.experimental: doc += '\n\n**EXPERIMENTAL**' if self.parameters and doc: doc += '\n\n' elif not self.parameters and self.returns: doc += '\n' doc += '\n'.join(p.generate_doc() for p in self.parameters) if len(self.returns) == 1: doc += '\n' ret_doc = self.returns[0].generate_doc() doc += f':returns: {ret_doc}' elif len(self.returns) > 1: doc += '\n' doc += ':returns: A tuple with the following items:\n\n' ret_docs = '\n'.join(f'{i}. **{r.name}** - {r.generate_doc()}' for i, r in enumerate(self.returns)) doc += indent(ret_docs, 4) if doc: code += indent(docstring(doc), 4) # Generate the function body if self.parameters: code += '\n' code += indent('params: T_JSON_DICT = dict()', 4) code += '\n' assigns = (p.generate_to_json(dict_='params', use_self=False) for p in self.parameters) code += indent('\n'.join(assigns), 4) code += '\n' code += indent('cmd_dict: T_JSON_DICT = {\n', 4) code += indent(f"'method': '{self.domain}.{self.name}',\n", 8) if self.parameters: code += indent("'params': params,\n", 8) code += indent('}\n', 4) code += indent('json = yield cmd_dict', 4) if len(self.returns) == 0: pass elif len(self.returns) == 1: ret = self.returns[0].generate_return(dict_='json') code += indent(f'\nreturn {ret}', 4) else: ret = '\nreturn (\n' expr = ',\n'.join(r.generate_return(dict_='json') for r in self.returns) ret += indent(expr, 4) ret += '\n)' code += indent(ret, 4) return code def get_refs(self): ''' Get all refs for this command. ''' refs = set() for type_ in itertools.chain(self.parameters, self.returns): if type_.items and type_.items.ref: refs.add(type_.items.ref) elif type_.ref: refs.add(type_.ref) return refs @dataclass class CdpEvent: ''' A CDP event object. ''' name: str description: typing.Optional[str] deprecated: bool experimental: bool parameters: typing.List[CdpParameter] domain: str @property def py_name(self): ''' Return the Python class name for this event. ''' return inflection.camelize(self.name, uppercase_first_letter=True) @classmethod def from_json(cls, json: dict, domain: str): ''' Create a new CDP event instance from a JSON dict. ''' return cls( json['name'], json.get('description'), json.get('deprecated', False), json.get('experimental', False), [typing.cast(CdpParameter, CdpParameter.from_json(p)) for p in json.get('parameters', [])], domain ) def generate_code(self): ''' Generate code for a CDP event. ''' global current_version code = dedent(f'''\ @event_class('{self.domain}.{self.name}') @dataclass class {self.py_name}:''') code += '\n' desc = '' if self.description or self.experimental: if self.experimental: desc += '**EXPERIMENTAL**\n\n' if self.description: desc += self.description code += indent(docstring(desc), 4) code += '\n' code += indent( '\n'.join(p.generate_decl() for p in self.parameters), 4) code += '\n\n' def_from_json = dedent(f'''\ @classmethod def from_json(cls, json: T_JSON_DICT) -> {self.py_name}: return cls( ''') code += indent(def_from_json, 4) from_json = ',\n'.join(p.generate_from_json(dict_='json') for p in self.parameters) code += indent(from_json, 12) code += '\n' code += indent(')', 8) return code def get_refs(self): ''' Get all refs for this event. ''' refs = set() for param in self.parameters: if param.items and param.items.ref: refs.add(param.items.ref) elif param.ref: refs.add(param.ref) return refs @dataclass class CdpDomain: ''' A CDP domain contains metadata, types, commands, and events. ''' domain: str description: typing.Optional[str] experimental: bool dependencies: typing.List[str] types: typing.List[CdpType] commands: typing.List[CdpCommand] events: typing.List[CdpEvent] @property def module(self): ''' The name of the Python module for this CDP domain. ''' return snake_case(self.domain) @classmethod def from_json(cls, domain: dict): ''' Instantiate a CDP domain from a JSON object. ''' types = domain.get('types', []) commands = domain.get('commands', []) events = domain.get('events', []) domain_name = domain['domain'] return cls( domain_name, domain.get('description'), domain.get('experimental', False), domain.get('dependencies', []), [CdpType.from_json(type) for type in types], [CdpCommand.from_json(command, domain_name) for command in commands], [CdpEvent.from_json(event, domain_name) for event in events] ) def generate_code(self): ''' Generate the Python module code for a given CDP domain. ''' exp = ' (experimental)' if self.experimental else '' code = MODULE_HEADER.format(self.domain, exp) import_code = self.generate_imports() if import_code: code += import_code code += '\n\n' code += '\n' item_iter_t = typing.Union[CdpEvent, CdpCommand, CdpType] item_iter: typing.Iterator[item_iter_t] = itertools.chain( iter(self.types), iter(self.commands), iter(self.events), ) code += '\n\n\n'.join(item.generate_code() for item in item_iter) code += '\n' return code def generate_imports(self): ''' Determine which modules this module depends on and emit the code to import those modules. Notice that CDP defines a ``dependencies`` field for each domain, but these dependencies are a subset of the modules that we actually need to import to make our Python code work correctly and type safe. So we ignore the CDP's declared dependencies and compute them ourselves. ''' refs = set() for type_ in self.types: refs |= type_.get_refs() for command in self.commands: refs |= command.get_refs() for event in self.events: refs |= event.get_refs() dependencies = set() for ref in refs: try: domain, _ = ref.split('.') except ValueError: continue if domain != self.domain: dependencies.add(snake_case(domain)) code = '\n'.join(f'from . import {d}' for d in sorted(dependencies)) return code def generate_sphinx(self): ''' Generate a Sphinx document for this domain. ''' docs = self.domain + '\n' docs += '=' * len(self.domain) + '\n\n' if self.description: docs += f'{self.description}\n\n' if self.experimental: docs += '*This CDP domain is experimental.*\n\n' docs += f'.. module:: cdp.{self.module}\n\n' docs += '* Types_\n* Commands_\n* Events_\n\n' docs += 'Types\n-----\n\n' if self.types: docs += dedent('''\ Generally, you do not need to instantiate CDP types yourself. Instead, the API creates objects for you as return values from commands, and then you can use those objects as arguments to other commands. ''') else: docs += '*There are no types in this module.*\n' for type in self.types: docs += f'\n.. autoclass:: {type.id}\n' docs += ' :members:\n' docs += ' :undoc-members:\n' docs += ' :exclude-members: from_json, to_json\n' docs += '\nCommands\n--------\n\n' if self.commands: docs += dedent('''\ Each command is a generator function. The return type ``Generator[x, y, z]`` indicates that the generator *yields* arguments of type ``x``, it must be resumed with an argument of type ``y``, and it returns type ``z``. In this library, types ``x`` and ``y`` are the same for all commands, and ``z`` is the return type you should pay attention to. For more information, see :ref:`Getting Started: Commands `. ''') else: docs += '*There are no types in this module.*\n' for command in sorted(self.commands, key=operator.attrgetter('py_name')): docs += f'\n.. autofunction:: {command.py_name}\n' docs += '\nEvents\n------\n\n' if self.events: docs += dedent('''\ Generally, you do not need to instantiate CDP events yourself. Instead, the API creates events for you and then you use the event\'s attributes. ''') else: docs += '*There are no events in this module.*\n' for event in self.events: docs += f'\n.. autoclass:: {event.py_name}\n' docs += ' :members:\n' docs += ' :undoc-members:\n' docs += ' :exclude-members: from_json, to_json\n' return docs def parse(json_path, output_path): ''' Parse JSON protocol description and return domain objects. :param Path json_path: path to a JSON CDP schema :param Path output_path: a directory path to create the modules in :returns: a list of CDP domain objects ''' global current_version with open(json_path, encoding="utf-8") as json_file: schema = json.load(json_file) version = schema['version'] assert (version['major'], version['minor']) == ('1', '3') current_version = f'{version["major"]}.{version["minor"]}' domains = [] for domain in schema['domains']: domains.append(CdpDomain.from_json(domain)) return domains def generate_init(init_path, domains): ''' Generate an ``__init__.py`` that exports the specified modules. :param Path init_path: a file path to create the init file in :param list[tuple] modules: a list of modules each represented as tuples of (name, list_of_exported_symbols) ''' with open(init_path, "w", encoding="utf-8") as init_file: init_file.write(INIT_HEADER) for domain in domains: init_file.write(f'from . import {domain.module}\n') init_file.write('from . import util\n\n') def generate_docs(docs_path, domains): ''' Generate Sphinx documents for each domain. ''' logger.info('Generating Sphinx documents') # Remove generated documents for subpath in docs_path.iterdir(): subpath.unlink() # Generate document for each domain for domain in domains: doc = docs_path / f'{domain.module}.rst' with doc.open('w') as f: f.write(domain.generate_sphinx()) def main(browser_protocol_path, js_protocol_path, output_path): ''' Main entry point. ''' output_path = Path(output_path).resolve() json_paths = [ browser_protocol_path, js_protocol_path, ] # Generate util.py util_path = output_path / "util.py" with util_path.open('w') as util_file: util_file.write(UTIL_PY) # Remove generated code for subpath in output_path.iterdir(): if subpath.is_file() and subpath.name not in ('py.typed', 'util.py'): subpath.unlink() # Parse domains domains = [] for json_path in json_paths: logger.info('Parsing JSON file %s', json_path) domains.extend(parse(json_path, output_path)) domains.sort(key=operator.attrgetter('domain')) # Patch up CDP errors. It's easier to patch that here than it is to modify # the generator code. # 1. DOM includes an erroneous $ref that refers to itself. # 2. Page includes an event with an extraneous backtick in the description. for domain in domains: if domain.domain == 'DOM': for cmd in domain.commands: if cmd.name == 'resolveNode': # Patch 1 cmd.parameters[1].ref = 'BackendNodeId' elif domain.domain == 'Page': for event in domain.events: if event.name == 'screencastVisibilityChanged': # Patch 2 event.description = event.description.replace('`', '') for domain in domains: logger.info('Generating module: %s → %s.py', domain.domain, domain.module) module_path = output_path / f'{domain.module}.py' with module_path.open('w') as module_file: module_file.write(domain.generate_code()) init_path = output_path / '__init__.py' generate_init(init_path, domains) # Not generating the docs as we don't want people to directly # Use the CDP APIs # docs_path = here.parent / 'docs' / 'api' # generate_docs(docs_path, domains) py_typed_path = output_path / 'py.typed' py_typed_path.touch() if __name__ == '__main__': import sys assert sys.version_info >= (3, 7), "To generate the CDP code requires python 3.7 or later" args = sys.argv[1:] main(*args) selenium-selenium-4.18.1/conftest.py0000644000175000017500000002410614564764517017352 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import os import platform import socket import subprocess import time from test.selenium.webdriver.common.network import get_lan_ip from test.selenium.webdriver.common.webserver import SimpleWebServer from urllib.request import urlopen import pytest from selenium import webdriver drivers = ( "chrome", "edge", "firefox", "ie", "remote", "safari", "webkitgtk", "chromiumedge", "wpewebkit", ) def pytest_addoption(parser): parser.addoption( "--driver", action="append", choices=drivers, dest="drivers", metavar="DRIVER", help="driver to run tests against ({})".format(", ".join(drivers)), ) parser.addoption( "--browser-binary", action="store", dest="binary", help="location of the browser binary", ) parser.addoption( "--driver-binary", action="store", dest="executable", help="location of the service executable binary", ) parser.addoption( "--browser-args", action="store", dest="args", help="arguments to start the browser with", ) parser.addoption( "--headless", action="store", dest="headless", help="Allow tests to run in headless", ) parser.addoption( "--use-lan-ip", action="store_true", dest="use_lan_ip", help="Whether to start test server with lan ip instead of localhost", ) def pytest_ignore_collect(path, config): drivers_opt = config.getoption("drivers") _drivers = set(drivers).difference(drivers_opt or drivers) if drivers_opt: _drivers.add("unit") parts = path.dirname.split(os.path.sep) return len([d for d in _drivers if d.lower() in parts]) > 0 driver_instance = None @pytest.fixture(scope="function") def driver(request): kwargs = {} # browser can be changed with `--driver=firefox` as an argument or to addopts in pytest.ini driver_class = getattr(request, "param", "Chrome").capitalize() # skip tests if not available on the platform _platform = platform.system() if driver_class == "Safari" and _platform != "Darwin": pytest.skip("Safari tests can only run on an Apple OS") if (driver_class == "Ie") and _platform != "Windows": pytest.skip("IE and EdgeHTML Tests can only run on Windows") if "WebKit" in driver_class and _platform != "Linux": pytest.skip("Webkit tests can only run on Linux") # conditionally mark tests as expected to fail based on driver marker = request.node.get_closest_marker(f"xfail_{driver_class.lower()}") if marker is not None: if "run" in marker.kwargs: if marker.kwargs["run"] is False: pytest.skip() yield return if "raises" in marker.kwargs: marker.kwargs.pop("raises") pytest.xfail(**marker.kwargs) def fin(): global driver_instance if driver_instance is not None: driver_instance.quit() driver_instance = None request.addfinalizer(fin) driver_path = request.config.option.executable options = None global driver_instance if driver_instance is None: if driver_class == "Firefox": options = get_options(driver_class, request.config) if driver_class == "Chrome": options = get_options(driver_class, request.config) if driver_class == "Remote": options = get_options("Firefox", request.config) or webdriver.FirefoxOptions() options.set_capability("moz:firefoxOptions", {}) options.enable_downloads = True if driver_class == "WebKitGTK": options = get_options(driver_class, request.config) if driver_class == "Edge": options = get_options(driver_class, request.config) if driver_class.lower() == "wpewebkit": driver_class = "WPEWebKit" options = get_options(driver_class, request.config) if driver_path is not None: kwargs["service"] = get_service(driver_class, driver_path) if options is not None: kwargs["options"] = options driver_instance = getattr(webdriver, driver_class)(**kwargs) yield driver_instance if request.node.get_closest_marker("no_driver_after_test"): driver_instance = None def get_options(driver_class, config): browser_path = config.option.binary browser_args = config.option.args headless = bool(config.option.headless) options = None if driver_class == "ChromiumEdge": options = getattr(webdriver, "EdgeOptions")() if browser_path or browser_args: if not options: options = getattr(webdriver, f"{driver_class}Options")() if driver_class == "WebKitGTK": options.overlay_scrollbars_enabled = False if browser_path is not None: options.binary_location = browser_path if browser_args is not None: for arg in browser_args.split(): options.add_argument(arg) if headless: if not options: options = getattr(webdriver, f"{driver_class}Options")() if driver_class == "Chrome" or driver_class == "Edge": options.add_argument("--headless=new") if driver_class == "Firefox": options.add_argument("-headless") return options def get_service(driver_class, executable): # Let the default behaviour be used if we don't set the driver executable if not executable: return None module = getattr(webdriver, driver_class.lower()) service = module.service.Service(executable_path=executable) return service @pytest.fixture(scope="session", autouse=True) def stop_driver(request): def fin(): global driver_instance if driver_instance is not None: driver_instance.quit() driver_instance = None request.addfinalizer(fin) def pytest_exception_interact(node, call, report): if report.failed: global driver_instance if driver_instance is not None: driver_instance.quit() driver_instance = None @pytest.fixture def pages(driver, webserver): class Pages: def url(self, name, localhost=False): return webserver.where_is(name, localhost) def load(self, name): driver.get(self.url(name)) return Pages() @pytest.fixture(autouse=True, scope="session") def server(request): drivers = request.config.getoption("drivers") if drivers is None or "remote" not in drivers: yield None return _host = "localhost" _port = 4444 _path = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "java/src/org/openqa/selenium/grid/selenium_server_deploy.jar", ) def wait_for_server(url, timeout): start = time.time() while time.time() - start < timeout: try: urlopen(url) return 1 except OSError: time.sleep(0.2) return 0 _socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) url = f"http://{_host}:{_port}/status" try: _socket.connect((_host, _port)) print( "The remote driver server is already running or something else" "is using port {}, continuing...".format(_port) ) except Exception: print("Starting the Selenium server") process = subprocess.Popen( [ "java", "-jar", _path, "standalone", "--port", "4444", "--selenium-manager", "true", "--enable-managed-downloads", "true", ] ) print(f"Selenium server running as process: {process.pid}") assert wait_for_server(url, 10), f"Timed out waiting for Selenium server at {url}" print("Selenium server is ready") yield process process.terminate() process.wait() print("Selenium server has been terminated") @pytest.fixture(autouse=True, scope="session") def webserver(request): host = get_lan_ip() if request.config.getoption("use_lan_ip") else "0.0.0.0" webserver = SimpleWebServer(host=host) webserver.start() yield webserver webserver.stop() @pytest.fixture def edge_service(): from selenium.webdriver.edge.service import Service as EdgeService return EdgeService @pytest.fixture(scope="function") def driver_executable(request): return request.config.option.executable @pytest.fixture(scope="function") def clean_service(request): try: driver_class = request.config.option.drivers[0].capitalize() except AttributeError: raise Exception("This test requires a --driver to be specified.") yield get_service(driver_class, request.config.option.executable) @pytest.fixture(scope="function") def clean_driver(request): try: driver_class = request.config.option.drivers[0].capitalize() except AttributeError: raise Exception("This test requires a --driver to be specified.") driver_reference = getattr(webdriver, driver_class) yield driver_reference if request.node.get_closest_marker("no_driver_after_test"): driver_reference = None selenium-selenium-4.18.1/AUTHORS0000644000175000017500000010440314564764517016222 0ustar carstencarsten0uk 1kastner <1kastner@users.noreply.github.com> 43081j <43081j@users.noreply.github.com> Aaron Evans Aaron McKinley Abdelrahman Talaat Abdullah Aslam <48642109+code-with-abdullah@users.noreply.github.com> Abhijeet Kasurde Abhilash Thaduka abidema <44252090+abidema@users.noreply.github.com> Adam Demuri Adam Goucher Adam Smith AdamPDotty <81536237+AdamPDotty@users.noreply.github.com> Adi Roiban adiohana Aditya Pratap Singh Adrian Dymorz Adrian Leonhard Agustin Pequeno <33221555+aguspe@users.noreply.github.com> Ahmed Ashour AJ Ajay Kemparaj Akhil Lb Akuli Al Sutton Alan Baird Alan Verresen Albert Alberto Alberto Scotto albertor24 Aleksei Moskvin Alex <72409387+fergushev@users.noreply.github.com> Alex Alex Eagle Alex Henrie Alex Rodionov Alex Savchuk Alexander Bayandin Alexander Dobrynin Alexander Kavanaugh Alexandr Savchuk Alexandre Abreu Alexei Barantsev Alexei Vinogradov Alexey Pelykh Alexis J. Vuillemin Alexis Vuillemin Alfonso Presa Alice Yang aliking Allon Murienik Alpatron Amil Uslu Amit Bhoraniya Amitabh Saikia Anand Bagmar Anand Jayaram Anastasia Vataman Andras Hatvani Andre Wiggins <459878+andrewiggins@users.noreply.github.com> Andreas Tolf Tolfsen Andreas Tolfsen Andrei Botalov Andrei Rusu Andrei Solntsev Andrey Botalov Andrii Rohovets Andy Duncan anonymous_sdet Anthony Sottile Anton Usmansky Anton Velma Anton Vynogradenko Ardi <47633543+dev-ardi@users.noreply.github.com> Argo Triwidodo Ariel Juodziukynas arnonax arnonax-tr <62980738+arnonax-tr@users.noreply.github.com> Artem Koshelev Artem Kozaev ArthurGIT2017 <25633602+ArthurGIT2017@users.noreply.github.com> Artur Artur Orlov Ashley Trinh Aslak Hellesøy asmundak Atsushi Tatsuma Aurélien Pupier Austin Michael Wilkins <42476341+amwilkins@users.noreply.github.com> BaerMitUmlaut Baran Ozgul Bartek Florczak Ben Congleton Ben Kucera <14625260+Bkucera@users.noreply.github.com> Ben Lamm Ben Sedat Benjamin Forehand Jr bhecquet bhkwan Bill Agee bob Bob Baron Bob Lubecker Bobby Jap Bogdan Bogdan Condurache Bohdan Tkachenko Boni García bootstraponline Boris Osipov Boris Petrov Boris Wrubel bozdemir84 Branden Cash <203336+ammmze@users.noreply.github.com> Brandon Walderman Brandon Williams Brendan Mannix Bret Pettichord Brett Porter Brett Randall Brian Burg Brian Hawley Caleb P. Burns Calin Marina camelmasa Carlos Garcia Campos Carlos Ortega Carlos Villela Carson McDonald ce86f3bb9faf71e <118820152+ce86f3bb9faf71e@users.noreply.github.com> Cervac Petru cezarelnazli ch-saeki <31008335+ch-saeki@users.noreply.github.com> ChanMin Kim Charles Lavery Charles Thomas Chethana Paniyadi Chirag Jayswal chris Chris Block Chris Gamache Chris Martin Chris Mohr Chris Stringer Chris Ward Christian Biesinger Christian Clauss Christopher Buttkus Christopher Wood CI Build cjayswal clarkenciel Clay Martin cliffordcheng <48222691+cliffordcheng@users.noreply.github.com> clubfest ColinF colons Connor Shea Corey Goldberg Corey Schooler Coty Rosenblath Craig Nishina CsolG customcommander Cédric Boutillier Dakkaron Damien Allison Damir Dan Fabulich Dana Sherson Daniel Bengtsson Daniel Boelzle [:dbo] Daniel Brown Daniel Davison Daniel Fackrell Daniel Hahler Daniel Montoya Daniel P. Purkhús Daniel Rozenberg Daniel Wagner-Hall Danilo Bargen Danny Staple danvine DanZeuss darek8686 Darrell DeBoer Darren Cotterill Darrin Cherry Dave Hoover Dave Hunt daviande David Burns David English David Fischer David Haeffner David Hewson David Kemp David Lai David Sanders David Shaffer David Vargas David Wang David Zhu Debanjan Choudhury deedy5 <65482418+deedy5@users.noreply.github.com> Denis Demchenko Dennis Oelkers dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Derrick Isaacson DevineLiu <23489096+DevineLiu@users.noreply.github.com> Dharin Shah Dharrya Diego Fernández Santos Diego Molina Dima Kovalenko Dima Veselov Dmitriy Sintsov Dmitry Dubenets Dmitry Tokarev Dmytro Shpakovskyi dnknitro doctor-house <66467615+doctor-house@users.noreply.github.com> Dominik Dary Dominik Rauch Dominik Stadler Donald Pipowitch Dor Blayzer <59066376+Dor-bl@users.noreply.github.com> dosas Doug Simmons Dounia Berrada dratler Dvoryadkin Pavel <52860505+DvoryadkinPavel@users.noreply.github.com> Dylan Lacey Dylan Reichstadt Dylan Semler Earlopain <14981592+Earlopain@users.noreply.github.com> Eberhard Beilharz Edi Weissmann Edirin Atumah Eduardo Wermuth Edward Ned Harvey EdwinVanVliet Ela Makiej elgatov Eli Flanagan Elias Faxö Ellis Percival Enrique Daimiel eoff Eran Messeri Eric Allen Eric Plaster Erik Beans Erik E. Beerepoot Erik Kuefler Evan Sangaline Evgeniy Roldukhin EwaMarek Fan <1135611487@qq.com> Felipe Knorr Kuhn Fenil Mehta <42742240+fenilgmehta@users.noreply.github.com> Florian Apolloner Florian LOPES Florian Mutter <32459530+florianmutter@users.noreply.github.com> Florian Zipperle Francis Bergin Franz Liedke François Freitag François JACQUES François Reynaud Frederik Carlier Fredrik Wollsén freynaud FrySabotage Fumiaki MATSUSHIMA fuyou Gaurav gentoo90 George Adams Georgii Dolzhykov Gerald Ehmayer Gerry Gao Gestalt LUR GFHuang <4510984+GF-Huang@users.noreply.github.com> ggkiokas <115367874+ggkiokas@users.noreply.github.com> Ghjuvan Lacambre Giorgos Tzampanakis glaszig Glib Briia Godefroid Chapelle Godefroid Chapelle gopackgo90 Gopal Patel GPT14 GQAssurance <34662917+GQAssurance@users.noreply.github.com> Grace Tang Graham Russell granak Grant <34662917+GQAssurance@users.noreply.github.com> Greg Fraley Greg Hogan Gregory Block gregory.kleiner@accolade.com Grey Li Grigory Mischenko Grzegorz Halat Guangyue Xu <64437609+guangyuexu@users.noreply.github.com> Guilherme Sousa <33522742+dilhelh@users.noreply.github.com> Guille h-arlt Hamir Mahal Hanbo Wang haqer1 Harmandeep Singh Harry Harshit Agrawal <94462364+harshit-bs@users.noreply.github.com> havja Haw-bin Chai hectorhon Heky helen3141 <54561656+helen3141@users.noreply.github.com> Henrik Skupin Herryanto Siatono Herst Hiroaki Ninomiya Hirotaka Tagawa / wafuwafu13 hornyja4 Hugo van Kemenade huntr-helper Hyesung Lee Iain Dawson Iain Dawson Ian Lesperance ian zhang Iaroslav Naidon ifland Ilya Kozhevnikov Ilyas Bayraktar Immanuel Hayden Innokenty Shuvalov Isaac A. Murchie Isaul Vargas Ish Abbi Ivan De Marino Ivan Kalinin Ivan Krutov Ivan Pozdeev J.D. Purcell Jack Allen <38332643+jackall3n@users.noreply.github.com> Jacob Kiesel Jacob Walls Jacob Wejendorp Jake Jake Garelick Jake Klingensmith Jakub Vrána jamadam James Braza James Cooper James Garbutt <43081j@users.noreply.github.com> James Hilliard James Martin James Strachen jamespdo Jan Trejbal Jan Weitz Jane Tymoschuk Jared Webber Jari Bakken Jason Jason Anderson Jason Carr Jason Hu Jason Huggins Jason Juang Jason Leyba Jason Parry Jason Watt Javier Candeira Jayakumar Chinnappan Jayasankar Jayme Jayson Smith Jean-Francois Roche Jeff Moore Jeff Xiong Jennifer Bevan Jens Diemer Jeremy Herault Jeroen van Warmerdam jerome-nexedi Jerry Pussinen JerryJia jess010 Jesserd July Jewen Xiao Jiahua Fan Jiayao Yu Jie Tina Wang Jigar wala Jim Jim Brännlund Jim Brännlund Jim Evans Jim Reid Jim van Musscher jkohls jmuramatsu Joaquín Romero jochenberger Joe Lencioni Joe Schulte Joe Walnes Joel Hillacre joe_schulte Johan Lorenzo JohanBrorson John Barbuto John Chen John Comeau John Dorlus John F. Douthat John J. Barton John Pelly Johnny.H Johnson <20457146+j3soon@users.noreply.github.com> joma74 Jon Dufresne Jon Spalding Jon Wallsten Jonah Jonah Stiennon Jonatan Kronqvist Jonathan Leitschuh Jonathan Lipps Jonathon Kereliuk Jongkuen Hong Jordan Mace josephg Josh Goldberg Joshua Bruning Joshua Fehler Joshua Grant João Luca Ripardo JT Archie jugglinmike Julian Didier Julian Harty Julian Kung Julie Ralph Julien Phalip Junpei Kawamoto juperala JustasM <59362982+JustasMonkev@users.noreply.github.com> Justin Tulloss Justine Tunney justinwoolley@gmail.com jwoolley <19597672+jwoolley@users.noreply.github.com> Jörg Sautter Kamen Litchev Karl Kuehn Karl-Philipp Richter kateposener katrina95 <34797724+katrina95@users.noreply.github.com> Kazuaki Matsuo Kazuhiro NISHIYAMA Kazuki Higashiguchi keenangraham Ken Kania Kensuke Numakura KentGu Kevin C Kevin Dew Kevin Menard kevin.cho Kian Eliasi Kian Meng Ang Kim Hyeonseok kjleftin Konstantin Kotenko <36271666+kkotenko@users.noreply.github.com> kou1okada Kouzukii Kris <1611248+Rinzwind@users.noreply.github.com> Krishna Suravarapu <36037520+KrishnaSuravarapu@users.noreply.github.com> Krishnan Mahadevan Kristian Rosenvold Krzysztof Księżyk kuhtich Kunal Gosar kurniady@gmail.com Kurt Alfred Kluever kvetko <37440134+kvetko@users.noreply.github.com> Kyle McGonagle Lamberto Larry Diamond <1066589+larrydiamond@users.noreply.github.com> Larry Yu larsiver Laura Laurence Rowe Lauro Moura Leo Laskin Leon Shams <52867365+LeonShams@users.noreply.github.com> Leonardo Salles Levi Noecker lhuang Long Ly Long Nguyen lsowen Lucas Diniz Lucas Tierney Luis Correia Luis Pflamminger Luke Hill Luke Inman-Semerau lukec Lukáš Linhart Lyudmil Latinov Machinexa2 <60662297+machinexa2@users.noreply.github.com> Maciej Pakulski Magnus E. Halvorsen Maid <37146904+ParadiseWitch@users.noreply.github.com> Malcolm Rowe MandarJKulkarni <33712629+MandarJKulkarni@users.noreply.github.com> Maneesh MS Manoj Kumar Manuel Blanco Marc Fisher Marc Guillemot Marc Schlegel Marcel Wilson Marcin Strzyz <37447884+mastrzyz@users.noreply.github.com> marcotcr Marcus Merrell Maria Filonova Mark Banner Mark Charsley Mark Christian Mark Collin Mark Mayo Mark Stacey Mark Watson Marvin A. Ruder Marvin Ojwang Masayuki Hokimoto Mateusz Kajka <18029907+codemrkay@users.noreply.github.com> Mathias Kresin Mathias Rangel Wulff mathlang Matt McCartney Matt Q Matthew Kempkers <118692289+matt-kemp-m2x@users.noreply.github.com> Matthew Lymer Matthew Rahtz matthewdoerksen MatzFan Max Perrello Max Schmitt Maxim Lobanov Maxim Perepelitsa mcharsley Meir Blachman Melroy van den Berg Michael Benz Michael Glass Michael Keeley Michael Klepikov Michael Mintz Michael Nikitochkin Michael P. Jung Michael Render Michael Tamm Michael Zhou Michal Čihař Michał Herda Michele Sama Mickaël Schoentgen Microsoft Provenance Contributions middlingphys <38708390+middlingphys@users.noreply.github.com> Miguel Carboni Mike Bellew Mike Melia Mike Pennisi Mike Roberts Mike Williams Mikhail Fedosov Mikhail Panin Miki Tebeka Mikko Tiihonen Milan Falešník ming Mirko Nasato mitchloudenbeck Miten Chauhan mkvetko MMK-IBSEN <124664589+MMK-IBSEN@users.noreply.github.com> Mohab Mohie mohammadsavadkuhi Moisés Moritz Kiefer Moritz Sichert morrishoresh morskyrv <18137385+morskyrv@users.noreply.github.com> Moshe Atlow mpurland mtrea <32470080+mtrea@users.noreply.github.com> Mubariz Hajimuradov Muhammad Hammad <33136628+mhnaeem@users.noreply.github.com> Muthu Kannan MWschutte <72599545+MWschutte@users.noreply.github.com> myslak71 Nate Lowry Nathan Isom native-api Naveen <172697+naveensrinivasan@users.noreply.github.com> Naveen Singh <36371707+Naveen3Singh@users.noreply.github.com> Neil Carvalho Nelson Sproul Nick Crews Nick Gaya Nick Schonning Nicolas Sotgui Nik Nyby Nikhil Agarwal Nikolay Borisenko Nina Satragno nir-tal-talkspace <71274151+nir-tal-talkspace@users.noreply.github.com> Nirantak Raghav Nitish Noel Gordon Nowell Strite Nozomi Ito no_author nvonop Oboleninov Anton Oleg Höfling Oleg Ridchenko <73664101+oleg-rd@users.noreply.github.com> Oleksii Olivier SCHNEIDER Olle Jonsson Olly Dean Ondřej Machulda Ondřej Čertík orangeudav Oscar Devora <100381276+RevealOscar@users.noreply.github.com> Outsider Paladin Wang <49390614+eversoutheast@users.noreply.github.com> Palmer Bandy <37938675+palmermbandy@users.noreply.github.com> Pat Tullmann Patrice Jaton Patrick Beart Patrick Gansterer Patrick Lightbody Paul G Webster Paul Hammant Pavel Lobashov Perryn Fowler Pete Johns Peter Hedenskog Peter M. Landwehr petruc Phani Rithvij Philipp Hancke Philippe Hanrigou Phillip Haydon phoenix384 pinterior Piotr Witoslawski pitachips PombaM Potapov Dmitriy Prakhar Rawat praveendvd <45095911+praveendvd@users.noreply.github.com> Puja Jagani Pulkit Sharma Pydi Chandra Qays H. Poonawala Radosław Sporny Rafael Chavez Rahul Shah Rajendra Kadam Ram Rachum Rami Ravi Sawlani rbri rchatley rchatley@gmail.com reichsta Reinaldo Rossetti Reinhold Degenfellner Remco richard.hines RichCrook richseviora Rishav Trivedi Rob Richardson Rob Wu Robert Elliot Robert Fletcher Roberto Rivera Robin Stocker Rod McNew Roman Yurchak Roman Yurchak Roman Zoller rompic Rory Craig-Barnes Roubal Sehgal <44202409+roubalsehgal@users.noreply.github.com> Rouke Broersma roushikk rovner Rune Flobakk Russ Amos RussiaVk <43515485+RussiaVk@users.noreply.github.com> RustyNail Ryan Fitzpatrick Ryan Wilcox Ryszard Perkowski Sajad Torkamani Saksham Gupta Salvador Cabrera Lozano Sam Uong Samit Badle Samuel Bétrisey Sandeep Suryaprasad <26169602+sandeepsuryaprasad@users.noreply.github.com> Sankha Narayan Guria Santiago Suarez Ordoñez Sarah Bird Sayyid Ali Sajjad Rizavi <58586026+ali-sajjad-rizavi@users.noreply.github.com> Scott Babcock Scott Sauber Scott Stevens Sean Gomez <34379448+Sean-Gomez@users.noreply.github.com> Sean Poulter seanrand57 Sebastian Meyer Sebastian Monte Sebastien Guillemot seidnerj Selenium CI Bot Sen ZmaKi <90490506+SenZmaKi@users.noreply.github.com> Sergey Chipiga Sergey Fursov Sergey Tikhomirov Seth Lemanek Seva Lotoshnikov Shan Shashank <42868640+snsten@users.noreply.github.com> Shay Dratler Shengfa <3363396+k7z45@users.noreply.github.com> shin Shinya Kasatani Shishu Raj Pandey Shreyan Avigyan <74560907+shreyanavigyan@users.noreply.github.com> Shubham Singh <41840111+singh811@users.noreply.github.com> Shuhai Shen Simon K Simon Perepelitsa Simon Stewart skratchdot smhc Snail space88man Sri Harsha sridharUpputuri <52928428+sridharUpputuri@users.noreply.github.com> Srinivasan Sekar Sripathi Pai Sruthi Stanley Hon Stanley Hon Stephen Kuenzli Steve Brown Steve Smith Steven Hazel stevetracvc <70416691+stevetracvc@users.noreply.github.com> Stoyan Dimkov Stuart Knightly sufyanAbbasi sugama sunnyyukaige symonk Take take0x <89313929+take0x@users.noreply.github.com> Takeshi Kishi Takuho NAKANO Takuma Chiba Tamas Utasi <3823780+utamas@users.noreply.github.com> Tamsil Sajid Amani Tamás Buka Tatsuya Hoshino Terence Haddock thecr8tr Thomas Flori Thomas Grainger Thomas Walpole Thunderforge Tim Sutton Tim van der Lippe timm-permeance Timofey Vasenin Timur Zolotuhin ting <44369205+71n9@users.noreply.github.com> tirana Titus Fortner Tobias Lidskog Tobias Smolka <37370256+tosmolka@users.noreply.github.com> Toda Hiroshi Toilal Tom Longhurst Tom Trumper tomaszn Tomer Steinfeld Tommy Beadle tommywo Tomohiro Endo Tony Hignett Tony Narlock tporeba trabulmonkee trademark18 Trey Chadick Tricia Crichton TriciaCrichton <54917582+TriciaCrichton@users.noreply.github.com> Trig Troy Walsh ttanaka tvataire Ulf Adams Ulrich Buchgraber User253489 V24 <55334829+umarfarouk98@users.noreply.github.com> Valery Yatsynovich Varun Menon varunsurapaneni <67070327+varunsurapaneni@users.noreply.github.com> Vedanth Vasu Dev <61700595+vedanthvdev@users.noreply.github.com> vedanthvdev <61700595+vedanthvdev@users.noreply.github.com> vergiliu vflame <0x484x0@gmail.com> Victor Tang Viet Nguyen Duc Vijay Singh Vijendarn Selvarajah <11275608+vijay44@users.noreply.github.com> VijendraEAtech <39116868+VijendraEAtech@users.noreply.github.com> Vikas Goel VimalRaj Selvam Vincent Ladeuil vinoth959 Viren Negi <63040+meetme2meat@users.noreply.github.com> Virender Singh Vishnuprakash P K Vitaliy Potapov Vladimir Támara Patiño VladimirPodolyan <36446855+VladimirPodolyan@users.noreply.github.com> Vladislav Velichko <111522705+vlad8x8@users.noreply.github.com> Vyvyan Codd Václav Votípka Werner Robitza wiggin15 wildloop WORKSTATION02 wpc y-yagi Yaroslav Admin Yash Ladha <201551061@iiitvadodara.ac.in> Yehuda Davis Yevgeniy Shunevych Yi Zeng yk9772 <93392713+yk9772@users.noreply.github.com> Yurii Karabas <1998uriyyo@gmail.com> Yusuke Noda <91508381+yusuke-noda@users.noreply.github.com> Zach Attas Zeki Mokhtarzada zhangwenqiang00 Zhuo Peng Ziyu Zoltar - Knower of All zsong Ákos Lukács Étienne Barrié 保木本将之 selenium-selenium-4.18.1/LICENSE0000644000175000017500000002614514564764517016165 0ustar carstencarsten Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2024 Software Freedom Conservancy (SFC) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. selenium-selenium-4.18.1/NOTICE0000644000175000017500000000013114564764517016047 0ustar carstencarstenCopyright 2011-2024 Software Freedom Conservancy Copyright 2004-2011 Selenium committers selenium-selenium-4.18.1/setup.cfg0000644000175000017500000000046614564764517016777 0ustar carstencarsten[flake8] exclude = .tox,docs/source/conf.py,*venv # Disable this once black is applied throughout & line length is better handled. extend-ignore = E501, E203 # This does nothing for now as E501 is ignored. max-line-length = 120 [tool:pytest] addopts = -ra python_files = test_*.py *_tests.py testpaths = test selenium-selenium-4.18.1/docs/0000755000175000017500000000000014564764517016100 5ustar carstencarstenselenium-selenium-4.18.1/docs/requirements.txt0000644000175000017500000000003414564764517021361 0ustar carstencarstenJinja2==3.1.3 Sphinx==1.8.2 selenium-selenium-4.18.1/docs/source/0000755000175000017500000000000014564764517017400 5ustar carstencarstenselenium-selenium-4.18.1/docs/source/index.rst0000755000175000017500000001350314564764517021246 0ustar carstencarsten====================== Selenium Client Driver ====================== Introduction ============ Python language bindings for Selenium WebDriver. The `selenium` package is used to automate web browser interaction from Python. +-----------------+--------------------------------------------------------------------------------------+ | **Home**: | https://selenium.dev | +-----------------+--------------------------------------------------------------------------------------+ | **GitHub**: | https://github.com/SeleniumHQ/Selenium | +-----------------+--------------------------------------------------------------------------------------+ | **PyPI**: | https://pypi.org/project/selenium/ | +-----------------+--------------------------------------------------------------------------------------+ | **IRC/Slack**: | `Selenium chat room `_ | +-----------------+--------------------------------------------------------------------------------------+ Several browsers/drivers are supported (Firefox, Chrome, Internet Explorer), as well as the Remote protocol. Supported Python Versions ========================= * Python 3.8+ Installing ========== If you have `pip `_ on your system, you can simply install or upgrade the Python bindings:: pip install -U selenium Alternately, you can download the source distribution from `PyPI `, unarchive it, and run:: python setup.py install Note: You may want to consider using `virtualenv `_ to create isolated Python environments. Drivers ======= Selenium requires a driver to interface with the chosen browser. Firefox, for example, requires `geckodriver `_, which needs to be installed before the below examples can be run. Make sure it's in your `PATH`, e. g., place it in `/usr/bin` or `/usr/local/bin`. Failure to observe this step will give you an error `selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs to be in PATH.` Other supported browsers will have their own drivers available. Links to some of the more popular browser drivers follow. +--------------+-----------------------------------------------------------------------+ | **Chrome**: | https://chromedriver.chromium.org/downloads | +--------------+-----------------------------------------------------------------------+ | **Edge**: | https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ | +--------------+-----------------------------------------------------------------------+ | **Firefox**: | https://github.com/mozilla/geckodriver/releases | +--------------+-----------------------------------------------------------------------+ | **Safari**: | https://webkit.org/blog/6900/webdriver-support-in-safari-10/ | +--------------+-----------------------------------------------------------------------+ Example 0: ========== * open a new Firefox browser * load the page at the given URL .. code-block:: python from selenium import webdriver browser = webdriver.Firefox() browser.get('http://selenium.dev/') Example 1: ========== * open a new Firefox browser * load the Yahoo homepage * search for "seleniumhq" * close the browser .. code-block:: python from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys browser = webdriver.Firefox() browser.get('http://www.yahoo.com') assert 'Yahoo' in browser.title elem = browser.find_element(By.NAME, 'p') # Find the search box elem.send_keys('seleniumhq' + Keys.RETURN) browser.quit() Example 2: ========== Selenium WebDriver is often used as a basis for testing web applications. Here is a simple example using Python's standard `unittest `_ library: .. code-block:: python import unittest from selenium import webdriver class GoogleTestCase(unittest.TestCase): def setUp(self): self.browser = webdriver.Firefox() self.addCleanup(self.browser.quit) def test_page_title(self): self.browser.get('http://www.google.com') self.assertIn('Google', self.browser.title) if __name__ == '__main__': unittest.main(verbosity=2) Selenium Grid (optional) ========================== For local Selenium scripts, the Java server is not needed. To use Selenium remotely, you need to also run the Selenium grid. For information on running Selenium Grid: https://www.selenium.dev/documentation/grid/getting_started/ To use Remote WebDriver see: https://www.selenium.dev/documentation/webdriver/drivers/remote_webdriver/?tab=python Use The Source Luke! ==================== View source code online: +-----------+------------------------------------------------------+ | Official: | https://github.com/SeleniumHQ/selenium/tree/trunk/py | +-----------+------------------------------------------------------+ Contributing ============= - Create a branch for your work - Ensure `tox` is installed (using a `virtualenv` is recommended) - `python3.8 -m venv .venv && . .venv/bin/activate && pip install tox` - After making changes, before committing execute `tox -e linting` - If tox exits `0`, commit and push otherwise fix the newly introduced breakages. - `flake8` requires manual fixes - `black` will often rewrite the breakages automatically, however the files are unstaged and should staged again. - `isort` will often rewrite the breakages automatically, however the files are unstaged and should staged again. selenium-selenium-4.18.1/docs/source/common/0000755000175000017500000000000014564764517020670 5ustar carstencarstenselenium-selenium-4.18.1/docs/source/common/selenium.common.exceptions.rst0000644000175000017500000000231314564764517026711 0ustar carstencarstenselenium.common.exceptions ========================== .. automodule:: selenium.common.exceptions .. rubric:: Exceptions .. autosummary:: ElementClickInterceptedException ElementNotInteractableException ElementNotSelectableException ElementNotVisibleException ImeActivationFailedException ImeNotAvailableException InsecureCertificateException InvalidArgumentException InvalidCookieDomainException InvalidCoordinatesException InvalidElementStateException InvalidSelectorException InvalidSessionIdException InvalidSwitchToTargetException JavascriptException MoveTargetOutOfBoundsException NoAlertPresentException NoSuchAttributeException NoSuchCookieException NoSuchElementException NoSuchFrameException NoSuchShadowRootException NoSuchWindowException ScreenshotException SeleniumManagerException SessionNotCreatedException StaleElementReferenceException TimeoutException UnableToSetCookieException UnexpectedAlertPresentException UnexpectedTagNameException UnknownMethodException WebDriverException selenium-selenium-4.18.1/docs/source/api.rst0000644000175000017500000001064714564764517020713 0ustar carstencarsten:orphan: ====================== Selenium Documentation ====================== Common ------ .. currentmodule:: selenium.common .. autosummary:: :toctree: common selenium.common.exceptions Webdriver.common ---------------- .. currentmodule:: selenium.webdriver.common .. autosummary:: :toctree: webdriver selenium.webdriver.common.action_chains selenium.webdriver.common.alert selenium.webdriver.common.by selenium.webdriver.common.desired_capabilities selenium.webdriver.common.keys selenium.webdriver.common.log selenium.webdriver.common.print_page_options selenium.webdriver.common.proxy selenium.webdriver.common.utils selenium.webdriver.common.service selenium.webdriver.common.options selenium.webdriver.common.timeouts selenium.webdriver.common.window selenium.webdriver.common.actions.action_builder selenium.webdriver.common.actions.input_device selenium.webdriver.common.actions.interaction selenium.webdriver.common.actions.key_actions selenium.webdriver.common.actions.key_input selenium.webdriver.common.actions.mouse_button selenium.webdriver.common.actions.pointer_input selenium.webdriver.common.actions.pointer_actions selenium.webdriver.common.actions.wheel_input selenium.webdriver.common.actions.wheel_actions selenium.webdriver.common.html5.application_cache selenium.webdriver.common.virtual_authenticator Webdriver.support ----------------- .. currentmodule:: selenium.webdriver.support .. autosummary:: :toctree: webdriver_support selenium.webdriver.support.abstract_event_listener selenium.webdriver.support.color selenium.webdriver.support.event_firing_webdriver selenium.webdriver.support.expected_conditions selenium.webdriver.support.relative_locator selenium.webdriver.support.select selenium.webdriver.support.wait Webdriver.chrome ---------------- .. currentmodule:: selenium.webdriver.chrome .. autosummary:: :toctree: webdriver_chrome selenium.webdriver.chrome.options selenium.webdriver.chrome.service selenium.webdriver.chrome.webdriver Webdriver.chromium ------------------ .. currentmodule:: selenium.webdriver.chromium .. autosummary:: :toctree: webdriver_chromium selenium.webdriver.chromium.options selenium.webdriver.chromium.service selenium.webdriver.chromium.remote_connection selenium.webdriver.chromium.webdriver Webdriver.edge -------------- .. currentmodule:: selenium.webdriver.edge .. autosummary:: :toctree: webdriver_edge selenium.webdriver.edge.options selenium.webdriver.edge.service selenium.webdriver.edge.webdriver Webdriver.firefox ----------------- .. currentmodule:: selenium.webdriver.firefox .. autosummary:: :toctree: webdriver_firefox selenium.webdriver.firefox.extension_connection selenium.webdriver.firefox.remote_connection selenium.webdriver.firefox.firefox_binary selenium.webdriver.firefox.options selenium.webdriver.firefox.firefox_profile selenium.webdriver.firefox.webdriver selenium.webdriver.firefox.service Webdriver.ie ------------ .. currentmodule:: selenium.webdriver.ie .. autosummary:: :toctree: webdriver_ie selenium.webdriver.ie.service selenium.webdriver.ie.options selenium.webdriver.ie.webdriver Webdriver.remote ---------------- .. currentmodule:: selenium.webdriver.remote .. autosummary:: :toctree: webdriver_remote selenium.webdriver.remote.command selenium.webdriver.remote.bidi_connection selenium.webdriver.remote.errorhandler selenium.webdriver.remote.mobile selenium.webdriver.remote.remote_connection selenium.webdriver.remote.shadowroot selenium.webdriver.remote.utils selenium.webdriver.remote.webdriver selenium.webdriver.remote.webelement selenium.webdriver.remote.file_detector selenium.webdriver.remote.script_key selenium.webdriver.remote.switch_to Webdriver.safari ---------------- .. currentmodule:: selenium.webdriver.safari .. autosummary:: :toctree: webdriver_safari selenium.webdriver.safari.options selenium.webdriver.safari.remote_connection selenium.webdriver.safari.service selenium.webdriver.safari.webdriver Webdriver.webkitgtk ------------------- .. currentmodule:: selenium.webdriver.webkitgtk .. autosummary:: :toctree: webdriver_webkitgtk selenium.webdriver.webkitgtk.options selenium.webdriver.webkitgtk.service selenium.webdriver.webkitgtk.webdriver Indices and tables * :ref:`genindex` * :ref:`modindex` * :ref:`search` selenium-selenium-4.18.1/docs/source/webdriver_support/0000755000175000017500000000000014564764517023165 5ustar carstencarstenselenium-selenium-4.18.1/docs/source/webdriver_support/selenium.webdriver.support.color.rst0000644000175000017500000000035614564764517032364 0ustar carstencarstenselenium.webdriver.support.color ================================ .. automodule:: selenium.webdriver.support.color .. rubric:: Classes .. autosummary:: Color ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootselenium-selenium-4.18.1/docs/source/webdriver_support/selenium.webdriver.support.expected_conditions.rstselenium-selenium-4.18.1/docs/source/webdriver_support/selenium.webdriver.support.expected_condition0000644000175000017500000000223114564764517034300 0ustar carstencarstenselenium.webdriver.support.expected\_conditions =============================================== .. automodule:: selenium.webdriver.support.expected_conditions .. rubric:: Functions .. autosummary:: alert_is_present all_of any_of element_attribute_to_include element_located_selection_state_to_be element_located_to_be_selected element_selection_state_to_be element_to_be_clickable element_to_be_selected frame_to_be_available_and_switch_to_it invisibility_of_element invisibility_of_element_located new_window_is_opened none_of number_of_windows_to_be presence_of_all_elements_located presence_of_element_located staleness_of text_to_be_present_in_element text_to_be_present_in_element_attribute text_to_be_present_in_element_value title_contains title_is url_changes url_contains url_matches url_to_be visibility_of visibility_of_all_elements_located visibility_of_any_elements_located visibility_of_element_located selenium-selenium-4.18.1/docs/source/webdriver_support/selenium.webdriver.support.wait.rst0000644000175000017500000000036314564764517032210 0ustar carstencarstenselenium.webdriver.support.wait =============================== .. automodule:: selenium.webdriver.support.wait .. rubric:: Classes .. autosummary:: WebDriverWait ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootselenium-selenium-4.18.1/docs/source/webdriver_support/selenium.webdriver.support.abstract_event_listener.rstselenium-selenium-4.18.1/docs/source/webdriver_support/selenium.webdriver.support.abstract_event_lis0000644000175000017500000000047014564764517034307 0ustar carstencarstenselenium.webdriver.support.abstract\_event\_listener ==================================================== .. automodule:: selenium.webdriver.support.abstract_event_listener .. rubric:: Classes .. autosummary:: AbstractEventListener ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootselenium-selenium-4.18.1/docs/source/webdriver_support/selenium.webdriver.support.event_firing_webdriver.rstselenium-selenium-4.18.1/docs/source/webdriver_support/selenium.webdriver.support.event_firing_webdr0000644000175000017500000000052014564764517034272 0ustar carstencarstenselenium.webdriver.support.event\_firing\_webdriver =================================================== .. automodule:: selenium.webdriver.support.event_firing_webdriver .. rubric:: Classes .. autosummary:: EventFiringWebDriver EventFiringWebElement ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootselenium-selenium-4.18.1/docs/source/webdriver_support/selenium.webdriver.support.relative_locator.rstselenium-selenium-4.18.1/docs/source/webdriver_support/selenium.webdriver.support.relative_locator.r0000644000175000017500000000056214564764517034234 0ustar carstencarstenselenium.webdriver.support.relative\_locator ============================================ .. automodule:: selenium.webdriver.support.relative_locator .. rubric:: Functions .. autosummary:: locate_with with_tag_name .. rubric:: Classes .. autosummary:: RelativeBy selenium-selenium-4.18.1/docs/source/webdriver_support/selenium.webdriver.support.select.rst0000644000175000017500000000036214564764517032522 0ustar carstencarstenselenium.webdriver.support.select ================================= .. automodule:: selenium.webdriver.support.select .. rubric:: Classes .. autosummary:: Select selenium-selenium-4.18.1/docs/source/webdriver_ie/0000755000175000017500000000000014564764517022046 5ustar carstencarstenselenium-selenium-4.18.1/docs/source/webdriver_ie/selenium.webdriver.ie.service.rst0000644000175000017500000000034714564764517030450 0ustar carstencarstenselenium.webdriver.ie.service ============================= .. automodule:: selenium.webdriver.ie.service .. rubric:: Classes .. autosummary:: Service selenium-selenium-4.18.1/docs/source/webdriver_ie/selenium.webdriver.ie.webdriver.rst0000644000175000017500000000035714564764517031002 0ustar carstencarstenselenium.webdriver.ie.webdriver =============================== .. automodule:: selenium.webdriver.ie.webdriver .. rubric:: Classes .. autosummary:: WebDriver selenium-selenium-4.18.1/docs/source/webdriver_ie/selenium.webdriver.ie.options.rst0000644000175000017500000000040314564764517030474 0ustar carstencarstenselenium.webdriver.ie.options ============================= .. automodule:: selenium.webdriver.ie.options .. rubric:: Classes .. autosummary:: ElementScrollBehavior Options selenium-selenium-4.18.1/docs/source/webdriver_safari/0000755000175000017500000000000014564764517022716 5ustar carstencarsten././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootselenium-selenium-4.18.1/docs/source/webdriver_safari/selenium.webdriver.safari.remote_connection.rstselenium-selenium-4.18.1/docs/source/webdriver_safari/selenium.webdriver.safari.remote_connection.rs0000644000175000017500000000044214564764517034052 0ustar carstencarstenselenium.webdriver.safari.remote\_connection ============================================ .. automodule:: selenium.webdriver.safari.remote_connection .. rubric:: Classes .. autosummary:: SafariRemoteConnection selenium-selenium-4.18.1/docs/source/webdriver_safari/selenium.webdriver.safari.options.rst0000644000175000017500000000037514564764517032224 0ustar carstencarstenselenium.webdriver.safari.options ================================= .. automodule:: selenium.webdriver.safari.options .. rubric:: Classes .. autosummary:: Log Options selenium-selenium-4.18.1/docs/source/webdriver_safari/selenium.webdriver.safari.service.rst0000644000175000017500000000036314564764517032166 0ustar carstencarstenselenium.webdriver.safari.service ================================= .. automodule:: selenium.webdriver.safari.service .. rubric:: Classes .. autosummary:: Service selenium-selenium-4.18.1/docs/source/webdriver_safari/selenium.webdriver.safari.webdriver.rst0000644000175000017500000000037314564764517032520 0ustar carstencarstenselenium.webdriver.safari.webdriver =================================== .. automodule:: selenium.webdriver.safari.webdriver .. rubric:: Classes .. autosummary:: WebDriver selenium-selenium-4.18.1/docs/source/webdriver_chrome/0000755000175000017500000000000014564764517022726 5ustar carstencarstenselenium-selenium-4.18.1/docs/source/webdriver_chrome/selenium.webdriver.chrome.service.rst0000644000175000017500000000036314564764517032206 0ustar carstencarstenselenium.webdriver.chrome.service ================================= .. automodule:: selenium.webdriver.chrome.service .. rubric:: Classes .. autosummary:: Service selenium-selenium-4.18.1/docs/source/webdriver_chrome/selenium.webdriver.chrome.options.rst0000644000175000017500000000036314564764517032241 0ustar carstencarstenselenium.webdriver.chrome.options ================================= .. automodule:: selenium.webdriver.chrome.options .. rubric:: Classes .. autosummary:: Options selenium-selenium-4.18.1/docs/source/webdriver_chrome/selenium.webdriver.chrome.webdriver.rst0000644000175000017500000000037314564764517032540 0ustar carstencarstenselenium.webdriver.chrome.webdriver =================================== .. automodule:: selenium.webdriver.chrome.webdriver .. rubric:: Classes .. autosummary:: WebDriver selenium-selenium-4.18.1/docs/source/webdriver/0000755000175000017500000000000014564764517021371 5ustar carstencarstenselenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.options.rst0000644000175000017500000000041014564764517030710 0ustar carstencarstenselenium.webdriver.common.options ================================= .. automodule:: selenium.webdriver.common.options .. rubric:: Classes .. autosummary:: ArgOptions BaseOptions selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.actions.wheel_actions.rst0000644000175000017500000000044414564764517033507 0ustar carstencarstenselenium.webdriver.common.actions.wheel\_actions ================================================ .. automodule:: selenium.webdriver.common.actions.wheel_actions .. rubric:: Classes .. autosummary:: WheelActions selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.proxy.rst0000644000175000017500000000042214564764517030401 0ustar carstencarstenselenium.webdriver.common.proxy =============================== .. automodule:: selenium.webdriver.common.proxy .. rubric:: Classes .. autosummary:: Proxy ProxyType ProxyTypeFactory selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.action_chains.rst0000644000175000017500000000041414564764517032023 0ustar carstencarstenselenium.webdriver.common.action\_chains ======================================== .. automodule:: selenium.webdriver.common.action_chains .. rubric:: Classes .. autosummary:: ActionChains selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.actions.key_actions.rst0000644000175000017500000000043414564764517033172 0ustar carstencarstenselenium.webdriver.common.actions.key\_actions ============================================== .. automodule:: selenium.webdriver.common.actions.key_actions .. rubric:: Classes .. autosummary:: KeyActions selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.keys.rst0000644000175000017500000000034714564764517030201 0ustar carstencarstenselenium.webdriver.common.keys ============================== .. automodule:: selenium.webdriver.common.keys .. rubric:: Classes .. autosummary:: Keys selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.actions.action_builder.rst0000644000175000017500000000045014564764517033643 0ustar carstencarstenselenium.webdriver.common.actions.action\_builder ================================================= .. automodule:: selenium.webdriver.common.actions.action_builder .. rubric:: Classes .. autosummary:: ActionBuilder selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.by.rst0000644000175000017500000000033714564764517027637 0ustar carstencarstenselenium.webdriver.common.by ============================ .. automodule:: selenium.webdriver.common.by .. rubric:: Classes .. autosummary:: By selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.log.rst0000644000175000017500000000045214564764517030004 0ustar carstencarstenselenium.webdriver.common.log ============================= .. automodule:: selenium.webdriver.common.log .. rubric:: Functions .. autosummary:: import_cdp .. rubric:: Classes .. autosummary:: Log selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.alert.rst0000644000175000017500000000035314564764517030332 0ustar carstencarstenselenium.webdriver.common.alert =============================== .. automodule:: selenium.webdriver.common.alert .. rubric:: Classes .. autosummary:: Alert selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.actions.input_device.rst0000644000175000017500000000044014564764517033335 0ustar carstencarstenselenium.webdriver.common.actions.input\_device =============================================== .. automodule:: selenium.webdriver.common.actions.input_device .. rubric:: Classes .. autosummary:: InputDevice selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.service.rst0000644000175000017500000000036314564764517030664 0ustar carstencarstenselenium.webdriver.common.service ================================= .. automodule:: selenium.webdriver.common.service .. rubric:: Classes .. autosummary:: Service selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.actions.pointer_actions.rst0000644000175000017500000000045414564764517034064 0ustar carstencarstenselenium.webdriver.common.actions.pointer\_actions ================================================== .. automodule:: selenium.webdriver.common.actions.pointer_actions .. rubric:: Classes .. autosummary:: PointerActions selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.virtual_authenticator.rst0000644000175000017500000000074414564764517033647 0ustar carstencarstenselenium.webdriver.common.virtual\_authenticator ================================================ .. automodule:: selenium.webdriver.common.virtual_authenticator .. rubric:: Functions .. autosummary:: required_chromium_based_browser required_virtual_authenticator .. rubric:: Classes .. autosummary:: Credential Protocol Transport VirtualAuthenticatorOptions selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.utils.rst0000644000175000017500000000054314564764517030364 0ustar carstencarstenselenium.webdriver.common.utils =============================== .. automodule:: selenium.webdriver.common.utils .. rubric:: Functions .. autosummary:: find_connectable_ip free_port is_connectable is_url_connectable join_host_port keys_to_typing selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.actions.mouse_button.rst0000644000175000017500000000044014564764517033402 0ustar carstencarstenselenium.webdriver.common.actions.mouse\_button =============================================== .. automodule:: selenium.webdriver.common.actions.mouse_button .. rubric:: Classes .. autosummary:: MouseButton selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.window.rst0000644000175000017500000000036414564764517030534 0ustar carstencarstenselenium.webdriver.common.window ================================ .. automodule:: selenium.webdriver.common.window .. rubric:: Classes .. autosummary:: WindowTypes selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.actions.interaction.rst0000644000175000017500000000044714564764517033205 0ustar carstencarstenselenium.webdriver.common.actions.interaction ============================================= .. automodule:: selenium.webdriver.common.actions.interaction .. rubric:: Classes .. autosummary:: Interaction Pause selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.actions.wheel_input.rst0000644000175000017500000000045714564764517033212 0ustar carstencarstenselenium.webdriver.common.actions.wheel\_input ============================================== .. automodule:: selenium.webdriver.common.actions.wheel_input .. rubric:: Classes .. autosummary:: ScrollOrigin WheelInput selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.timeouts.rst0000644000175000017500000000036714564764517031101 0ustar carstencarstenselenium.webdriver.common.timeouts ================================== .. automodule:: selenium.webdriver.common.timeouts .. rubric:: Classes .. autosummary:: Timeouts selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.desired_capabilities.rst0000644000175000017500000000045014564764517033351 0ustar carstencarstenselenium.webdriver.common.desired\_capabilities =============================================== .. automodule:: selenium.webdriver.common.desired_capabilities .. rubric:: Classes .. autosummary:: DesiredCapabilities selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.actions.pointer_input.rst0000644000175000017500000000044414564764517033562 0ustar carstencarstenselenium.webdriver.common.actions.pointer\_input ================================================ .. automodule:: selenium.webdriver.common.actions.pointer_input .. rubric:: Classes .. autosummary:: PointerInput selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.actions.key_input.rst0000644000175000017500000000045414564764517032673 0ustar carstencarstenselenium.webdriver.common.actions.key\_input ============================================ .. automodule:: selenium.webdriver.common.actions.key_input .. rubric:: Classes .. autosummary:: KeyInput TypingInteraction selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.html5.application_cache.rst0000644000175000017500000000045614564764517033705 0ustar carstencarstenselenium.webdriver.common.html5.application\_cache ================================================== .. automodule:: selenium.webdriver.common.html5.application_cache .. rubric:: Classes .. autosummary:: ApplicationCache selenium-selenium-4.18.1/docs/source/webdriver/selenium.webdriver.common.print_page_options.rst0000644000175000017500000000043514564764517033127 0ustar carstencarstenselenium.webdriver.common.print\_page\_options ============================================== .. automodule:: selenium.webdriver.common.print_page_options .. rubric:: Classes .. autosummary:: PrintOptions selenium-selenium-4.18.1/docs/source/webdriver_firefox/0000755000175000017500000000000014564764517023113 5ustar carstencarstenselenium-selenium-4.18.1/docs/source/webdriver_firefox/selenium.webdriver.firefox.webdriver.rst0000644000175000017500000000037614564764517033115 0ustar carstencarstenselenium.webdriver.firefox.webdriver ==================================== .. automodule:: selenium.webdriver.firefox.webdriver .. rubric:: Classes .. autosummary:: WebDriver selenium-selenium-4.18.1/docs/source/webdriver_firefox/selenium.webdriver.firefox.firefox_binary.rst0000644000175000017500000000042314564764517034123 0ustar carstencarstenselenium.webdriver.firefox.firefox\_binary ========================================== .. automodule:: selenium.webdriver.firefox.firefox_binary .. rubric:: Classes .. autosummary:: FirefoxBinary selenium-selenium-4.18.1/docs/source/webdriver_firefox/selenium.webdriver.firefox.options.rst0000644000175000017500000000040014564764517032603 0ustar carstencarstenselenium.webdriver.firefox.options ================================== .. automodule:: selenium.webdriver.firefox.options .. rubric:: Classes .. autosummary:: Log Options ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootselenium-selenium-4.18.1/docs/source/webdriver_firefox/selenium.webdriver.firefox.extension_connection.rstselenium-selenium-4.18.1/docs/source/webdriver_firefox/selenium.webdriver.firefox.extension_connecti0000644000175000017500000000060114564764517034202 0ustar carstencarstenselenium.webdriver.firefox.extension\_connection ================================================ .. automodule:: selenium.webdriver.firefox.extension_connection .. rubric:: Classes .. autosummary:: ExtensionConnection .. rubric:: Exceptions .. autosummary:: ExtensionConnectionError selenium-selenium-4.18.1/docs/source/webdriver_firefox/selenium.webdriver.firefox.service.rst0000644000175000017500000000036614564764517032563 0ustar carstencarstenselenium.webdriver.firefox.service ================================== .. automodule:: selenium.webdriver.firefox.service .. rubric:: Classes .. autosummary:: Service ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootselenium-selenium-4.18.1/docs/source/webdriver_firefox/selenium.webdriver.firefox.remote_connection.rstselenium-selenium-4.18.1/docs/source/webdriver_firefox/selenium.webdriver.firefox.remote_connection.0000644000175000017500000000044614564764517034103 0ustar carstencarstenselenium.webdriver.firefox.remote\_connection ============================================= .. automodule:: selenium.webdriver.firefox.remote_connection .. rubric:: Classes .. autosummary:: FirefoxRemoteConnection ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootselenium-selenium-4.18.1/docs/source/webdriver_firefox/selenium.webdriver.firefox.firefox_profile.rstselenium-selenium-4.18.1/docs/source/webdriver_firefox/selenium.webdriver.firefox.firefox_profile.rs0000644000175000017500000000054514564764517034120 0ustar carstencarstenselenium.webdriver.firefox.firefox\_profile =========================================== .. automodule:: selenium.webdriver.firefox.firefox_profile .. rubric:: Classes .. autosummary:: FirefoxProfile .. rubric:: Exceptions .. autosummary:: AddonFormatError selenium-selenium-4.18.1/docs/source/webdriver_remote/0000755000175000017500000000000014564764517022744 5ustar carstencarstenselenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.webelement.rst0000644000175000017500000000042414564764517032727 0ustar carstencarstenselenium.webdriver.remote.webelement ==================================== .. automodule:: selenium.webdriver.remote.webelement .. rubric:: Classes .. autosummary:: BaseWebElement WebElement selenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.switch_to.rst0000644000175000017500000000037414564764517032607 0ustar carstencarstenselenium.webdriver.remote.switch\_to ==================================== .. automodule:: selenium.webdriver.remote.switch_to .. rubric:: Classes .. autosummary:: SwitchTo selenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.command.rst0000644000175000017500000000036314564764517032220 0ustar carstencarstenselenium.webdriver.remote.command ================================= .. automodule:: selenium.webdriver.remote.command .. rubric:: Classes .. autosummary:: Command selenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.script_key.rst0000644000175000017500000000040014564764517032746 0ustar carstencarstenselenium.webdriver.remote.script\_key ===================================== .. automodule:: selenium.webdriver.remote.script_key .. rubric:: Classes .. autosummary:: ScriptKey selenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.bidi_connection.rst0000644000175000017500000000042414564764517033726 0ustar carstencarstenselenium.webdriver.remote.bidi\_connection ========================================== .. automodule:: selenium.webdriver.remote.bidi_connection .. rubric:: Classes .. autosummary:: BidiConnection selenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.shadowroot.rst0000644000175000017500000000037714564764517033000 0ustar carstencarstenselenium.webdriver.remote.shadowroot ==================================== .. automodule:: selenium.webdriver.remote.shadowroot .. rubric:: Classes .. autosummary:: ShadowRoot selenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.webdriver.rst0000644000175000017500000000060714564764517032574 0ustar carstencarstenselenium.webdriver.remote.webdriver =================================== .. automodule:: selenium.webdriver.remote.webdriver .. rubric:: Functions .. autosummary:: create_matches get_remote_connection import_cdp .. rubric:: Classes .. autosummary:: BaseWebDriver WebDriver ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootselenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.remote_connection.rstselenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.remote_connection.rs0000644000175000017500000000043414564764517034127 0ustar carstencarstenselenium.webdriver.remote.remote\_connection ============================================ .. automodule:: selenium.webdriver.remote.remote_connection .. rubric:: Classes .. autosummary:: RemoteConnection selenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.mobile.rst0000644000175000017500000000035714564764517032054 0ustar carstencarstenselenium.webdriver.remote.mobile ================================ .. automodule:: selenium.webdriver.remote.mobile .. rubric:: Classes .. autosummary:: Mobile selenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.file_detector.rst0000644000175000017500000000047614564764517033417 0ustar carstencarstenselenium.webdriver.remote.file\_detector ======================================== .. automodule:: selenium.webdriver.remote.file_detector .. rubric:: Classes .. autosummary:: FileDetector LocalFileDetector UselessFileDetector selenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.errorhandler.rst0000644000175000017500000000042714564764517033272 0ustar carstencarstenselenium.webdriver.remote.errorhandler ====================================== .. automodule:: selenium.webdriver.remote.errorhandler .. rubric:: Classes .. autosummary:: ErrorCode ErrorHandler selenium-selenium-4.18.1/docs/source/webdriver_remote/selenium.webdriver.remote.utils.rst0000644000175000017500000000040114564764517031733 0ustar carstencarstenselenium.webdriver.remote.utils =============================== .. automodule:: selenium.webdriver.remote.utils .. rubric:: Functions .. autosummary:: dump_json load_json selenium-selenium-4.18.1/docs/source/conf.py0000644000175000017500000002231614564764517020703 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import sys import os import os.path # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.join(os.getcwd(), "..", "..")) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.imgmath', 'sphinx.ext.viewcode'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'Selenium' copyright = '2009-2023 Software Freedom Conservancy' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '4.18' # The full version, including alpha/beta/rc tags. release = '4.18.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. html_show_sphinx = False # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'Seleniumdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'Selenium.tex', 'Selenium Documentation', 'plightbo, simon.m.stewart, hbchai, jrhuggins, et al.', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'selenium', 'Selenium Documentation', ['plightbo, simon.m.stewart, hbchai, jrhuggins, et al.'], 1) ] # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. epub_title = 'Selenium' epub_author = 'The Selenium Project' epub_publisher = 'The Selenium Project' epub_copyright = '2009-2023 Software Freedom Conservancy' # The language of the text. It defaults to the language option # or en if the language is not set. #epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. #epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. #epub_identifier = '' # A unique identification for the text. #epub_uid = '' # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_pre_files = [] # HTML files that should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_post_files = [] # A list of files that should not be packed into the epub file. #epub_exclude_files = [] # The depth of the table of contents in toc.ncx. #epub_tocdepth = 3 # Allow duplicate toc entries. #epub_tocdup = True # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'http://docs.python.org/': None} # 'members' includes anything that has a docstring, 'undoc-members' includes # functions without docstrings. autodoc_default_flags = ['members', 'undoc-members'] # configuration for keeping the methods that can be invoked on said classes autodoc_default_options = { 'members': True, 'member-order': 'bysource', 'undoc-members': True, 'inherited-members': True, } # Include __init__ comments autoclass_content = "both" selenium-selenium-4.18.1/docs/source/webdriver_chromium/0000755000175000017500000000000014564764517023274 5ustar carstencarsten././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootselenium-selenium-4.18.1/docs/source/webdriver_chromium/selenium.webdriver.chromium.remote_connection.rstselenium-selenium-4.18.1/docs/source/webdriver_chromium/selenium.webdriver.chromium.remote_connectio0000644000175000017500000000045214564764517034206 0ustar carstencarstenselenium.webdriver.chromium.remote\_connection ============================================== .. automodule:: selenium.webdriver.chromium.remote_connection .. rubric:: Classes .. autosummary:: ChromiumRemoteConnection selenium-selenium-4.18.1/docs/source/webdriver_chromium/selenium.webdriver.chromium.webdriver.rst0000644000175000017500000000040614564764517033451 0ustar carstencarstenselenium.webdriver.chromium.webdriver ===================================== .. automodule:: selenium.webdriver.chromium.webdriver .. rubric:: Classes .. autosummary:: ChromiumDriver selenium-selenium-4.18.1/docs/source/webdriver_chromium/selenium.webdriver.chromium.options.rst0000644000175000017500000000040114564764517033146 0ustar carstencarstenselenium.webdriver.chromium.options =================================== .. automodule:: selenium.webdriver.chromium.options .. rubric:: Classes .. autosummary:: ChromiumOptions selenium-selenium-4.18.1/docs/source/webdriver_chromium/selenium.webdriver.chromium.service.rst0000644000175000017500000000040114564764517033113 0ustar carstencarstenselenium.webdriver.chromium.service =================================== .. automodule:: selenium.webdriver.chromium.service .. rubric:: Classes .. autosummary:: ChromiumService selenium-selenium-4.18.1/docs/source/webdriver_edge/0000755000175000017500000000000014564764517022355 5ustar carstencarstenselenium-selenium-4.18.1/docs/source/webdriver_edge/selenium.webdriver.edge.options.rst0000644000175000017500000000035514564764517031320 0ustar carstencarstenselenium.webdriver.edge.options =============================== .. automodule:: selenium.webdriver.edge.options .. rubric:: Classes .. autosummary:: Options selenium-selenium-4.18.1/docs/source/webdriver_edge/selenium.webdriver.edge.service.rst0000644000175000017500000000035514564764517031265 0ustar carstencarstenselenium.webdriver.edge.service =============================== .. automodule:: selenium.webdriver.edge.service .. rubric:: Classes .. autosummary:: Service selenium-selenium-4.18.1/docs/source/webdriver_edge/selenium.webdriver.edge.webdriver.rst0000644000175000017500000000036514564764517031617 0ustar carstencarstenselenium.webdriver.edge.webdriver ================================= .. automodule:: selenium.webdriver.edge.webdriver .. rubric:: Classes .. autosummary:: WebDriver selenium-selenium-4.18.1/docs/source/webdriver_webkitgtk/0000755000175000017500000000000014564764517023444 5ustar carstencarstenselenium-selenium-4.18.1/docs/source/webdriver_webkitgtk/selenium.webdriver.webkitgtk.webdriver.rst0000644000175000017500000000040414564764517033767 0ustar carstencarstenselenium.webdriver.webkitgtk.webdriver ====================================== .. automodule:: selenium.webdriver.webkitgtk.webdriver .. rubric:: Classes .. autosummary:: WebDriver selenium-selenium-4.18.1/docs/source/webdriver_webkitgtk/selenium.webdriver.webkitgtk.options.rst0000644000175000017500000000037414564764517033477 0ustar carstencarstenselenium.webdriver.webkitgtk.options ==================================== .. automodule:: selenium.webdriver.webkitgtk.options .. rubric:: Classes .. autosummary:: Options selenium-selenium-4.18.1/docs/source/webdriver_webkitgtk/selenium.webdriver.webkitgtk.service.rst0000644000175000017500000000037414564764517033444 0ustar carstencarstenselenium.webdriver.webkitgtk.service ==================================== .. automodule:: selenium.webdriver.webkitgtk.service .. rubric:: Classes .. autosummary:: Service selenium-selenium-4.18.1/docs/Makefile0000644000175000017500000001105714564764517017544 0ustar carstencarsten# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source HTML_DESTINATION = ../../docs/api/py .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: clean $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(HTML_DESTINATION) @echo @echo "Build finished. The HTML pages are in $(HTML_DESTINATION)." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Selenium.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Selenium.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/Selenium" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Selenium" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." selenium-selenium-4.18.1/mypy.ini0000644000175000017500000000371014564764517016650 0ustar carstencarsten; The aim in future here is we would be able to turn (most) of these flags on, however the typing technical ; debt is quite colossal right now. For now we should maybe get everything working with the config here ; then look at going after partially or completely untyped defs as a phase-2. [mypy] files = selenium ; warn about per-module sections in the config file that do not match any files processed. warn_unused_configs = True ; disallows subclassing of typing.Any. disallow_subclassing_any = False ; disallow usage of generic types that do not specify explicit type parameters. disallow_any_generics = False ; disallow calling functions without type annotations from functions that have type annotations. disallow_untyped_calls = False ; disallow defining functions without type annotations or with incomplete annotations. disallow_untyped_defs = False ; disallow defining functions with incomplete type annotations. disallow_incomplete_defs = False ; type-checks the interior of functions without type annotations. check_untyped_defs = False ; reports an error whenever a function with type annotations is decorated with a decorator without annotations. disallow_untyped_decorators = False ; changes the treatment of arguments with a default value of None by not implicitly making their type `typing.Optional`. no_implicit_optional = False ; warns about casting an expression to it's inferred type. warn_redundant_casts = True ; warns about unneeded `# type: ignore` comments. warn_unused_ignores = True ; warns when returning a value with typing.Any from a function with a non typing.Any return type. warn_return_any = False ; Shows a warning when encountering any code inferred to be unreachable after performing type analysis. warn_unreachable = False [mypy-trio_websocket] ; suppress error messages about imports that cannot be resolved. ignore_missing_imports = True [mypy-_winreg] ; suppress error messages about imports that cannot be resolved. ignore_missing_imports = True selenium-selenium-4.18.1/.readthedocs.yaml0000644000175000017500000000147514564764517020406 0ustar carstencarsten# .readthedocs.yaml # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Set the OS, Python version and other tools you might need build: os: ubuntu-22.04 tools: python: "3.11" # You can also specify other tool versions: # nodejs: "19" # rust: "1.64" # golang: "1.19" # Build documentation in the "docs/" directory with Sphinx sphinx: configuration: py/docs/source/conf.py # Optionally build your docs in additional formats such as PDF and ePub # formats: # - pdf # - epub # Optional but recommended, declare the Python requirements required # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html python: install: - requirements: py/docs/requirements.txt selenium-selenium-4.18.1/.OLD_AUTHORS0000644000175000017500000000044414564764517016776 0ustar carstencarstenJoe Walnes Vyvyan Codd Zoltar - Knower of All Carlos Villela James Cooper Malcolm Rowe Mirko Nasato Marc Guillemot Alexis Vuillemin Noel Gordon David Wang Amitabh Saikia Jon Spalding James Strachen Rune Flobakk Michele Sama Muthu Kannan Terence Haddock Jean-Francois Roche Godefroid Chapelle selenium-selenium-4.18.1/requirements_lock.txt0000644000175000017500000010121514564764517021444 0ustar carstencarsten# # This file is autogenerated by pip-compile with Python 3.8 # by the following command: # # bazel run //py:requirements.update # async-generator==1.10 \ --hash=sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b \ --hash=sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144 # via # -r py/requirements.txt # trio # trio-websocket attrs==23.1.0 \ --hash=sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04 \ --hash=sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015 # via # -r py/requirements.txt # outcome # trio certifi==2023.7.22 \ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 # via # -r py/requirements.txt # requests cffi==1.16.0 \ --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \ --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \ --hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \ --hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \ --hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \ --hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \ --hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \ --hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \ --hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \ --hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \ --hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \ --hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \ --hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \ --hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \ --hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \ --hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \ --hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \ --hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \ --hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \ --hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \ --hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \ --hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \ --hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \ --hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \ --hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \ --hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \ --hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \ --hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \ --hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \ --hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \ --hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \ --hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \ --hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \ --hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \ --hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \ --hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \ --hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \ --hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \ --hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \ --hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \ --hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \ --hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \ --hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \ --hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \ --hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \ --hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \ --hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \ --hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \ --hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \ --hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \ --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \ --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357 # via # -r py/requirements.txt # cryptography charset-normalizer==3.3.2 \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \ --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \ --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \ --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \ --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \ --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \ --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \ --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \ --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \ --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \ --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \ --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \ --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \ --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \ --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \ --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \ --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \ --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \ --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \ --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \ --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \ --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \ --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \ --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \ --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \ --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \ --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \ --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \ --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \ --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \ --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \ --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \ --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \ --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \ --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \ --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \ --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \ --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \ --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \ --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \ --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \ --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \ --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \ --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \ --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \ --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \ --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \ --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \ --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \ --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \ --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \ --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \ --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \ --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \ --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \ --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \ --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \ --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \ --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \ --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \ --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \ --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \ --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \ --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \ --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \ --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \ --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \ --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \ --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \ --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \ --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \ --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \ --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \ --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \ --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \ --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \ --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \ --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \ --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \ --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \ --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \ --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \ --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \ --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \ --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \ --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \ --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \ --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \ --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 # via requests cryptography==41.0.4 \ --hash=sha256:004b6ccc95943f6a9ad3142cfabcc769d7ee38a3f60fb0dddbfb431f818c3a67 \ --hash=sha256:047c4603aeb4bbd8db2756e38f5b8bd7e94318c047cfe4efeb5d715e08b49311 \ --hash=sha256:0d9409894f495d465fe6fda92cb70e8323e9648af912d5b9141d616df40a87b8 \ --hash=sha256:23a25c09dfd0d9f28da2352503b23e086f8e78096b9fd585d1d14eca01613e13 \ --hash=sha256:2ed09183922d66c4ec5fdaa59b4d14e105c084dd0febd27452de8f6f74704143 \ --hash=sha256:35c00f637cd0b9d5b6c6bd11b6c3359194a8eba9c46d4e875a3660e3b400005f \ --hash=sha256:37480760ae08065437e6573d14be973112c9e6dcaf5f11d00147ee74f37a3829 \ --hash=sha256:3b224890962a2d7b57cf5eeb16ccaafba6083f7b811829f00476309bce2fe0fd \ --hash=sha256:5a0f09cefded00e648a127048119f77bc2b2ec61e736660b5789e638f43cc397 \ --hash=sha256:5b72205a360f3b6176485a333256b9bcd48700fc755fef51c8e7e67c4b63e3ac \ --hash=sha256:7e53db173370dea832190870e975a1e09c86a879b613948f09eb49324218c14d \ --hash=sha256:7febc3094125fc126a7f6fb1f420d0da639f3f32cb15c8ff0dc3997c4549f51a \ --hash=sha256:80907d3faa55dc5434a16579952ac6da800935cd98d14dbd62f6f042c7f5e839 \ --hash=sha256:86defa8d248c3fa029da68ce61fe735432b047e32179883bdb1e79ed9bb8195e \ --hash=sha256:8ac4f9ead4bbd0bc8ab2d318f97d85147167a488be0e08814a37eb2f439d5cf6 \ --hash=sha256:93530900d14c37a46ce3d6c9e6fd35dbe5f5601bf6b3a5c325c7bffc030344d9 \ --hash=sha256:9eeb77214afae972a00dee47382d2591abe77bdae166bda672fb1e24702a3860 \ --hash=sha256:b5f4dfe950ff0479f1f00eda09c18798d4f49b98f4e2006d644b3301682ebdca \ --hash=sha256:c3391bd8e6de35f6f1140e50aaeb3e2b3d6a9012536ca23ab0d9c35ec18c8a91 \ --hash=sha256:c880eba5175f4307129784eca96f4e70b88e57aa3f680aeba3bab0e980b0f37d \ --hash=sha256:cecfefa17042941f94ab54f769c8ce0fe14beff2694e9ac684176a2535bf9714 \ --hash=sha256:e40211b4923ba5a6dc9769eab704bdb3fbb58d56c5b336d30996c24fcf12aadb \ --hash=sha256:efc8ad4e6fc4f1752ebfb58aefece8b4e3c4cae940b0994d43649bdfce8d0d4f # via # -r py/requirements.txt # pyopenssl dataclasses==0.6 \ --hash=sha256:454a69d788c7fda44efd71e259be79577822f5e3f53f029a22d08004e951dc9f \ --hash=sha256:6988bd2b895eef432d562370bb707d540f32f7360ab13da45340101bc2307d84 # via -r py/requirements.txt debugpy==1.8.0 \ --hash=sha256:125b9a637e013f9faac0a3d6a82bd17c8b5d2c875fb6b7e2772c5aba6d082332 \ --hash=sha256:12af2c55b419521e33d5fb21bd022df0b5eb267c3e178f1d374a63a2a6bdccd0 \ --hash=sha256:3c6fb41c98ec51dd010d7ed650accfd07a87fe5e93eca9d5f584d0578f28f35f \ --hash=sha256:46ab6780159eeabb43c1495d9c84cf85d62975e48b6ec21ee10c95767c0590aa \ --hash=sha256:57161629133113c97b387382045649a2b985a348f0c9366e22217c87b68b73c6 \ --hash=sha256:5d9de202f5d42e62f932507ee8b21e30d49aae7e46d5b1dd5c908db1d7068637 \ --hash=sha256:60009b132c91951354f54363f8ebdf7457aeb150e84abba5ae251b8e9f29a8a6 \ --hash=sha256:61eab4a4c8b6125d41a34bad4e5fe3d2cc145caecd63c3fe953be4cc53e65bf8 \ --hash=sha256:7fb95ca78f7ac43393cd0e0f2b6deda438ec7c5e47fa5d38553340897d2fbdfb \ --hash=sha256:8cd0197141eb9e8a4566794550cfdcdb8b3db0818bdf8c49a8e8f8053e56e38b \ --hash=sha256:9c9b0ac1ce2a42888199df1a1906e45e6f3c9555497643a85e0bf2406e3ffbc4 \ --hash=sha256:a64093656c4c64dc6a438e11d59369875d200bd5abb8f9b26c1f5f723622e153 \ --hash=sha256:a8b7a2fd27cd9f3553ac112f356ad4ca93338feadd8910277aff71ab24d8775f \ --hash=sha256:b05a6b503ed520ad58c8dc682749113d2fd9f41ffd45daec16e558ca884008cd \ --hash=sha256:bdc5ef99d14b9c0fcb35351b4fbfc06ac0ee576aeab6b2511702e5a648a2e595 \ --hash=sha256:e3412f9faa9ade82aa64a50b602544efcba848c91384e9f93497a458767e6926 \ --hash=sha256:ef54404365fae8d45cf450d0544ee40cefbcb9cb85ea7afe89a963c27028261e \ --hash=sha256:ef9ab7df0b9a42ed9c878afd3eaaff471fce3fa73df96022e1f5c9f8f8c87ada # via -r py/requirements.txt docutils==0.20.1 \ --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \ --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b # via readme-renderer exceptiongroup==1.1.1 \ --hash=sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e \ --hash=sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785 # via # pytest # trio h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via # -r py/requirements.txt # wsproto idna==3.4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 # via # -r py/requirements.txt # requests # trio importlib-metadata==6.8.0 \ --hash=sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb \ --hash=sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743 # via # -r py/requirements.txt # keyring # twine importlib-resources==6.1.1 \ --hash=sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a \ --hash=sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6 # via keyring inflection==0.5.1 \ --hash=sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417 \ --hash=sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2 # via -r py/requirements.txt iniconfig==2.0.0 \ --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \ --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 # via # -r py/requirements.txt # pytest jaraco-classes==3.3.0 \ --hash=sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb \ --hash=sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621 # via keyring keyring==24.3.0 \ --hash=sha256:4446d35d636e6a10b8bce7caa66913dd9eca5fd222ca03a3d42c38608ac30836 \ --hash=sha256:e730ecffd309658a08ee82535a3b5ec4b4c8669a9be11efb66249d8e0aeb9a25 # via twine markdown-it-py==3.0.0 \ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb # via rich mdurl==0.1.2 \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba # via markdown-it-py more-itertools==10.1.0 \ --hash=sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a \ --hash=sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6 # via # -r py/requirements.txt # jaraco-classes multidict==6.0.2 \ --hash=sha256:0327292e745a880459ef71be14e709aaea2f783f3537588fb4ed09b6c01bca60 \ --hash=sha256:041b81a5f6b38244b34dc18c7b6aba91f9cdaf854d9a39e5ff0b58e2b5773b9c \ --hash=sha256:0556a1d4ea2d949efe5fd76a09b4a82e3a4a30700553a6725535098d8d9fb672 \ --hash=sha256:05f6949d6169878a03e607a21e3b862eaf8e356590e8bdae4227eedadacf6e51 \ --hash=sha256:07a017cfa00c9890011628eab2503bee5872f27144936a52eaab449be5eaf032 \ --hash=sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2 \ --hash=sha256:19adcfc2a7197cdc3987044e3f415168fc5dc1f720c932eb1ef4f71a2067e08b \ --hash=sha256:19d9bad105dfb34eb539c97b132057a4e709919ec4dd883ece5838bcbf262b80 \ --hash=sha256:225383a6603c086e6cef0f2f05564acb4f4d5f019a4e3e983f572b8530f70c88 \ --hash=sha256:23b616fdc3c74c9fe01d76ce0d1ce872d2d396d8fa8e4899398ad64fb5aa214a \ --hash=sha256:2957489cba47c2539a8eb7ab32ff49101439ccf78eab724c828c1a54ff3ff98d \ --hash=sha256:2d36e929d7f6a16d4eb11b250719c39560dd70545356365b494249e2186bc389 \ --hash=sha256:2e4a0785b84fb59e43c18a015ffc575ba93f7d1dbd272b4cdad9f5134b8a006c \ --hash=sha256:3368bf2398b0e0fcbf46d85795adc4c259299fec50c1416d0f77c0a843a3eed9 \ --hash=sha256:373ba9d1d061c76462d74e7de1c0c8e267e9791ee8cfefcf6b0b2495762c370c \ --hash=sha256:4070613ea2227da2bfb2c35a6041e4371b0af6b0be57f424fe2318b42a748516 \ --hash=sha256:45183c96ddf61bf96d2684d9fbaf6f3564d86b34cb125761f9a0ef9e36c1d55b \ --hash=sha256:4571f1beddff25f3e925eea34268422622963cd8dc395bb8778eb28418248e43 \ --hash=sha256:47e6a7e923e9cada7c139531feac59448f1f47727a79076c0b1ee80274cd8eee \ --hash=sha256:47fbeedbf94bed6547d3aa632075d804867a352d86688c04e606971595460227 \ --hash=sha256:497988d6b6ec6ed6f87030ec03280b696ca47dbf0648045e4e1d28b80346560d \ --hash=sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae \ --hash=sha256:50bd442726e288e884f7be9071016c15a8742eb689a593a0cac49ea093eef0a7 \ --hash=sha256:514fe2b8d750d6cdb4712346a2c5084a80220821a3e91f3f71eec11cf8d28fd4 \ --hash=sha256:5774d9218d77befa7b70d836004a768fb9aa4fdb53c97498f4d8d3f67bb9cfa9 \ --hash=sha256:5fdda29a3c7e76a064f2477c9aab1ba96fd94e02e386f1e665bca1807fc5386f \ --hash=sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013 \ --hash=sha256:626fe10ac87851f4cffecee161fc6f8f9853f0f6f1035b59337a51d29ff3b4f9 \ --hash=sha256:6701bf8a5d03a43375909ac91b6980aea74b0f5402fbe9428fc3f6edf5d9677e \ --hash=sha256:684133b1e1fe91eda8fa7447f137c9490a064c6b7f392aa857bba83a28cfb693 \ --hash=sha256:6f3cdef8a247d1eafa649085812f8a310e728bdf3900ff6c434eafb2d443b23a \ --hash=sha256:75bdf08716edde767b09e76829db8c1e5ca9d8bb0a8d4bd94ae1eafe3dac5e15 \ --hash=sha256:7c40b7bbece294ae3a87c1bc2abff0ff9beef41d14188cda94ada7bcea99b0fb \ --hash=sha256:8004dca28e15b86d1b1372515f32eb6f814bdf6f00952699bdeb541691091f96 \ --hash=sha256:8064b7c6f0af936a741ea1efd18690bacfbae4078c0c385d7c3f611d11f0cf87 \ --hash=sha256:89171b2c769e03a953d5969b2f272efa931426355b6c0cb508022976a17fd376 \ --hash=sha256:8cbf0132f3de7cc6c6ce00147cc78e6439ea736cee6bca4f068bcf892b0fd658 \ --hash=sha256:9cc57c68cb9139c7cd6fc39f211b02198e69fb90ce4bc4a094cf5fe0d20fd8b0 \ --hash=sha256:a007b1638e148c3cfb6bf0bdc4f82776cef0ac487191d093cdc316905e504071 \ --hash=sha256:a2c34a93e1d2aa35fbf1485e5010337c72c6791407d03aa5f4eed920343dd360 \ --hash=sha256:a45e1135cb07086833ce969555df39149680e5471c04dfd6a915abd2fc3f6dbc \ --hash=sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3 \ --hash=sha256:aef9cc3d9c7d63d924adac329c33835e0243b5052a6dfcbf7732a921c6e918ba \ --hash=sha256:b9d153e7f1f9ba0b23ad1568b3b9e17301e23b042c23870f9ee0522dc5cc79e8 \ --hash=sha256:bfba7c6d5d7c9099ba21f84662b037a0ffd4a5e6b26ac07d19e423e6fdf965a9 \ --hash=sha256:c207fff63adcdf5a485969131dc70e4b194327666b7e8a87a97fbc4fd80a53b2 \ --hash=sha256:d0509e469d48940147e1235d994cd849a8f8195e0bca65f8f5439c56e17872a3 \ --hash=sha256:d16cce709ebfadc91278a1c005e3c17dd5f71f5098bfae1035149785ea6e9c68 \ --hash=sha256:d48b8ee1d4068561ce8033d2c344cf5232cb29ee1a0206a7b828c79cbc5982b8 \ --hash=sha256:de989b195c3d636ba000ee4281cd03bb1234635b124bf4cd89eeee9ca8fcb09d \ --hash=sha256:e07c8e79d6e6fd37b42f3250dba122053fddb319e84b55dd3a8d6446e1a7ee49 \ --hash=sha256:e2c2e459f7050aeb7c1b1276763364884595d47000c1cddb51764c0d8976e608 \ --hash=sha256:e5b20e9599ba74391ca0cfbd7b328fcc20976823ba19bc573983a25b32e92b57 \ --hash=sha256:e875b6086e325bab7e680e4316d667fc0e5e174bb5611eb16b3ea121c8951b86 \ --hash=sha256:f4f052ee022928d34fe1f4d2bc743f32609fb79ed9c49a1710a5ad6b2198db20 \ --hash=sha256:fcb91630817aa8b9bc4a74023e4198480587269c272c58b3279875ed7235c293 \ --hash=sha256:fd9fc9c4849a07f3635ccffa895d57abce554b467d611a5009ba4f39b78a8849 \ --hash=sha256:feba80698173761cddd814fa22e88b0661e98cb810f9f986c54aa34d281e4937 \ --hash=sha256:feea820722e69451743a3d56ad74948b68bf456984d63c1a92e8347b7b88452d # via -r py/requirements.txt nh3==0.2.15 \ --hash=sha256:0d02d0ff79dfd8208ed25a39c12cbda092388fff7f1662466e27d97ad011b770 \ --hash=sha256:3277481293b868b2715907310c7be0f1b9d10491d5adf9fce11756a97e97eddf \ --hash=sha256:3b803a5875e7234907f7d64777dfde2b93db992376f3d6d7af7f3bc347deb305 \ --hash=sha256:427fecbb1031db085eaac9931362adf4a796428ef0163070c484b5a768e71601 \ --hash=sha256:5f0d77272ce6d34db6c87b4f894f037d55183d9518f948bba236fe81e2bb4e28 \ --hash=sha256:60684857cfa8fdbb74daa867e5cad3f0c9789415aba660614fe16cd66cbb9ec7 \ --hash=sha256:6f42f99f0cf6312e470b6c09e04da31f9abaadcd3eb591d7d1a88ea931dca7f3 \ --hash=sha256:86e447a63ca0b16318deb62498db4f76fc60699ce0a1231262880b38b6cff911 \ --hash=sha256:8d595df02413aa38586c24811237e95937ef18304e108b7e92c890a06793e3bf \ --hash=sha256:9c0d415f6b7f2338f93035bba5c0d8c1b464e538bfbb1d598acd47d7969284f0 \ --hash=sha256:a5167a6403d19c515217b6bcaaa9be420974a6ac30e0da9e84d4fc67a5d474c5 \ --hash=sha256:ac19c0d68cd42ecd7ead91a3a032fdfff23d29302dbb1311e641a130dfefba97 \ --hash=sha256:b1e97221cedaf15a54f5243f2c5894bb12ca951ae4ddfd02a9d4ea9df9e1a29d \ --hash=sha256:bc2d086fb540d0fa52ce35afaded4ea526b8fc4d3339f783db55c95de40ef02e \ --hash=sha256:d1e30ff2d8d58fb2a14961f7aac1bbb1c51f9bdd7da727be35c63826060b0bf3 \ --hash=sha256:f3b53ba93bb7725acab1e030bc2ecd012a817040fd7851b332f86e2f9bb98dc6 # via readme-renderer outcome==1.3.0 \ --hash=sha256:588ef4dc10b64e8df160d8d1310c44e1927129a66d6d2ef86845cef512c5f24c \ --hash=sha256:7b688fd82db72f4b0bc9e883a00359d4d4179cd97d27f09c9644d0c842ba7786 # via # -r py/requirements.txt # pytest-trio # trio packaging==23.2 \ --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7 # via # -r py/requirements.txt # pytest pkginfo==1.9.6 \ --hash=sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546 \ --hash=sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046 # via twine pluggy==1.3.0 \ --hash=sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12 \ --hash=sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7 # via # -r py/requirements.txt # pytest py==1.11.0 \ --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 # via -r py/requirements.txt pycparser==2.21 \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 # via # -r py/requirements.txt # cffi pygments==2.17.2 \ --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \ --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367 # via # readme-renderer # rich pyopenssl==22.0.0 \ --hash=sha256:660b1b1425aac4a1bea1d94168a85d99f0b3144c869dd4390d27629d0087f1bf \ --hash=sha256:ea252b38c87425b64116f808355e8da644ef9b07e429398bfece610f893ee2e0 # via -r py/requirements.txt pyparsing==3.1.1 \ --hash=sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb \ --hash=sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db # via -r py/requirements.txt pysocks==1.7.1 \ --hash=sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299 \ --hash=sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5 \ --hash=sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0 # via # -r py/requirements.txt # urllib3 pytest==7.4.2 \ --hash=sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002 \ --hash=sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069 # via # -r py/requirements.txt # pytest-instafail # pytest-mock # pytest-trio pytest-instafail==0.5.0 \ --hash=sha256:33a606f7e0c8e646dc3bfee0d5e3a4b7b78ef7c36168cfa1f3d93af7ca706c9e \ --hash=sha256:6855414487e9e4bb76a118ce952c3c27d3866af15487506c4ded92eb72387819 # via -r py/requirements.txt pytest-mock==3.12.0 \ --hash=sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f \ --hash=sha256:31a40f038c22cad32287bb43932054451ff5583ff094bca6f675df2f8bc1a6e9 # via -r py/requirements.txt pytest-trio==0.8.0 \ --hash=sha256:8363db6336a79e6c53375a2123a41ddbeccc4aa93f93788651641789a56fb52e \ --hash=sha256:e6a7e7351ae3e8ec3f4564d30ee77d1ec66e1df611226e5618dbb32f9545c841 # via -r py/requirements.txt readme-renderer==42.0 \ --hash=sha256:13d039515c1f24de668e2c93f2e877b9dbe6c6c32328b90a40a49d8b2b85f36d \ --hash=sha256:2d55489f83be4992fe4454939d1a051c33edbab778e82761d060c9fc6b308cd1 # via twine requests==2.31.0 \ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 # via # requests-toolbelt # twine requests-toolbelt==1.0.0 \ --hash=sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6 \ --hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06 # via twine rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c # via twine rich==13.7.0 \ --hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \ --hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235 # via twine sniffio==1.3.0 \ --hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \ --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384 # via # -r py/requirements.txt # trio sortedcontainers==2.4.0 \ --hash=sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88 \ --hash=sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0 # via # -r py/requirements.txt # trio toml==0.10.2 \ --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f # via -r py/requirements.txt tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f # via pytest trio==0.22.0 \ --hash=sha256:ce68f1c5400a47b137c5a4de72c7c901bd4e7a24fbdebfe9b41de8c6c04eaacf \ --hash=sha256:f1dd0780a89bfc880c7c7994519cb53f62aacb2c25ff487001c0052bd721cdf0 # via # -r py/requirements.txt # pytest-trio # trio-websocket trio-websocket==0.9.2 \ --hash=sha256:5b558f6e83cc20a37c3b61202476c5295d1addf57bd65543364e0337e37ed2bc \ --hash=sha256:a3d34de8fac26023eee701ed1e7bf4da9a8326b61a62934ec9e53b64970fd8fe # via -r py/requirements.txt twine==4.0.2 \ --hash=sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8 \ --hash=sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8 # via -r py/requirements.txt typing-extensions==4.9.0 \ --hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \ --hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd # via # -r py/requirements.txt # rich urllib3[socks]==2.0.7 \ --hash=sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84 \ --hash=sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e # via # -r py/requirements.txt # requests # twine wsproto==1.2.0 \ --hash=sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065 \ --hash=sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736 # via # -r py/requirements.txt # trio-websocket zipp==3.17.0 \ --hash=sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31 \ --hash=sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0 # via # -r py/requirements.txt # importlib-metadata # importlib-resources selenium-selenium-4.18.1/README.md0000644000175000017500000005006714564764517016437 0ustar carstencarsten# Selenium [![CI](https://github.com/SeleniumHQ/selenium/actions/workflows/ci.yml/badge.svg?branch=trunk&event=schedule)](https://github.com/SeleniumHQ/selenium/actions/workflows/ci.yml) Selenium Selenium is an umbrella project encapsulating a variety of tools and libraries enabling web browser automation. Selenium specifically provides an infrastructure for the [W3C WebDriver specification](https://w3c.github.io/webdriver/) — a platform and language-neutral coding interface compatible with all major web browsers. The project is made possible by volunteer contributors who've generously donated thousands of hours in code development and upkeep. Selenium's source code is made available under the [Apache 2.0 license](https://github.com/SeleniumHQ/selenium/blob/trunk/LICENSE). This README is for developers interested in contributing to the project. For people looking to get started using Selenium, please check out our [User Manual](https://selenium.dev/documentation/) for detailed examples and descriptions, and if you get stuck, there are several ways to [Get Help](https://www.selenium.dev/support/). ## Contributing Please read [CONTRIBUTING.md](https://github.com/SeleniumHQ/selenium/blob/trunk/CONTRIBUTING.md) before submitting your pull requests. ## Installing These are the requirements to create your own local dev environment to contribute to Selenium. ### All Platforms * [Bazelisk](https://github.com/bazelbuild/bazelisk), a Bazel wrapper that automatically downloads the version of Bazel specified in `.bazelversion` file and transparently passes through all command-line arguments to the real Bazel binary. * Java JDK version 17 or greater (e.g., [Java 17 Temurin](https://adoptium.net/temurin/releases/?version=17)) * Set `JAVA_HOME` environment variable to location of Java executable (the JDK not the JRE) * To test this, try running the command `javac`. This command won't exist if you only have the JRE installed. If you're met with a list of command-line options, you're referencing the JDK properly. ### MacOS * Xcode including the command-line tools. Install the latest version using: `xcode-select --install` * Rosetta for Apple Silicon Macs. Add `build --host_platform=//:rosetta` to the `.bazelrc.local` file. We are working to make sure this isn't required in the long run. ### Windows Several years ago [Jim Evans](https://www.linkedin.com/in/jimevansmusic/) published a great article on [Setting Up a Windows Development Environment for the Selenium .NET Language Bindings](https://jimevansmusic.blogspot.com/2020/04/setting-up-windows-development.html); This article is out of date, but it includes more detailed descriptions and screenshots that some people might find useful.

Click to see Current Windows Setup Requirements #### Option 1: Automatic Installation from Scratch This script will ensure a complete ready to execute developer environment. (nothing is installed or set that is already present unless otherwise prompted) 1. Open Powershell as an Administrator 2. Execute: `Set-ExecutionPolicy Bypass -Scope Process -Force` to allow running the script in the process 3. Navigate to the directory you want to clone Selenium in, or the parent directory of an already cloned Selenium repo 4. Download and execute this script in the powershell terminal: [scripts/dev-environment-setup.ps1]` #### Option 2: Manual Installation 1. Allow running scripts in Selenium in general: ``` Set-ExecutionPolicy -ExecutionPolicy RemoteSigned ``` 2. Enable Developer Mode: ``` reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1" ``` 3. Install [MSYS2](https://www.msys2.org/), which is an alternative shell environment that provides Unix-like commands * Add bin directory to `PATH` environment variable (e.g., `"C:\tools\msys64\usr\bin"`) * Add `bash.exe` location as the `BAZEL_SH` environment variable (e.g., `"C:\tools\msys64\usr\bin\bash.exe"`) 4. Install the latest version of [Visual Studio Community](https://visualstudio.microsoft.com/vs/community/) * Use the visual studio installer to modify and add the "Desktop development with C++" Workload * Add Visual C++ build tools installation directory location to `BAZEL_VC` environment variable (e.g. `"C:\Program Files\Microsoft Visual Studio\2022\Community\VC"`) * Add Visual C++ Build tools version to `BAZEL_VC_FULL_VERSION` environment variable (this can be discovered from the directory name in `"$BAZEL_VC\Tools\MSVC\"`) 5. Add support for long file names (bazel has a lot of nested directories that can exceed default limits in Windows) * Enable Long Paths support with these 2 registry commands: ```shell reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor" /t REG_DWORD /f /v "DisableUNCCheck" /d "1" reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem" /t REG_DWORD /f /v "LongPathsEnabled" /d "1" ``` * Allow Bazel to create short name versions of long file paths: `fsutil 8dot3name set 0` * Set bazel output to `C:/tmp` instead of nested inside project directory: * Create a file `selenium/.bazelrc.windows.local` * Add "startup --output_user_root=C:/tmp" to the file
### Alternative Dev Environments If you want to contribute to the project, but do not want to set up your own local dev environment, there are two alternatives available. #### Using GitPod Rather than creating your own local dev environment, GitPod provides a ready to use environment for you. [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/SeleniumHQ/selenium) #### Using Docker Image You can also build a Docker image suitable for building and testing Selenium using the Dockerfile in the [dev image](scripts/dev-image/Dockerfile) directory. ## Building Selenium is built using a common build tool called [Bazel](https://bazel.build/), to allow us to easily manage dependency downloads, generate required binaries, build and release packages, and execute tests; all in a fast, efficient manner. For a more detailed discussion, read Simon Stewart's article on [Building Selenium](https://www.selenium.dev/blog/2023/building-selenium/) Often we wrap Bazel commands with our custom [Rake](http://rake.rubyforge.org/) wrapper. These are run with the `./go` command. The common Bazel commands are: * `bazel build` — evaluates dependencies, compiles source files and generates output files for the specified target. It's used to create executable binaries, libraries, or other artifacts. * `bazel run` — builds the target and then executes it. It's typically used for targets that produce executable binaries. * `bazel test` — builds and runs the target in a context with additional testing functionality * `bazel query` — identifies available targets for the provided path. Each module that can be built is defined in a `BUILD.bazel` file. To execute the module you refer to it starting with a `//`, then include the relative path to the file that defines it, then `:`, then the name of the target. For example, the target to build the Grid is named `executable-grid` and it is defined in the `'selenium/java/src/org/openqa/selenium/grid/BAZEL.build'` file. So to build the grid you would run: `bazel build //java/src/org/openqa/selenium/grid:executable-grid`. The Bazel documentation has a [handy guide](https://bazel.build/run/build#specifying-build-targets) for various shortcuts and all the ways to build multiple targets, which Selenium makes frequent use of. To build everything for a given language: ```shell bazel build ///... ``` To build just the grid there is an alias name to use (the log will show where the output jar is located): ```sh bazel build grid ``` To make things more simple, building each of the bindings is available with this `./go` command ```shell ./go :build ``` ## Developing ### Java #### IntelliJ Most of the team uses Intellij for their day-to-day editing. If you're working in IntelliJ, then we highly recommend installing the [Bazel IJ plugin](https://plugins.jetbrains.com/plugin/8609-bazel) which is documented on [its own site](https://plugins.jetbrains.com/plugin/8609-bazel). To use Selenium with the IntelliJ Bazel plugin, import the repository as a Bazel project, and select the project view file from the [scripts](scripts) directory. `ij.bazelproject` for Mac/Linux and `ij-win.bazelproject` for Windows. #### Linting We also use Google Java Format for linting, so using the Google Java Formatter Plugin is useful; there are a few steps to get it working, so read their [configuration documentation](https://github.com/google/google-java-format/blob/master/README.md#intellij-jre-config). There is also an auto-formatting script that can be run: `./scripts/format.sh` #### Local Installation While Selenium is not built with Maven, you can build and install the Selenium pieces for Maven to use locally by deploying to your local maven repository (`~/.m2/repository`), using: ```shell ./go java:install ``` #### Updating Dependencies Dependencies are defined in the file [maven_deps.bzl](https://github.com/SeleniumHQ/selenium/blob/trunk/java/maven_deps.bzl). To automatically update and pin new dependencies, run: ```shell ./go java:update ``` ### Python You can run Python code locally by updating generated files in the python directory using: ```shell ./go py:update ``` To install Selenium locally based on a specific commit, you can use: ```shell ./go py:install ``` ### Ruby Instead of using `irb`, you can create an interactive REPL with all gems loaded using: `bazel run //rb:console` If you want to debug code, you can do it via [`debug`](https://github.com/ruby/debug) gem: 1. Add `binding.break` to the code where you want the debugger to start. 2. Run tests with `ruby_debug` configuration: `bazel test --config ruby_debug `. 3. When debugger starts, run the following in a separate terminal to connect to debugger: ```sh bazel-selenium/external/bundle/bin/rdbg -A ``` If you want to use [RubyMine](https://www.jetbrains.com/ruby/) for development, you can configure it use Bazel artifacts: 1. Open `rb/` as a main project directory. 2. Run `bundle exec rake update` as necessary to create up-to-date artifacts. If this does not work, run `./go rb:update` from the `selenium` (parent) directory. 3. In Settings / Languages & Frameworks / Ruby SDK and Gems add new Interpreter pointing to `../bazel-selenium/external/rules_ruby_dist/dist/bin/ruby`. 4. You should now be able to run and debug any spec. It uses Chrome by default, but you can alter it using environment variables secified in [Ruby Testing](#ruby-2) section below. ### Rust To keep `Carbo.Bazel.lock` synchronized with `Cargo.lock`, run: ```shell CARGO_BAZEL_REPIN=true bazel sync --only=crates ``` ## Testing There are a number of bazel configurations specific for testing. ### Common Options Examples Here are examples of arguments we make use of in testing the Selenium code: * `--pin_browsers=true` - run specific browser versions defined in the build (versions are updated regularly) * `--flaky_test_attempts 3` - re-run failed tests up to 3 times * `--local_test_jobs 1` - control parallelism of tests * `--cache_test_results=no`, `-t-` - disable caching of test results and re-runs all of them * `--test_output all` - print all output from the tests, not just errors * `--test_output streamed` - run all tests one by one and print its output immediately * `--test_env FOO=bar` - pass extra environment variable to test process * `--run_under="xvfb-run -a"` - prefix to insert before the execution ### Filtering Selenium tests can be filtered by size: * small — typically unit tests where no browser is opened * large — typically tests that actually drive a browser * medium — tests that are more involved than simple unit tests, but not fully driving a browser These can be filtered using the `test_size_filters` argument like this: ```sh bazel test ///... --test_size_filters=small ``` Tests can also be filtered by tag like: ```sh bazel test ///... --test_tag_filters=this,-not-this ``` ### Java
Click to see Java Test Commands To run unit tests: ```shell bazel test //java/... --test_size_filters=small ``` To run integration tests: ```shell bazel test //java/... --test_size_filters=medium ``` To run browser tests: ```shell bazel test //java/... --test_size_filters=large --test_tag_filters= ``` To run a specific test: ```shell bazel test //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest ```
### JavaScript
Click to see JavaScript Test Commands To run the tests run: ```sh bazel test //javascript/node/selenium-webdriver:tests ``` You can use `--test_env` to pass in the browser name as `SELENIUM_BROWSER`. ```sh bazel test //javascript/node/selenium-webdriver:tests --test_env=SELENIUM_BROWSER=firefox ```
### Python
Click to see Python Test Commands Run unit tests with: ```shell bazel test //py:unit ``` To run tests with a specific browser: ```sh bazel test //py:test- ``` To run all Python tests: ```shell bazel test //py:all ```
### Ruby
Click to see Ruby Test Commands Test targets: | Command | Description | |--------------------------------------------------------------------------------------|------------------------------------------------| | `bazel test //rb/...` | Run unit, integration tests (Chrome) and lint | | `bazel test //rb:lint` | Run RuboCop linter | | `bazel test //rb/spec/...` | Run unit and integration tests (Chrome) | | `bazel test --test_size_filters large //rb/...` | Run integration tests using (Chrome) | | `bazel test //rb/spec/integration/...` | Run integration tests using (Chrome) | | `bazel test //rb/spec/integration/... --define browser=firefox` | Run integration tests using (Firefox) | | `bazel test //rb/spec/integration/... --define remote=true` | Run integration tests using (Chrome and Grid) | | `bazel test //rb/spec/integration/... --define browser=firefox --define remote=true` | Run integration tests using (Firefox and Grid) | | `bazel test --test_size_filters small //rb/...` | Run unit tests | | `bazel test //rb/spec/unit/...` | Run unit tests | Ruby test modules have the same name as the spec file with `_spec.rb` removed, so you can run them individually: | Test file | Test target | |----------------------------------------------------------------|----------------------------------------------------------| | `rb/spec/integration/selenium/webdriver/chrome/driver_spec.rb` | `//rb/spec/integration/selenium/webdriver/chrome:driver` | | `rb/spec/unit/selenium/webdriver/proxy_spec.rb` | `//rb/spec/unit/selenium/webdriver:proxy` | Supported browsers: * `chrome` * `edge` * `firefox` * `ie` * `safari` (cannot be run in parallel - use `--local_test_jobs 1`) * `safari-preview` (cannot be run in parallel - use `--local_test_jobs 1`) Useful command line options: In addition to the [Common Options Examples](#common-options-examples), here are some additional Ruby specific ones: * `--test_arg "-tfocus"` - test only [focused specs](https://relishapp.com/rspec/rspec-core/v/3-12/docs/filtering/inclusion-filters) * `--test_arg "-eTimeouts"` - test only specs which name include "Timeouts" * `--test_arg ""` - pass any extra RSpec arguments (see `bazel run @bundle//bin:rspec -- --help`) Supported environment variables for use with `--test_env`: - `WD_SPEC_DRIVER` - the driver to test; either the browser name or 'remote' (gets set by Bazel) - `WD_REMOTE_BROWSER` - when `WD_SPEC_DRIVER` is `remote`; the name of the browser to test (gets set by Bazel) - `WD_REMOTE_URL` - URL of an already running server to use for remote tests - `DOWNLOAD_SERVER` - when `WD_REMOTE_URL` not set; whether to download and use most recently released server version for remote tests - `DEBUG` - turns on verbose debugging - `HEADLESS` - for chrome, edge and firefox; runs tests in headless mode - `DISABLE_BUILD_CHECK` - for chrome and edge; whether to ignore driver and browser version mismatches (allows testing Canary builds) - `CHROME_BINARY` - path to test specific Chrome browser - `EDGE_BINARY` - path to test specific Edge browser - `FIREFOX_BINARY` - path to test specific Firefox browser To run with a specific version of Ruby you can change the version in `rb/.ruby-version` or from command line: ```sh echo '' > rb/.ruby-version ```
### .NET
Click to see .NET Test Commands .NET tests currently only work with pinned browsers, so make sure to include that. Run all tests with: ```sh bazel test //dotnet/test/common:AllTests --pin_browsers=true ``` You can run specific tests by specifying the class name: ```shell bazel test //dotnet/test/common:ElementFindingTest --pin_browsers=true ``` If the module supports multiple browsers: ```shell bazel test //dotnet/test/common:ElementFindingTest-edge --pin_browsers=true ```
### Rust
Click to see Rust Test Commands Rust tests are run with: ```shell bazel test //rust/... ```
### Linux
Click to see Linux Testing Requirements By default, Bazel runs these tests in your current X-server UI. If you prefer, you can alternatively run them in a virtual or nested X-server. 1. Run the X server `Xvfb :99` or `Xnest :99` 2. Run a window manager, for example, `DISPLAY=:99 jwm` 3. Run the tests you are interested in: ```sh bazel test --test_env=DISPLAY=:99 //java/... --test_tag_filters=chrome ``` An easy way to run tests in a virtual X-server is to use Bazel's `--run_under` functionality: ``` bazel test --run_under="xvfb-run -a" //java/... ```
## Documenting API documentation can be found here: * [C#](https://seleniumhq.github.io/selenium/docs/api/dotnet/) * [JavaScript](https://seleniumhq.github.io/selenium/docs/api/javascript/) * [Java](https://seleniumhq.github.io/selenium/docs/api/java/index.html) * [Python](https://seleniumhq.github.io/selenium/docs/api/py/) * [Ruby](https://seleniumhq.github.io/selenium/docs/api/rb/) To update API documentation for a specific language: `./generate_api_docs.sh ` To update all documentation: `./generate_api_docs.sh all` Note that JavaScript generation is [currently broken](https://github.com/SeleniumHQ/selenium/issues/10185). ## Releasing The full process for doing a release can be found in [the wiki](https://github.com/SeleniumHQ/selenium/wiki/Releasing-Selenium) Releasing is a combination of building and publishing, which often requires coordination of multiple executions and additional processing. As discussed in the [Building](#building) section, we use Rake tasks with the `./go` command for these things. These `./go` commands include the `--stamp` argument to provide necessary information about the constructed asset. You can build and release everything with: ```shell ./go all:release ``` To build and release a specific language: ```shell ./go :release ``` If you have access to the Selenium EngFlow repository, you can have the assets built remotely and downloaded locally using: ```shell ./go all:release['--config', 'release'] ``` selenium-selenium-4.18.1/selenium/0000755000175000017500000000000014564764517016771 5ustar carstencarstenselenium-selenium-4.18.1/selenium/common/0000755000175000017500000000000014564764517020261 5ustar carstencarstenselenium-selenium-4.18.1/selenium/common/__init__.py0000644000175000017500000000672414564764517022403 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from .exceptions import ElementClickInterceptedException from .exceptions import ElementNotInteractableException from .exceptions import ElementNotSelectableException from .exceptions import ElementNotVisibleException from .exceptions import ImeActivationFailedException from .exceptions import ImeNotAvailableException from .exceptions import InsecureCertificateException from .exceptions import InvalidArgumentException from .exceptions import InvalidCookieDomainException from .exceptions import InvalidCoordinatesException from .exceptions import InvalidElementStateException from .exceptions import InvalidSelectorException from .exceptions import InvalidSessionIdException from .exceptions import InvalidSwitchToTargetException from .exceptions import JavascriptException from .exceptions import MoveTargetOutOfBoundsException from .exceptions import NoAlertPresentException from .exceptions import NoSuchAttributeException from .exceptions import NoSuchCookieException from .exceptions import NoSuchDriverException from .exceptions import NoSuchElementException from .exceptions import NoSuchFrameException from .exceptions import NoSuchShadowRootException from .exceptions import NoSuchWindowException from .exceptions import ScreenshotException from .exceptions import SessionNotCreatedException from .exceptions import StaleElementReferenceException from .exceptions import TimeoutException from .exceptions import UnableToSetCookieException from .exceptions import UnexpectedAlertPresentException from .exceptions import UnexpectedTagNameException from .exceptions import UnknownMethodException from .exceptions import WebDriverException __all__ = [ "WebDriverException", "InvalidSwitchToTargetException", "NoSuchFrameException", "NoSuchWindowException", "NoSuchElementException", "NoSuchAttributeException", "NoSuchDriverException", "NoSuchShadowRootException", "StaleElementReferenceException", "InvalidElementStateException", "UnexpectedAlertPresentException", "NoAlertPresentException", "ElementNotVisibleException", "ElementNotInteractableException", "ElementNotSelectableException", "InvalidCookieDomainException", "UnableToSetCookieException", "TimeoutException", "MoveTargetOutOfBoundsException", "UnexpectedTagNameException", "InvalidSelectorException", "ImeNotAvailableException", "ImeActivationFailedException", "InvalidArgumentException", "JavascriptException", "NoSuchCookieException", "ScreenshotException", "ElementClickInterceptedException", "InsecureCertificateException", "InvalidCoordinatesException", "InvalidSessionIdException", "SessionNotCreatedException", "UnknownMethodException", ] selenium-selenium-4.18.1/selenium/common/exceptions.py0000644000175000017500000002370214564764517023020 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """Exceptions that may happen in all the webdriver code.""" from typing import Optional from typing import Sequence SUPPORT_MSG = "For documentation on this error, please visit:" ERROR_URL = "https://www.selenium.dev/documentation/webdriver/troubleshooting/errors" class WebDriverException(Exception): """Base webdriver exception.""" def __init__( self, msg: Optional[str] = None, screen: Optional[str] = None, stacktrace: Optional[Sequence[str]] = None ) -> None: super().__init__() self.msg = msg self.screen = screen self.stacktrace = stacktrace def __str__(self) -> str: exception_msg = f"Message: {self.msg}\n" if self.screen: exception_msg += "Screenshot: available via screen\n" if self.stacktrace: stacktrace = "\n".join(self.stacktrace) exception_msg += f"Stacktrace:\n{stacktrace}" return exception_msg class InvalidSwitchToTargetException(WebDriverException): """Thrown when frame or window target to be switched doesn't exist.""" class NoSuchFrameException(InvalidSwitchToTargetException): """Thrown when frame target to be switched doesn't exist.""" class NoSuchWindowException(InvalidSwitchToTargetException): """Thrown when window target to be switched doesn't exist. To find the current set of active window handles, you can get a list of the active window handles in the following way:: print driver.window_handles """ class NoSuchElementException(WebDriverException): """Thrown when element could not be found. If you encounter this exception, you may want to check the following: * Check your selector used in your find_by... * Element may not yet be on the screen at the time of the find operation, (webpage is still loading) see selenium.webdriver.support.wait.WebDriverWait() for how to write a wait wrapper to wait for an element to appear. """ def __init__( self, msg: Optional[str] = None, screen: Optional[str] = None, stacktrace: Optional[Sequence[str]] = None ) -> None: with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#no-such-element-exception" super().__init__(with_support, screen, stacktrace) class NoSuchAttributeException(WebDriverException): """Thrown when the attribute of element could not be found. You may want to check if the attribute exists in the particular browser you are testing against. Some browsers may have different property names for the same property. (IE8's .innerText vs. Firefox .textContent) """ class NoSuchShadowRootException(WebDriverException): """Thrown when trying to access the shadow root of an element when it does not have a shadow root attached.""" class StaleElementReferenceException(WebDriverException): """Thrown when a reference to an element is now "stale". Stale means the element no longer appears on the DOM of the page. Possible causes of StaleElementReferenceException include, but not limited to: * You are no longer on the same page, or the page may have refreshed since the element was located. * The element may have been removed and re-added to the screen, since it was located. Such as an element being relocated. This can happen typically with a javascript framework when values are updated and the node is rebuilt. * Element may have been inside an iframe or another context which was refreshed. """ def __init__( self, msg: Optional[str] = None, screen: Optional[str] = None, stacktrace: Optional[Sequence[str]] = None ) -> None: with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#stale-element-reference-exception" super().__init__(with_support, screen, stacktrace) class InvalidElementStateException(WebDriverException): """Thrown when a command could not be completed because the element is in an invalid state. This can be caused by attempting to clear an element that isn't both editable and resettable. """ class UnexpectedAlertPresentException(WebDriverException): """Thrown when an unexpected alert has appeared. Usually raised when an unexpected modal is blocking the webdriver from executing commands. """ def __init__( self, msg: Optional[str] = None, screen: Optional[str] = None, stacktrace: Optional[Sequence[str]] = None, alert_text: Optional[str] = None, ) -> None: super().__init__(msg, screen, stacktrace) self.alert_text = alert_text def __str__(self) -> str: return f"Alert Text: {self.alert_text}\n{super().__str__()}" class NoAlertPresentException(WebDriverException): """Thrown when switching to no presented alert. This can be caused by calling an operation on the Alert() class when an alert is not yet on the screen. """ class ElementNotVisibleException(InvalidElementStateException): """Thrown when an element is present on the DOM, but it is not visible, and so is not able to be interacted with. Most commonly encountered when trying to click or read text of an element that is hidden from view. """ class ElementNotInteractableException(InvalidElementStateException): """Thrown when an element is present in the DOM but interactions with that element will hit another element due to paint order.""" class ElementNotSelectableException(InvalidElementStateException): """Thrown when trying to select an unselectable element. For example, selecting a 'script' element. """ class InvalidCookieDomainException(WebDriverException): """Thrown when attempting to add a cookie under a different domain than the current URL.""" class UnableToSetCookieException(WebDriverException): """Thrown when a driver fails to set a cookie.""" class TimeoutException(WebDriverException): """Thrown when a command does not complete in enough time.""" class MoveTargetOutOfBoundsException(WebDriverException): """Thrown when the target provided to the `ActionsChains` move() method is invalid, i.e. out of document.""" class UnexpectedTagNameException(WebDriverException): """Thrown when a support class did not get an expected web element.""" class InvalidSelectorException(WebDriverException): """Thrown when the selector which is used to find an element does not return a WebElement. Currently this only happens when the selector is an xpath expression and it is either syntactically invalid (i.e. it is not a xpath expression) or the expression does not select WebElements (e.g. "count(//input)"). """ def __init__( self, msg: Optional[str] = None, screen: Optional[str] = None, stacktrace: Optional[Sequence[str]] = None ) -> None: with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#invalid-selector-exception" super().__init__(with_support, screen, stacktrace) class ImeNotAvailableException(WebDriverException): """Thrown when IME support is not available. This exception is thrown for every IME-related method call if IME support is not available on the machine. """ class ImeActivationFailedException(WebDriverException): """Thrown when activating an IME engine has failed.""" class InvalidArgumentException(WebDriverException): """The arguments passed to a command are either invalid or malformed.""" class JavascriptException(WebDriverException): """An error occurred while executing JavaScript supplied by the user.""" class NoSuchCookieException(WebDriverException): """No cookie matching the given path name was found amongst the associated cookies of the current browsing context's active document.""" class ScreenshotException(WebDriverException): """A screen capture was made impossible.""" class ElementClickInterceptedException(WebDriverException): """The Element Click command could not be completed because the element receiving the events is obscuring the element that was requested to be clicked.""" class InsecureCertificateException(WebDriverException): """Navigation caused the user agent to hit a certificate warning, which is usually the result of an expired or invalid TLS certificate.""" class InvalidCoordinatesException(WebDriverException): """The coordinates provided to an interaction's operation are invalid.""" class InvalidSessionIdException(WebDriverException): """Occurs if the given session id is not in the list of active sessions, meaning the session either does not exist or that it's not active.""" class SessionNotCreatedException(WebDriverException): """A new session could not be created.""" class UnknownMethodException(WebDriverException): """The requested command matched a known URL but did not match any methods for that URL.""" class NoSuchDriverException(WebDriverException): """Raised when driver is not specified and cannot be located.""" def __init__( self, msg: Optional[str] = None, screen: Optional[str] = None, stacktrace: Optional[Sequence[str]] = None ) -> None: with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}/driver_location" super().__init__(with_support, screen, stacktrace) selenium-selenium-4.18.1/selenium/py.typed0000644000175000017500000000000014564764517020456 0ustar carstencarstenselenium-selenium-4.18.1/selenium/__init__.py0000644000175000017500000000145414564764517021106 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. __version__ = "4.18.1" selenium-selenium-4.18.1/selenium/types.py0000644000175000017500000000176614564764517020521 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """Selenium type definitions.""" import typing AnyKey = typing.Union[str, int, float] WaitExcTypes = typing.Iterable[typing.Type[Exception]] # Service Types SubprocessStdAlias = typing.Union[int, str, typing.IO[typing.Any]] selenium-selenium-4.18.1/selenium/webdriver/0000755000175000017500000000000014564764517020762 5ustar carstencarstenselenium-selenium-4.18.1/selenium/webdriver/common/0000755000175000017500000000000014564764517022252 5ustar carstencarstenselenium-selenium-4.18.1/selenium/webdriver/common/keys.py0000644000175000017500000000441414564764517023602 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """The Keys implementation.""" class Keys: """Set of special keys codes.""" NULL = "\ue000" CANCEL = "\ue001" # ^break HELP = "\ue002" BACKSPACE = "\ue003" BACK_SPACE = BACKSPACE TAB = "\ue004" CLEAR = "\ue005" RETURN = "\ue006" ENTER = "\ue007" SHIFT = "\ue008" LEFT_SHIFT = SHIFT CONTROL = "\ue009" LEFT_CONTROL = CONTROL ALT = "\ue00a" LEFT_ALT = ALT PAUSE = "\ue00b" ESCAPE = "\ue00c" SPACE = "\ue00d" PAGE_UP = "\ue00e" PAGE_DOWN = "\ue00f" END = "\ue010" HOME = "\ue011" LEFT = "\ue012" ARROW_LEFT = LEFT UP = "\ue013" ARROW_UP = UP RIGHT = "\ue014" ARROW_RIGHT = RIGHT DOWN = "\ue015" ARROW_DOWN = DOWN INSERT = "\ue016" DELETE = "\ue017" SEMICOLON = "\ue018" EQUALS = "\ue019" NUMPAD0 = "\ue01a" # number pad keys NUMPAD1 = "\ue01b" NUMPAD2 = "\ue01c" NUMPAD3 = "\ue01d" NUMPAD4 = "\ue01e" NUMPAD5 = "\ue01f" NUMPAD6 = "\ue020" NUMPAD7 = "\ue021" NUMPAD8 = "\ue022" NUMPAD9 = "\ue023" MULTIPLY = "\ue024" ADD = "\ue025" SEPARATOR = "\ue026" SUBTRACT = "\ue027" DECIMAL = "\ue028" DIVIDE = "\ue029" F1 = "\ue031" # function keys F2 = "\ue032" F3 = "\ue033" F4 = "\ue034" F5 = "\ue035" F6 = "\ue036" F7 = "\ue037" F8 = "\ue038" F9 = "\ue039" F10 = "\ue03a" F11 = "\ue03b" F12 = "\ue03c" META = "\ue03d" COMMAND = "\ue03d" ZENKAKU_HANKAKU = "\ue040" selenium-selenium-4.18.1/selenium/webdriver/common/bidi/0000755000175000017500000000000014564764517023161 5ustar carstencarstenselenium-selenium-4.18.1/selenium/webdriver/common/bidi/cdp.py0000644000175000017500000004333614564764517024312 0ustar carstencarsten# The MIT License(MIT) # # Copyright(c) 2018 Hyperion Gray # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # This code comes from https://github.com/HyperionGray/trio-chrome-devtools-protocol/tree/master/trio_cdp # flake8: noqa import contextvars import importlib import itertools import json import logging import pathlib import typing from collections import defaultdict from contextlib import asynccontextmanager from contextlib import contextmanager from dataclasses import dataclass import trio from trio_websocket import ConnectionClosed as WsConnectionClosed from trio_websocket import connect_websocket_url logger = logging.getLogger("trio_cdp") T = typing.TypeVar("T") MAX_WS_MESSAGE_SIZE = 2**24 devtools = None version = None def import_devtools(ver): """Attempt to load the current latest available devtools into the module cache for use later.""" global devtools global version version = ver base = "selenium.webdriver.common.devtools.v" try: devtools = importlib.import_module(f"{base}{ver}") return devtools except ModuleNotFoundError: # Attempt to parse and load the 'most recent' devtools module. This is likely # because cdp has been updated but selenium python has not been released yet. devtools_path = pathlib.Path(__file__).parents[1].joinpath("devtools") versions = tuple(f.name for f in devtools_path.iterdir() if f.is_dir()) latest = max(int(x[1:]) for x in versions) selenium_logger = logging.getLogger(__name__) selenium_logger.debug("Falling back to loading `devtools`: v%s", latest) devtools = importlib.import_module(f"{base}{latest}") return devtools _connection_context: contextvars.ContextVar = contextvars.ContextVar("connection_context") _session_context: contextvars.ContextVar = contextvars.ContextVar("session_context") def get_connection_context(fn_name): """Look up the current connection. If there is no current connection, raise a ``RuntimeError`` with a helpful message. """ try: return _connection_context.get() except LookupError: raise RuntimeError(f"{fn_name}() must be called in a connection context.") def get_session_context(fn_name): """Look up the current session. If there is no current session, raise a ``RuntimeError`` with a helpful message. """ try: return _session_context.get() except LookupError: raise RuntimeError(f"{fn_name}() must be called in a session context.") @contextmanager def connection_context(connection): """This context manager installs ``connection`` as the session context for the current Trio task.""" token = _connection_context.set(connection) try: yield finally: _connection_context.reset(token) @contextmanager def session_context(session): """This context manager installs ``session`` as the session context for the current Trio task.""" token = _session_context.set(session) try: yield finally: _session_context.reset(token) def set_global_connection(connection): """Install ``connection`` in the root context so that it will become the default connection for all tasks. This is generally not recommended, except it may be necessary in certain use cases such as running inside Jupyter notebook. """ global _connection_context _connection_context = contextvars.ContextVar("_connection_context", default=connection) def set_global_session(session): """Install ``session`` in the root context so that it will become the default session for all tasks. This is generally not recommended, except it may be necessary in certain use cases such as running inside Jupyter notebook. """ global _session_context _session_context = contextvars.ContextVar("_session_context", default=session) class BrowserError(Exception): """This exception is raised when the browser's response to a command indicates that an error occurred.""" def __init__(self, obj): self.code = obj.get("code") self.message = obj.get("message") self.detail = obj.get("data") def __str__(self): return f"BrowserError {self.detail}" class CdpConnectionClosed(WsConnectionClosed): """Raised when a public method is called on a closed CDP connection.""" def __init__(self, reason): """Constructor. :param reason: :type reason: wsproto.frame_protocol.CloseReason """ self.reason = reason def __repr__(self): """Return representation.""" return f"{self.__class__.__name__}<{self.reason}>" class InternalError(Exception): """This exception is only raised when there is faulty logic in TrioCDP or the integration with PyCDP.""" @dataclass class CmEventProxy: """A proxy object returned by :meth:`CdpBase.wait_for()``. After the context manager executes, this proxy object will have a value set that contains the returned event. """ value: typing.Any = None class CdpBase: def __init__(self, ws, session_id, target_id): self.ws = ws self.session_id = session_id self.target_id = target_id self.channels = defaultdict(set) self.id_iter = itertools.count() self.inflight_cmd = {} self.inflight_result = {} async def execute(self, cmd: typing.Generator[dict, T, typing.Any]) -> T: """Execute a command on the server and wait for the result. :param cmd: any CDP command :returns: a CDP result """ cmd_id = next(self.id_iter) cmd_event = trio.Event() self.inflight_cmd[cmd_id] = cmd, cmd_event request = next(cmd) request["id"] = cmd_id if self.session_id: request["sessionId"] = self.session_id request_str = json.dumps(request) try: await self.ws.send_message(request_str) except WsConnectionClosed as wcc: raise CdpConnectionClosed(wcc.reason) from None await cmd_event.wait() response = self.inflight_result.pop(cmd_id) if isinstance(response, Exception): raise response return response def listen(self, *event_types, buffer_size=10): """Return an async iterator that iterates over events matching the indicated types.""" sender, receiver = trio.open_memory_channel(buffer_size) for event_type in event_types: self.channels[event_type].add(sender) return receiver @asynccontextmanager async def wait_for(self, event_type: typing.Type[T], buffer_size=10) -> typing.AsyncGenerator[CmEventProxy, None]: """Wait for an event of the given type and return it. This is an async context manager, so you should open it inside an async with block. The block will not exit until the indicated event is received. """ sender, receiver = trio.open_memory_channel(buffer_size) self.channels[event_type].add(sender) proxy = CmEventProxy() yield proxy async with receiver: event = await receiver.receive() proxy.value = event def _handle_data(self, data): """Handle incoming WebSocket data. :param dict data: a JSON dictionary """ if "id" in data: self._handle_cmd_response(data) else: self._handle_event(data) def _handle_cmd_response(self, data): """Handle a response to a command. This will set an event flag that will return control to the task that called the command. :param dict data: response as a JSON dictionary """ cmd_id = data["id"] try: cmd, event = self.inflight_cmd.pop(cmd_id) except KeyError: logger.warning("Got a message with a command ID that does not exist: %s", data) return if "error" in data: # If the server reported an error, convert it to an exception and do # not process the response any further. self.inflight_result[cmd_id] = BrowserError(data["error"]) else: # Otherwise, continue the generator to parse the JSON result # into a CDP object. try: _ = cmd.send(data["result"]) raise InternalError("The command's generator function did not exit when expected!") except StopIteration as exit: return_ = exit.value self.inflight_result[cmd_id] = return_ event.set() def _handle_event(self, data): """Handle an event. :param dict data: event as a JSON dictionary """ global devtools event = devtools.util.parse_json_event(data) logger.debug("Received event: %s", event) to_remove = set() for sender in self.channels[type(event)]: try: sender.send_nowait(event) except trio.WouldBlock: logger.error('Unable to send event "%r" due to full channel %s', event, sender) except trio.BrokenResourceError: to_remove.add(sender) if to_remove: self.channels[type(event)] -= to_remove class CdpSession(CdpBase): """Contains the state for a CDP session. Generally you should not instantiate this object yourself; you should call :meth:`CdpConnection.open_session`. """ def __init__(self, ws, session_id, target_id): """Constructor. :param trio_websocket.WebSocketConnection ws: :param devtools.target.SessionID session_id: :param devtools.target.TargetID target_id: """ super().__init__(ws, session_id, target_id) self._dom_enable_count = 0 self._dom_enable_lock = trio.Lock() self._page_enable_count = 0 self._page_enable_lock = trio.Lock() @asynccontextmanager async def dom_enable(self): """A context manager that executes ``dom.enable()`` when it enters and then calls ``dom.disable()``. This keeps track of concurrent callers and only disables DOM events when all callers have exited. """ global devtools async with self._dom_enable_lock: self._dom_enable_count += 1 if self._dom_enable_count == 1: await self.execute(devtools.dom.enable()) yield async with self._dom_enable_lock: self._dom_enable_count -= 1 if self._dom_enable_count == 0: await self.execute(devtools.dom.disable()) @asynccontextmanager async def page_enable(self): """A context manager that executes ``page.enable()`` when it enters and then calls ``page.disable()`` when it exits. This keeps track of concurrent callers and only disables page events when all callers have exited. """ global devtools async with self._page_enable_lock: self._page_enable_count += 1 if self._page_enable_count == 1: await self.execute(devtools.page.enable()) yield async with self._page_enable_lock: self._page_enable_count -= 1 if self._page_enable_count == 0: await self.execute(devtools.page.disable()) class CdpConnection(CdpBase, trio.abc.AsyncResource): """Contains the connection state for a Chrome DevTools Protocol server. CDP can multiplex multiple "sessions" over a single connection. This class corresponds to the "root" session, i.e. the implicitly created session that has no session ID. This class is responsible for reading incoming WebSocket messages and forwarding them to the corresponding session, as well as handling messages targeted at the root session itself. You should generally call the :func:`open_cdp()` instead of instantiating this class directly. """ def __init__(self, ws): """Constructor. :param trio_websocket.WebSocketConnection ws: """ super().__init__(ws, session_id=None, target_id=None) self.sessions = {} async def aclose(self): """Close the underlying WebSocket connection. This will cause the reader task to gracefully exit when it tries to read the next message from the WebSocket. All of the public APIs (``execute()``, ``listen()``, etc.) will raise ``CdpConnectionClosed`` after the CDP connection is closed. It is safe to call this multiple times. """ await self.ws.aclose() @asynccontextmanager async def open_session(self, target_id) -> typing.AsyncIterator[CdpSession]: """This context manager opens a session and enables the "simple" style of calling CDP APIs. For example, inside a session context, you can call ``await dom.get_document()`` and it will execute on the current session automatically. """ session = await self.connect_session(target_id) with session_context(session): yield session async def connect_session(self, target_id) -> "CdpSession": """Returns a new :class:`CdpSession` connected to the specified target.""" global devtools session_id = await self.execute(devtools.target.attach_to_target(target_id, True)) session = CdpSession(self.ws, session_id, target_id) self.sessions[session_id] = session return session async def _reader_task(self): """Runs in the background and handles incoming messages: dispatching responses to commands and events to listeners.""" global devtools while True: try: message = await self.ws.get_message() except WsConnectionClosed: # If the WebSocket is closed, we don't want to throw an # exception from the reader task. Instead we will throw # exceptions from the public API methods, and we can quietly # exit the reader task here. break try: data = json.loads(message) except json.JSONDecodeError: raise BrowserError({"code": -32700, "message": "Client received invalid JSON", "data": message}) logger.debug("Received message %r", data) if "sessionId" in data: session_id = devtools.target.SessionID(data["sessionId"]) try: session = self.sessions[session_id] except KeyError: raise BrowserError( { "code": -32700, "message": "Browser sent a message for an invalid session", "data": f"{session_id!r}", } ) session._handle_data(data) else: self._handle_data(data) for _, session in self.sessions.items(): for _, senders in session.channels.items(): for sender in senders: sender.close() @asynccontextmanager async def open_cdp(url) -> typing.AsyncIterator[CdpConnection]: """This async context manager opens a connection to the browser specified by ``url`` before entering the block, then closes the connection when the block exits. The context manager also sets the connection as the default connection for the current task, so that commands like ``await target.get_targets()`` will run on this connection automatically. If you want to use multiple connections concurrently, it is recommended to open each on in a separate task. """ async with trio.open_nursery() as nursery: conn = await connect_cdp(nursery, url) try: with connection_context(conn): yield conn finally: await conn.aclose() async def connect_cdp(nursery, url) -> CdpConnection: """Connect to the browser specified by ``url`` and spawn a background task in the specified nursery. The ``open_cdp()`` context manager is preferred in most situations. You should only use this function if you need to specify a custom nursery. This connection is not automatically closed! You can either use the connection object as a context manager (``async with conn:``) or else call ``await conn.aclose()`` on it when you are done with it. If ``set_context`` is True, then the returned connection will be installed as the default connection for the current task. This argument is for unusual use cases, such as running inside of a notebook. """ ws = await connect_websocket_url(nursery, url, max_message_size=MAX_WS_MESSAGE_SIZE) cdp_conn = CdpConnection(ws) nursery.start_soon(cdp_conn._reader_task) return cdp_conn selenium-selenium-4.18.1/selenium/webdriver/common/bidi/__init__.py0000644000175000017500000000142314564764517025272 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/selenium/webdriver/common/bidi/console.py0000644000175000017500000000156514564764517025204 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from enum import Enum class Console(Enum): ALL = "all" LOG = "log" ERROR = "error" selenium-selenium-4.18.1/selenium/webdriver/common/utils.py0000644000175000017500000001041014564764517023760 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """The Utils methods.""" import socket from typing import Iterable from typing import List from typing import Optional from typing import Union from selenium.types import AnyKey from selenium.webdriver.common.keys import Keys _is_connectable_exceptions = (socket.error, ConnectionResetError) def free_port() -> int: """Determines a free port using sockets.""" free_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) free_socket.bind(("127.0.0.1", 0)) free_socket.listen(5) port: int = free_socket.getsockname()[1] free_socket.close() return port def find_connectable_ip(host: Union[str, bytes, bytearray, None], port: Optional[int] = None) -> Optional[str]: """Resolve a hostname to an IP, preferring IPv4 addresses. We prefer IPv4 so that we don't change behavior from previous IPv4-only implementations, and because some drivers (e.g., FirefoxDriver) do not support IPv6 connections. If the optional port number is provided, only IPs that listen on the given port are considered. :Args: - host - A hostname. - port - Optional port number. :Returns: A single IP address, as a string. If any IPv4 address is found, one is returned. Otherwise, if any IPv6 address is found, one is returned. If neither, then None is returned. """ try: addrinfos = socket.getaddrinfo(host, None) except socket.gaierror: return None ip = None for family, _, _, _, sockaddr in addrinfos: connectable = True if port: connectable = is_connectable(port, sockaddr[0]) if connectable and family == socket.AF_INET: return sockaddr[0] if connectable and not ip and family == socket.AF_INET6: ip = sockaddr[0] return ip def join_host_port(host: str, port: int) -> str: """Joins a hostname and port together. This is a minimal implementation intended to cope with IPv6 literals. For example, _join_host_port('::1', 80) == '[::1]:80'. :Args: - host - A hostname. - port - An integer port. """ if ":" in host and not host.startswith("["): return f"[{host}]:{port}" return f"{host}:{port}" def is_connectable(port: int, host: Optional[str] = "localhost") -> bool: """Tries to connect to the server at port to see if it is running. :Args: - port - The port to connect. """ socket_ = None try: socket_ = socket.create_connection((host, port), 1) result = True except _is_connectable_exceptions: result = False finally: if socket_: socket_.close() return result def is_url_connectable(port: Union[int, str]) -> bool: """Tries to connect to the HTTP server at /status path and specified port to see if it responds successfully. :Args: - port - The port to connect. """ from urllib import request as url_request try: res = url_request.urlopen(f"http://127.0.0.1:{port}/status") return res.getcode() == 200 except Exception: return False def keys_to_typing(value: Iterable[AnyKey]) -> List[str]: """Processes the values that will be typed in the element.""" characters: List[str] = [] for val in value: if isinstance(val, Keys): # Todo: Does this even work? characters.append(val) elif isinstance(val, (int, float)): characters.extend(str(val)) else: characters.extend(val) return characters selenium-selenium-4.18.1/selenium/webdriver/common/desired_capabilities.py0000644000175000017500000000541014564764517026754 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """The Desired Capabilities implementation.""" class DesiredCapabilities: """Set of default supported desired capabilities. Use this as a starting point for creating a desired capabilities object for requesting remote webdrivers for connecting to selenium server or selenium grid. Usage Example:: from selenium import webdriver selenium_grid_url = "http://198.0.0.1:4444/wd/hub" # Create a desired capabilities object as a starting point. capabilities = DesiredCapabilities.FIREFOX.copy() capabilities['platform'] = "WINDOWS" capabilities['version'] = "10" # Instantiate an instance of Remote WebDriver with the desired capabilities. driver = webdriver.Remote(desired_capabilities=capabilities, command_executor=selenium_grid_url) Note: Always use '.copy()' on the DesiredCapabilities object to avoid the side effects of altering the Global class instance. """ FIREFOX = { "browserName": "firefox", "acceptInsecureCerts": True, "moz:debuggerAddress": True, } INTERNETEXPLORER = { "browserName": "internet explorer", "platformName": "windows", } EDGE = { "browserName": "MicrosoftEdge", } CHROME = { "browserName": "chrome", } SAFARI = { "browserName": "safari", "platformName": "mac", } HTMLUNIT = { "browserName": "htmlunit", "version": "", "platform": "ANY", } HTMLUNITWITHJS = { "browserName": "htmlunit", "version": "firefox", "platform": "ANY", "javascriptEnabled": True, } IPHONE = { "browserName": "iPhone", "version": "", "platform": "mac", } IPAD = { "browserName": "iPad", "version": "", "platform": "mac", } WEBKITGTK = { "browserName": "MiniBrowser", } WPEWEBKIT = { "browserName": "MiniBrowser", } selenium-selenium-4.18.1/selenium/webdriver/common/by.py0000644000175000017500000000210214564764517023231 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """The By implementation.""" class By: """Set of supported locator strategies.""" ID = "id" XPATH = "xpath" LINK_TEXT = "link text" PARTIAL_LINK_TEXT = "partial link text" NAME = "name" TAG_NAME = "tag name" CLASS_NAME = "class name" CSS_SELECTOR = "css selector" selenium-selenium-4.18.1/selenium/webdriver/common/service.py0000644000175000017500000002072414564764517024271 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import errno import logging import os import subprocess import typing from abc import ABC from abc import abstractmethod from io import IOBase from platform import system from subprocess import PIPE from time import sleep from urllib import request from urllib.error import URLError from selenium.common.exceptions import WebDriverException from selenium.types import SubprocessStdAlias from selenium.webdriver.common import utils logger = logging.getLogger(__name__) class Service(ABC): """The abstract base class for all service objects. Services typically launch a child program in a new process as an interim process to communicate with a browser. :param executable: install path of the executable. :param port: Port for the service to run on, defaults to 0 where the operating system will decide. :param log_output: (Optional) int representation of STDOUT/DEVNULL, any IO instance or String path to file. :param env: (Optional) Mapping of environment variables for the new process, defaults to `os.environ`. """ def __init__( self, executable_path: str = None, port: int = 0, log_output: SubprocessStdAlias = None, env: typing.Optional[typing.Mapping[typing.Any, typing.Any]] = None, **kwargs, ) -> None: if isinstance(log_output, str): self.log_output = open(log_output, "a+", encoding="utf-8") elif log_output == subprocess.STDOUT: self.log_output = None elif log_output is None or log_output == subprocess.DEVNULL: self.log_output = subprocess.DEVNULL else: self.log_output = log_output self._path = executable_path self.port = port or utils.free_port() # Default value for every python subprocess: subprocess.Popen(..., creationflags=0) self.popen_kw = kwargs.pop("popen_kw", {}) self.creation_flags = self.popen_kw.pop("creation_flags", 0) self.env = env or os.environ @property def service_url(self) -> str: """Gets the url of the Service.""" return f"http://{utils.join_host_port('localhost', self.port)}" @abstractmethod def command_line_args(self) -> typing.List[str]: """A List of program arguments (excluding the executable).""" raise NotImplementedError("This method needs to be implemented in a sub class") @property def path(self) -> str: return self._path @path.setter def path(self, value: str) -> None: self._path = str(value) def start(self) -> None: """Starts the Service. :Exceptions: - WebDriverException : Raised either when it can't start the service or when it can't connect to the service """ self._start_process(self._path) count = 0 while True: self.assert_process_still_running() if self.is_connectable(): break # sleep increasing: 0.01, 0.06, 0.11, 0.16, 0.21, 0.26, 0.31, 0.36, 0.41, 0.46, 0.5 sleep(min(0.01 + 0.05 * count, 0.5)) count += 1 if count == 70: raise WebDriverException(f"Can not connect to the Service {self._path}") def assert_process_still_running(self) -> None: """Check if the underlying process is still running.""" return_code = self.process.poll() if return_code: raise WebDriverException(f"Service {self._path} unexpectedly exited. Status code was: {return_code}") def is_connectable(self) -> bool: """Establishes a socket connection to determine if the service running on the port is accessible.""" return utils.is_connectable(self.port) def send_remote_shutdown_command(self) -> None: """Dispatch an HTTP request to the shutdown endpoint for the service in an attempt to stop it.""" try: request.urlopen(f"{self.service_url}/shutdown") except URLError: return for _ in range(30): if not self.is_connectable(): break sleep(1) def stop(self) -> None: """Stops the service.""" if self.log_output not in {PIPE, subprocess.DEVNULL}: if isinstance(self.log_output, IOBase): self.log_output.close() elif isinstance(self.log_output, int): os.close(self.log_output) if self.process is not None: try: self.send_remote_shutdown_command() except TypeError: pass self._terminate_process() def _terminate_process(self) -> None: """Terminate the child process. On POSIX this attempts a graceful SIGTERM followed by a SIGKILL, on a Windows OS kill is an alias to terminate. Terminating does not raise itself if something has gone wrong but (currently) silently ignores errors here. """ try: stdin, stdout, stderr = ( self.process.stdin, self.process.stdout, self.process.stderr, ) for stream in stdin, stdout, stderr: try: stream.close() # type: ignore except AttributeError: pass self.process.terminate() try: self.process.wait(60) except subprocess.TimeoutExpired: logger.error( "Service process refused to terminate gracefully with SIGTERM, escalating to SIGKILL.", exc_info=True, ) self.process.kill() except OSError: logger.error("Error terminating service process.", exc_info=True) def __del__(self) -> None: # `subprocess.Popen` doesn't send signal on `__del__`; # so we attempt to close the launched process when `__del__` # is triggered. # do not use globals here; interpreter shutdown may have already cleaned them up # and they would be `None`. This goes for anything this method is referencing internally. try: self.stop() except Exception: pass def _start_process(self, path: str) -> None: """Creates a subprocess by executing the command provided. :param cmd: full command to execute """ cmd = [path] cmd.extend(self.command_line_args()) close_file_descriptors = self.popen_kw.pop("close_fds", system() != "Windows") try: start_info = None if system() == "Windows": start_info = subprocess.STARTUPINFO() start_info.dwFlags = subprocess.CREATE_NEW_CONSOLE | subprocess.STARTF_USESHOWWINDOW start_info.wShowWindow = subprocess.SW_HIDE self.process = subprocess.Popen( cmd, env=self.env, close_fds=close_file_descriptors, stdout=self.log_output, stderr=self.log_output, stdin=PIPE, creationflags=self.creation_flags, startupinfo=start_info, **self.popen_kw, ) logger.debug( "Started executable: `%s` in a child process with pid: %s using %s to output %s", self._path, self.process.pid, self.creation_flags, self.log_output, ) except TypeError: raise except OSError as err: if err.errno == errno.EACCES: raise WebDriverException( f"'{os.path.basename(self._path)}' executable may have wrong permissions." ) from err raise selenium-selenium-4.18.1/selenium/webdriver/common/print_page_options.py0000644000175000017500000002154214564764517026533 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from typing import TYPE_CHECKING from typing import List from typing import Optional if TYPE_CHECKING: from typing import Literal from typing import TypedDict Orientation = Literal["portrait", "landscape"] class _MarginOpts(TypedDict, total=False): left: float right: float top: float bottom: float class _PageOpts(TypedDict, total=False): width: float height: float class _PrintOpts(TypedDict, total=False): margin: _MarginOpts page: _PageOpts background: bool orientation: Orientation scale: float shrinkToFit: bool pageRanges: List[str] else: from typing import Any from typing import Dict Orientation = str _MarginOpts = _PageOpts = _PrintOpts = Dict[str, Any] class _PageSettingsDescriptor: """Descriptor which validates `height` and 'width' of page.""" def __init__(self, name): self.name = name def __get__(self, obj, cls) -> Optional[float]: return obj._page.get(self.name, None) def __set__(self, obj, value) -> None: getattr(obj, "_validate_num_property")(self.name, value) obj._page[self.name] = value obj._print_options["page"] = obj._page class _MarginSettingsDescriptor: """Descriptor which validates below attributes. - top - bottom - left - right """ def __init__(self, name): self.name = name def __get__(self, obj, cls) -> Optional[float]: return obj._margin.get(self.name, None) def __set__(self, obj, value) -> None: getattr(obj, "_validate_num_property")(f"Margin {self.name}", value) obj._margin[self.name] = value obj._print_options["margin"] = obj._margin class _ScaleDescriptor: """Scale descriptor which validates scale.""" def __init__(self, name): self.name = name def __get__(self, obj, cls) -> Optional[float]: return obj._print_options.get(self.name) def __set__(self, obj, value) -> None: getattr(obj, "_validate_num_property")(self.name, value) if value < 0.1 or value > 2: raise ValueError("Value of scale should be between 0.1 and 2") obj._print_options[self.name] = value class _PageOrientationDescriptor: """PageOrientation descriptor which validates orientation of page.""" ORIENTATION_VALUES = ["portrait", "landscape"] def __init__(self, name): self.name = name def __get__(self, obj, cls) -> Optional[Orientation]: return obj._print_options.get(self.name, None) def __set__(self, obj, value) -> None: if value not in self.ORIENTATION_VALUES: raise ValueError(f"Orientation value must be one of {self.ORIENTATION_VALUES}") obj._print_options[self.name] = value class _ValidateTypeDescriptor: """Base Class Descriptor which validates type of any subclass attribute.""" expected_type = None def __init__(self, name, expected_type): self.name = name def __get__(self, obj, cls): return obj._print_options.get(self.name, None) def __set__(self, obj, value) -> None: if not isinstance(value, self.expected_type): raise ValueError(f"{self.name} should be of type {self.expected_type.__name__}") obj._print_options[self.name] = value class _ValidateBackGround(_ValidateTypeDescriptor): """Expected type of background attribute.""" expected_type = bool class _ValidateShrinkToFit(_ValidateTypeDescriptor): """Expected type of shirnk to fit attribute.""" expected_type = bool class _ValidatePageRanges(_ValidateTypeDescriptor): """Excepted type of page ranges attribute.""" expected_type = list class PrintOptions: page_height = _PageSettingsDescriptor("height") """Gets and Sets page_height: Usage ----- - Get - `self.page_height` - Set - `self.page_height` = `value` Parameters ---------- `value`: `float` Returns ------- - Get - `Optional[float]` - Set - `None` """ page_width = _PageSettingsDescriptor("width") """Gets and Sets page_width: Usage ----- - Get - `self.page_width` - Set - `self.page_width` = `value` Patameters ---------- `value`: `float` Returns ------- - Get - `Optional[float]` - Set - `None` """ margin_top = _MarginSettingsDescriptor("top") """Gets and Sets margin_top: Usage ----- - Get - `self.margin_top` - Set - `slef.margin_top` = `value` Parameters ---------- `value`: `float` Returns ------- - Get - `Optional[float]` - Set - `None` """ margin_bottom = _MarginSettingsDescriptor("bottom") """Gets and Sets margin_bottom: Usage ----- - Get - `self.margin_bottom` - Set - `self.margin_bottom` = `value` Parameters ---------- `value`: `float` Returns ------- - Get - `Optional[float]` - Set - `None` """ margin_left = _MarginSettingsDescriptor("left") """Gets and Sets margin_left: Usage ----- - Get - `self.margin_left` -Set - `self.margin_left` = `value` Parameters ---------- `value`: `float` Returns ------- - Get - `Optional[float]` - Set - `None` """ margin_right = _MarginSettingsDescriptor("right") """Gets and Sets margin_right: Usage ----- - Get - `self.margin_right` - Set - `self.margin_right` = `value` Parameters ---------- `value`: `float` Returns ------- - Get - `Optional[float]` - Set - `None` """ scale = _ScaleDescriptor("scale") """Gets and Sets scale: Usage ----- - Get - `self.scale` - Set - `self.scale` = `value` Parameters ---------- `value`: `float` Returns ------- - Get - `Optional[float]` - Set - `None` """ orientation = _PageOrientationDescriptor("orientation") """Gets and Sets orientation: Usage ----- - Get - `self.orientation` - Set - `self.orientation` = `value` Parameters ---------- `value`: `Orientation` Returns ------- - Get - `Optional[Orientation]` - Set - `None` """ background = _ValidateBackGround("background", bool) """Gets and Sets background: Usage ----- - Get - `self.backgorund` - Set - `self.background` = `value` Parameters ---------- `value`: `bool` Returns ------- - Get - `Optional[bool]` - Set - `None` """ shrink_to_fit = _ValidateShrinkToFit("shrinkToFit", bool) """Gets and Sets shrink_to_fit: Usage ----- - Get - `self.shrink_to_fit` - Set - `self.shrink_to_fit` = `value` Parameters ---------- `value`: `bool` Returns ------- - Get - `Optional[bool]` - Set - `None` """ page_ranges = _ValidatePageRanges("pageRanges", list) """Gets and Sets page_ranges: Usage ----- - Get - `self.page_ranges` - Set - `self.page_ranges` = `value` Parameters ---------- `value`: ` List[str]` Returns ------- - Get - `Optional[List[str]]` - Set - `None` """ def __init__(self) -> None: self._print_options: _PrintOpts = {} self._page: _PageOpts = {} self._margin: _MarginOpts = {} def to_dict(self) -> _PrintOpts: """:Returns: A hash of print options configured.""" return self._print_options def _validate_num_property(self, property_name: str, value: float) -> None: """Helper function to validate some of the properties.""" if not isinstance(value, (int, float)): raise ValueError(f"{property_name} should be an integer or a float") if value < 0: raise ValueError(f"{property_name} cannot be less then 0") selenium-selenium-4.18.1/selenium/webdriver/common/selenium_manager.py0000644000175000017500000001300714564764517026140 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import json import logging import os import platform import subprocess import sys from pathlib import Path from typing import List from selenium.common import WebDriverException from selenium.webdriver.common.options import BaseOptions logger = logging.getLogger(__name__) class SeleniumManager: """Wrapper for getting information from the Selenium Manager binaries. This implementation is still in beta, and may change. """ @staticmethod def get_binary() -> Path: """Determines the path of the correct Selenium Manager binary. :Returns: The Selenium Manager executable location :Raises: WebDriverException if the platform is unsupported """ if (path := os.getenv("SE_MANAGER_PATH")) is not None: return Path(path) dirs = { ("darwin", "any"): "macos", ("win32", "any"): "windows", ("cygwin", "any"): "windows", ("linux", "x86_64"): "linux", ("freebsd", "x86_64"): "linux", ("openbsd", "x86_64"): "linux", } arch = platform.machine() if sys.platform in ("linux", "freebsd", "openbsd") else "any" directory = dirs.get((sys.platform, arch)) if directory is None: raise WebDriverException(f"Unsupported platform/architecture combination: {sys.platform}/{arch}") if sys.platform in ["freebsd", "openbsd"]: logger.warning("Selenium Manager binary may not be compatible with %s; verify settings", sys.platform) file = "selenium-manager.exe" if directory == "windows" else "selenium-manager" path = Path(__file__).parent.joinpath(directory, file) if not path.is_file(): raise WebDriverException(f"Unable to obtain working Selenium Manager binary; {path}") logger.debug("Selenium Manager binary found at: %s", path) return path def driver_location(self, options: BaseOptions) -> str: """Determines the path of the correct driver. :Args: - browser: which browser to get the driver path for. :Returns: The driver path to use """ browser = options.capabilities["browserName"] args = [str(self.get_binary()), "--browser", browser] if options.browser_version: args.append("--browser-version") args.append(str(options.browser_version)) binary_location = getattr(options, "binary_location", None) if binary_location: args.append("--browser-path") args.append(str(binary_location)) proxy = options.proxy if proxy and (proxy.http_proxy or proxy.ssl_proxy): args.append("--proxy") value = proxy.ssl_proxy if proxy.ssl_proxy else proxy.http_proxy args.append(value) output = self.run(args) browser_path = output["browser_path"] driver_path = output["driver_path"] logger.debug("Using driver at: %s", driver_path) if hasattr(options.__class__, "binary_location") and browser_path: options.binary_location = browser_path options.browser_version = None # if we have the binary location we no longer need the version return driver_path @staticmethod def run(args: List[str]) -> dict: """Executes the Selenium Manager Binary. :Args: - args: the components of the command being executed. :Returns: The log string containing the driver location. """ if logger.getEffectiveLevel() == logging.DEBUG: args.append("--debug") args.append("--language-binding") args.append("python") args.append("--output") args.append("json") command = " ".join(args) logger.debug("Executing process: %s", command) try: if sys.platform == "win32": completed_proc = subprocess.run(args, capture_output=True, creationflags=subprocess.CREATE_NO_WINDOW) else: completed_proc = subprocess.run(args, capture_output=True) stdout = completed_proc.stdout.decode("utf-8").rstrip("\n") stderr = completed_proc.stderr.decode("utf-8").rstrip("\n") output = json.loads(stdout) result = output["result"] except Exception as err: raise WebDriverException(f"Unsuccessful command executed: {command}") from err for item in output["logs"]: if item["level"] == "WARN": logger.warning(item["message"]) if item["level"] == "DEBUG" or item["level"] == "INFO": logger.debug(item["message"]) if completed_proc.returncode: raise WebDriverException(f"Unsuccessful command executed: {command}.\n{result}{stderr}") return result selenium-selenium-4.18.1/selenium/webdriver/common/__init__.py0000644000175000017500000000142314564764517024363 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/selenium/webdriver/common/driver_finder.py0000644000175000017500000000351714564764517025454 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import logging from pathlib import Path from selenium.common.exceptions import NoSuchDriverException from selenium.webdriver.common.options import BaseOptions from selenium.webdriver.common.selenium_manager import SeleniumManager from selenium.webdriver.common.service import Service logger = logging.getLogger(__name__) class DriverFinder: """Utility to find if a given file is present and executable. This implementation is still in beta, and may change. """ @staticmethod def get_path(service: Service, options: BaseOptions) -> str: path = service.path try: path = SeleniumManager().driver_location(options) if path is None else path except Exception as err: msg = f"Unable to obtain driver for {options.capabilities['browserName']} using Selenium Manager." raise NoSuchDriverException(msg) from err if path is None or not Path(path).is_file(): raise NoSuchDriverException(f"Unable to locate or obtain driver for {options.capabilities['browserName']}") return path selenium-selenium-4.18.1/selenium/webdriver/common/timeouts.py0000644000175000017500000000765314564764517024510 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from typing import TYPE_CHECKING if TYPE_CHECKING: from typing import TypedDict class JSONTimeouts(TypedDict, total=False): implicit: int pageLoad: int script: int else: from typing import Dict JSONTimeouts = Dict[str, int] class _TimeoutsDescriptor: """Get or set the value of the attributes listed below. _implicit_wait _page_load _script This does not set the value on the remote end. """ def __init__(self, name): self.name = name def __get__(self, obj, cls) -> float: return getattr(obj, self.name) / 1000 def __set__(self, obj, value) -> None: converted_value = getattr(obj, "_convert")(value) setattr(obj, self.name, converted_value) class Timeouts: def __init__(self, implicit_wait: float = 0, page_load: float = 0, script: float = 0) -> None: """Create a new Timeouts object. This implements https://w3c.github.io/webdriver/#timeouts. :Args: - implicit_wait - Either an int or a float. Set how many seconds to wait when searching for elements before throwing an error. - page_load - Either an int or a float. Set how many seconds to wait for a page load to complete before throwing an error. - script - Either an int or a float. Set how many seconds to wait for an asynchronous script to finish execution before throwing an error. """ self.implicit_wait = implicit_wait self.page_load = page_load self.script = script # Creating descriptor objects implicit_wait = _TimeoutsDescriptor("_implicit_wait") """Get or set how many seconds to wait when searching for elements. This does not set the value on the remote end. Usage ----- - Get - `self.implicit_wait` - Set - `self.implicit_wait` = `value` Parameters ---------- `value`: `float` """ page_load = _TimeoutsDescriptor("_page_load") """Get or set how many seconds to wait for the page to load. This does not set the value on the remote end. Usage ----- - Get - `self.page_load` - Set - `self.page_load` = `value` Parameters ---------- `value`: `float` """ script = _TimeoutsDescriptor("_script") """Get or set how many seconds to wait for an asynchronous script to finish execution. This does not set the value on the remote end. Usage ------ - Get - `self.script` - Set - `self.script` = `value` Parameters ----------- `value`: `float` """ def _convert(self, timeout: float) -> int: if isinstance(timeout, (int, float)): return int(float(timeout) * 1000) raise TypeError("Timeouts can only be an int or a float") def _to_json(self) -> JSONTimeouts: timeouts: JSONTimeouts = {} if self._implicit_wait: timeouts["implicit"] = self._implicit_wait if self._page_load: timeouts["pageLoad"] = self._page_load if self._script: timeouts["script"] = self._script return timeouts selenium-selenium-4.18.1/selenium/webdriver/common/proxy.py0000644000175000017500000002071614564764517024013 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """The Proxy implementation.""" class ProxyTypeFactory: """Factory for proxy types.""" @staticmethod def make(ff_value, string): return {"ff_value": ff_value, "string": string} class ProxyType: """Set of possible types of proxy. Each proxy type has 2 properties: 'ff_value' is value of Firefox profile preference, 'string' is id of proxy type. """ DIRECT = ProxyTypeFactory.make(0, "DIRECT") # Direct connection, no proxy (default on Windows). MANUAL = ProxyTypeFactory.make(1, "MANUAL") # Manual proxy settings (e.g., for httpProxy). PAC = ProxyTypeFactory.make(2, "PAC") # Proxy autoconfiguration from URL. RESERVED_1 = ProxyTypeFactory.make(3, "RESERVED1") # Never used. AUTODETECT = ProxyTypeFactory.make(4, "AUTODETECT") # Proxy autodetection (presumably with WPAD). SYSTEM = ProxyTypeFactory.make(5, "SYSTEM") # Use system settings (default on Linux). UNSPECIFIED = ProxyTypeFactory.make(6, "UNSPECIFIED") # Not initialized (for internal use). @classmethod def load(cls, value): if isinstance(value, dict) and "string" in value: value = value["string"] value = str(value).upper() for attr in dir(cls): attr_value = getattr(cls, attr) if isinstance(attr_value, dict) and "string" in attr_value and attr_value["string"] == value: return attr_value raise Exception(f"No proxy type is found for {value}") class _ProxyTypeDescriptor: def __init__(self, name, p_type): self.name = name self.p_type = p_type def __get__(self, obj, cls): return getattr(obj, self.name) def __set__(self, obj, value): if self.name == "autodetect" and not isinstance(value, bool): raise ValueError("Autodetect proxy value needs to be a boolean") getattr(obj, "_verify_proxy_type_compatibility")(self.p_type) setattr(obj, "proxyType", self.p_type) setattr(obj, self.name, value) class Proxy: """Proxy contains information about proxy type and necessary proxy settings.""" proxyType = ProxyType.UNSPECIFIED autodetect = False ftpProxy = "" httpProxy = "" noProxy = "" proxyAutoconfigUrl = "" sslProxy = "" socksProxy = "" socksUsername = "" socksPassword = "" socksVersion = None # create descriptor type objects auto_detect = _ProxyTypeDescriptor("autodetect", ProxyType.AUTODETECT) """Gets and Sets `auto_detect` Usage ----- - Get - `self.auto_detect` - Set - `self.auto_detect` = `value` Parameters ---------- `value`: `str` """ ftp_proxy = _ProxyTypeDescriptor("ftpProxy", ProxyType.MANUAL) """Gets and Sets `ftp_proxy` Usage ----- - Get - `self.ftp_proxy` - Set - `self.ftp_proxy` = `value` Parameters ---------- `value`: `str` """ http_proxy = _ProxyTypeDescriptor("httpProxy", ProxyType.MANUAL) """Gets and Sets `http_proxy` Usage ----- - Get - `self.http_proxy` - Set - `self.http_proxy` = `value` Parameters ---------- `value`: `str` """ no_proxy = _ProxyTypeDescriptor("noProxy", ProxyType.MANUAL) """Gets and Sets `no_proxy` Usage ----- - Get - `self.no_proxy` - Set - `self.no_proxy` = `value` Parameters ---------- `value`: `str` """ proxy_autoconfig_url = _ProxyTypeDescriptor("proxyAutoconfigUrl", ProxyType.PAC) """Gets and Sets `proxy_autoconfig_url` Usage ----- - Get - `self.proxy_autoconfig_url` - Set - `self.proxy_autoconfig_url` = `value` Parameter --------- `value`: `str` """ ssl_proxy = _ProxyTypeDescriptor("sslProxy", ProxyType.MANUAL) """Gets and Sets `ssl_proxy` Usage ----- - Get - `self.ssl_proxy` - Set - `self.ssl_proxy` = `value` Parameter --------- `value`: `str` """ socks_proxy = _ProxyTypeDescriptor("socksProxy", ProxyType.MANUAL) """Gets and Sets `socks_proxy` Usage ----- - Get - `self.sock_proxy` - Set - `self.socks_proxy` = `value` Parameter --------- `value`: `str` """ socks_username = _ProxyTypeDescriptor("socksUsername", ProxyType.MANUAL) """Gets and Sets `socks_password` Usage ----- - Get - `self.socks_password` - Set - `self.socks_password` = `value` Parameter --------- `value`: `str` """ socks_password = _ProxyTypeDescriptor("socksPassword", ProxyType.MANUAL) """Gets and Sets `socks_password` Usage ----- - Get - `self.socks_password` - Set - `self.socks_password` = `value` Parameter --------- `value`: `str` """ socks_version = _ProxyTypeDescriptor("socksVersion", ProxyType.MANUAL) """Gets and Sets `socks_version` Usage ----- - Get - `self.socks_version` - Set - `self.socks_version` = `value` Parameter --------- `value`: `str` """ def __init__(self, raw=None): """Creates a new Proxy. :Args: - raw: raw proxy data. If None, default class values are used. """ if raw: if "proxyType" in raw and raw["proxyType"]: self.proxy_type = ProxyType.load(raw["proxyType"]) if "ftpProxy" in raw and raw["ftpProxy"]: self.ftp_proxy = raw["ftpProxy"] if "httpProxy" in raw and raw["httpProxy"]: self.http_proxy = raw["httpProxy"] if "noProxy" in raw and raw["noProxy"]: self.no_proxy = raw["noProxy"] if "proxyAutoconfigUrl" in raw and raw["proxyAutoconfigUrl"]: self.proxy_autoconfig_url = raw["proxyAutoconfigUrl"] if "sslProxy" in raw and raw["sslProxy"]: self.sslProxy = raw["sslProxy"] if "autodetect" in raw and raw["autodetect"]: self.auto_detect = raw["autodetect"] if "socksProxy" in raw and raw["socksProxy"]: self.socks_proxy = raw["socksProxy"] if "socksUsername" in raw and raw["socksUsername"]: self.socks_username = raw["socksUsername"] if "socksPassword" in raw and raw["socksPassword"]: self.socks_password = raw["socksPassword"] if "socksVersion" in raw and raw["socksVersion"]: self.socks_version = raw["socksVersion"] @property def proxy_type(self): """Returns proxy type as `ProxyType`.""" return self.proxyType @proxy_type.setter def proxy_type(self, value) -> None: """Sets proxy type. :Args: - value: The proxy type. """ self._verify_proxy_type_compatibility(value) self.proxyType = value def _verify_proxy_type_compatibility(self, compatible_proxy): if self.proxyType not in (ProxyType.UNSPECIFIED, compatible_proxy): raise ValueError( f"Specified proxy type ({compatible_proxy}) not compatible with current setting ({self.proxyType})" ) def to_capabilities(self): proxy_caps = {"proxyType": self.proxyType["string"].lower()} proxies = [ "autodetect", "ftpProxy", "httpProxy", "proxyAutoconfigUrl", "sslProxy", "noProxy", "socksProxy", "socksUsername", "socksPassword", "socksVersion", ] for proxy in proxies: attr_value = getattr(self, proxy) if attr_value: proxy_caps[proxy] = attr_value return proxy_caps selenium-selenium-4.18.1/selenium/webdriver/common/action_chains.py0000644000175000017500000003251314564764517025432 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """The ActionChains implementation.""" from __future__ import annotations from typing import TYPE_CHECKING from typing import Union from selenium.webdriver.remote.webelement import WebElement from .actions.action_builder import ActionBuilder from .actions.key_input import KeyInput from .actions.pointer_input import PointerInput from .actions.wheel_input import ScrollOrigin from .actions.wheel_input import WheelInput from .utils import keys_to_typing if TYPE_CHECKING: from selenium.webdriver.remote.webdriver import WebDriver AnyDevice = Union[PointerInput, KeyInput, WheelInput] class ActionChains: """ActionChains are a way to automate low level interactions such as mouse movements, mouse button actions, key press, and context menu interactions. This is useful for doing more complex actions like hover over and drag and drop. Generate user actions. When you call methods for actions on the ActionChains object, the actions are stored in a queue in the ActionChains object. When you call perform(), the events are fired in the order they are queued up. ActionChains can be used in a chain pattern:: menu = driver.find_element(By.CSS_SELECTOR, ".nav") hidden_submenu = driver.find_element(By.CSS_SELECTOR, ".nav #submenu1") ActionChains(driver).move_to_element(menu).click(hidden_submenu).perform() Or actions can be queued up one by one, then performed.:: menu = driver.find_element(By.CSS_SELECTOR, ".nav") hidden_submenu = driver.find_element(By.CSS_SELECTOR, ".nav #submenu1") actions = ActionChains(driver) actions.move_to_element(menu) actions.click(hidden_submenu) actions.perform() Either way, the actions are performed in the order they are called, one after another. """ def __init__(self, driver: WebDriver, duration: int = 250, devices: list[AnyDevice] | None = None) -> None: """Creates a new ActionChains. :Args: - driver: The WebDriver instance which performs user actions. - duration: override the default 250 msecs of DEFAULT_MOVE_DURATION in PointerInput """ self._driver = driver mouse = None keyboard = None wheel = None if devices is not None and isinstance(devices, list): for device in devices: if isinstance(device, PointerInput): mouse = device if isinstance(device, KeyInput): keyboard = device if isinstance(device, WheelInput): wheel = device self.w3c_actions = ActionBuilder(driver, mouse=mouse, keyboard=keyboard, wheel=wheel, duration=duration) def perform(self) -> None: """Performs all stored actions.""" self.w3c_actions.perform() def reset_actions(self) -> None: """Clears actions that are already stored locally and on the remote end.""" self.w3c_actions.clear_actions() for device in self.w3c_actions.devices: device.clear_actions() def click(self, on_element: WebElement | None = None) -> ActionChains: """Clicks an element. :Args: - on_element: The element to click. If None, clicks on current mouse position. """ if on_element: self.move_to_element(on_element) self.w3c_actions.pointer_action.click() self.w3c_actions.key_action.pause() self.w3c_actions.key_action.pause() return self def click_and_hold(self, on_element: WebElement | None = None) -> ActionChains: """Holds down the left mouse button on an element. :Args: - on_element: The element to mouse down. If None, clicks on current mouse position. """ if on_element: self.move_to_element(on_element) self.w3c_actions.pointer_action.click_and_hold() self.w3c_actions.key_action.pause() return self def context_click(self, on_element: WebElement | None = None) -> ActionChains: """Performs a context-click (right click) on an element. :Args: - on_element: The element to context-click. If None, clicks on current mouse position. """ if on_element: self.move_to_element(on_element) self.w3c_actions.pointer_action.context_click() self.w3c_actions.key_action.pause() self.w3c_actions.key_action.pause() return self def double_click(self, on_element: WebElement | None = None) -> ActionChains: """Double-clicks an element. :Args: - on_element: The element to double-click. If None, clicks on current mouse position. """ if on_element: self.move_to_element(on_element) self.w3c_actions.pointer_action.double_click() for _ in range(4): self.w3c_actions.key_action.pause() return self def drag_and_drop(self, source: WebElement, target: WebElement) -> ActionChains: """Holds down the left mouse button on the source element, then moves to the target element and releases the mouse button. :Args: - source: The element to mouse down. - target: The element to mouse up. """ self.click_and_hold(source) self.release(target) return self def drag_and_drop_by_offset(self, source: WebElement, xoffset: int, yoffset: int) -> ActionChains: """Holds down the left mouse button on the source element, then moves to the target offset and releases the mouse button. :Args: - source: The element to mouse down. - xoffset: X offset to move to. - yoffset: Y offset to move to. """ self.click_and_hold(source) self.move_by_offset(xoffset, yoffset) self.release() return self def key_down(self, value: str, element: WebElement | None = None) -> ActionChains: """Sends a key press only, without releasing it. Should only be used with modifier keys (Control, Alt and Shift). :Args: - value: The modifier key to send. Values are defined in `Keys` class. - element: The element to send keys. If None, sends a key to current focused element. Example, pressing ctrl+c:: ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform() """ if element: self.click(element) self.w3c_actions.key_action.key_down(value) self.w3c_actions.pointer_action.pause() return self def key_up(self, value: str, element: WebElement | None = None) -> ActionChains: """Releases a modifier key. :Args: - value: The modifier key to send. Values are defined in Keys class. - element: The element to send keys. If None, sends a key to current focused element. Example, pressing ctrl+c:: ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform() """ if element: self.click(element) self.w3c_actions.key_action.key_up(value) self.w3c_actions.pointer_action.pause() return self def move_by_offset(self, xoffset: int, yoffset: int) -> ActionChains: """Moving the mouse to an offset from current mouse position. :Args: - xoffset: X offset to move to, as a positive or negative integer. - yoffset: Y offset to move to, as a positive or negative integer. """ self.w3c_actions.pointer_action.move_by(xoffset, yoffset) self.w3c_actions.key_action.pause() return self def move_to_element(self, to_element: WebElement) -> ActionChains: """Moving the mouse to the middle of an element. :Args: - to_element: The WebElement to move to. """ self.w3c_actions.pointer_action.move_to(to_element) self.w3c_actions.key_action.pause() return self def move_to_element_with_offset(self, to_element: WebElement, xoffset: int, yoffset: int) -> ActionChains: """Move the mouse by an offset of the specified element. Offsets are relative to the in-view center point of the element. :Args: - to_element: The WebElement to move to. - xoffset: X offset to move to, as a positive or negative integer. - yoffset: Y offset to move to, as a positive or negative integer. """ self.w3c_actions.pointer_action.move_to(to_element, int(xoffset), int(yoffset)) self.w3c_actions.key_action.pause() return self def pause(self, seconds: float | int) -> ActionChains: """Pause all inputs for the specified duration in seconds.""" self.w3c_actions.pointer_action.pause(seconds) self.w3c_actions.key_action.pause(seconds) return self def release(self, on_element: WebElement | None = None) -> ActionChains: """Releasing a held mouse button on an element. :Args: - on_element: The element to mouse up. If None, releases on current mouse position. """ if on_element: self.move_to_element(on_element) self.w3c_actions.pointer_action.release() self.w3c_actions.key_action.pause() return self def send_keys(self, *keys_to_send: str) -> ActionChains: """Sends keys to current focused element. :Args: - keys_to_send: The keys to send. Modifier keys constants can be found in the 'Keys' class. """ typing = keys_to_typing(keys_to_send) for key in typing: self.key_down(key) self.key_up(key) return self def send_keys_to_element(self, element: WebElement, *keys_to_send: str) -> ActionChains: """Sends keys to an element. :Args: - element: The element to send keys. - keys_to_send: The keys to send. Modifier keys constants can be found in the 'Keys' class. """ self.click(element) self.send_keys(*keys_to_send) return self def scroll_to_element(self, element: WebElement) -> ActionChains: """If the element is outside the viewport, scrolls the bottom of the element to the bottom of the viewport. :Args: - element: Which element to scroll into the viewport. """ self.w3c_actions.wheel_action.scroll(origin=element) return self def scroll_by_amount(self, delta_x: int, delta_y: int) -> ActionChains: """Scrolls by provided amounts with the origin in the top left corner of the viewport. :Args: - delta_x: Distance along X axis to scroll using the wheel. A negative value scrolls left. - delta_y: Distance along Y axis to scroll using the wheel. A negative value scrolls up. """ self.w3c_actions.wheel_action.scroll(delta_x=delta_x, delta_y=delta_y) return self def scroll_from_origin(self, scroll_origin: ScrollOrigin, delta_x: int, delta_y: int) -> ActionChains: """Scrolls by provided amount based on a provided origin. The scroll origin is either the center of an element or the upper left of the viewport plus any offsets. If the origin is an element, and the element is not in the viewport, the bottom of the element will first be scrolled to the bottom of the viewport. :Args: - origin: Where scroll originates (viewport or element center) plus provided offsets. - delta_x: Distance along X axis to scroll using the wheel. A negative value scrolls left. - delta_y: Distance along Y axis to scroll using the wheel. A negative value scrolls up. :Raises: If the origin with offset is outside the viewport. - MoveTargetOutOfBoundsException - If the origin with offset is outside the viewport. """ if not isinstance(scroll_origin, ScrollOrigin): raise TypeError(f"Expected object of type ScrollOrigin, got: {type(scroll_origin)}") self.w3c_actions.wheel_action.scroll( origin=scroll_origin.origin, x=scroll_origin.x_offset, y=scroll_origin.y_offset, delta_x=delta_x, delta_y=delta_y, ) return self # Context manager so ActionChains can be used in a 'with .. as' statements. def __enter__(self) -> ActionChains: return self # Return created instance of self. def __exit__(self, _type, _value, _traceback) -> None: pass # Do nothing, does not require additional cleanup. selenium-selenium-4.18.1/selenium/webdriver/common/virtual_authenticator.py0000644000175000017500000001722314564764517027251 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import functools import typing from base64 import urlsafe_b64decode from base64 import urlsafe_b64encode from enum import Enum class Protocol(str, Enum): """Protocol to communicate with the authenticator.""" CTAP2: str = "ctap2" U2F: str = "ctap1/u2f" class Transport(str, Enum): """Transport method to communicate with the authenticator.""" BLE: str = "ble" USB: str = "usb" NFC: str = "nfc" INTERNAL: str = "internal" class VirtualAuthenticatorOptions: # These are so unnecessary but are now public API so we can't remove them without deprecating first. # These should not be class level state in here. Protocol = Protocol Transport = Transport def __init__( self, protocol: str = Protocol.CTAP2, transport: str = Transport.USB, has_resident_key: bool = False, has_user_verification: bool = False, is_user_consenting: bool = True, is_user_verified: bool = False, ) -> None: """Constructor. Initialize VirtualAuthenticatorOptions object. """ self.protocol: str = protocol self.transport: str = transport self.has_resident_key: bool = has_resident_key self.has_user_verification: bool = has_user_verification self.is_user_consenting: bool = is_user_consenting self.is_user_verified: bool = is_user_verified def to_dict(self) -> typing.Dict[str, typing.Union[str, bool]]: return { "protocol": self.protocol, "transport": self.transport, "hasResidentKey": self.has_resident_key, "hasUserVerification": self.has_user_verification, "isUserConsenting": self.is_user_consenting, "isUserVerified": self.is_user_verified, } class Credential: def __init__( self, credential_id: bytes, is_resident_credential: bool, rp_id: str, user_handle: typing.Optional[bytes], private_key: bytes, sign_count: int, ): """Constructor. A credential stored in a virtual authenticator. https://w3c.github.io/webauthn/#credential-parameters. :Args: - credential_id (bytes): Unique base64 encoded string. is_resident_credential (bool): Whether the credential is client-side discoverable. rp_id (str): Relying party identifier. user_handle (bytes): userHandle associated to the credential. Must be Base64 encoded string. Can be None. private_key (bytes): Base64 encoded PKCS#8 private key. sign_count (int): intital value for a signature counter. """ self._id = credential_id self._is_resident_credential = is_resident_credential self._rp_id = rp_id self._user_handle = user_handle self._private_key = private_key self._sign_count = sign_count @property def id(self) -> str: return urlsafe_b64encode(self._id).decode() @property def is_resident_credential(self) -> bool: return self._is_resident_credential @property def rp_id(self) -> str: return self._rp_id @property def user_handle(self) -> typing.Optional[str]: if self._user_handle: return urlsafe_b64encode(self._user_handle).decode() return None @property def private_key(self) -> str: return urlsafe_b64encode(self._private_key).decode() @property def sign_count(self) -> int: return self._sign_count @classmethod def create_non_resident_credential(cls, id: bytes, rp_id: str, private_key: bytes, sign_count: int) -> "Credential": """Creates a non-resident (i.e. stateless) credential. :Args: - id (bytes): Unique base64 encoded string. - rp_id (str): Relying party identifier. - private_key (bytes): Base64 encoded PKCS - sign_count (int): intital value for a signature counter. :Returns: - Credential: A non-resident credential. """ return cls(id, False, rp_id, None, private_key, sign_count) @classmethod def create_resident_credential( cls, id: bytes, rp_id: str, user_handle: typing.Optional[bytes], private_key: bytes, sign_count: int ) -> "Credential": """Creates a resident (i.e. stateful) credential. :Args: - id (bytes): Unique base64 encoded string. - rp_id (str): Relying party identifier. - user_handle (bytes): userHandle associated to the credential. Must be Base64 encoded string. - private_key (bytes): Base64 encoded PKCS - sign_count (int): intital value for a signature counter. :returns: - Credential: A resident credential. """ return cls(id, True, rp_id, user_handle, private_key, sign_count) def to_dict(self) -> typing.Dict[str, typing.Any]: credential_data = { "credentialId": self.id, "isResidentCredential": self._is_resident_credential, "rpId": self.rp_id, "privateKey": self.private_key, "signCount": self.sign_count, } if self.user_handle: credential_data["userHandle"] = self.user_handle return credential_data @classmethod def from_dict(cls, data: typing.Dict[str, typing.Any]) -> "Credential": _id = urlsafe_b64decode(f"{data['credentialId']}==") is_resident_credential = bool(data["isResidentCredential"]) rp_id = data.get("rpId", None) private_key = urlsafe_b64decode(f"{data['privateKey']}==") sign_count = int(data["signCount"]) user_handle = urlsafe_b64decode(f"{data['userHandle']}==") if data.get("userHandle", None) else None return cls(_id, is_resident_credential, rp_id, user_handle, private_key, sign_count) def __str__(self) -> str: return f"Credential(id={self.id}, is_resident_credential={self.is_resident_credential}, rp_id={self.rp_id},\ user_handle={self.user_handle}, private_key={self.private_key}, sign_count={self.sign_count})" def required_chromium_based_browser(func): """A decorator to ensure that the client used is a chromium based browser.""" @functools.wraps(func) def wrapper(self, *args, **kwargs): assert self.caps["browserName"].lower() not in [ "firefox", "safari", ], "This only currently works in Chromium based browsers" return func(self, *args, **kwargs) return wrapper def required_virtual_authenticator(func): """A decorator to ensure that the function is called with a virtual authenticator.""" @functools.wraps(func) @required_chromium_based_browser def wrapper(self, *args, **kwargs): if not self.virtual_authenticator_id: raise ValueError("This function requires a virtual authenticator to be set.") return func(self, *args, **kwargs) return wrapper selenium-selenium-4.18.1/selenium/webdriver/common/alert.py0000644000175000017500000000502514564764517023735 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """The Alert implementation.""" from selenium.webdriver.common.utils import keys_to_typing from selenium.webdriver.remote.command import Command class Alert: """Allows to work with alerts. Use this class to interact with alert prompts. It contains methods for dismissing, accepting, inputting, and getting text from alert prompts. Accepting / Dismissing alert prompts:: Alert(driver).accept() Alert(driver).dismiss() Inputting a value into an alert prompt:: name_prompt = Alert(driver) name_prompt.send_keys("Willian Shakesphere") name_prompt.accept() Reading a the text of a prompt for verification:: alert_text = Alert(driver).text self.assertEqual("Do you wish to quit?", alert_text) """ def __init__(self, driver) -> None: """Creates a new Alert. :Args: - driver: The WebDriver instance which performs user actions. """ self.driver = driver @property def text(self) -> str: """Gets the text of the Alert.""" return self.driver.execute(Command.W3C_GET_ALERT_TEXT)["value"] def dismiss(self) -> None: """Dismisses the alert available.""" self.driver.execute(Command.W3C_DISMISS_ALERT) def accept(self) -> None: """Accepts the alert available. :Usage: :: Alert(driver).accept() # Confirm a alert dialog. """ self.driver.execute(Command.W3C_ACCEPT_ALERT) def send_keys(self, keysToSend: str) -> None: """Send Keys to the Alert. :Args: - keysToSend: The text to be sent to Alert. """ self.driver.execute(Command.W3C_SET_ALERT_VALUE, {"value": keys_to_typing(keysToSend), "text": keysToSend}) selenium-selenium-4.18.1/selenium/webdriver/common/log.py0000644000175000017500000001324314564764517023410 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import json import pkgutil from contextlib import asynccontextmanager from importlib import import_module from selenium.webdriver.common.by import By cdp = None def import_cdp(): global cdp if not cdp: cdp = import_module("selenium.webdriver.common.bidi.cdp") class Log: """This class allows access to logging APIs that use the new WebDriver Bidi protocol. This class is not to be used directly and should be used from the webdriver base classes. """ def __init__(self, driver, bidi_session) -> None: self.driver = driver self.session = bidi_session.session self.cdp = bidi_session.cdp self.devtools = bidi_session.devtools _pkg = ".".join(__name__.split(".")[:-1]) self._mutation_listener_js = pkgutil.get_data(_pkg, "mutation-listener.js").decode("utf8").strip() @asynccontextmanager async def mutation_events(self) -> dict: """Listen for mutation events and emit them as they are found. :Usage: :: async with driver.log.mutation_events() as event: pages.load("dynamic.html") driver.find_element(By.ID, "reveal").click() WebDriverWait(driver, 5)\ .until(EC.visibility_of(driver.find_element(By.ID, "revealed"))) assert event["attribute_name"] == "style" assert event["current_value"] == "" assert event["old_value"] == "display:none;" """ page = self.cdp.get_session_context("page.enable") await page.execute(self.devtools.page.enable()) runtime = self.cdp.get_session_context("runtime.enable") await runtime.execute(self.devtools.runtime.enable()) await runtime.execute(self.devtools.runtime.add_binding("__webdriver_attribute")) self.driver.pin_script(self._mutation_listener_js) script_key = await page.execute( self.devtools.page.add_script_to_evaluate_on_new_document(self._mutation_listener_js) ) self.driver.pin_script(self._mutation_listener_js, script_key) self.driver.execute_script(f"return {self._mutation_listener_js}") event = {} async with runtime.wait_for(self.devtools.runtime.BindingCalled) as evnt: yield event payload = json.loads(evnt.value.payload) elements: list = self.driver.find_elements(By.CSS_SELECTOR, f"*[data-__webdriver_id={payload['target']}") if not elements: elements.append(None) event["element"] = elements[0] event["attribute_name"] = payload["name"] event["current_value"] = payload["value"] event["old_value"] = payload["oldValue"] @asynccontextmanager async def add_js_error_listener(self): """Listen for JS errors and when the contextmanager exits check if there were JS Errors. :Usage: :: async with driver.log.add_js_error_listener() as error: driver.find_element(By.ID, "throwing-mouseover").click() assert bool(error) assert error.exception_details.stack_trace.call_frames[0].function_name == "onmouseover" """ session = self.cdp.get_session_context("page.enable") await session.execute(self.devtools.page.enable()) session = self.cdp.get_session_context("runtime.enable") await session.execute(self.devtools.runtime.enable()) js_exception = self.devtools.runtime.ExceptionThrown(None, None) async with session.wait_for(self.devtools.runtime.ExceptionThrown) as exception: yield js_exception js_exception.timestamp = exception.value.timestamp js_exception.exception_details = exception.value.exception_details @asynccontextmanager async def add_listener(self, event_type) -> dict: """Listen for certain events that are passed in. :Args: - event_type: The type of event that we want to look at. :Usage: :: async with driver.log.add_listener(Console.log) as messages: driver.execute_script("console.log('I like cheese')") assert messages["message"] == "I love cheese" """ from selenium.webdriver.common.bidi.console import Console session = self.cdp.get_session_context("page.enable") await session.execute(self.devtools.page.enable()) session = self.cdp.get_session_context("runtime.enable") await session.execute(self.devtools.runtime.enable()) console = {"message": None, "level": None} async with session.wait_for(self.devtools.runtime.ConsoleAPICalled) as messages: yield console if event_type == Console.ALL or event_type.value == messages.value.type_: console["message"] = messages.value.args[0].value console["level"] = messages.value.args[0].type_ selenium-selenium-4.18.1/selenium/webdriver/common/options.py0000644000175000017500000002547314564764517024332 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import typing from abc import ABCMeta from abc import abstractmethod from enum import Enum from selenium.common.exceptions import InvalidArgumentException from selenium.webdriver.common.proxy import Proxy class PageLoadStrategy(str, Enum): """Enum of possible page load strategies. Selenium support following strategies: * normal (default) - waits for all resources to download * eager - DOM access is ready, but other resources like images may still be loading * none - does not block `WebDriver` at all Docs: https://www.selenium.dev/documentation/webdriver/drivers/options/#pageloadstrategy. """ normal = "normal" eager = "eager" none = "none" class _BaseOptionsDescriptor: def __init__(self, name): self.name = name def __get__(self, obj, cls): if self.name in ("acceptInsecureCerts", "strictFileInteractability", "setWindowRect", "se:downloadsEnabled"): return obj._caps.get(self.name, False) return obj._caps.get(self.name) def __set__(self, obj, value): obj.set_capability(self.name, value) class _PageLoadStrategyDescriptor: """Determines the point at which a navigation command is returned: https://w3c.github.io/webdriver/#dfn-table-of-page-load-strategies. :param strategy: the strategy corresponding to a document readiness state """ def __init__(self, name): self.name = name def __get__(self, obj, cls): return obj._caps.get(self.name) def __set__(self, obj, value): if value in ("normal", "eager", "none"): obj.set_capability(self.name, value) else: raise ValueError("Strategy can only be one of the following: normal, eager, none") class _UnHandledPromptBehaviorDescriptor: """How the driver should respond when an alert is present and the: command sent is not handling the alert: https://w3c.github.io/webdriver/#dfn-table-of-page-load-strategies: :param behavior: behavior to use when an alert is encountered :returns: Values for implicit timeout, pageLoad timeout and script timeout if set (in milliseconds) """ def __init__(self, name): self.name = name def __get__(self, obj, cls): return obj._caps.get(self.name) def __set__(self, obj, value): if value in ("dismiss", "accept", "dismiss and notify", "accept and notify", "ignore"): obj.set_capability(self.name, value) else: raise ValueError( "Behavior can only be one of the following: dismiss, accept, dismiss and notify, " "accept and notify, ignore" ) class _TimeoutsDescriptor: """How long the driver should wait for actions to complete before: returning an error https://w3c.github.io/webdriver/#timeouts: :param timeouts: values in milliseconds for implicit wait, page load and script timeout :returns: Values for implicit timeout, pageLoad timeout and script timeout if set (in milliseconds) """ def __init__(self, name): self.name = name def __get__(self, obj, cls): return obj._caps.get(self.name) def __set__(self, obj, value): if all(x in ("implicit", "pageLoad", "script") for x in value.keys()): obj.set_capability(self.name, value) else: raise ValueError("Timeout keys can only be one of the following: implicit, pageLoad, script") class _ProxyDescriptor: """:Returns: Proxy if set, otherwise None.""" def __init__(self, name): self.name = name def __get__(self, obj, cls): return obj._proxy def __set__(self, obj, value): if not isinstance(value, Proxy): raise InvalidArgumentException("Only Proxy objects can be passed in.") obj._proxy = value obj._caps[self.name] = value.to_capabilities() class BaseOptions(metaclass=ABCMeta): """Base class for individual browser options.""" browser_version = _BaseOptionsDescriptor("browserVersion") """Gets and Sets the version of the browser. Usage ----- - Get - `self.browser_version` - Set - `self.browser_version` = `value` Parameters ---------- `value`: `str` Returns ------- - Get - `str` - Set - `None` """ platform_name = _BaseOptionsDescriptor("platformName") """Gets and Sets name of the platform. Usage ----- - Get - `self.platform_name` - Set - `self.platform_name` = `value` Parameters ---------- `value`: `str` Returns ------- - Get - `str` - Set - `None` """ accept_insecure_certs = _BaseOptionsDescriptor("acceptInsecureCerts") """Gets and Set whether the session accepts insecure certificates. Usage ----- - Get - `self.accept_insecure_certs` - Set - `self.accept_insecure_certs` = `value` Parameters ---------- `value`: `bool` Returns ------- - Get - `bool` - Set - `None` """ strict_file_interactability = _BaseOptionsDescriptor("strictFileInteractability") """Gets and Sets whether session is about file interactability. Usage ----- - Get - `self.strict_file_interactability` - Set - `self.strict_file_interactability` = `value` Parameters ---------- `value`: `bool` Returns ------- - Get - `bool` - Set - `None` """ set_window_rect = _BaseOptionsDescriptor("setWindowRect") """Gets and Sets window size and position. Usage ----- - Get - `self.set_window_rect` - Set - `self.set_window_rect` = `value` Parameters ---------- `value`: `bool` Returns ------- - Get - `bool` - Set - `None` """ page_load_strategy = _PageLoadStrategyDescriptor("pageLoadStrategy") """:Gets and Sets page load strategy, the default is "normal". Usage ----- - Get - `self.page_load_strategy` - Set - `self.page_load_strategy` = `value` Parameters ---------- `value`: `str` Returns ------- - Get - `str` - Set - `None` """ unhandled_prompt_behavior = _UnHandledPromptBehaviorDescriptor("unhandledPromptBehavior") """:Gets and Sets unhandled prompt behavior, the default is "dismiss and notify". Usage ----- - Get - `self.unhandled_prompt_behavior` - Set - `self.unhandled_prompt_behavior` = `value` Parameters ---------- `value`: `str` Returns ------- - Get - `str` - Set - `None` """ timeouts = _TimeoutsDescriptor("timeouts") """:Gets and Sets implicit timeout, pageLoad timeout and script timeout if set (in milliseconds) Usage ----- - Get - `self.timeouts` - Set - `self.timeouts` = `value` Parameters ---------- `value`: `dict` Returns ------- - Get - `dict` - Set - `None` """ proxy = _ProxyDescriptor("proxy") """Sets and Gets Proxy. Usage ----- - Get - `self.proxy` - Set - `self.proxy` = `value` Parameters ---------- `value`: `Proxy` Returns ------- - Get - `Proxy` - Set - `None` """ enable_downloads = _BaseOptionsDescriptor("se:downloadsEnabled") """Gets and Sets whether session can download files. Usage ----- - Get - `self.enable_downloads` - Set - `self.enable_downloads` = `value` Parameters ---------- `value`: `bool` Returns ------- - Get - `bool` - Set - `None` """ def __init__(self) -> None: super().__init__() self._caps = self.default_capabilities self._proxy = None self.set_capability("pageLoadStrategy", PageLoadStrategy.normal) self.mobile_options = None @property def capabilities(self): return self._caps def set_capability(self, name, value) -> None: """Sets a capability.""" self._caps[name] = value def enable_mobile( self, android_package: typing.Optional[str] = None, android_activity: typing.Optional[str] = None, device_serial: typing.Optional[str] = None, ) -> None: """Enables mobile browser use for browsers that support it. :Args: android_activity: The name of the android package to start """ if not android_package: raise AttributeError("android_package must be passed in") self.mobile_options = {"androidPackage": android_package} if android_activity: self.mobile_options["androidActivity"] = android_activity if device_serial: self.mobile_options["androidDeviceSerial"] = device_serial @abstractmethod def to_capabilities(self): """Convert options into capabilities dictionary.""" @property @abstractmethod def default_capabilities(self): """Return minimal capabilities necessary as a dictionary.""" class ArgOptions(BaseOptions): BINARY_LOCATION_ERROR = "Binary Location Must be a String" def __init__(self) -> None: super().__init__() self._arguments = [] self._ignore_local_proxy = False @property def arguments(self): """:Returns: A list of arguments needed for the browser.""" return self._arguments def add_argument(self, argument) -> None: """Adds an argument to the list. :Args: - Sets the arguments """ if argument: self._arguments.append(argument) else: raise ValueError("argument can not be null") def ignore_local_proxy_environment_variables(self) -> None: """By calling this you will ignore HTTP_PROXY and HTTPS_PROXY from being picked up and used.""" self._ignore_local_proxy = True def to_capabilities(self): return self._caps @property def default_capabilities(self): return {} selenium-selenium-4.18.1/selenium/webdriver/common/actions/0000755000175000017500000000000014564764517023712 5ustar carstencarstenselenium-selenium-4.18.1/selenium/webdriver/common/actions/mouse_button.py0000644000175000017500000000155714564764517027017 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. class MouseButton: LEFT = 0 MIDDLE = 1 RIGHT = 2 BACK = 3 FORWARD = 4 selenium-selenium-4.18.1/selenium/webdriver/common/actions/wheel_input.py0000644000175000017500000000506214564764517026612 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from typing import Union from selenium.webdriver.remote.webelement import WebElement from . import interaction from .input_device import InputDevice class ScrollOrigin: def __init__(self, origin: Union[str, WebElement], x_offset: int, y_offset: int) -> None: self._origin = origin self._x_offset = x_offset self._y_offset = y_offset @classmethod def from_element(cls, element: WebElement, x_offset: int = 0, y_offset: int = 0): return cls(element, x_offset, y_offset) @classmethod def from_viewport(cls, x_offset: int = 0, y_offset: int = 0): return cls("viewport", x_offset, y_offset) @property def origin(self) -> Union[str, WebElement]: return self._origin @property def x_offset(self) -> int: return self._x_offset @property def y_offset(self) -> int: return self._y_offset class WheelInput(InputDevice): def __init__(self, name) -> None: super().__init__(name=name) self.name = name self.type = interaction.WHEEL def encode(self) -> dict: return {"type": self.type, "id": self.name, "actions": self.actions} def create_scroll(self, x: int, y: int, delta_x: int, delta_y: int, duration: int, origin) -> None: if isinstance(origin, WebElement): origin = {"element-6066-11e4-a52e-4f735466cecf": origin.id} self.add_action( { "type": "scroll", "x": x, "y": y, "deltaX": delta_x, "deltaY": delta_y, "duration": duration, "origin": origin, } ) def create_pause(self, pause_duration: float) -> None: self.add_action({"type": "pause", "duration": int(pause_duration * 1000)}) selenium-selenium-4.18.1/selenium/webdriver/common/actions/input_device.py0000644000175000017500000000232414564764517026743 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import uuid from typing import Optional class InputDevice: """Describes the input device being used for the action.""" def __init__(self, name: Optional[str] = None): self.name = name or uuid.uuid4() self.actions = [] def add_action(self, action): """""" self.actions.append(action) def clear_actions(self): self.actions = [] def create_pause(self, duration: int = 0): pass selenium-selenium-4.18.1/selenium/webdriver/common/actions/key_input.py0000644000175000017500000000342114564764517026273 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from . import interaction from .input_device import InputDevice from .interaction import Interaction from .interaction import Pause class KeyInput(InputDevice): def __init__(self, name: str) -> None: super().__init__() self.name = name self.type = interaction.KEY def encode(self) -> dict: return {"type": self.type, "id": self.name, "actions": [acts.encode() for acts in self.actions]} def create_key_down(self, key) -> None: self.add_action(TypingInteraction(self, "keyDown", key)) def create_key_up(self, key) -> None: self.add_action(TypingInteraction(self, "keyUp", key)) def create_pause(self, pause_duration: float = 0) -> None: self.add_action(Pause(self, pause_duration)) class TypingInteraction(Interaction): def __init__(self, source, type_, key) -> None: super().__init__(source) self.type = type_ self.key = key def encode(self) -> dict: return {"type": self.type, "value": self.key} selenium-selenium-4.18.1/selenium/webdriver/common/actions/key_actions.py0000644000175000017500000000372714564764517026605 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from __future__ import annotations from ..utils import keys_to_typing from .interaction import KEY from .interaction import Interaction from .key_input import KeyInput from .pointer_input import PointerInput from .wheel_input import WheelInput class KeyActions(Interaction): def __init__(self, source: KeyInput | PointerInput | WheelInput | None = None) -> None: if not source: source = KeyInput(KEY) self.source = source super().__init__(source) def key_down(self, letter: str) -> KeyActions: return self._key_action("create_key_down", letter) def key_up(self, letter: str) -> KeyActions: return self._key_action("create_key_up", letter) def pause(self, duration: int = 0) -> KeyActions: return self._key_action("create_pause", duration) def send_keys(self, text: str | list) -> KeyActions: if not isinstance(text, list): text = keys_to_typing(text) for letter in text: self.key_down(letter) self.key_up(letter) return self def _key_action(self, action: str, letter) -> KeyActions: meth = getattr(self.source, action) meth(letter) return self selenium-selenium-4.18.1/selenium/webdriver/common/actions/__init__.py0000644000175000017500000000142314564764517026023 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/selenium/webdriver/common/actions/action_builder.py0000644000175000017500000000715114564764517027253 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from typing import List from typing import Optional from typing import Union from selenium.webdriver.remote.command import Command from . import interaction from .key_actions import KeyActions from .key_input import KeyInput from .pointer_actions import PointerActions from .pointer_input import PointerInput from .wheel_actions import WheelActions from .wheel_input import WheelInput class ActionBuilder: def __init__( self, driver, mouse: Optional[PointerInput] = None, wheel: Optional[WheelInput] = None, keyboard: Optional[KeyInput] = None, duration: int = 250, ) -> None: mouse = mouse or PointerInput(interaction.POINTER_MOUSE, "mouse") keyboard = keyboard or KeyInput(interaction.KEY) wheel = wheel or WheelInput(interaction.WHEEL) self.devices = [mouse, keyboard, wheel] self._key_action = KeyActions(keyboard) self._pointer_action = PointerActions(mouse, duration=duration) self._wheel_action = WheelActions(wheel) self.driver = driver def get_device_with(self, name: str) -> Optional[Union["WheelInput", "PointerInput", "KeyInput"]]: return next(filter(lambda x: x == name, self.devices), None) @property def pointer_inputs(self) -> List[PointerInput]: return [device for device in self.devices if device.type == interaction.POINTER] @property def key_inputs(self) -> List[KeyInput]: return [device for device in self.devices if device.type == interaction.KEY] @property def key_action(self) -> KeyActions: return self._key_action @property def pointer_action(self) -> PointerActions: return self._pointer_action @property def wheel_action(self) -> WheelActions: return self._wheel_action def add_key_input(self, name: str) -> KeyInput: new_input = KeyInput(name) self._add_input(new_input) return new_input def add_pointer_input(self, kind: str, name: str) -> PointerInput: new_input = PointerInput(kind, name) self._add_input(new_input) return new_input def add_wheel_input(self, name: str) -> WheelInput: new_input = WheelInput(name) self._add_input(new_input) return new_input def perform(self) -> None: enc = {"actions": []} for device in self.devices: encoded = device.encode() if encoded["actions"]: enc["actions"].append(encoded) device.actions = [] self.driver.execute(Command.W3C_ACTIONS, enc) def clear_actions(self) -> None: """Clears actions that are already stored on the remote end.""" self.driver.execute(Command.W3C_CLEAR_ACTIONS) def _add_input(self, new_input: Union[KeyInput, PointerInput, WheelInput]) -> None: self.devices.append(new_input) selenium-selenium-4.18.1/selenium/webdriver/common/actions/interaction.py0000644000175000017500000000267014564764517026610 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from typing import Dict from typing import Union KEY = "key" POINTER = "pointer" NONE = "none" WHEEL = "wheel" SOURCE_TYPES = {KEY, POINTER, NONE} POINTER_MOUSE = "mouse" POINTER_TOUCH = "touch" POINTER_PEN = "pen" POINTER_KINDS = {POINTER_MOUSE, POINTER_TOUCH, POINTER_PEN} class Interaction: PAUSE = "pause" def __init__(self, source: str) -> None: self.source = source class Pause(Interaction): def __init__(self, source, duration: float = 0) -> None: super().__init__(source) self.duration = duration def encode(self) -> Dict[str, Union[str, int]]: return {"type": self.PAUSE, "duration": int(self.duration * 1000)} selenium-selenium-4.18.1/selenium/webdriver/common/actions/pointer_actions.py0000644000175000017500000001356714564764517027500 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from typing import Optional from selenium.webdriver.remote.webelement import WebElement from . import interaction from .interaction import Interaction from .mouse_button import MouseButton from .pointer_input import PointerInput class PointerActions(Interaction): def __init__(self, source: Optional[PointerInput] = None, duration: int = 250): """ Args: - source: PointerInput instance - duration: override the default 250 msecs of DEFAULT_MOVE_DURATION in source """ if not source: source = PointerInput(interaction.POINTER_MOUSE, "mouse") self.source = source self._duration = duration super().__init__(source) def pointer_down( self, button=MouseButton.LEFT, width=None, height=None, pressure=None, tangential_pressure=None, tilt_x=None, tilt_y=None, twist=None, altitude_angle=None, azimuth_angle=None, ): self._button_action( "create_pointer_down", button=button, width=width, height=height, pressure=pressure, tangential_pressure=tangential_pressure, tilt_x=tilt_x, tilt_y=tilt_y, twist=twist, altitude_angle=altitude_angle, azimuth_angle=azimuth_angle, ) return self def pointer_up(self, button=MouseButton.LEFT): self._button_action("create_pointer_up", button=button) return self def move_to( self, element, x=0, y=0, width=None, height=None, pressure=None, tangential_pressure=None, tilt_x=None, tilt_y=None, twist=None, altitude_angle=None, azimuth_angle=None, ): if not isinstance(element, WebElement): raise AttributeError("move_to requires a WebElement") self.source.create_pointer_move( origin=element, duration=self._duration, x=int(x), y=int(y), width=width, height=height, pressure=pressure, tangential_pressure=tangential_pressure, tilt_x=tilt_x, tilt_y=tilt_y, twist=twist, altitude_angle=altitude_angle, azimuth_angle=azimuth_angle, ) return self def move_by( self, x, y, width=None, height=None, pressure=None, tangential_pressure=None, tilt_x=None, tilt_y=None, twist=None, altitude_angle=None, azimuth_angle=None, ): self.source.create_pointer_move( origin=interaction.POINTER, duration=self._duration, x=int(x), y=int(y), width=width, height=height, pressure=pressure, tangential_pressure=tangential_pressure, tilt_x=tilt_x, tilt_y=tilt_y, twist=twist, altitude_angle=altitude_angle, azimuth_angle=azimuth_angle, ) return self def move_to_location( self, x, y, width=None, height=None, pressure=None, tangential_pressure=None, tilt_x=None, tilt_y=None, twist=None, altitude_angle=None, azimuth_angle=None, ): self.source.create_pointer_move( origin="viewport", duration=self._duration, x=int(x), y=int(y), width=width, height=height, pressure=pressure, tangential_pressure=tangential_pressure, tilt_x=tilt_x, tilt_y=tilt_y, twist=twist, altitude_angle=altitude_angle, azimuth_angle=azimuth_angle, ) return self def click(self, element: Optional[WebElement] = None, button=MouseButton.LEFT): if element: self.move_to(element) self.pointer_down(button) self.pointer_up(button) return self def context_click(self, element: Optional[WebElement] = None): return self.click(element=element, button=MouseButton.RIGHT) def click_and_hold(self, element: Optional[WebElement] = None, button=MouseButton.LEFT): if element: self.move_to(element) self.pointer_down(button=button) return self def release(self, button=MouseButton.LEFT): self.pointer_up(button=button) return self def double_click(self, element: Optional[WebElement] = None): if element: self.move_to(element) self.pointer_down(MouseButton.LEFT) self.pointer_up(MouseButton.LEFT) self.pointer_down(MouseButton.LEFT) self.pointer_up(MouseButton.LEFT) return self def pause(self, duration: float = 0): self.source.create_pause(duration) return self def _button_action(self, action, **kwargs): meth = getattr(self.source, action) meth(**kwargs) return self selenium-selenium-4.18.1/selenium/webdriver/common/actions/wheel_actions.py0000644000175000017500000000246314564764517027115 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from .interaction import Interaction from .wheel_input import WheelInput class WheelActions(Interaction): def __init__(self, source: WheelInput = None): if not source: source = WheelInput("wheel") super().__init__(source) def pause(self, duration: float = 0): self.source.create_pause(duration) return self def scroll(self, x=0, y=0, delta_x=0, delta_y=0, duration=0, origin="viewport"): self.source.create_scroll(x, y, delta_x, delta_y, duration, origin) return self selenium-selenium-4.18.1/selenium/webdriver/common/actions/pointer_input.py0000644000175000017500000000564614564764517027176 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import typing from selenium.common.exceptions import InvalidArgumentException from selenium.webdriver.remote.webelement import WebElement from .input_device import InputDevice from .interaction import POINTER from .interaction import POINTER_KINDS class PointerInput(InputDevice): DEFAULT_MOVE_DURATION = 250 def __init__(self, kind, name): super().__init__() if kind not in POINTER_KINDS: raise InvalidArgumentException(f"Invalid PointerInput kind '{kind}'") self.type = POINTER self.kind = kind self.name = name def create_pointer_move( self, duration=DEFAULT_MOVE_DURATION, x: float = 0, y: float = 0, origin: typing.Optional[WebElement] = None, **kwargs, ): action = {"type": "pointerMove", "duration": duration, "x": x, "y": y, **kwargs} if isinstance(origin, WebElement): action["origin"] = {"element-6066-11e4-a52e-4f735466cecf": origin.id} elif origin is not None: action["origin"] = origin self.add_action(self._convert_keys(action)) def create_pointer_down(self, **kwargs): data = {"type": "pointerDown", "duration": 0, **kwargs} self.add_action(self._convert_keys(data)) def create_pointer_up(self, button): self.add_action({"type": "pointerUp", "duration": 0, "button": button}) def create_pointer_cancel(self): self.add_action({"type": "pointerCancel"}) def create_pause(self, pause_duration: float) -> None: self.add_action({"type": "pause", "duration": int(pause_duration * 1000)}) def encode(self): return {"type": self.type, "parameters": {"pointerType": self.kind}, "id": self.name, "actions": self.actions} def _convert_keys(self, actions: typing.Dict[str, typing.Any]): out = {} for k, v in actions.items(): if v is None: continue if k in ("x", "y"): out[k] = int(v) continue splits = k.split("_") new_key = splits[0] + "".join(v.title() for v in splits[1:]) out[new_key] = v return out selenium-selenium-4.18.1/selenium/webdriver/common/window.py0000644000175000017500000000163614564764517024141 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """The WindowTypes implementation.""" class WindowTypes: """Set of supported window types.""" TAB = "tab" WINDOW = "window" selenium-selenium-4.18.1/selenium/webdriver/chromium/0000755000175000017500000000000014564764517022605 5ustar carstencarstenselenium-selenium-4.18.1/selenium/webdriver/chromium/service.py0000644000175000017500000000454514564764517024627 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import typing from selenium.types import SubprocessStdAlias from selenium.webdriver.common import service class ChromiumService(service.Service): """A Service class that is responsible for the starting and stopping the WebDriver instance of the ChromiumDriver. :param executable_path: install path of the executable. :param port: Port for the service to run on, defaults to 0 where the operating system will decide. :param service_args: (Optional) List of args to be passed to the subprocess when launching the executable. :param log_output: (Optional) int representation of STDOUT/DEVNULL, any IO instance or String path to file. :param env: (Optional) Mapping of environment variables for the new process, defaults to `os.environ`. """ def __init__( self, executable_path: str = None, port: int = 0, service_args: typing.Optional[typing.List[str]] = None, log_output: SubprocessStdAlias = None, env: typing.Optional[typing.Mapping[str, str]] = None, **kwargs, ) -> None: self.service_args = service_args or [] if isinstance(log_output, str): self.service_args.append(f"--log-path={log_output}") self.log_output = None else: self.log_output = log_output super().__init__( executable_path=executable_path, port=port, env=env, log_output=self.log_output, **kwargs, ) def command_line_args(self) -> typing.List[str]: return [f"--port={self.port}"] + self.service_args selenium-selenium-4.18.1/selenium/webdriver/chromium/remote_connection.py0000644000175000017500000000511614564764517026674 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.remote.remote_connection import RemoteConnection class ChromiumRemoteConnection(RemoteConnection): def __init__( self, remote_server_addr: str, vendor_prefix: str, browser_name: str, keep_alive: bool = True, ignore_proxy: bool = False, ) -> None: super().__init__(remote_server_addr, keep_alive, ignore_proxy) self.browser_name = browser_name commands = self._remote_commands(vendor_prefix) for key, value in commands.items(): self._commands[key] = value def _remote_commands(self, vendor_prefix): remote_commands = { "launchApp": ("POST", "/session/$sessionId/chromium/launch_app"), "setPermissions": ("POST", "/session/$sessionId/permissions"), "setNetworkConditions": ("POST", "/session/$sessionId/chromium/network_conditions"), "getNetworkConditions": ("GET", "/session/$sessionId/chromium/network_conditions"), "deleteNetworkConditions": ("DELETE", "/session/$sessionId/chromium/network_conditions"), "executeCdpCommand": ("POST", f"/session/$sessionId/{vendor_prefix}/cdp/execute"), "getSinks": ("GET", f"/session/$sessionId/{vendor_prefix}/cast/get_sinks"), "getIssueMessage": ("GET", f"/session/$sessionId/{vendor_prefix}/cast/get_issue_message"), "setSinkToUse": ("POST", f"/session/$sessionId/{vendor_prefix}/cast/set_sink_to_use"), "startDesktopMirroring": ("POST", f"/session/$sessionId/{vendor_prefix}/cast/start_desktop_mirroring"), "startTabMirroring": ("POST", f"/session/$sessionId/{vendor_prefix}/cast/start_tab_mirroring"), "stopCasting": ("POST", f"/session/$sessionId/{vendor_prefix}/cast/stop_casting"), } return remote_commands selenium-selenium-4.18.1/selenium/webdriver/chromium/__init__.py0000644000175000017500000000142314564764517024716 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/selenium/webdriver/chromium/options.py0000644000175000017500000001267214564764517024662 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import base64 import os from typing import BinaryIO from typing import List from typing import Union from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.options import ArgOptions class ChromiumOptions(ArgOptions): KEY = "goog:chromeOptions" def __init__(self) -> None: super().__init__() self._binary_location = "" self._extension_files = [] self._extensions = [] self._experimental_options = {} self._debugger_address = None @property def binary_location(self) -> str: """:Returns: The location of the binary, otherwise an empty string.""" return self._binary_location @binary_location.setter def binary_location(self, value: str) -> None: """Allows you to set where the chromium binary lives. :Args: - value: path to the Chromium binary """ if not isinstance(value, str): raise TypeError(self.BINARY_LOCATION_ERROR) self._binary_location = value @property def debugger_address(self) -> str: """:Returns: The address of the remote devtools instance.""" return self._debugger_address @debugger_address.setter def debugger_address(self, value: str) -> None: """Allows you to set the address of the remote devtools instance that the ChromeDriver instance will try to connect to during an active wait. :Args: - value: address of remote devtools instance if any (hostname[:port]) """ if not isinstance(value, str): raise TypeError("Debugger Address must be a string") self._debugger_address = value @property def extensions(self) -> List[str]: """:Returns: A list of encoded extensions that will be loaded.""" def _decode(file_data: BinaryIO) -> str: # Should not use base64.encodestring() which inserts newlines every # 76 characters (per RFC 1521). Chromedriver has to remove those # unnecessary newlines before decoding, causing performance hit. return base64.b64encode(file_data.read()).decode("utf-8") encoded_extensions = [] for extension in self._extension_files: with open(extension, "rb") as f: encoded_extensions.append(_decode(f)) return encoded_extensions + self._extensions def add_extension(self, extension: str) -> None: """Adds the path to the extension to a list that will be used to extract it to the ChromeDriver. :Args: - extension: path to the \\*.crx file """ if extension: extension_to_add = os.path.abspath(os.path.expanduser(extension)) if os.path.exists(extension_to_add): self._extension_files.append(extension_to_add) else: raise OSError("Path to the extension doesn't exist") else: raise ValueError("argument can not be null") def add_encoded_extension(self, extension: str) -> None: """Adds Base64 encoded string with extension data to a list that will be used to extract it to the ChromeDriver. :Args: - extension: Base64 encoded string with extension data """ if extension: self._extensions.append(extension) else: raise ValueError("argument can not be null") @property def experimental_options(self) -> dict: """:Returns: A dictionary of experimental options for chromium.""" return self._experimental_options def add_experimental_option(self, name: str, value: Union[str, int, dict, List[str]]) -> None: """Adds an experimental option which is passed to chromium. :Args: name: The experimental option name. value: The option value. """ self._experimental_options[name] = value def to_capabilities(self) -> dict: """Creates a capabilities with all the options that have been set :Returns: A dictionary with everything.""" caps = self._caps chrome_options = self.experimental_options.copy() if self.mobile_options: chrome_options.update(self.mobile_options) chrome_options["extensions"] = self.extensions if self.binary_location: chrome_options["binary"] = self.binary_location chrome_options["args"] = self._arguments if self.debugger_address: chrome_options["debuggerAddress"] = self.debugger_address caps[self.KEY] = chrome_options return caps @property def default_capabilities(self) -> dict: return DesiredCapabilities.CHROME.copy() selenium-selenium-4.18.1/selenium/webdriver/chromium/webdriver.py0000644000175000017500000001600014564764517025145 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.chromium.remote_connection import ChromiumRemoteConnection from selenium.webdriver.common.driver_finder import DriverFinder from selenium.webdriver.common.options import ArgOptions from selenium.webdriver.common.service import Service from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver class ChromiumDriver(RemoteWebDriver): """Controls the WebDriver instance of ChromiumDriver and allows you to drive the browser.""" def __init__( self, browser_name: str = None, vendor_prefix: str = None, options: ArgOptions = ArgOptions(), service: Service = None, keep_alive: bool = True, ) -> None: """Creates a new WebDriver instance of the ChromiumDriver. Starts the service and then creates new WebDriver instance of ChromiumDriver. :Args: - browser_name - Browser name used when matching capabilities. - vendor_prefix - Company prefix to apply to vendor-specific WebDriver extension commands. - options - this takes an instance of ChromiumOptions - service - Service object for handling the browser driver if you need to pass extra details - keep_alive - Whether to configure ChromiumRemoteConnection to use HTTP keep-alive. """ self.service = service self.service.path = DriverFinder.get_path(self.service, options) self.service.start() executor = ChromiumRemoteConnection( remote_server_addr=self.service.service_url, browser_name=browser_name, vendor_prefix=vendor_prefix, keep_alive=keep_alive, ignore_proxy=options._ignore_local_proxy, ) try: super().__init__(command_executor=executor, options=options) except Exception: self.quit() raise self._is_remote = False def launch_app(self, id): """Launches Chromium app specified by id.""" return self.execute("launchApp", {"id": id}) def get_network_conditions(self): """Gets Chromium network emulation settings. :Returns: A dict. For example: {'latency': 4, 'download_throughput': 2, 'upload_throughput': 2, 'offline': False} """ return self.execute("getNetworkConditions")["value"] def set_network_conditions(self, **network_conditions) -> None: """Sets Chromium network emulation settings. :Args: - network_conditions: A dict with conditions specification. :Usage: :: driver.set_network_conditions( offline=False, latency=5, # additional latency (ms) download_throughput=500 * 1024, # maximal throughput upload_throughput=500 * 1024) # maximal throughput Note: 'throughput' can be used to set both (for download and upload). """ self.execute("setNetworkConditions", {"network_conditions": network_conditions}) def delete_network_conditions(self) -> None: """Resets Chromium network emulation settings.""" self.execute("deleteNetworkConditions") def set_permissions(self, name: str, value: str) -> None: """Sets Applicable Permission. :Args: - name: The item to set the permission on. - value: The value to set on the item :Usage: :: driver.set_permissions('clipboard-read', 'denied') """ self.execute("setPermissions", {"descriptor": {"name": name}, "state": value}) def execute_cdp_cmd(self, cmd: str, cmd_args: dict): """Execute Chrome Devtools Protocol command and get returned result The command and command args should follow chrome devtools protocol domains/commands, refer to link https://chromedevtools.github.io/devtools-protocol/ :Args: - cmd: A str, command name - cmd_args: A dict, command args. empty dict {} if there is no command args :Usage: :: driver.execute_cdp_cmd('Network.getResponseBody', {'requestId': requestId}) :Returns: A dict, empty dict {} if there is no result to return. For example to getResponseBody: {'base64Encoded': False, 'body': 'response body string'} """ return self.execute("executeCdpCommand", {"cmd": cmd, "params": cmd_args})["value"] def get_sinks(self) -> list: """:Returns: A list of sinks available for Cast.""" return self.execute("getSinks")["value"] def get_issue_message(self): """:Returns: An error message when there is any issue in a Cast session.""" return self.execute("getIssueMessage")["value"] def set_sink_to_use(self, sink_name: str) -> dict: """Sets a specific sink, using its name, as a Cast session receiver target. :Args: - sink_name: Name of the sink to use as the target. """ return self.execute("setSinkToUse", {"sinkName": sink_name}) def start_desktop_mirroring(self, sink_name: str) -> dict: """Starts a desktop mirroring session on a specific receiver target. :Args: - sink_name: Name of the sink to use as the target. """ return self.execute("startDesktopMirroring", {"sinkName": sink_name}) def start_tab_mirroring(self, sink_name: str) -> dict: """Starts a tab mirroring session on a specific receiver target. :Args: - sink_name: Name of the sink to use as the target. """ return self.execute("startTabMirroring", {"sinkName": sink_name}) def stop_casting(self, sink_name: str) -> dict: """Stops the existing Cast session on a specific receiver target. :Args: - sink_name: Name of the sink to stop the Cast session. """ return self.execute("stopCasting", {"sinkName": sink_name}) def quit(self) -> None: """Closes the browser and shuts down the ChromiumDriver executable.""" try: super().quit() except Exception: # We don't care about the message because something probably has gone wrong pass finally: self.service.stop() selenium-selenium-4.18.1/selenium/webdriver/webkitgtk/0000755000175000017500000000000014564764517022755 5ustar carstencarstenselenium-selenium-4.18.1/selenium/webdriver/webkitgtk/service.py0000644000175000017500000000440214564764517024767 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import typing from selenium.webdriver.common import service DEFAULT_EXECUTABLE_PATH = "WebKitWebDriver" class Service(service.Service): """A Service class that is responsible for the starting and stopping of `WPEWebDriver`. :param executable_path: install path of the WebKitWebDriver executable, defaults to `WebKitWebDriver`. :param port: Port for the service to run on, defaults to 0 where the operating system will decide. :param service_args: (Optional) List of args to be passed to the subprocess when launching the executable. :param log_path: (Optional) File path for the file to be opened and passed as the subprocess stdout/stderr handler. :param env: (Optional) Mapping of environment variables for the new process, defaults to `os.environ`. """ def __init__( self, executable_path: str = DEFAULT_EXECUTABLE_PATH, port: int = 0, log_path: typing.Optional[str] = None, service_args: typing.Optional[typing.List[str]] = None, env: typing.Optional[typing.Mapping[str, str]] = None, **kwargs, ): self.service_args = service_args or [] log_file = open(log_path, "wb") if log_path else None super().__init__( executable_path=executable_path, port=port, log_file=log_file, env=env, **kwargs, ) # type: ignore def command_line_args(self) -> typing.List[str]: return ["-p", f"{self.port}"] + self.service_args selenium-selenium-4.18.1/selenium/webdriver/webkitgtk/__init__.py0000644000175000017500000000142314564764517025066 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/selenium/webdriver/webkitgtk/options.py0000644000175000017500000000513514564764517025026 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.options import ArgOptions class Options(ArgOptions): KEY = "webkitgtk:browserOptions" def __init__(self) -> None: super().__init__() self._binary_location = "" self._overlay_scrollbars_enabled = True @property def binary_location(self) -> str: """:Returns: The location of the browser binary otherwise an empty string.""" return self._binary_location @binary_location.setter def binary_location(self, value: str) -> None: """Allows you to set the browser binary to launch. :Args: - value : path to the browser binary """ self._binary_location = value @property def overlay_scrollbars_enabled(self): """:Returns: Whether overlay scrollbars should be enabled.""" return self._overlay_scrollbars_enabled @overlay_scrollbars_enabled.setter def overlay_scrollbars_enabled(self, value) -> None: """Allows you to enable or disable overlay scrollbars. :Args: - value : True or False """ self._overlay_scrollbars_enabled = value def to_capabilities(self): """Creates a capabilities with all the options that have been set and returns a dictionary with everything.""" caps = self._caps browser_options = {} if self.binary_location: browser_options["binary"] = self.binary_location if self.arguments: browser_options["args"] = self.arguments browser_options["useOverlayScrollbars"] = self.overlay_scrollbars_enabled caps[Options.KEY] = browser_options return caps @property def default_capabilities(self): return DesiredCapabilities.WEBKITGTK.copy() selenium-selenium-4.18.1/selenium/webdriver/webkitgtk/webdriver.py0000644000175000017500000000610014564764517025315 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import http.client as http_client from selenium.webdriver.common.driver_finder import DriverFinder from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver from .options import Options from .service import DEFAULT_EXECUTABLE_PATH from .service import Service class WebDriver(RemoteWebDriver): """Controls the WebKitGTKDriver and allows you to drive the browser.""" def __init__( self, executable_path=DEFAULT_EXECUTABLE_PATH, port=0, options=None, desired_capabilities=None, service_log_path=None, keep_alive=False, ): """Creates a new instance of the WebKitGTK driver. Starts the service and then creates new instance of WebKitGTK Driver. :Args: - executable_path : path to the executable. If the default is used it assumes the executable is in the $PATH. - port : port you would like the service to run, if left as 0, a free port will be found. - options : an instance of WebKitGTKOptions - desired_capabilities : Dictionary object with desired capabilities - service_log_path : Path to write service stdout and stderr output. - keep_alive : Whether to configure RemoteConnection to use HTTP keep-alive. """ if not options: options = Options() if not desired_capabilities: desired_capabilities = options.to_capabilities() else: capabilities = options.to_capabilities() if desired_capabilities: capabilities.update(desired_capabilities) desired_capabilities = capabilities self.service = Service(executable_path, port=port, log_path=service_log_path) self.service.path = DriverFinder.get_path(self.service, options) self.service.start() super().__init__( command_executor=self.service.service_url, desired_capabilities=desired_capabilities, keep_alive=keep_alive ) self._is_remote = False def quit(self): """Closes the browser and shuts down the WebKitGTKDriver executable that is started when starting the WebKitGTKDriver.""" try: super().quit() except http_client.BadStatusLine: pass finally: self.service.stop() selenium-selenium-4.18.1/selenium/webdriver/__init__.py0000644000175000017500000000577314564764517023107 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from .chrome.options import Options as ChromeOptions # noqa from .chrome.service import Service as ChromeService # noqa from .chrome.webdriver import WebDriver as Chrome # noqa from .common.action_chains import ActionChains # noqa from .common.desired_capabilities import DesiredCapabilities # noqa from .common.keys import Keys # noqa from .common.proxy import Proxy # noqa from .edge.options import Options as EdgeOptions # noqa from .edge.service import Service as EdgeService # noqa from .edge.webdriver import WebDriver as ChromiumEdge # noqa from .edge.webdriver import WebDriver as Edge # noqa from .firefox.firefox_profile import FirefoxProfile # noqa from .firefox.options import Options as FirefoxOptions # noqa from .firefox.service import Service as FirefoxService # noqa from .firefox.webdriver import WebDriver as Firefox # noqa from .ie.options import Options as IeOptions # noqa from .ie.service import Service as IeService # noqa from .ie.webdriver import WebDriver as Ie # noqa from .remote.webdriver import WebDriver as Remote # noqa from .safari.options import Options as SafariOptions from .safari.service import Service as SafariService # noqa from .safari.webdriver import WebDriver as Safari # noqa from .webkitgtk.options import Options as WebKitGTKOptions # noqa from .webkitgtk.service import Service as WebKitGTKService # noqa from .webkitgtk.webdriver import WebDriver as WebKitGTK # noqa from .wpewebkit.options import Options as WPEWebKitOptions # noqa from .wpewebkit.service import Service as WPEWebKitService # noqa from .wpewebkit.webdriver import WebDriver as WPEWebKit # noqa __version__ = "4.18.1" # We need an explicit __all__ because the above won't otherwise be exported. __all__ = [ "Firefox", "FirefoxProfile", "FirefoxOptions", "FirefoxService", "Chrome", "ChromeOptions", "ChromeService", "Ie", "IeOptions", "IeService", "Edge", "ChromiumEdge", "EdgeOptions", "EdgeService", "Safari", "SafariOptions", "SafariService", "WebKitGTK", "WebKitGTKOptions", "WebKitGTKService", "WPEWebKit", "WPEWebKitOptions", "WPEWebKitService", "Remote", "DesiredCapabilities", "ActionChains", "Proxy", "Keys", ] selenium-selenium-4.18.1/selenium/webdriver/support/0000755000175000017500000000000014564764517022476 5ustar carstencarstenselenium-selenium-4.18.1/selenium/webdriver/support/expected_conditions.py0000644000175000017500000004233014564764517027104 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import re from collections.abc import Iterable from typing import Any from typing import Callable from typing import List from typing import Literal from typing import Tuple from typing import TypeVar from typing import Union from selenium.common.exceptions import NoAlertPresentException from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import NoSuchFrameException from selenium.common.exceptions import StaleElementReferenceException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.alert import Alert from selenium.webdriver.remote.webdriver import WebDriver from selenium.webdriver.remote.webdriver import WebElement """ * Canned "Expected Conditions" which are generally useful within webdriver * tests. """ D = TypeVar("D") T = TypeVar("T") WebDriverOrWebElement = Union[WebDriver, WebElement] def title_is(title: str) -> Callable[[WebDriver], bool]: """An expectation for checking the title of a page. title is the expected title, which must be an exact match returns True if the title matches, false otherwise. """ def _predicate(driver: WebDriver): return driver.title == title return _predicate def title_contains(title: str) -> Callable[[WebDriver], bool]: """An expectation for checking that the title contains a case-sensitive substring. title is the fragment of title expected returns True when the title matches, False otherwise """ def _predicate(driver: WebDriver): return title in driver.title return _predicate def presence_of_element_located(locator: Tuple[str, str]) -> Callable[[WebDriverOrWebElement], WebElement]: """An expectation for checking that an element is present on the DOM of a page. This does not necessarily mean that the element is visible. locator - used to find the element returns the WebElement once it is located """ def _predicate(driver: WebDriverOrWebElement): return driver.find_element(*locator) return _predicate def url_contains(url: str) -> Callable[[WebDriver], bool]: """An expectation for checking that the current url contains a case- sensitive substring. url is the fragment of url expected, returns True when the url matches, False otherwise """ def _predicate(driver: WebDriver): return url in driver.current_url return _predicate def url_matches(pattern: str) -> Callable[[WebDriver], bool]: """An expectation for checking the current url. pattern is the expected pattern. This finds the first occurrence of pattern in the current url and as such does not require an exact full match. """ def _predicate(driver: WebDriver): return re.search(pattern, driver.current_url) is not None return _predicate def url_to_be(url: str) -> Callable[[WebDriver], bool]: """An expectation for checking the current url. url is the expected url, which must be an exact match returns True if the url matches, false otherwise. """ def _predicate(driver: WebDriver): return url == driver.current_url return _predicate def url_changes(url: str) -> Callable[[WebDriver], bool]: """An expectation for checking the current url. url is the expected url, which must not be an exact match returns True if the url is different, false otherwise. """ def _predicate(driver: WebDriver): return url != driver.current_url return _predicate def visibility_of_element_located( locator: Tuple[str, str] ) -> Callable[[WebDriverOrWebElement], Union[Literal[False], WebElement]]: """An expectation for checking that an element is present on the DOM of a page and visible. Visibility means that the element is not only displayed but also has a height and width that is greater than 0. locator - used to find the element returns the WebElement once it is located and visible """ def _predicate(driver: WebDriverOrWebElement): try: return _element_if_visible(driver.find_element(*locator)) except StaleElementReferenceException: return False return _predicate def visibility_of(element: WebElement) -> Callable[[Any], Union[Literal[False], WebElement]]: """An expectation for checking that an element, known to be present on the DOM of a page, is visible. Visibility means that the element is not only displayed but also has a height and width that is greater than 0. element is the WebElement returns the (same) WebElement once it is visible """ def _predicate(_): return _element_if_visible(element) return _predicate def _element_if_visible(element: WebElement, visibility: bool = True) -> Union[Literal[False], WebElement]: return element if element.is_displayed() == visibility else False def presence_of_all_elements_located(locator: Tuple[str, str]) -> Callable[[WebDriverOrWebElement], List[WebElement]]: """An expectation for checking that there is at least one element present on a web page. locator is used to find the element returns the list of WebElements once they are located """ def _predicate(driver: WebDriverOrWebElement): return driver.find_elements(*locator) return _predicate def visibility_of_any_elements_located(locator: Tuple[str, str]) -> Callable[[WebDriverOrWebElement], List[WebElement]]: """An expectation for checking that there is at least one element visible on a web page. locator is used to find the element returns the list of WebElements once they are located """ def _predicate(driver: WebDriverOrWebElement): return [element for element in driver.find_elements(*locator) if _element_if_visible(element)] return _predicate def visibility_of_all_elements_located( locator: Tuple[str, str] ) -> Callable[[WebDriverOrWebElement], Union[List[WebElement], Literal[False]]]: """An expectation for checking that all elements are present on the DOM of a page and visible. Visibility means that the elements are not only displayed but also has a height and width that is greater than 0. locator - used to find the elements returns the list of WebElements once they are located and visible """ def _predicate(driver: WebDriverOrWebElement): try: elements = driver.find_elements(*locator) for element in elements: if _element_if_visible(element, visibility=False): return False return elements except StaleElementReferenceException: return False return _predicate def text_to_be_present_in_element(locator: Tuple[str, str], text_: str) -> Callable[[WebDriverOrWebElement], bool]: """An expectation for checking if the given text is present in the specified element. locator, text """ def _predicate(driver: WebDriverOrWebElement): try: element_text = driver.find_element(*locator).text return text_ in element_text except StaleElementReferenceException: return False return _predicate def text_to_be_present_in_element_value( locator: Tuple[str, str], text_: str ) -> Callable[[WebDriverOrWebElement], bool]: """An expectation for checking if the given text is present in the element's value. locator, text """ def _predicate(driver: WebDriverOrWebElement): try: element_text = driver.find_element(*locator).get_attribute("value") return text_ in element_text except StaleElementReferenceException: return False return _predicate def text_to_be_present_in_element_attribute( locator: Tuple[str, str], attribute_: str, text_: str ) -> Callable[[WebDriverOrWebElement], bool]: """An expectation for checking if the given text is present in the element's attribute. locator, attribute, text """ def _predicate(driver: WebDriverOrWebElement): try: element_text = driver.find_element(*locator).get_attribute(attribute_) if element_text is None: return False return text_ in element_text except StaleElementReferenceException: return False return _predicate def frame_to_be_available_and_switch_to_it(locator: Union[Tuple[str, str], str]) -> Callable[[WebDriver], bool]: """An expectation for checking whether the given frame is available to switch to. If the frame is available it switches the given driver to the specified frame. """ def _predicate(driver: WebDriver): try: if isinstance(locator, Iterable) and not isinstance(locator, str): driver.switch_to.frame(driver.find_element(*locator)) else: driver.switch_to.frame(locator) return True except NoSuchFrameException: return False return _predicate def invisibility_of_element_located( locator: Union[WebElement, Tuple[str, str]] ) -> Callable[[WebDriverOrWebElement], Union[WebElement, bool]]: """An Expectation for checking that an element is either invisible or not present on the DOM. locator used to find the element """ def _predicate(driver: WebDriverOrWebElement): try: target = locator if not isinstance(target, WebElement): target = driver.find_element(*target) return _element_if_visible(target, visibility=False) except (NoSuchElementException, StaleElementReferenceException): # In the case of NoSuchElement, returns true because the element is # not present in DOM. The try block checks if the element is present # but is invisible. # In the case of StaleElementReference, returns true because stale # element reference implies that element is no longer visible. return True return _predicate def invisibility_of_element( element: Union[WebElement, Tuple[str, str]] ) -> Callable[[WebDriverOrWebElement], Union[WebElement, bool]]: """An Expectation for checking that an element is either invisible or not present on the DOM. element is either a locator (text) or an WebElement """ return invisibility_of_element_located(element) def element_to_be_clickable( mark: Union[WebElement, Tuple[str, str]] ) -> Callable[[WebDriverOrWebElement], Union[Literal[False], WebElement]]: """An Expectation for checking an element is visible and enabled such that you can click it. element is either a locator (text) or an WebElement """ # renamed argument to 'mark', to indicate that both locator # and WebElement args are valid def _predicate(driver: WebDriverOrWebElement): target = mark if not isinstance(target, WebElement): # if given locator instead of WebElement target = driver.find_element(*target) # grab element at locator element = visibility_of(target)(driver) if element and element.is_enabled(): return element return False return _predicate def staleness_of(element: WebElement) -> Callable[[Any], bool]: """Wait until an element is no longer attached to the DOM. element is the element to wait for. returns False if the element is still attached to the DOM, true otherwise. """ def _predicate(_): try: # Calling any method forces a staleness check element.is_enabled() return False except StaleElementReferenceException: return True return _predicate def element_to_be_selected(element: WebElement) -> Callable[[Any], bool]: """An expectation for checking the selection is selected. element is WebElement object """ def _predicate(_): return element.is_selected() return _predicate def element_located_to_be_selected(locator: Tuple[str, str]) -> Callable[[WebDriverOrWebElement], bool]: """An expectation for the element to be located is selected. locator is a tuple of (by, path) """ def _predicate(driver: WebDriverOrWebElement): return driver.find_element(*locator).is_selected() return _predicate def element_selection_state_to_be(element: WebElement, is_selected: bool) -> Callable[[Any], bool]: """An expectation for checking if the given element is selected. element is WebElement object is_selected is a Boolean. """ def _predicate(_): return element.is_selected() == is_selected return _predicate def element_located_selection_state_to_be( locator: Tuple[str, str], is_selected: bool ) -> Callable[[WebDriverOrWebElement], bool]: """An expectation to locate an element and check if the selection state specified is in that state. locator is a tuple of (by, path) is_selected is a boolean """ def _predicate(driver: WebDriverOrWebElement): try: element = driver.find_element(*locator) return element.is_selected() == is_selected except StaleElementReferenceException: return False return _predicate def number_of_windows_to_be(num_windows: int) -> Callable[[WebDriver], bool]: """An expectation for the number of windows to be a certain value.""" def _predicate(driver: WebDriver): return len(driver.window_handles) == num_windows return _predicate def new_window_is_opened(current_handles: List[str]) -> Callable[[WebDriver], bool]: """An expectation that a new window will be opened and have the number of windows handles increase.""" def _predicate(driver: WebDriver): return len(driver.window_handles) > len(current_handles) return _predicate def alert_is_present() -> Callable[[WebDriver], Union[Alert, Literal[False]]]: """An expectation for checking if an alert is currently present and switching to it.""" def _predicate(driver: WebDriver): try: return driver.switch_to.alert except NoAlertPresentException: return False return _predicate def element_attribute_to_include(locator: Tuple[str, str], attribute_: str) -> Callable[[WebDriverOrWebElement], bool]: """An expectation for checking if the given attribute is included in the specified element. locator, attribute """ def _predicate(driver: WebDriverOrWebElement): try: element_attribute = driver.find_element(*locator).get_attribute(attribute_) return element_attribute is not None except StaleElementReferenceException: return False return _predicate def any_of(*expected_conditions: Callable[[D], T]) -> Callable[[D], Union[Literal[False], T]]: """An expectation that any of multiple expected conditions is true. Equivalent to a logical 'OR'. Returns results of the first matching condition, or False if none do. """ def any_of_condition(driver: D): for expected_condition in expected_conditions: try: result = expected_condition(driver) if result: return result except WebDriverException: pass return False return any_of_condition def all_of( *expected_conditions: Callable[[D], Union[T, Literal[False]]] ) -> Callable[[D], Union[List[T], Literal[False]]]: """An expectation that all of multiple expected conditions is true. Equivalent to a logical 'AND'. Returns: When any ExpectedCondition is not met: False. When all ExpectedConditions are met: A List with each ExpectedCondition's return value. """ def all_of_condition(driver: D): results: List[T] = [] for expected_condition in expected_conditions: try: result = expected_condition(driver) if not result: return False results.append(result) except WebDriverException: return False return results return all_of_condition def none_of(*expected_conditions: Callable[[D], Any]) -> Callable[[D], bool]: """An expectation that none of 1 or multiple expected conditions is true. Equivalent to a logical 'NOT-OR'. Returns a Boolean """ def none_of_condition(driver: D): for expected_condition in expected_conditions: try: result = expected_condition(driver) if result: return False except WebDriverException: pass return True return none_of_condition selenium-selenium-4.18.1/selenium/webdriver/support/abstract_event_listener.py0000644000175000017500000000420214564764517027757 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. class AbstractEventListener: """Event listener must subclass and implement this fully or partially.""" def before_navigate_to(self, url: str, driver) -> None: pass def after_navigate_to(self, url: str, driver) -> None: pass def before_navigate_back(self, driver) -> None: pass def after_navigate_back(self, driver) -> None: pass def before_navigate_forward(self, driver) -> None: pass def after_navigate_forward(self, driver) -> None: pass def before_find(self, by, value, driver) -> None: pass def after_find(self, by, value, driver) -> None: pass def before_click(self, element, driver) -> None: pass def after_click(self, element, driver) -> None: pass def before_change_value_of(self, element, driver) -> None: pass def after_change_value_of(self, element, driver) -> None: pass def before_execute_script(self, script, driver) -> None: pass def after_execute_script(self, script, driver) -> None: pass def before_close(self, driver) -> None: pass def after_close(self, driver) -> None: pass def before_quit(self, driver) -> None: pass def after_quit(self, driver) -> None: pass def on_exception(self, exception, driver) -> None: pass selenium-selenium-4.18.1/selenium/webdriver/support/color.py0000644000175000017500000002764314564764517024202 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from __future__ import annotations import sys from typing import TYPE_CHECKING from typing import Any from typing import Sequence if sys.version_info >= (3, 9): from re import Match else: from typing import Match if TYPE_CHECKING: from typing import SupportsFloat from typing import SupportsIndex from typing import SupportsInt from typing import Union ParseableFloat = Union[SupportsFloat, SupportsIndex, str, bytes, bytearray] ParseableInt = Union[SupportsInt, SupportsIndex, str, bytes] else: ParseableFloat = Any ParseableInt = Any RGB_PATTERN = r"^\s*rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)\s*$" RGB_PCT_PATTERN = ( r"^\s*rgb\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*\)\s*$" ) RGBA_PATTERN = r"^\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0\.\d+)\s*\)\s*$" RGBA_PCT_PATTERN = r"^\s*rgba\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(0|1|0\.\d+)\s*\)\s*$" HEX_PATTERN = r"#([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})" HEX3_PATTERN = r"#([A-Fa-f0-9])([A-Fa-f0-9])([A-Fa-f0-9])" HSL_PATTERN = r"^\s*hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*\)\s*$" HSLA_PATTERN = r"^\s*hsla\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*,\s*(0|1|0\.\d+)\s*\)\s*$" class Color: """Color conversion support class. Example: :: from selenium.webdriver.support.color import Color print(Color.from_string('#00ff33').rgba) print(Color.from_string('rgb(1, 255, 3)').hex) print(Color.from_string('blue').rgba) """ @classmethod def from_string(cls, str_: str) -> Color: import re class Matcher: match_obj: Match[str] | None def __init__(self) -> None: self.match_obj = None def match(self, pattern: str, str_: str) -> Match[str] | None: self.match_obj = re.match(pattern, str_) return self.match_obj @property def groups(self) -> Sequence[str]: return () if not self.match_obj else self.match_obj.groups() m = Matcher() if m.match(RGB_PATTERN, str_): return cls(*m.groups) if m.match(RGB_PCT_PATTERN, str_): rgb = tuple(float(each) / 100 * 255 for each in m.groups) return cls(*rgb) if m.match(RGBA_PATTERN, str_): return cls(*m.groups) if m.match(RGBA_PCT_PATTERN, str_): rgba = tuple([float(each) / 100 * 255 for each in m.groups[:3]] + [m.groups[3]]) return cls(*rgba) if m.match(HEX_PATTERN, str_): rgb = tuple(int(each, 16) for each in m.groups) return cls(*rgb) if m.match(HEX3_PATTERN, str_): rgb = tuple(int(each * 2, 16) for each in m.groups) return cls(*rgb) if m.match(HSL_PATTERN, str_) or m.match(HSLA_PATTERN, str_): return cls._from_hsl(*m.groups) if str_.upper() in Colors: return Colors[str_.upper()] raise ValueError("Could not convert %s into color" % str_) @classmethod def _from_hsl(cls, h: ParseableFloat, s: ParseableFloat, light: ParseableFloat, a: ParseableFloat = 1) -> Color: h = float(h) / 360 s = float(s) / 100 _l = float(light) / 100 if s == 0: r = _l g = r b = r else: luminocity2 = _l * (1 + s) if _l < 0.5 else _l + s - _l * s luminocity1 = 2 * _l - luminocity2 def hue_to_rgb(lum1: float, lum2: float, hue: float) -> float: if hue < 0.0: hue += 1 if hue > 1.0: hue -= 1 if hue < 1.0 / 6.0: return lum1 + (lum2 - lum1) * 6.0 * hue if hue < 1.0 / 2.0: return lum2 if hue < 2.0 / 3.0: return lum1 + (lum2 - lum1) * ((2.0 / 3.0) - hue) * 6.0 return lum1 r = hue_to_rgb(luminocity1, luminocity2, h + 1.0 / 3.0) g = hue_to_rgb(luminocity1, luminocity2, h) b = hue_to_rgb(luminocity1, luminocity2, h - 1.0 / 3.0) return cls(round(r * 255), round(g * 255), round(b * 255), a) def __init__(self, red: ParseableInt, green: ParseableInt, blue: ParseableInt, alpha: ParseableFloat = 1) -> None: self.red = int(red) self.green = int(green) self.blue = int(blue) self.alpha = "1" if float(alpha) == 1 else str(float(alpha) or 0) @property def rgb(self) -> str: return f"rgb({self.red}, {self.green}, {self.blue})" @property def rgba(self) -> str: return f"rgba({self.red}, {self.green}, {self.blue}, {self.alpha})" @property def hex(self) -> str: return f"#{self.red:02x}{self.green:02x}{self.blue:02x}" def __eq__(self, other: object) -> bool: if isinstance(other, Color): return self.rgba == other.rgba return NotImplemented def __ne__(self, other: Any) -> bool: result = self.__eq__(other) if result is NotImplemented: return result return not result def __hash__(self) -> int: return hash((self.red, self.green, self.blue, self.alpha)) def __repr__(self) -> str: return f"Color(red={self.red}, green={self.green}, blue={self.blue}, alpha={self.alpha})" def __str__(self) -> str: return f"Color: {self.rgba}" # Basic, extended and transparent colour keywords as defined by the W3C HTML4 spec # See http://www.w3.org/TR/css3-color/#html4 Colors = { "TRANSPARENT": Color(0, 0, 0, 0), "ALICEBLUE": Color(240, 248, 255), "ANTIQUEWHITE": Color(250, 235, 215), "AQUA": Color(0, 255, 255), "AQUAMARINE": Color(127, 255, 212), "AZURE": Color(240, 255, 255), "BEIGE": Color(245, 245, 220), "BISQUE": Color(255, 228, 196), "BLACK": Color(0, 0, 0), "BLANCHEDALMOND": Color(255, 235, 205), "BLUE": Color(0, 0, 255), "BLUEVIOLET": Color(138, 43, 226), "BROWN": Color(165, 42, 42), "BURLYWOOD": Color(222, 184, 135), "CADETBLUE": Color(95, 158, 160), "CHARTREUSE": Color(127, 255, 0), "CHOCOLATE": Color(210, 105, 30), "CORAL": Color(255, 127, 80), "CORNFLOWERBLUE": Color(100, 149, 237), "CORNSILK": Color(255, 248, 220), "CRIMSON": Color(220, 20, 60), "CYAN": Color(0, 255, 255), "DARKBLUE": Color(0, 0, 139), "DARKCYAN": Color(0, 139, 139), "DARKGOLDENROD": Color(184, 134, 11), "DARKGRAY": Color(169, 169, 169), "DARKGREEN": Color(0, 100, 0), "DARKGREY": Color(169, 169, 169), "DARKKHAKI": Color(189, 183, 107), "DARKMAGENTA": Color(139, 0, 139), "DARKOLIVEGREEN": Color(85, 107, 47), "DARKORANGE": Color(255, 140, 0), "DARKORCHID": Color(153, 50, 204), "DARKRED": Color(139, 0, 0), "DARKSALMON": Color(233, 150, 122), "DARKSEAGREEN": Color(143, 188, 143), "DARKSLATEBLUE": Color(72, 61, 139), "DARKSLATEGRAY": Color(47, 79, 79), "DARKSLATEGREY": Color(47, 79, 79), "DARKTURQUOISE": Color(0, 206, 209), "DARKVIOLET": Color(148, 0, 211), "DEEPPINK": Color(255, 20, 147), "DEEPSKYBLUE": Color(0, 191, 255), "DIMGRAY": Color(105, 105, 105), "DIMGREY": Color(105, 105, 105), "DODGERBLUE": Color(30, 144, 255), "FIREBRICK": Color(178, 34, 34), "FLORALWHITE": Color(255, 250, 240), "FORESTGREEN": Color(34, 139, 34), "FUCHSIA": Color(255, 0, 255), "GAINSBORO": Color(220, 220, 220), "GHOSTWHITE": Color(248, 248, 255), "GOLD": Color(255, 215, 0), "GOLDENROD": Color(218, 165, 32), "GRAY": Color(128, 128, 128), "GREY": Color(128, 128, 128), "GREEN": Color(0, 128, 0), "GREENYELLOW": Color(173, 255, 47), "HONEYDEW": Color(240, 255, 240), "HOTPINK": Color(255, 105, 180), "INDIANRED": Color(205, 92, 92), "INDIGO": Color(75, 0, 130), "IVORY": Color(255, 255, 240), "KHAKI": Color(240, 230, 140), "LAVENDER": Color(230, 230, 250), "LAVENDERBLUSH": Color(255, 240, 245), "LAWNGREEN": Color(124, 252, 0), "LEMONCHIFFON": Color(255, 250, 205), "LIGHTBLUE": Color(173, 216, 230), "LIGHTCORAL": Color(240, 128, 128), "LIGHTCYAN": Color(224, 255, 255), "LIGHTGOLDENRODYELLOW": Color(250, 250, 210), "LIGHTGRAY": Color(211, 211, 211), "LIGHTGREEN": Color(144, 238, 144), "LIGHTGREY": Color(211, 211, 211), "LIGHTPINK": Color(255, 182, 193), "LIGHTSALMON": Color(255, 160, 122), "LIGHTSEAGREEN": Color(32, 178, 170), "LIGHTSKYBLUE": Color(135, 206, 250), "LIGHTSLATEGRAY": Color(119, 136, 153), "LIGHTSLATEGREY": Color(119, 136, 153), "LIGHTSTEELBLUE": Color(176, 196, 222), "LIGHTYELLOW": Color(255, 255, 224), "LIME": Color(0, 255, 0), "LIMEGREEN": Color(50, 205, 50), "LINEN": Color(250, 240, 230), "MAGENTA": Color(255, 0, 255), "MAROON": Color(128, 0, 0), "MEDIUMAQUAMARINE": Color(102, 205, 170), "MEDIUMBLUE": Color(0, 0, 205), "MEDIUMORCHID": Color(186, 85, 211), "MEDIUMPURPLE": Color(147, 112, 219), "MEDIUMSEAGREEN": Color(60, 179, 113), "MEDIUMSLATEBLUE": Color(123, 104, 238), "MEDIUMSPRINGGREEN": Color(0, 250, 154), "MEDIUMTURQUOISE": Color(72, 209, 204), "MEDIUMVIOLETRED": Color(199, 21, 133), "MIDNIGHTBLUE": Color(25, 25, 112), "MINTCREAM": Color(245, 255, 250), "MISTYROSE": Color(255, 228, 225), "MOCCASIN": Color(255, 228, 181), "NAVAJOWHITE": Color(255, 222, 173), "NAVY": Color(0, 0, 128), "OLDLACE": Color(253, 245, 230), "OLIVE": Color(128, 128, 0), "OLIVEDRAB": Color(107, 142, 35), "ORANGE": Color(255, 165, 0), "ORANGERED": Color(255, 69, 0), "ORCHID": Color(218, 112, 214), "PALEGOLDENROD": Color(238, 232, 170), "PALEGREEN": Color(152, 251, 152), "PALETURQUOISE": Color(175, 238, 238), "PALEVIOLETRED": Color(219, 112, 147), "PAPAYAWHIP": Color(255, 239, 213), "PEACHPUFF": Color(255, 218, 185), "PERU": Color(205, 133, 63), "PINK": Color(255, 192, 203), "PLUM": Color(221, 160, 221), "POWDERBLUE": Color(176, 224, 230), "PURPLE": Color(128, 0, 128), "REBECCAPURPLE": Color(128, 51, 153), "RED": Color(255, 0, 0), "ROSYBROWN": Color(188, 143, 143), "ROYALBLUE": Color(65, 105, 225), "SADDLEBROWN": Color(139, 69, 19), "SALMON": Color(250, 128, 114), "SANDYBROWN": Color(244, 164, 96), "SEAGREEN": Color(46, 139, 87), "SEASHELL": Color(255, 245, 238), "SIENNA": Color(160, 82, 45), "SILVER": Color(192, 192, 192), "SKYBLUE": Color(135, 206, 235), "SLATEBLUE": Color(106, 90, 205), "SLATEGRAY": Color(112, 128, 144), "SLATEGREY": Color(112, 128, 144), "SNOW": Color(255, 250, 250), "SPRINGGREEN": Color(0, 255, 127), "STEELBLUE": Color(70, 130, 180), "TAN": Color(210, 180, 140), "TEAL": Color(0, 128, 128), "THISTLE": Color(216, 191, 216), "TOMATO": Color(255, 99, 71), "TURQUOISE": Color(64, 224, 208), "VIOLET": Color(238, 130, 238), "WHEAT": Color(245, 222, 179), "WHITE": Color(255, 255, 255), "WHITESMOKE": Color(245, 245, 245), "YELLOW": Color(255, 255, 0), "YELLOWGREEN": Color(154, 205, 50), } selenium-selenium-4.18.1/selenium/webdriver/support/event_firing_webdriver.py0000644000175000017500000002175114564764517027606 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import typing from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.remote.webdriver import WebDriver from selenium.webdriver.remote.webelement import WebElement from .abstract_event_listener import AbstractEventListener def _wrap_elements(result, ef_driver): # handle the case if another wrapper wraps EventFiringWebElement if isinstance(result, EventFiringWebElement): return result if isinstance(result, WebElement): return EventFiringWebElement(result, ef_driver) if isinstance(result, list): return [_wrap_elements(item, ef_driver) for item in result] return result class EventFiringWebDriver: """A wrapper around an arbitrary WebDriver instance which supports firing events.""" def __init__(self, driver: WebDriver, event_listener: AbstractEventListener) -> None: """Creates a new instance of the EventFiringWebDriver. :Args: - driver : A WebDriver instance - event_listener : Instance of a class that subclasses AbstractEventListener and implements it fully or partially Example: :: from selenium.webdriver import Firefox from selenium.webdriver.support.events import EventFiringWebDriver, AbstractEventListener class MyListener(AbstractEventListener): def before_navigate_to(self, url, driver): print("Before navigate to %s" % url) def after_navigate_to(self, url, driver): print("After navigate to %s" % url) driver = Firefox() ef_driver = EventFiringWebDriver(driver, MyListener()) ef_driver.get("http://www.google.co.in/") """ if not isinstance(driver, WebDriver): raise WebDriverException("A WebDriver instance must be supplied") if not isinstance(event_listener, AbstractEventListener): raise WebDriverException("Event listener must be a subclass of AbstractEventListener") self._driver = driver self._driver._wrap_value = self._wrap_value self._listener = event_listener @property def wrapped_driver(self) -> WebDriver: """Returns the WebDriver instance wrapped by this EventsFiringWebDriver.""" return self._driver def get(self, url: str) -> None: self._dispatch("navigate_to", (url, self._driver), "get", (url,)) def back(self) -> None: self._dispatch("navigate_back", (self._driver,), "back", ()) def forward(self) -> None: self._dispatch("navigate_forward", (self._driver,), "forward", ()) def execute_script(self, script, *args): unwrapped_args = (script,) + self._unwrap_element_args(args) return self._dispatch("execute_script", (script, self._driver), "execute_script", unwrapped_args) def execute_async_script(self, script, *args): unwrapped_args = (script,) + self._unwrap_element_args(args) return self._dispatch("execute_script", (script, self._driver), "execute_async_script", unwrapped_args) def close(self) -> None: self._dispatch("close", (self._driver,), "close", ()) def quit(self) -> None: self._dispatch("quit", (self._driver,), "quit", ()) def find_element(self, by=By.ID, value=None) -> WebElement: return self._dispatch("find", (by, value, self._driver), "find_element", (by, value)) def find_elements(self, by=By.ID, value=None) -> typing.List[WebElement]: return self._dispatch("find", (by, value, self._driver), "find_elements", (by, value)) def _dispatch( self, l_call: str, l_args: typing.Tuple[typing.Any, ...], d_call: str, d_args: typing.Tuple[typing.Any, ...] ): getattr(self._listener, f"before_{l_call}")(*l_args) try: result = getattr(self._driver, d_call)(*d_args) except Exception as exc: self._listener.on_exception(exc, self._driver) raise getattr(self._listener, f"after_{l_call}")(*l_args) return _wrap_elements(result, self) def _unwrap_element_args(self, args): if isinstance(args, EventFiringWebElement): return args.wrapped_element if isinstance(args, tuple): return tuple(self._unwrap_element_args(item) for item in args) if isinstance(args, list): return [self._unwrap_element_args(item) for item in args] return args def _wrap_value(self, value): if isinstance(value, EventFiringWebElement): return WebDriver._wrap_value(self._driver, value.wrapped_element) return WebDriver._wrap_value(self._driver, value) def __setattr__(self, item, value): if item.startswith("_") or not hasattr(self._driver, item): object.__setattr__(self, item, value) else: try: object.__setattr__(self._driver, item, value) except Exception as exc: self._listener.on_exception(exc, self._driver) raise def __getattr__(self, name): def _wrap(*args, **kwargs): try: result = attrib(*args, **kwargs) return _wrap_elements(result, self) except Exception as exc: self._listener.on_exception(exc, self._driver) raise try: attrib = getattr(self._driver, name) return _wrap if callable(attrib) else attrib except Exception as exc: self._listener.on_exception(exc, self._driver) raise class EventFiringWebElement: """A wrapper around WebElement instance which supports firing events.""" def __init__(self, webelement: WebElement, ef_driver: EventFiringWebDriver) -> None: """Creates a new instance of the EventFiringWebElement.""" self._webelement = webelement self._ef_driver = ef_driver self._driver = ef_driver.wrapped_driver self._listener = ef_driver._listener @property def wrapped_element(self) -> WebElement: """Returns the WebElement wrapped by this EventFiringWebElement instance.""" return self._webelement def click(self) -> None: self._dispatch("click", (self._webelement, self._driver), "click", ()) def clear(self) -> None: self._dispatch("change_value_of", (self._webelement, self._driver), "clear", ()) def send_keys(self, *value) -> None: self._dispatch("change_value_of", (self._webelement, self._driver), "send_keys", value) def find_element(self, by=By.ID, value=None) -> WebElement: return self._dispatch("find", (by, value, self._driver), "find_element", (by, value)) def find_elements(self, by=By.ID, value=None) -> typing.List[WebElement]: return self._dispatch("find", (by, value, self._driver), "find_elements", (by, value)) def _dispatch(self, l_call, l_args, d_call, d_args): getattr(self._listener, f"before_{l_call}")(*l_args) try: result = getattr(self._webelement, d_call)(*d_args) except Exception as exc: self._listener.on_exception(exc, self._driver) raise getattr(self._listener, f"after_{l_call}")(*l_args) return _wrap_elements(result, self._ef_driver) def __setattr__(self, item, value): if item.startswith("_") or not hasattr(self._webelement, item): object.__setattr__(self, item, value) else: try: object.__setattr__(self._webelement, item, value) except Exception as exc: self._listener.on_exception(exc, self._driver) raise def __getattr__(self, name): def _wrap(*args, **kwargs): try: result = attrib(*args, **kwargs) return _wrap_elements(result, self._ef_driver) except Exception as exc: self._listener.on_exception(exc, self._driver) raise try: attrib = getattr(self._webelement, name) return _wrap if callable(attrib) else attrib except Exception as exc: self._listener.on_exception(exc, self._driver) raise # Register a virtual subclass. WebElement.register(EventFiringWebElement) selenium-selenium-4.18.1/selenium/webdriver/support/__init__.py0000644000175000017500000000142314564764517024607 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. selenium-selenium-4.18.1/selenium/webdriver/support/events.py0000644000175000017500000000163014564764517024354 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from .abstract_event_listener import AbstractEventListener # noqa from .event_firing_webdriver import EventFiringWebDriver # noqa selenium-selenium-4.18.1/selenium/webdriver/support/relative_locator.py0000644000175000017500000001337214564764517026414 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from typing import Dict from typing import List from typing import Optional from typing import Union from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement def with_tag_name(tag_name: str) -> "RelativeBy": """Start searching for relative objects using a tag name. Note: This method may be removed in future versions, please use `locate_with` instead. :Args: - tag_name: the DOM tag of element to start searching. :Returns: - RelativeBy - use this object to create filters within a `find_elements` call. """ if not tag_name: raise WebDriverException("tag_name can not be null") return RelativeBy({"css selector": tag_name}) def locate_with(by: By, using: str) -> "RelativeBy": """Start searching for relative objects your search criteria with By. :Args: - by: The value from `By` passed in. - using: search term to find the element with. :Returns: - RelativeBy - use this object to create filters within a `find_elements` call. """ assert by is not None, "Please pass in a by argument" assert using is not None, "Please pass in a using argument" return RelativeBy({by: using}) class RelativeBy: """Gives the opportunity to find elements based on their relative location on the page from a root elelemt. It is recommended that you use the helper function to create it. Example: lowest = driver.find_element(By.ID, "below") elements = driver.find_elements(locate_with(By.CSS_SELECTOR, "p").above(lowest)) ids = [el.get_attribute('id') for el in elements] assert "above" in ids assert "mid" in ids """ def __init__(self, root: Optional[Dict[Union[By, str], str]] = None, filters: Optional[List] = None): """Creates a new RelativeBy object. It is preferred if you use the `locate_with` method as this signature could change. :Args: root - A dict with `By` enum as the key and the search query as the value filters - A list of the filters that will be searched. If none are passed in please use the fluent API on the object to create the filters """ self.root = root self.filters = filters or [] def above(self, element_or_locator: Union[WebElement, Dict] = None) -> "RelativeBy": """Add a filter to look for elements above. :Args: - element_or_locator: Element to look above """ if not element_or_locator: raise WebDriverException("Element or locator must be given when calling above method") self.filters.append({"kind": "above", "args": [element_or_locator]}) return self def below(self, element_or_locator: Union[WebElement, Dict] = None) -> "RelativeBy": """Add a filter to look for elements below. :Args: - element_or_locator: Element to look below """ if not element_or_locator: raise WebDriverException("Element or locator must be given when calling below method") self.filters.append({"kind": "below", "args": [element_or_locator]}) return self def to_left_of(self, element_or_locator: Union[WebElement, Dict] = None) -> "RelativeBy": """Add a filter to look for elements to the left of. :Args: - element_or_locator: Element to look to the left of """ if not element_or_locator: raise WebDriverException("Element or locator must be given when calling to_left_of method") self.filters.append({"kind": "left", "args": [element_or_locator]}) return self def to_right_of(self, element_or_locator: Union[WebElement, Dict] = None) -> "RelativeBy": """Add a filter to look for elements right of. :Args: - element_or_locator: Element to look right of """ if not element_or_locator: raise WebDriverException("Element or locator must be given when calling to_right_of method") self.filters.append({"kind": "right", "args": [element_or_locator]}) return self def near(self, element_or_locator_distance: Union[WebElement, Dict, int] = None) -> "RelativeBy": """Add a filter to look for elements near. :Args: - element_or_locator_distance: Element to look near by the element or within a distance """ if not element_or_locator_distance: raise WebDriverException("Element or locator or distance must be given when calling near method") self.filters.append({"kind": "near", "args": [element_or_locator_distance]}) return self def to_dict(self) -> Dict: """Create a dict that will be passed to the driver to start searching for the element.""" return { "relative": { "root": self.root, "filters": self.filters, } } selenium-selenium-4.18.1/selenium/webdriver/support/ui.py0000644000175000017500000000153714564764517023473 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from .select import Select # noqa from .wait import WebDriverWait # noqa selenium-selenium-4.18.1/selenium/webdriver/support/wait.py0000644000175000017500000001230114564764517024011 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import time import typing from typing import Callable from typing import Generic from typing import Literal from typing import TypeVar from typing import Union from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import TimeoutException from selenium.types import WaitExcTypes from selenium.webdriver.remote.webdriver import WebDriver from selenium.webdriver.remote.webelement import WebElement POLL_FREQUENCY: float = 0.5 # How long to sleep in between calls to the method IGNORED_EXCEPTIONS: typing.Tuple[typing.Type[Exception]] = (NoSuchElementException,) # default to be ignored. D = TypeVar("D", bound=Union[WebDriver, WebElement]) T = TypeVar("T") class WebDriverWait(Generic[D]): def __init__( self, driver: D, timeout: float, poll_frequency: float = POLL_FREQUENCY, ignored_exceptions: typing.Optional[WaitExcTypes] = None, ): """Constructor, takes a WebDriver instance and timeout in seconds. :Args: - driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote) or a WebElement - timeout - Number of seconds before timing out - poll_frequency - sleep interval between calls By default, it is 0.5 second. - ignored_exceptions - iterable structure of exception classes ignored during calls. By default, it contains NoSuchElementException only. Example:: from selenium.webdriver.support.wait import WebDriverWait \n element = WebDriverWait(driver, 10).until(lambda x: x.find_element(By.ID, "someId")) \n is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).\\ \n until_not(lambda x: x.find_element(By.ID, "someId").is_displayed()) """ self._driver = driver self._timeout = float(timeout) self._poll = poll_frequency # avoid the divide by zero if self._poll == 0: self._poll = POLL_FREQUENCY exceptions = list(IGNORED_EXCEPTIONS) if ignored_exceptions: try: exceptions.extend(iter(ignored_exceptions)) except TypeError: # ignored_exceptions is not iterable exceptions.append(ignored_exceptions) self._ignored_exceptions = tuple(exceptions) def __repr__(self): return f'<{type(self).__module__}.{type(self).__name__} (session="{self._driver.session_id}")>' def until(self, method: Callable[[D], Union[Literal[False], T]], message: str = "") -> T: """Calls the method provided with the driver as an argument until the \ return value does not evaluate to ``False``. :param method: callable(WebDriver) :param message: optional message for :exc:`TimeoutException` :returns: the result of the last call to `method` :raises: :exc:`selenium.common.exceptions.TimeoutException` if timeout occurs """ screen = None stacktrace = None end_time = time.monotonic() + self._timeout while True: try: value = method(self._driver) if value: return value except self._ignored_exceptions as exc: screen = getattr(exc, "screen", None) stacktrace = getattr(exc, "stacktrace", None) time.sleep(self._poll) if time.monotonic() > end_time: break raise TimeoutException(message, screen, stacktrace) def until_not(self, method: Callable[[D], T], message: str = "") -> Union[T, Literal[True]]: """Calls the method provided with the driver as an argument until the \ return value evaluates to ``False``. :param method: callable(WebDriver) :param message: optional message for :exc:`TimeoutException` :returns: the result of the last call to `method`, or ``True`` if `method` has raised one of the ignored exceptions :raises: :exc:`selenium.common.exceptions.TimeoutException` if timeout occurs """ end_time = time.monotonic() + self._timeout while True: try: value = method(self._driver) if not value: return value except self._ignored_exceptions: return True time.sleep(self._poll) if time.monotonic() > end_time: break raise TimeoutException(message) selenium-selenium-4.18.1/selenium/webdriver/support/select.py0000644000175000017500000002244114564764517024332 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from typing import List from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import UnexpectedTagNameException from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement class Select: def __init__(self, webelement: WebElement) -> None: """Constructor. A check is made that the given element is, indeed, a SELECT tag. If it is not, then an UnexpectedTagNameException is thrown. :Args: - webelement - SELECT element to wrap Example: from selenium.webdriver.support.ui import Select \n Select(driver.find_element(By.TAG_NAME, "select")).select_by_index(2) """ if webelement.tag_name.lower() != "select": raise UnexpectedTagNameException(f"Select only works on Selenium 2.52.0 * Fixing case where UnexpectedAlertException doesn't get the alert_text in the error object * Firefox: Actually use launch_browser timeout Fixes #1300 Selenium 2.51.1 * correcting bundling issue missing README.rst file Selenium 2.51.0 * Firefox updates (see java changelog) Selenium 2.50.1 * Fixing error message handling. Fixes issue #1497 * Fixing error message handling. Fixes issue #1507 * Update webelement to handle W3C commands for size/location and rect * rewrite click scrolling tests to match the Java ones Selenium 2.50.0 * handle potential URLError from sending shutdown, set self.process to None after it's already been quit * Add support for submit() with W3C compliant endpoint Selenium 2.49.1 * Ensure you can close stream before attempting to close it. * message response may cause json loads ValueError when it's not actually json and just a string (like the message that occurs when firefox driver thinks another element will receive the click) * Cleanup some error handling when sniffing what protocol you are speaking Selenium 2.49.0 * Have Firefox service write to a file instead of PIPE * on osx for firefox, fallback to checking homebrew install, if the default isn't there * Added Firefox path variable for string placeholder * Update README to show Python 3.2+ * refactoring all the service classes to use a common one. * Add Firefox specific command to switch context between Browser content and Browser chrome * updating files after go copyright:update * Use specificationLevel to know that we are speaking GeckoDriver * Bug fixes: #1294, #1186 Selenium 2.48.0 * Update error pulling to match spec when we encounter a spec compliant browser. * Disable tests that are not working with Marionette when running Marionette tests * Add the ability to run python marionette tests * Python 3 compatibility for remote Authorization * changing casing of children finding tests Selenium 2.47.3 * Bring back py 3 support Selenium 2.47.2 * Fix running Edge driver locally on win10 * adding repr to WebDriver and WebElement Selenium 2.47.1 * Fix the issue of deleting the profile when shutting down Firefox * WebElement **eq** compares against more types * Issues fixed: 850 Selenium 2.47.0 * Add in support for when communicating with a Spec compliant browsers * Initial support for Edge using EdgeDriver * Issues fixed: 818 Selenium 2.46.1 * Adding ability to make remote call for webelement screenshots in accordance to the W3C spec * Adding api to authenticate HTTP Auth modal dialogs via driver.switch_to.alert (beta) * Add rebeccapurple to Color Object * Add element screenshot * Add service handler and minimal update to driver to use service for Marionette * Add the ability to start FirefoxDriver backed with Marionette via a capability * support socket timeout for connections * free_port checks if port is available on all interfaces * Allow error handling to handle both current errors and w3c errors * Update find_elements to match spec * phantomjs: service: remove unused import of signal * phantomjs: add port information to WebDriverException * Issues fixed (Github): 478, 612, 734, 780 Selenium 2.46.0 * Firefox support up to 38 * BlackBerry browser support * remove Presto-Opera support * firefox extension extraction fixes * process management fixes with phantomjs * Comparing remote web element for equality does not require a remote command * Issues Fixed: (gcode) 8493, 8521, 8498, 8274, 8497, 5923 * Issues Fixed: (github) 401 Selenium 2.45.0 * Firefox support up to 35, support for native events up to 34. * Make Opera driver support also the new Blink based Opera * README: Fix the Yahoo example * WebElement docstring fixes * Add debugger_address option to the ChromeDriver options list to optionally instruct ChromeDriver to wait for the target devtools instance to be started at a given host:ip * Set default value for PhantomJS process reference * Allow setting of FileDetector for send_keys * Pass info to TimeoutException in WebDriverWait * Issues Fixed: 8065, 8310, 8539 Selenium 2.44.0 * (previous release person forgot to add release notes! DAVID!) Selenium 2.43.0 * Expand WebElement.get_attribute API docs * firefox may be installed without administrator privileges and therefore there may be no HKEY_LOCAL_MACHINE entry. Issue #7784 * UnexpectedAlertPresentException should contain the alert text in python too. Issue #7745 * don't mutate the global 'ignored exceptions', take a copy of the globally specified ones, change the global to be a tuple instead. Issue #7725 * raise exception when the firefox binary isn't actually found, which usually implies the upgrade failed (on windows) Issue #6092 ,#6847 * Fixing NameError: global name 'options' is not defined. * Remove unused import subprocess.PIPE * Redirect Firefox output to /dev/null by default Fixes Issue #7677 * More flexible management of http timeouts in Selenium RC python client * Generate Python API docs for selenium.webdriver.chrome.options. Fixes issue #7471 * Use 127.0.0.1 as localhost name resolving might fail on some systems Selenium 2.42.1 * Fixed Py3 issues * Make firefox_binary.py and firefox_profile.py not executable * Make exceptions Python 3 compatible Selenium 2.42 * Support for Firefox 29 Native Events * "remote_url" and "remote_browser" parameters for "./go test_remote". * missing **init** in new android module * issue #7304 Fix memory leak caused by **del** in PhantomJS * File upload using remotedriver on python3 * Updating xpi install to align with mozprofile * command_executor should also support unicode strings as well. Selenium 2.41 * Support for Firefox 28 * deprecating switch_to_* in favour of driver.switch_to.* Selenium 2.40 * Support for Firefox 27 * Fixes related to http connection * Fix for phantomjs running on windows #6736 Selenium 2.39 * Support for Firefox 26 Selenium 2.38.4 * keep-alive can't be used for phantomjs / IE, fix for that and tested for py3 :) Selenium 2.38.3 * really supporting py3 :) Selenium 2.38.2 * py3 support (once again) Selenium 2.38.1 * fix packaging problem where firefox/webdriver_prefs.json was missing Selenium 2.38 * Support for Firefox 25 * FirefoxProfile now using common webdriver.json instead of having our own copy in py * behavior change to the preferences is that they now should be treated like raw types rather than strings and allow the json library to translate the types appropriated (e.g. True => true) * Set proper 'Accept' request header so that Python bindings work with some old WebDriver implementations that reply 404 to requests with no 'Accept' set. * handle redirect response explicitly (since switching to using keep-alive) * phantomjs service needs to really kill the spawned process Issue #5921 * removing old api endpoints from command listing * using keep-alive for remote connection * adjusting phantomjs subprocess.Popen * ActionsChains.send_keys should use /keys endpoint Issue #6348 * fix TypeError in chrome_options.extensions for Python3.x * Other Bugs Fixed: #6531, #6513, #4569, #6454 Selenium 2.37.2 * fix regression added with unicode fix * Bug fix #6360 Selenium 2.37.1 * fix find_elements on webelement using unicode locators and py 2.7 Selenium 2.37 * repackage with fix for Firefox native events on Linux * fix issue with unicode By locators w/ python 2.7 #6430 Selenium 2.36 * Added Safari WebDriver. Fixes issue 5352. * fix platform for safari caps * Convert all offsets/coordinates/speeds into integers * Fix drag and drop by offset behaviour * Fix initialization of Proxy by capabilities when proxyType is set * Enable SOCKS proxy support * Validation of passed locator for find_element(s) methods #5690 * Adding support for /status, /sessions commands * Doc fixes * ability to set Chrome extensions by using base64 encoded strings #4013 * fix logic regarding Select.select_by_visible_text #3910 * Bugs fixed: #6165, #6231 Selenium 2.35 * Remove duplicate 'get screenshot as file' methods. Add method 'get_screenshot_as_png' * fixing UnicodeEncodeError on get attribute of webelement Selenium 2.34 * Corrected webdriverbackedselenium session handling. Fixes issue 4283 * Corrected use of basestring for python 3. Fixes issue 5924 * Support for Firefox 22 * Added support for logging from the browser * corrected proxy handling on FirefoxProfile * Corrected handling of chrome extensions. Fixes issue 5762 Selenium 2.33 * getText() ignores elements in the * Adding both official and informal string representations to Color object. * Replace distutils.dir_util by shutil * Allow finding firefox binary at ProgramFiles(x86) on windows(64 bit) * Py3 compatible winreg import and content-type access Selenium 2.32 * Support for FF20 Native Events * Python 3 support * Misc Python 3 patches * Allow easy FirefoxBinary subclassing Selenium 2.31 * Support for FF19 native events * web element equality is now in conformance with other language bindings Selenium 2.30 * Allow env to be specified for the chromedriver service * Allow log path to be specified for phantomjs driver service. * Bug Fixes: 4608 4940 4974 5034 5075 Selenium 2.29 * Allow subclassing of driver and have the ability to send_keys Issue 4877, 5017 * Simplifying save_screenshot and allow phantomjs to take screenshots Selenium 2.28 * "null" can now be passed to executeScript * Add transparent and extended colour keywords to color support module. Fixes issue 4866 Selenium 2.27 * Added support for phantomjs / ghostdriver * Fix python client, avoid duplicate chrome option items after reusing options class. Fixes Issue 4744. * adding colour support to Python. fixes issue 4623 * Adding log_path/service_log_path as named kwargs for chrome Selenium 2.26 * Added location_when_scrolled_into_view - Bug 4357 * Added new expected_conditions support module to be used with WebDriverWait Selenium 2.25 * Jython 2.7 Support - Bug 3988 * EventFiringWebDriver added to Support module - Bug 2267 * Added IEDriverServer logging that can be accessed via desired capabilities * Fixed by data being passed into find_elements - bug 3735 * Removed deprecated ChromeDriver items around desiredcapabilities in favour of chrome options * Added default values for a number of action_chains calls Selenium 2.24 * Removing the ctypes approach of invoking IEDriver, you will need to download the IEDriverServer from Selenium 2.23 * Support for FF13 native events Selenium 2.22 * Moving IEDriver to be able to use IEDriverServer Selenium 2.21.3 * Fix for File Upload to remote servers * Better handling of typing in input=file. Bug 3831, 3736 * Better handling of unicode URLS Bug 3740 Selenium 2.21.2 * Fix typing to file input when not using Selenium Server. Bug 3736 Selenium 2.21.1 * focusmanager.testmode messes with native events, removing it. Selenium 2.21 * Local File upload capabilities for non-remote browser * Adding maximize_window api call * Updating default firefox profile to set focusmanager.testmode to true see * bugs fixed: 3506, 3528, 3607 Selenium 2.20 * disable native events for FF on Mac by default * fix webdriverwait to execute at least once when using 0 timeout * Fixed Issue 3438 Selenium 2.19 * WebDriverBackedSelenium is now available to all languages * Addon installation fixes Selenium 2.18 * Proxy capabilities passing Selenium 2.17 * OperaDriver can now be invoked by webdriver.Opera() * Support has been added for ChomeOptions. This deprecates support passing in DesiredCapabilities * Proxy class to tell the browser a proxy is in use. Currently only for Firefox Selenium 2.16 * bug fixes Selenium 2.15 * bug fixes Selenium 2.14 * Fix for LD_PRELOAD being polluted by WebDriver * Added Orientation API * A fix for Error Handling Selenium 2.13 * Fixed switch_to_window so that it didn't crash Firefox Bug 2633 * Fixed Screenshot handling to work in all browsers. Bug 2829 * Force Firefox to the Foreground Selenium 2.12 * Added Select as a support package * Added Beta window size / position api's * Bug Fixes Selenium 2.11.0 2.11.1 * no changes just packaging Selenum 2.10 * "Choose which apps" dialog has been disabled * Bug Fixes Selenium 2.9 * Bug Fixes * Documentation Selenium 2.8 * Actions updates * Bug Fixes Selenium 2.6 * Documentation fixes Selenium 2.5 * Fixed x64 IE Support * Bug Fixes Selenium 2.4 * Bug Fixes * x64 IE Support * Added WebDriverWait as a support package Selenium 2.3 * Bug Fixes Selenium 2.2 * Ability to get screenshots from Exceptions if they are given * Access to Remote StackTrace on error Selenium 2.1 * Bug Fixes Selenium 2 * Removed toggle() and select() Selenium 2 RC 3 * Added Opera to Desired Capabilities * Removed deprecrated methods * Deprecated toggle() and select() methods. This will be removed in the next release Selenium 2 Beta 4 * Fix for using existing Firefox Profiles * Alerts Support in IE * Fix to dictionary returned from size * Deprecated value property. Use the get_attribute("value") method * Deprecated get_page_source method. Use page_source property * Deprecated get_current_window_handle. Use current_window_handle property * Deprecated get_window_handles. Use window_handles property * Ability to install extensions into profiles * Added Location to the WebElement * ChromeDriver rewritten to use new built in mechanism * Added Advanced User Interaction API. Only Available for HTMLUnit at the moment * Profiles now delete their temp folders when driver.quit() is called Selenium 2 Beta 3 * Accept Untrusted Certificates in Firefox * Fixed Screenshots * Added DesiredCapabilities to simplify choosing Drivers * Fixed Firefox Profile creation * Added Firefox 4 support * DocStrings Improvements Selenium 2 Beta 2 * New bindings landed. Change webdriver namespace to "selenium.webdriver" * Ability to move to default content * Implicit Waits * Change the API to use properties instead of get_x * Changed the Element Finding to match other languages * Added ability to execute asynchronous scripts from the driver * Ability to get rendered element size * Ability to get CSS Value on a webelement * Corrected Element finding from the element * Alert and Prompt handling * Improved IEDriver * Basic Authentication support for Selenium 2 * Ability to have multiple Firefox instances selenium-selenium-4.18.1/README.rst0000777000175000017500000000000014564764517022725 2docs/source/index.rstustar carstencarstenselenium-selenium-4.18.1/pytest.ini0000644000175000017500000000112014564764517017173 0ustar carstencarsten[pytest] console_output_style = progress faulthandler_timeout = 60 log_cli = True trio_mode = true markers = xfail_chrome: Tests expected to fail in Chrome xfail_chromiumedge: Tests expected to fail in Chromium Edge xfail_firefox: Tests expected to fail in Firefox xfail_ie: Tests expected to fail in IE xfail_remote: Tests expected to fail with Remote webdriver xfail_safari: Tests expected to fail in Safari xfail_webkitgtk: Tests expected to fail in webkitgtk no_driver_after_test: If there are no drivers after the test it will create a new one. addopts = selenium-selenium-4.18.1/python.iml0000644000175000017500000000223214564764517017173 0ustar carstencarsten selenium-selenium-4.18.1/setup.py0000755000175000017500000000672514564764517016677 0ustar carstencarsten# Licensed to the Software Freedom Conservancy (SFC) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The SFC licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from distutils.command.install import INSTALL_SCHEMES from os.path import dirname, join, abspath from setuptools import setup from setuptools.command.install import install for scheme in INSTALL_SCHEMES.values(): scheme['data'] = scheme['purelib'] setup_args = { 'cmdclass': {'install': install}, 'name': 'selenium', 'version': "4.18.1", 'license': 'Apache 2.0', 'description': 'Python bindings for Selenium', 'long_description': open(join(abspath(dirname(__file__)), "README.rst")).read(), 'url': 'https://github.com/SeleniumHQ/selenium/', 'project_urls': { 'Bug Tracker': 'https://github.com/SeleniumHQ/selenium/issues', 'Changes': 'https://github.com/SeleniumHQ/selenium/blob/trunk/py/CHANGES', 'Documentation': 'https://www.selenium.dev/documentation/overview/', 'Source Code': 'https://github.com/SeleniumHQ/selenium/tree/trunk/py', }, 'python_requires': '~=3.8', 'classifiers': ['Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Operating System :: POSIX', 'Operating System :: Microsoft :: Windows', 'Operating System :: MacOS :: MacOS X', 'Topic :: Software Development :: Testing', 'Topic :: Software Development :: Libraries', 'Programming Language :: Python', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12'], 'package_dir': { 'selenium': 'selenium', 'selenium.common': 'selenium/common', 'selenium.webdriver': 'selenium/webdriver', }, 'packages': ['selenium', 'selenium.common', 'selenium.webdriver', 'selenium.webdriver.chromium', 'selenium.webdriver.chrome', 'selenium.webdriver.common', 'selenium.webdriver.support', 'selenium.webdriver.firefox', 'selenium.webdriver.ie', 'selenium.webdriver.edge', 'selenium.webdriver.remote', 'selenium.webdriver.support', ], 'include_package_data': True, 'install_requires': [ "typing_extensions~= 4.9", "urllib3[socks]>=1.26,<3", "trio~=0.17", "trio-websocket~=0.9", "certifi>=2021.10.8", ], 'zip_safe': False } setup(**setup_args)