pypi package 'percy-appium-app'

Popularity: Low
Description: Python client for visual testing with Percy for mobile apps
Installation: pip install percy-appium-app
Last version: 0.0.8 (Download)
Homepage: https://github.com/percy/percy-appium-python
Size: 14.47 kB
License: MIT
Keywords: appium, percy, visual, testing

Activity

Last modified: January 17, 2023 1:08 PM (a year ago)
Versions released in one year: 2
Weekly downloads: 7,860
12/11/202202/26/202305/14/202307/30/202310/15/202302,5005,0007,50010,00001234released versions / week
  • Versions released
  • Weekly downloads

What's new in version 0.0.8

Delta between version 0.0.7 and version 0.0.8

Source: Github
Commits:
  • ca5678c9f9f283f77bd99a1cb397ce082383cf2e, January 17, 2023 1:00 PM:
    percyOption fix (#24)
  • 5c613aa89ebda0342c655e3c65fb65b31d5399d7, January 17, 2023 1:00 PM:
    Version 0.0.8 (#25)
Files changed:
percy/lib/percy_options.py CHANGED
@@ -1,15 +1,15 @@
1
  class PercyOptions:
2
  IGNORE_ERRORS = 'ignoreErrors'
3
  ENABLED = 'enabled'
4
- PERCY_OPTIONS = ['percy:options']
5
 
6
  def __init__(self, capabilities):
7
  self._capabilities = capabilities
8
  self.percy_options = self._parse_percy_options() or {}
9
 
10
  def _parse_percy_options(self):
11
  options = list(map(self._capabilities.get, self.PERCY_OPTIONS))
12
- options = (options[0] if options else {}) or {}
13
  if options: return options
14
  if options is not None and self.IGNORE_ERRORS not in options:
15
  options[self.IGNORE_ERRORS] = self._capabilities.get(f'percy.{self.IGNORE_ERRORS}', True)
1
  class PercyOptions:
2
  IGNORE_ERRORS = 'ignoreErrors'
3
  ENABLED = 'enabled'
4
+ PERCY_OPTIONS = ['percy:options', 'percyOptions']
5
 
6
  def __init__(self, capabilities):
7
  self._capabilities = capabilities
8
  self.percy_options = self._parse_percy_options() or {}
9
 
10
  def _parse_percy_options(self):
11
  options = list(map(self._capabilities.get, self.PERCY_OPTIONS))
12
+ options = (options[0] or options[1]) if any(options) else {}
13
  if options: return options
14
  if options is not None and self.IGNORE_ERRORS not in options:
15
  options[self.IGNORE_ERRORS] = self._capabilities.get(f'percy.{self.IGNORE_ERRORS}', True)
percy/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.0.7'
1
+ __version__ = '0.0.8'
tests/mocks/android_capabilities.json CHANGED
@@ -12,6 +12,10 @@
12
  "enabled": true,
13
  "ignoreErrors": false
14
  },
 
 
 
 
15
  "platformName": "Android",
16
  "bstack:options": {
17
  "appiumVersion": "1.17.0"
@@ -42,6 +46,10 @@
42
  "enabled": true,
43
  "ignoreErrors": true
44
  },
 
 
 
 
45
  "platformName": "Android",
46
  "bstack:options": {
47
  "appiumVersion": "1.17.0"
12
  "enabled": true,
13
  "ignoreErrors": false
14
  },
15
+ "percyOptions": {
16
+ "enabled": true,
17
+ "ignoreErrors": false
18
+ },
19
  "platformName": "Android",
20
  "bstack:options": {
21
  "appiumVersion": "1.17.0"
46
  "enabled": true,
47
  "ignoreErrors": true
48
  },
49
+ "percyOptions": {
50
+ "enabled": true,
51
+ "ignoreErrors": true
52
+ },
53
  "platformName": "Android",
54
  "bstack:options": {
55
  "appiumVersion": "1.17.0"
tests/mocks/ios_capabilities.json CHANGED
@@ -11,6 +11,10 @@
11
  "enabled": true,
12
  "ignoreErrors": true
13
  },
 
 
 
 
14
  "platformName": "iOS",
15
  "bstack:options": {
16
  "appiumVersion": "1.21.0"
11
  "enabled": true,
12
  "ignoreErrors": true
13
  },
14
+ "percyOptions": {
15
+ "enabled": true,
16
+ "ignoreErrors": false
17
+ },
18
  "platformName": "iOS",
19
  "bstack:options": {
20
  "appiumVersion": "1.21.0"
tests/test_app_percy.py CHANGED
@@ -35,6 +35,8 @@ def setUp(self, mock_webdriver):
35
  def tearDown(self) -> None:
36
  self.mock_android_webdriver.capabilities['desired']['percy:options'] = {'enabled': True}
37
  self.mock_android_webdriver.capabilities['percy:options'] = {'enabled': True}
 
 
38
 
39
  @patch.object(CLIWrapper, 'post_screenshots', MagicMock(return_value=comparison_response))
40
  @patch.object(GenericProvider, '_write_screenshot', MagicMock(return_value='path-to-png-file'))
@@ -101,6 +103,13 @@ def test_screenshot_with_percy_options_disabled(self):
101
  app_percy = AppPercy(self.mock_android_webdriver)
102
  self.assertIsNone(app_percy.screenshot('screenshot 1'))
103
 
 
 
 
 
 
 
 
104
  @patch('percy.screenshot.log')
105
  @patch.object(AppPercy, 'screenshot', MagicMock(side_effect = Exception('RealException')))
106
  @patch.object(CLIWrapper, 'is_percy_enabled', MagicMock(return_value=True))
@@ -119,6 +128,16 @@ def test_percy_options_ignore_errors_not_raise(self, _mock_log):
119
  percy_screenshot(self.mock_android_webdriver, 'screenshot')
120
  _mock_log.assert_called_with(exception, on_debug=True)
121
 
 
 
 
 
 
 
 
 
 
 
122
  @patch.object(GenericProvider, 'supports', MagicMock(return_value=False))
123
  def test_invalid_provider(self):
124
  mock_command_executor = Mock()
35
  def tearDown(self) -> None:
36
  self.mock_android_webdriver.capabilities['desired']['percy:options'] = {'enabled': True}
37
  self.mock_android_webdriver.capabilities['percy:options'] = {'enabled': True}
38
+ self.mock_android_webdriver.capabilities['desired']['percyOptions'] = {'enabled': True}
39
+ self.mock_android_webdriver.capabilities['percyOptions'] = {'enabled': True}
40
 
41
  @patch.object(CLIWrapper, 'post_screenshots', MagicMock(return_value=comparison_response))
42
  @patch.object(GenericProvider, '_write_screenshot', MagicMock(return_value='path-to-png-file'))
103
  app_percy = AppPercy(self.mock_android_webdriver)
104
  self.assertIsNone(app_percy.screenshot('screenshot 1'))
105
 
106
+ def test_screenshot_with_percyOptions_disabled(self):
107
+ self.mock_android_webdriver.capabilities['percyOptions'] = {'enabled': False}
108
+ self.mock_android_webdriver.capabilities['percy:options'] = None
109
+
110
+ app_percy = AppPercy(self.mock_android_webdriver)
111
+ self.assertIsNone(app_percy.screenshot('screenshot 1'))
112
+
113
  @patch('percy.screenshot.log')
114
  @patch.object(AppPercy, 'screenshot', MagicMock(side_effect = Exception('RealException')))
115
  @patch.object(CLIWrapper, 'is_percy_enabled', MagicMock(return_value=True))
128
  percy_screenshot(self.mock_android_webdriver, 'screenshot')
129
  _mock_log.assert_called_with(exception, on_debug=True)
130
 
131
+ @patch('percy.screenshot.log')
132
+ @patch.object(CLIWrapper, 'is_percy_enabled', MagicMock(return_value=True))
133
+ def test_percyOptions_ignore_errors_not_raise(self, _mock_log):
134
+ with patch.object(AppPercy, 'screenshot') as mock_screenshot:
135
+ exception = Exception('Some Exception')
136
+ mock_screenshot.side_effect = exception
137
+ self.mock_android_webdriver.capabilities['percyOptions'] = {'ignoreErrors': True}
138
+ percy_screenshot(self.mock_android_webdriver, 'screenshot')
139
+ _mock_log.assert_called_with(exception, on_debug=True)
140
+
141
  @patch.object(GenericProvider, 'supports', MagicMock(return_value=False))
142
  def test_invalid_provider(self):
143
  mock_command_executor = Mock()
tests/test_percy_options.py CHANGED
@@ -1,7 +1,7 @@
1
  import unittest
2
  from percy.lib.percy_options import PercyOptions
3
 
4
-
5
  class TestPercyOptions(unittest.TestCase):
6
  def test_percy_options_not_provided(self): # Defaults
7
  capabilities = {}
@@ -15,6 +15,12 @@ def test_percy_options_w3c_enabled(self):
15
  self.assertTrue(percy_options.enabled)
16
  self.assertTrue(percy_options.ignore_errors)
17
 
 
 
 
 
 
 
18
  def test_percy_options_json_wire_enabled(self):
19
  capabilities = {'percy.enabled': True}
20
  percy_options = PercyOptions(capabilities)
@@ -27,6 +33,12 @@ def test_percy_options_w3c_not_enabled(self):
27
  self.assertFalse(percy_options.enabled)
28
  self.assertTrue(percy_options.ignore_errors)
29
 
 
 
 
 
 
 
30
  def test_percy_options_json_wire_not_enabled(self):
31
  capabilities = {'percy.enabled': False}
32
  percy_options = PercyOptions(capabilities)
@@ -39,6 +51,12 @@ def test_percy_options_w3c_ignore_errors(self):
39
  self.assertTrue(percy_options.ignore_errors)
40
  self.assertTrue(percy_options.enabled)
41
 
 
 
 
 
 
 
42
  def test_percy_options_json_wire_ignore_errors(self):
43
  capabilities = {'percy.ignoreErrors': True}
44
  percy_options = PercyOptions(capabilities)
@@ -51,6 +69,12 @@ def test_percy_options_w3c_not_ignore_errors(self):
51
  self.assertFalse(percy_options.ignore_errors)
52
  self.assertTrue(percy_options.enabled)
53
 
 
 
 
 
 
 
54
  def test_percy_options_json_wire_not_ignore_errors(self):
55
  capabilities = {'percy.ignoreErrors': False}
56
  percy_options = PercyOptions(capabilities)
@@ -63,6 +87,12 @@ def test_percy_options_w3c_all_options_false(self):
63
  self.assertFalse(percy_options.ignore_errors)
64
  self.assertFalse(percy_options.enabled)
65
 
 
 
 
 
 
 
66
  def test_percy_options_json_wire_all_options_false(self):
67
  capabilities = {'percy.ignoreErrors': False, 'percy.enabled': False}
68
  percy_options = PercyOptions(capabilities)
@@ -75,6 +105,12 @@ def test_percy_options_w3c_all_options_true(self):
75
  self.assertTrue(percy_options.ignore_errors)
76
  self.assertTrue(percy_options.enabled)
77
 
 
 
 
 
 
 
78
  def test_percy_options_json_wire_all_options_true(self):
79
  capabilities = {'percy.ignoreErrors': True, 'percy.enabled': True}
80
  percy_options = PercyOptions(capabilities)
@@ -92,3 +128,9 @@ def test_percy_options_json_wire_and_w3c_case_2(self):
92
  percy_options = PercyOptions(capabilities)
93
  self.assertFalse(percy_options.ignore_errors)
94
  self.assertTrue(percy_options.enabled)
 
 
 
 
 
 
1
  import unittest
2
  from percy.lib.percy_options import PercyOptions
3
 
4
+ # pylint: disable=R0904
5
  class TestPercyOptions(unittest.TestCase):
6
  def test_percy_options_not_provided(self): # Defaults
7
  capabilities = {}
15
  self.assertTrue(percy_options.enabled)
16
  self.assertTrue(percy_options.ignore_errors)
17
 
18
+ def test_percyOptions_w3c_enabled(self):
19
+ capabilities = {'percyOptions': {'enabled': True}}
20
+ percy_options = PercyOptions(capabilities)
21
+ self.assertTrue(percy_options.enabled)
22
+ self.assertTrue(percy_options.ignore_errors)
23
+
24
  def test_percy_options_json_wire_enabled(self):
25
  capabilities = {'percy.enabled': True}
26
  percy_options = PercyOptions(capabilities)
33
  self.assertFalse(percy_options.enabled)
34
  self.assertTrue(percy_options.ignore_errors)
35
 
36
+ def test_percyOptions_w3c_not_enabled(self):
37
+ capabilities = {'percyOptions': {'enabled': False}}
38
+ percy_options = PercyOptions(capabilities)
39
+ self.assertFalse(percy_options.enabled)
40
+ self.assertTrue(percy_options.ignore_errors)
41
+
42
  def test_percy_options_json_wire_not_enabled(self):
43
  capabilities = {'percy.enabled': False}
44
  percy_options = PercyOptions(capabilities)
51
  self.assertTrue(percy_options.ignore_errors)
52
  self.assertTrue(percy_options.enabled)
53
 
54
+ def test_percyOptions_w3c_ignore_errors(self):
55
+ capabilities = {'percyOptions': {'ignoreErrors': True}}
56
+ percy_options = PercyOptions(capabilities)
57
+ self.assertTrue(percy_options.ignore_errors)
58
+ self.assertTrue(percy_options.enabled)
59
+
60
  def test_percy_options_json_wire_ignore_errors(self):
61
  capabilities = {'percy.ignoreErrors': True}
62
  percy_options = PercyOptions(capabilities)
69
  self.assertFalse(percy_options.ignore_errors)
70
  self.assertTrue(percy_options.enabled)
71
 
72
+ def test_percyOptions_w3c_not_ignore_errors(self):
73
+ capabilities = {'percyOptions': {'ignoreErrors': False}}
74
+ percy_options = PercyOptions(capabilities)
75
+ self.assertFalse(percy_options.ignore_errors)
76
+ self.assertTrue(percy_options.enabled)
77
+
78
  def test_percy_options_json_wire_not_ignore_errors(self):
79
  capabilities = {'percy.ignoreErrors': False}
80
  percy_options = PercyOptions(capabilities)
87
  self.assertFalse(percy_options.ignore_errors)
88
  self.assertFalse(percy_options.enabled)
89
 
90
+ def test_percyOptions_w3c_all_options_false(self):
91
+ capabilities = {'percyOptions': {'ignoreErrors': False, 'enabled': False}}
92
+ percy_options = PercyOptions(capabilities)
93
+ self.assertFalse(percy_options.ignore_errors)
94
+ self.assertFalse(percy_options.enabled)
95
+
96
  def test_percy_options_json_wire_all_options_false(self):
97
  capabilities = {'percy.ignoreErrors': False, 'percy.enabled': False}
98
  percy_options = PercyOptions(capabilities)
105
  self.assertTrue(percy_options.ignore_errors)
106
  self.assertTrue(percy_options.enabled)
107
 
108
+ def test_percyOptions_w3c_all_options_true(self):
109
+ capabilities = {'percyOptions': {'ignoreErrors': True, 'enabled': True}}
110
+ percy_options = PercyOptions(capabilities)
111
+ self.assertTrue(percy_options.ignore_errors)
112
+ self.assertTrue(percy_options.enabled)
113
+
114
  def test_percy_options_json_wire_all_options_true(self):
115
  capabilities = {'percy.ignoreErrors': True, 'percy.enabled': True}
116
  percy_options = PercyOptions(capabilities)
128
  percy_options = PercyOptions(capabilities)
129
  self.assertFalse(percy_options.ignore_errors)
130
  self.assertTrue(percy_options.enabled)
131
+
132
+ def test_percyOptions_json_wire_and_w3c_case_2(self):
133
+ capabilities = {'percy.enabled': False, 'percyOptions': {'ignoreErrors': False}}
134
+ percy_options = PercyOptions(capabilities)
135
+ self.assertFalse(percy_options.ignore_errors)
136
+ self.assertTrue(percy_options.enabled)

Readme

percy-appium-python

Percy visual testing for Python Appium.

Installation

npm install @percy/cli:

$ npm install --save-dev @percy/cli

pip install Percy appium package:

$ pip install percy-appium-app

Usage

This is an example test using the percy_screenshot function.

from appium import webdriver
from percy import percy_screenshot

driver = webdriver.Remote("https://" + userName + ":" + accessKey + "@hub-cloud.browserstack.com/wd/hub", desired_caps)

# take a screenshot
percy_screenshot(driver, 'here is some name')

Running the test above normally will result in the following log:

[percy] Percy is not running, disabling screenshots

When running with percy app:exec, and your project's PERCY_TOKEN, a new Percy build will be created and screenshots will be uploaded to your project.

$ export PERCY_TOKEN=[your-project-token]
$ percy app:exec -- [python test command]
[percy] Percy has started!
[percy] Created build #1: https://percy.io/[your-project]
[percy] Screenshot taken "Python example"
[percy] Stopping percy...
[percy] Finalized build #1: https://percy.io/[your-project]
[percy] Done!

Configuration

percy_screenshot(driver, name[, **kwargs])

  • driver (required) - A appium driver instance
  • name (required) - The screenshot name; must be unique to each screenshot
  • device_name (optional) - The device name used for capturing screenshot
  • orientation (optional) - Orientation of device while capturing screeenshot; Allowed values [portrait | landscape]
  • status_bar_height (optional) - Height of status bar; number
  • nav_bar_height (optional) - Height of navigation bar; number
  • full_screen (optional) - Indicate whether app is full screen; boolean

Migrating Config

If you have a previous Percy configuration file, migrate it to the newest version with the config:migrate command:

$ percy config:migrate