Skip to content

Commit b6795db

Browse files
JavonDavisKazuCocoa
authored andcommitted
driver.push_file(destination_path, source_path) feature (appium#270)
* used base64 library for conversion * remove unnecessary library use * changed text in test file * * Using context when reading file * changed docstring format * Catch error thrown if file not present and present user with a better message * fixed incorrect file path in test * removed change in pul_file that broke backwards compat and updated docstring description for `destination_path`
1 parent cd91a70 commit b6795db

File tree

10 files changed

+122
-17
lines changed

10 files changed

+122
-17
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ dist
1919
__pycache__
2020
.idea
2121
.pytest_cache
22+
23+
# Virtual Environments
24+
venv*

appium/webdriver/webdriver.py

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,17 @@
1818
import copy
1919

2020
from selenium import webdriver
21-
22-
from selenium.webdriver.common.by import By
23-
from selenium.webdriver.support.ui import WebDriverWait
2421
from selenium.common.exceptions import TimeoutException, InvalidArgumentException
25-
22+
from selenium.webdriver.common.by import By
2623
from selenium.webdriver.remote.command import Command as RemoteCommand
24+
from selenium.webdriver.support.ui import WebDriverWait
2725

2826
from appium.webdriver.clipboard_content_type import ClipboardContentType
2927
from appium.webdriver.common.mobileby import MobileBy
30-
from appium.webdriver.common.touch_action import TouchAction
3128
from appium.webdriver.common.multi_action import MultiAction
32-
33-
from .mobilecommand import MobileCommand as Command
29+
from appium.webdriver.common.touch_action import TouchAction
3430
from .errorhandler import MobileErrorHandler
31+
from .mobilecommand import MobileCommand as Command
3532
from .switch_to import MobileSwitchTo
3633
from .webelement import WebElement as MobileWebElement
3734

@@ -776,8 +773,7 @@ def set_value(self, element, value):
776773
return self
777774

778775
def pull_file(self, path):
779-
"""Retrieves the file at `path`. Returns the file's content encoded as
780-
Base64.
776+
"""Retrieves the file at `path`. Returns the file's contents as base64.
781777
782778
:Args:
783779
- path - the path to the file on the device
@@ -799,15 +795,29 @@ def pull_folder(self, path):
799795
}
800796
return self.execute(Command.PULL_FOLDER, data)['value']
801797

802-
def push_file(self, path, base64data):
803-
"""Puts the data, encoded as Base64, in the file specified as `path`.
798+
def push_file(self, destination_path, base64data=None, source_path=None):
799+
"""Puts the data from the file at `source_path`, encoded as Base64, in the file specified as `path`.
804800
805-
:Args:
806-
- path - the path on the device
807-
- base64data - data, encoded as Base64, to be written to the file
801+
Specify either `base64data` or `source_path`, if both specified default to `source_path`
802+
:param destination_path: the location on the device/simulator where the local file contents should be saved
803+
:param base64data: file contents, encoded as Base64, to be written to the file on the device/simulator
804+
:param source_path: local file path for the file to be loaded on device
805+
:return: WebDriver instance
808806
"""
807+
if source_path is None and base64data is None:
808+
raise InvalidArgumentException('Must either pass base64 data or a local file path')
809+
810+
if source_path is not None:
811+
try:
812+
with open(source_path, 'rb') as file:
813+
data = file.read()
814+
except FileNotFoundError:
815+
message = 'source_path {} could not be found. Are you sure the file exists?'.format(source_path)
816+
raise InvalidArgumentException(message)
817+
base64data = base64.b64encode(data).decode('utf-8')
818+
809819
data = {
810-
'path': path,
820+
'path': destination_path,
811821
'data': base64data,
812822
}
813823
self.execute(Command.PUSH_FILE, data)

test/functional/android/desired_capabilities.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ def get_desired_capabilities(app):
2727
'platformName': 'Android',
2828
'deviceName': 'Android Emulator',
2929
'app': PATH('../../apps/' + app),
30-
'newCommandTimeout': 240
30+
'newCommandTimeout': 240,
31+
'automationName': 'UIAutomator2'
3132
}
3233

3334
return desired_caps
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env python
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import os
16+
import unittest
17+
18+
import desired_capabilities
19+
20+
from appium import webdriver
21+
22+
23+
class PushFileTests(unittest.TestCase):
24+
def setUp(self):
25+
desired_caps = desired_capabilities.get_desired_capabilities('ApiDemos-debug.apk')
26+
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
27+
28+
def tearDown(self):
29+
self.driver.quit()
30+
31+
def test_push_file(self):
32+
test_files = ['test_image.jpg', 'test_file.txt']
33+
for file_name in test_files:
34+
source_path = os.path.dirname(os.path.abspath(__file__)) + '//' + file_name
35+
destination_path = '/data/local/tmp/'+file_name
36+
37+
original_data = open(source_path, 'rb').read()
38+
39+
self.driver.push_file(destination_path, source_path=source_path)
40+
new_data = self.driver.pull_file(destination_path)
41+
self.assertEqual(original_data, new_data)
42+
43+
44+
if __name__ == "__main__":
45+
suite = unittest.TestLoader().loadTestsFromTestCase(PushFileTests)
46+
unittest.TextTestRunner(verbosity=2).run(suite)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
HEllo
20.9 KB
Loading

test/functional/ios/desired_capabilities.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def get_desired_capabilities(app):
2828
desired_caps = {
2929
'deviceName': iphone_device_name(),
3030
'platformName': 'iOS',
31-
'platformVersion': '11.4',
31+
'platformVersion': '12.1',
3232
'app': PATH('../../apps/' + app),
3333
'automationName': 'XCUITest',
3434
'allowTouchIdEnroll': True,
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/bin/env python
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import os
16+
import unittest
17+
18+
import desired_capabilities
19+
20+
from appium import webdriver
21+
22+
23+
class PushFileTests(unittest.TestCase):
24+
@classmethod
25+
def setUpClass(self):
26+
desired_caps = desired_capabilities.get_desired_capabilities('UICatalog.app.zip')
27+
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
28+
29+
@classmethod
30+
def tearDownClass(self):
31+
self.driver.quit()
32+
33+
def test_push_file(self):
34+
file_name = 'test_image.jpg'
35+
source_path = os.path.dirname(os.path.abspath(__file__)) + '/' + file_name
36+
destination_path = file_name
37+
38+
self.driver.push_file(destination_path, source_path=source_path)
39+
40+
41+
if __name__ == "__main__":
42+
suite = unittest.TestLoader().loadTestsFromTestCase(PushFileTests)
43+
unittest.TextTestRunner(verbosity=2).run(suite)

test/functional/ios/test_file.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"We have to stop optimizing for programmers and start optimizing for users." - Jeff Atwood

test/functional/ios/test_image.jpg

20.9 KB
Loading

0 commit comments

Comments
 (0)