diff --git a/appium/webdriver/extensions/log_event.py b/appium/webdriver/extensions/log_event.py new file mode 100644 index 00000000..383664d6 --- /dev/null +++ b/appium/webdriver/extensions/log_event.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +# 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. + +from selenium import webdriver + +from ..mobilecommand import MobileCommand as Command + + +class LogEvent(webdriver.Remote): + + def get_events(self, type=None): + """ Retrieves events information from the current session + (Since Appium 1.16.0) + + Args: + type (:obj:`list` of :obj:`str`): The event type to filter with + + Usage: + events = driver.get_events() + events = driver.get_events(['appium:funEvent']) + + Returns: + `dict`: A dictionary of events timing information containing the following entries + commands: (`list` of `dict`) List of dictionaries containing the following entries + cmd: (str) The command name that has been sent to the appium server + startTime: (int) Received time + endTime: (init) Response time + """ + data = {} + if type is not None: + data['type'] = type + return self.execute(Command.GET_EVENTS, data)['value'] + + def log_event(self, vendor, event): + """Log a custom event on the Appium server. + (Since Appium 1.16.0) + + Args: + vendor (str): The vendor to log + event (str): The event to log + + Usage: + driver.log_event('appium', 'funEvent') + + Returns: + `appium.webdriver.webdriver.WebDriver` + """ + data = { + 'vendor': vendor, + 'event': event + } + self.execute(Command.LOG_EVENT, data) + return self + + # pylint: disable=protected-access + + def _addCommands(self): + self.command_executor._commands[Command.GET_EVENTS] = \ + ('POST', '/session/$sessionId/appium/events') + self.command_executor._commands[Command.LOG_EVENT] = \ + ('POST', '/session/$sessionId/appium/log_event') diff --git a/appium/webdriver/mobilecommand.py b/appium/webdriver/mobilecommand.py index eac5bda2..f6d90679 100644 --- a/appium/webdriver/mobilecommand.py +++ b/appium/webdriver/mobilecommand.py @@ -77,6 +77,9 @@ class MobileCommand(object): EXECUTE_DRIVER = 'executeDriver' + GET_EVENTS = 'getLogEvents' + LOG_EVENT = 'logCustomEvent' + # Android OPEN_NOTIFICATIONS = 'openNotifications' START_ACTIVITY = 'startActivity' diff --git a/appium/webdriver/webdriver.py b/appium/webdriver/webdriver.py index 1cf2f257..cb20e996 100644 --- a/appium/webdriver/webdriver.py +++ b/appium/webdriver/webdriver.py @@ -46,6 +46,7 @@ from .extensions.ime import IME from .extensions.keyboard import Keyboard from .extensions.location import Location +from .extensions.log_event import LogEvent from .extensions.remote_fs import RemoteFS from .extensions.screen_record import ScreenRecord from .extensions.search_context import AppiumSearchContext @@ -125,6 +126,7 @@ class WebDriver( IME, Keyboard, Location, + LogEvent, Network, Performance, Power, @@ -368,7 +370,7 @@ def battery_info(self): """Retrieves battery information for the device under test. Returns: - A dictionary containing the following entries + `dict`: containing the following entries level: Battery level in range [0.0, 1.0], where 1.0 means 100% charge. Any value lower than 0 means the level cannot be retrieved state: Platform-dependent battery state value. @@ -389,31 +391,38 @@ def battery_info(self): @property def session(self): """ Retrieves session information from the current session + Usage: session = driver.session + Returns: - `dict containing information from the current session` + `dict`: containing information from the current session """ return self.execute(Command.GET_SESSION)['value'] @property def all_sessions(self): """ Retrieves all sessions that are open + Usage: sessions = driver.all_sessions + Returns: - `dict containing all open sessions` + `dict`: containing all open sessions """ return self.execute(Command.GET_ALL_SESSIONS)['value'] + # pylint: disable=protected-access + @property def events(self): """ Retrieves events information from the current session + Usage: events = driver.events Returns: - `dict containing events timing information from the current session` + `dict`: containing events timing information from the current session """ try: session = self.session diff --git a/ci-jobs/functional_test.yml b/ci-jobs/functional_test.yml index 6c26a74b..117c595b 100644 --- a/ci-jobs/functional_test.yml +++ b/ci-jobs/functional_test.yml @@ -85,6 +85,6 @@ jobs: name: 'func_test_android8' vmImage: ${{ parameters.vmImage }} pytestOpt: ${{ parameters.pytestOpt }} - testFiles: 'network_connection_tests.py' + testFiles: 'network_connection_tests.py log_event_tests.py' sdkVer: ${{ parameters.androidSdkVer }} CI: ${{ parameters.ci }} diff --git a/test/functional/android/log_event_tests.py b/test/functional/android/log_event_tests.py new file mode 100644 index 00000000..8067e9f7 --- /dev/null +++ b/test/functional/android/log_event_tests.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# 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. + +import unittest + +from .helper.test_helper import BaseTestCase + + +class LogEventTests(BaseTestCase): + def test_log_event(self): + vendor = 'appium' + event = 'funEvent' + self.driver.log_event(vendor, event) + assert '{}:{}'.format(vendor, event) in self.driver.get_events().keys() + + +if __name__ == '__main__': + suite = unittest.TestLoader().loadTestsFromTestCase(LogEventTests) + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/test/unit/webdriver/log_events_test.py b/test/unit/webdriver/log_events_test.py new file mode 100644 index 00000000..be5a514f --- /dev/null +++ b/test/unit/webdriver/log_events_test.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +# 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. + +import json + +import httpretty + +from appium.webdriver.webdriver import WebDriver +from test.unit.helper.test_helper import ( + appium_command, + get_httpretty_request_body, + ios_w3c_driver +) + + +class TestWebDriverLogEvents(object): + + @httpretty.activate + def test_get_events(self): + driver = ios_w3c_driver() + httpretty.register_uri( + httpretty.POST, + appium_command('/session/1234567890/appium/events'), + body=json.dumps({'value': {'appium:funEvent': [12347]}}) + ) + events = driver.get_events() + assert events['appium:funEvent'] == [12347] + + d = get_httpretty_request_body(httpretty.last_request()) + assert 'type' not in d.keys() + + @httpretty.activate + def test_get_events_args(self): + driver = ios_w3c_driver() + httpretty.register_uri( + httpretty.POST, + appium_command('/session/1234567890/appium/events'), + body=json.dumps({'value': {'appium:funEvent': [12347]}}) + ) + events_to_filter = ['appium:funEvent'] + events = driver.get_events(events_to_filter) + assert events['appium:funEvent'] == [12347] + + d = get_httpretty_request_body(httpretty.last_request()) + assert d['type'] == events_to_filter + + @httpretty.activate + def test_log_event(self): + driver = ios_w3c_driver() + httpretty.register_uri( + httpretty.POST, + appium_command('/session/1234567890/appium/log_event'), + body="" + ) + vendor_name = 'appium' + event_name = 'funEvent' + assert isinstance(driver.log_event(vendor_name, event_name), WebDriver) + + d = get_httpretty_request_body(httpretty.last_request()) + assert d['vendor'] == vendor_name + assert d['event'] == event_name