Skip to content

Commit

Permalink
Add safari driver (#1220)
Browse files Browse the repository at this point in the history
* Add safari driver

* Add test for Safari remote

* Add MacOS CI

* Add more params for safari

* Change order of hub and node

* Add wait for selenium hub up for macos

* Add logs for hub and node

* Fix selenium filename

* Add timeout util for mac

* Install java for macos

* Debug java version

* Check java version other way

* Other way of java installation

* Try to reinstall java

* Try to install java11

* Try to run with java 11

* Rewrite all tests requested for new browser for safari

* Patch multisession tests instead of rewriting

* Add return to main page for test

* Check async element present on the page

* Move with statement test to setup for Safari

* Add particular browser selector for remote browsers

* Mark click test with xfail for Safari

* Skip one more test

* Add return to main page

* xfail one more click

* Add missed import

* Fix formatting

* Add macos filter for tox

* Add pytest markers

* Set parallel to 1 for macos to avoid new tab problem

* Try to limit parallel jobs

* Make explicit visit of main page for tab test

* Add test click to xfail

* Try to rerun failed tests

* Try to rerun less failed tests

* Clear cache before test run

* Run google search only if called directly

* Remove visit of main page in start of tests

* Add reason of skipping for user agent

* Remove all matrix limits
  • Loading branch information
Andmedoctopus committed Jan 9, 2024
1 parent 734f9ef commit ac7263b
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 7 deletions.
64 changes: 64 additions & 0 deletions .github/workflows/macos.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: CI-MacOS

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
selenium:
runs-on: macos-latest

strategy:
matrix:
include:
- PY_VER: py38
python-version: 3.8
- PY_VER: py39
python-version: 3.9
- PY_VER: py310
python-version: "3.10"
- PY_VER: py311
python-version: 3.11
- PY_VER: py312
python-version: "3.12"

steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4

- uses: actions/setup-python@v4
with:
python-version: ${{matrix.python-version}}

- name: Install test dependencies
run: pip install tox

- name: Enable Safari Webdriver
run: |
defaults write com.apple.Safari IncludeDevelopMenu YES
defaults write com.apple.Safari AllowRemoteAutomation 1
sudo safaridriver --enable
- name: Install timeout util and java
run: |
brew install coreutils
brew install java11
- name: Download Selenium Server
run: |
wget https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.16.0/selenium-server-4.16.1.jar -O selenium-server.jar
- name: Setup standalone
run: /usr/local/opt/openjdk@11/bin/java -jar selenium-server.jar standalone -I 'safari' > selenium-standalone.log 2>&1 &


- name: Run tests for macos
run: |
gtimeout 60 bash -c 'while ! wget -O /dev/null -T 1 http://localhost:4444/readyz; do echo waiting for selenium server; sleep 1; done' || (cat selenium-standalone.log && exit 2)
tox -e tests_macos_selenium -- --cache-clear -n 1 tests || tox -e tests_macos_selenium -- -n 1 --last-failed --last-failed-no-failures none
3 changes: 3 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[pytest]
markers =
macos: tests can be runned only on MacOS (Safari)
3 changes: 2 additions & 1 deletion samples/test_google_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ def test_filling_splinter_in_the_search_box_returns_splinter_website(self):
self.assertTrue(self.browser.is_text_present("https://splinter.readthedocs.io"))


unittest.main()
if __name__ == "__main__":
unittest.main()
8 changes: 8 additions & 0 deletions splinter/driver/webdriver/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from splinter.driver.webdriver.setup import _setup_chrome
from splinter.driver.webdriver.setup import _setup_edge
from splinter.driver.webdriver.setup import _setup_firefox
from splinter.driver.webdriver.setup import _setup_safari

# MonkeyPatch RemoteConnection
remote_connection.RemoteConnection._request = patch_request # type: ignore
Expand Down Expand Up @@ -64,5 +65,12 @@ def __init__(

options = options or Options()
driver = _setup_firefox(Remote, self.config, options, **kwargs)
elif browser_name == "SAFARI":
from selenium.webdriver.safari.options import Options

options = options or Options()
driver = _setup_safari(Remote, self.config, options, **kwargs)
else:
raise ValueError(f"Unsupporeted browser {browser_name}")

super().__init__(driver, wait_time)
12 changes: 12 additions & 0 deletions splinter/driver/webdriver/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,15 @@ def _setup_firefox(driver_class, config=None, options=None, service=None, **kwar
rv.fullscreen_window()

return rv


def _setup_safari(driver_class, config=None, options=None, service=None, **kwargs):
"""
Returns: selenium.webdriver.Safari || selenium.webdriver.Remote
"""
if driver_class == Remote:
rv = driver_class(options=options, **kwargs)
else:
rv = driver_class(options=options, service=service, **kwargs)

return rv
2 changes: 1 addition & 1 deletion tests/is_element_present.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def test_is_element_present_by_xpath_returns_false_if_element_is_not_present(sel
def test_is_element_not_present_by_xpath_returns_false_if_element_is_present(self):
"""should is_element_not_present_by_xpath returns False if element is present"""
self.browser.find_by_css(".add-async-element").click()
self.browser.find_by_xpath("//h4")
assert len(self.browser.find_by_xpath("//h4")) > 0
assert not self.browser.is_element_not_present_by_xpath("//h4")

def test_is_element_not_present_by_xpath_using_a_custom_wait_time(self):
Expand Down
169 changes: 165 additions & 4 deletions tests/test_webdriver_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
import unittest
from unittest.mock import patch
from urllib.request import urlopen

import pytest
Expand Down Expand Up @@ -32,11 +33,11 @@ def setUp(self):

def test_support_with_statement(self):
"Remote should support with statement"
with Browser("remote"):
with Browser("remote", browser="firefox"):
pass

@pytest.mark.skip(reason="Remote should not support custom user agent")
def test_should_be_able_to_change_user_agent(self):
"Remote should not support custom user agent"
pass


Expand All @@ -51,9 +52,169 @@ def setUp(self):

def test_support_with_statement(self):
"Remote should support with statement"
with Browser("remote"):
with Browser("remote", browser="chrome"):
pass

@pytest.mark.skip(reason="Remote should not support custom user agent")
def test_should_be_able_to_change_user_agent(self):
"Remote should not support custom user agent"
pass


@pytest.mark.macos
class RemoteBrowserSafariTest(WebDriverTests, unittest.TestCase):
@pytest.fixture(autouse=True, scope="class")
def setup_browser(self, request):
# test with statement. It can't be used as simple test
# because safari doesn't support multisessions
with Browser("remote", browser="safari"):
pass

request.cls.browser = Browser("remote", browser="safari")
request.addfinalizer(request.cls.browser.quit)

def setUp(self):
self.browser.visit(EXAMPLE_APP)

def test_support_with_statement(self):
"""
Remote should support with statement
See setup browser
"""

@pytest.mark.skip(reason="Remote should not support custom user agent")
def test_should_be_able_to_change_user_agent(self):
pass

# ------- BEGIN OF MULTISESSION TESTS -------
# Safari doesn't support multisessions.
# So next tests mock quit of browser.
def get_new_browser(self):
return self.browser

def test_can_forward_on_history(self):
with patch("splinter.driver.webdriver.remote.WebDriver.quit"):
super().test_can_forward_on_history()

def test_create_and_access_a_cookie(self):
with patch("splinter.driver.webdriver.remote.WebDriver.quit"):
super().test_create_and_access_a_cookie()

def test_create_many_cookies_at_once_as_dict(self):
with patch("splinter.driver.webdriver.remote.WebDriver.quit"):
super().test_create_many_cookies_at_once_as_dict()

def test_create_some_cookies_and_delete_them_all(self):
with patch("splinter.driver.webdriver.remote.WebDriver.quit"):
super().test_create_some_cookies_and_delete_them_all()

def test_create_and_delete_a_cookie(self):
with patch("splinter.driver.webdriver.remote.WebDriver.quit"):
super().test_create_and_delete_a_cookie()

def test_create_and_delete_many_cookies(self):
with patch("splinter.driver.webdriver.remote.WebDriver.quit"):
super().test_create_and_delete_many_cookies()

def test_try_to_destroy_an_absent_cookie_and_nothing_happens(self):
with patch("splinter.driver.webdriver.remote.WebDriver.quit"):
super().test_try_to_destroy_an_absent_cookie_and_nothing_happens()

def test_create_and_get_all_cookies(self):
with patch("splinter.driver.webdriver.remote.WebDriver.quit"):
super().test_create_and_get_all_cookies()

def test_create_and_use_contains(self):
with patch("splinter.driver.webdriver.remote.WebDriver.quit"):
super().test_create_and_use_contains()

# ------- END OF MULTISESSION TESTS -------

def test_can_fill_more_than_one_field_in_form(self):
"should provide a away to change field value"
self.browser.fill("query", "my name")
self.assertFalse(self.browser.find_by_id("gender-m").checked)
self.assertFalse(self.browser.find_option_by_value("rj").selected)
self.assertFalse(self.browser.find_by_name("some-check").checked)
self.assertTrue(self.browser.find_by_name("checked-checkbox").checked)
# Select of dropdown doesn't work for Safari 17 (remote). Safari as OS user works well
# for some reason select doesn't work for Safari
self.browser.fill_form(
{
"query": "another new query",
"description": "Just another description value in the textarea",
"gender": "M",
# "uf": "rj",
"some-check": True,
"checked-checkbox": False,
},
)
query_value = self.browser.find_by_name("query").value
self.assertEqual("another new query", query_value)
desc_value = self.browser.find_by_name("description").value
self.assertEqual("Just another description value in the textarea", desc_value)
self.assertTrue(self.browser.find_by_id("gender-m").checked)
# self.assertTrue(self.browser.find_option_by_value("rj").selected)
self.assertTrue(self.browser.find_by_name("some-check").checked)
self.assertFalse(self.browser.find_by_name("checked-checkbox").checked)

# ------- BEGIN OF CLICK PROBLEM TESTS -------
# https://stackoverflow.com/questions/77388720/automation-testing-with-selenium-click-doesnt-works-on-new-safari-17-ios-sonoma
@pytest.mark.xfail
def test_click_element_by_css_selector(self):
super().test_click_element_by_css_selector()

@pytest.mark.xfail
def test_click_input_by_css_selector(self):
super().test_click_input_by_css_selector()

@pytest.mark.xfail
def test_clicking_submit_button_doesnt_post_button_value_if_empty(self):
super().test_clicking_submit_button_doesnt_post_button_value_if_empty()

@pytest.mark.xfail
def test_clicking_submit_button_doesnt_post_button_value_if_name_not_present(self):
super().test_clicking_submit_button_doesnt_post_button_value_if_name_not_present()

@pytest.mark.xfail
def test_clicking_submit_button_posts_button_value_if_value_present(self):
super().test_clicking_submit_button_posts_button_value_if_value_present()

@pytest.mark.xfail
def test_clicking_submit_button_posts_empty_value_if_value_not_present(self):
super().test_clicking_submit_button_posts_empty_value_if_value_not_present()

@pytest.mark.xfail
def test_clicking_submit_input_doesnt_post_input_value_if_empty(self):
super().test_clicking_submit_input_doesnt_post_input_value_if_empty()

@pytest.mark.xfail
def test_clicking_submit_input_doesnt_post_input_value_if_name_not_present(self):
super().test_clicking_submit_input_doesnt_post_input_value_if_name_not_present()

@pytest.mark.xfail
def test_clicking_submit_input_posts_empty_value_if_value_not_present(self):
super().test_clicking_submit_input_posts_empty_value_if_value_not_present()

@pytest.mark.xfail
def test_clicking_submit_input_posts_input_value_if_value_present(self):
super().test_clicking_submit_input_posts_input_value_if_value_present()

@pytest.mark.xfail
def test_submiting_a_form_and_verifying_page_content(self):
super().test_submiting_a_form_and_verifying_page_content()

@pytest.mark.xfail
def test_click_links(self):
super().test_click_links()

# ------- END OF CLICK PROBLEM TESTS -------
# ------- START OF TYPE PROBLEM TESTS -------
@pytest.mark.xfail
def test_simple_type(self):
super().test_simple_type()

@pytest.mark.xfail
def test_simple_type_on_element(self):
super().test_simple_type_on_element()

# ------- END OF TYPE PROBLEM TESTS -------
9 changes: 8 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ extras = selenium
deps =
-rrequirements/test.txt
commands=
pytest --ignore-flaky -v {posargs}
pytest --ignore-flaky -m "not macos" -v {posargs}


[testenv:tests_windows_selenium]
Expand All @@ -21,3 +21,10 @@ passenv =
EDGEWEBDRIVER
commands=
pytest --ignore-flaky -v {posargs}

[testenv:tests_macos_selenium]
extras = selenium
deps =
-rrequirements/test.txt
commands=
pytest --ignore-flaky -m macos -v {posargs}

0 comments on commit ac7263b

Please sign in to comment.