Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync implementation #89

Merged
merged 6 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: 3.x
python-version: 3.11
- uses: actions/cache@v3
with:
path: ~/.cache/pip
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
restore-keys: v1/${{ runner.os }}/pypi-${matrix.python}/
- uses: actions/setup-node@v3
with:
node-version: 14
node-version: 16
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
Expand Down
7 changes: 4 additions & 3 deletions percy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ def percy_screenshot(driver, name, **kw):
raise UnsupportedWebDriverException("Provided driver is not supported")

if "RemoteConnection" in driver.command_executor.__class__.__name__:
percy_automate_screenshot(driver, name, **kw)
elif "AppiumConnection" in driver.command_executor.__class__.__name__:
return percy_automate_screenshot(driver, name, **kw)
if "AppiumConnection" in driver.command_executor.__class__.__name__:
try:
from percy.screenshot import percy_screenshot # pylint: disable=W0621,C0415
percy_screenshot(driver, name, **kw)
return percy_screenshot(driver, name, **kw)
except ImportError as exc:
raise ModuleNotFoundError("[percy] `percy-appium` package is not installed, "\
"please install it to use percy_screenshot command with appium") from exc
return None
14 changes: 10 additions & 4 deletions percy/snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def fetch_percy_dom():
# Take a DOM snapshot and post it to the snapshot endpoint
def percy_snapshot(driver, name, **kwargs):
session_type = is_percy_enabled()
if session_type is False: return # Since session_type can be None for old CLI version
if session_type is False: return None # Since session_type can be None for old CLI version
if session_type == "automate": raise Exception("Invalid function call - "\
"percy_snapshot(). Please use percy_screenshot() function while using Percy with Automate. "\
"For more information on usage of PercyScreenshot, "\
Expand All @@ -79,21 +79,24 @@ def percy_snapshot(driver, name, **kwargs):
'dom_snapshot': dom_snapshot,
'url': driver.current_url,
'name': name
}}, timeout=30)
}}, timeout=600)

# Handle errors
response.raise_for_status()
data = response.json()

if not data['success']: raise Exception(data['error'])
if not data["data"]: return None
return data["data"]
except Exception as e:
print(f'{LABEL} Could not take DOM snapshot "{name}"')
print(f'{LABEL} {e}')
return None

# Take screenshot on driver
def percy_automate_screenshot(driver, name, options = None, **kwargs):
session_type = is_percy_enabled()
if session_type is False: return # Since session_type can be None for old CLI version
if session_type is False: return None # Since session_type can be None for old CLI version
if session_type == "web": raise Exception("Invalid function call - "\
"percy_screenshot(). Please use percy_snapshot() function for taking screenshot. "\
"percy_screenshot() should be used only while using Percy with Automate. "\
Expand Down Expand Up @@ -134,16 +137,19 @@ def percy_automate_screenshot(driver, name, options = None, **kwargs):
'sessionCapabilites': metadata.session_capabilities,
'snapshotName': name,
'options': options
}}, timeout=60)
}}, timeout=600)

# Handle errors
response.raise_for_status()
data = response.json()

if not data['success']: raise Exception(data['error'])
if not data['data']: return None
chinmay-browserstack marked this conversation as resolved.
Show resolved Hide resolved
return data['data']
except Exception as e:
print(f'{LABEL} Could not take Screenshot "{name}"')
print(f'{LABEL} {e}')
return None

def get_element_ids(elements):
return [element.id for element in elements]
59 changes: 50 additions & 9 deletions tests/test_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ def dummy_method1(self):
mock_server_thread.daemon = True
mock_server_thread.start()

# initializing mock data
data_object = {"sync": "true", "diff": 0}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we should mock it properly.



# mock helpers
def mock_healthcheck(fail=False, fail_how='error', session_type=None):
health_body = { "success": True }
Expand Down Expand Up @@ -71,16 +75,25 @@ def mock_healthcheck(fail=False, fail_how='error', session_type=None):
body='window.PercyDOM = { serialize: () => document.documentElement.outerHTML };',
status=200)

def mock_snapshot(fail=False):
def mock_snapshot(fail=False, data=False):
httpretty.register_uri(
httpretty.POST, 'http://localhost:5338/percy/snapshot',
body=('{ "success": ' + ('true' if not fail else 'false, "error": "test"') + '}'),
body = json.dumps({
"success": "false" if fail else "true",
"error": "test" if fail else None,
"data": data_object if data else None
}),
status=(500 if fail else 200))

def mock_screenshot(fail=False):
def mock_screenshot(fail=False, data=False):

httpretty.register_uri(
httpretty.POST, 'http://localhost:5338/percy/automateScreenshot',
body=('{ "success": ' + ('true' if not fail else 'false, "error": "test"') + '}'),
body = json.dumps({
"success": not fail,
"error": "test" if fail else None,
"data": data_object if data else None
}),
status=(500 if fail else 200))

class TestPercySnapshot(unittest.TestCase):
Expand Down Expand Up @@ -154,7 +167,7 @@ def test_posts_snapshots_to_the_local_percy_server(self):
mock_snapshot()

percy_snapshot(self.driver, 'Snapshot 1')
percy_snapshot(self.driver, 'Snapshot 2', enable_javascript=True)
response = percy_snapshot(self.driver, 'Snapshot 2', enable_javascript=True)

self.assertEqual(httpretty.last_request().path, '/percy/snapshot')

Expand All @@ -169,6 +182,30 @@ def test_posts_snapshots_to_the_local_percy_server(self):
s2 = httpretty.latest_requests()[3].parsed_body
self.assertEqual(s2['name'], 'Snapshot 2')
self.assertEqual(s2['enable_javascript'], True)
self.assertEqual(response, None)

def test_posts_snapshots_to_the_local_percy_server_for_sync(self):
mock_healthcheck()
mock_snapshot(False, True)

percy_snapshot(self.driver, 'Snapshot 1')
response = percy_snapshot(self.driver, 'Snapshot 2', enable_javascript=True, sync=True)

self.assertEqual(httpretty.last_request().path, '/percy/snapshot')

s1 = httpretty.latest_requests()[2].parsed_body
self.assertEqual(s1['name'], 'Snapshot 1')
self.assertEqual(s1['url'], 'http://localhost:8000/')
self.assertEqual(s1['dom_snapshot'], '<html><head></head><body>Snapshot Me</body></html>')
self.assertRegex(s1['client_info'], r'percy-selenium-python/\d+')
self.assertRegex(s1['environment_info'][0], r'selenium/\d+')
self.assertRegex(s1['environment_info'][1], r'python/\d+')

s2 = httpretty.latest_requests()[3].parsed_body
self.assertEqual(s2['name'], 'Snapshot 2')
self.assertEqual(s2['enable_javascript'], True)
self.assertEqual(s2['sync'], True)
self.assertEqual(response, data_object)

def test_has_a_backwards_compatible_function(self):
mock_healthcheck()
Expand Down Expand Up @@ -283,22 +320,25 @@ def test_disables_screenshot_when_the_driver_is_not_selenium(self):

def test_camelcase_options(self):
mock_healthcheck()
mock_screenshot()
mock_screenshot(False, True)

element = Mock(spec=WebElement)
element.id = 'Dummy_id'

consider_element = Mock(spec=WebElement)
consider_element.id = 'Consider_Dummy_id'
percy_screenshot(self.driver, 'Snapshot C', options = {
response = percy_screenshot(self.driver, 'Snapshot C', options = {
"ignoreRegionSeleniumElements": [element],
"considerRegionSeleniumElements": [consider_element]
"considerRegionSeleniumElements": [consider_element],
"sync": "true"
})

s = httpretty.latest_requests()[1].parsed_body
self.assertEqual(s['snapshotName'], 'Snapshot C')
self.assertEqual(s['options']['ignore_region_elements'], ['Dummy_id'])
self.assertEqual(s['options']['consider_region_elements'], ['Consider_Dummy_id'])
self.assertEqual(s['options']['sync'], "true")
self.assertEqual(response, data_object)

def posts_screenshot_to_the_local_percy_server(self, driver):
mock_healthcheck()
Expand All @@ -311,7 +351,7 @@ def posts_screenshot_to_the_local_percy_server(self, driver):
consider_element.id = 'Consider_Dummy_id'

percy_screenshot(driver, 'Snapshot 1')
percy_screenshot(driver, 'Snapshot 2', options = {
response = percy_screenshot(driver, 'Snapshot 2', options = {
"enable_javascript": True,
"ignore_region_selenium_elements": [element],
"consider_region_selenium_elements": [consider_element]
Expand All @@ -334,6 +374,7 @@ def posts_screenshot_to_the_local_percy_server(self, driver):
self.assertEqual(s2['options']['enable_javascript'], True)
self.assertEqual(s2['options']['ignore_region_elements'], ['Dummy_id'])
self.assertEqual(s2['options']['consider_region_elements'], ['Consider_Dummy_id'])
self.assertEqual(response, None)

def test_posts_screenshot_to_the_local_percy_server_remote_connection(self):
self.posts_screenshot_to_the_local_percy_server(self.driver)
Expand Down
Loading