Skip to content

Commit 1a8ff99

Browse files
refactor: Deprecate custom event listener implementation and default to the one provided by Selenium4 (#1541)
1 parent ac625c3 commit 1a8ff99

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+716
-2224
lines changed

docs/The-event_firing.md

Lines changed: 69 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,151 +1,76 @@
1-
since 4.1.0
1+
since v8.0.0
22

33
# The purpose
44

5-
This feature allows end user to organize the event logging on the client side. Also this feature may be useful in a binding with standard or custom reporting
6-
frameworks.
7-
8-
9-
# The API
10-
11-
The API was designed the way which allows end user to select events (searching, navigation, exception throwing etc.) which should be listened to. It contains
12-
the following list of interfaces (new items may be added further):
13-
14-
- `io.appium.java_client.events.api.Listener` is the basic interface
15-
- `io.appium.java_client.events.api.general.AlertEventListener` is for the listening to alerts
16-
- `io.appium.java_client.events.api.general.ElementEventListener` is for the listening to actions related to elements
17-
- `io.appium.java_client.events.api.general.JavaScriptEventListener` is for the listening to java script executing
18-
- `io.appium.java_client.events.api.general.ListensToException` is for the listening to exceptions which are thrown
19-
- `io.appium.java_client.events.api.general.NavigationEventListener` is for the listening to events related to navigation
20-
- `io.appium.java_client.events.api.general.SearchingEventListener` is for the listening to events related to the searching.
21-
- `io.appium.java_client.events.api.general.WindowEventListener` is for the listening to actions on a window
22-
- `io.appium.java_client.events.api.mobile.ContextEventListener` is for the listening to the switching to mobile context
23-
- `io.appium.java_client.events.api.mobile.RotationEventListener` is for the listening to screen rotation
24-
- `io.appium.java_client.events.api.general.AppiumWebDriverEventListener` was added to provide the compatibility with
25-
user's implementation of `org.openqa.selenium.support.events.WebDriverEventListener`. Also it extends some interfaces above.
26-
27-
# Briefly about the engine.
28-
29-
This is pretty similar solution as the `org.openqa.selenium.support.events.EventFiringWebDriver` of the Selenium project. You
30-
can read about this thing there [The blog post](https://seleniumworks.blogspot.com/2014/02/eventfiringwebdriver.html).
31-
32-
Here we were trying to improve existing drawbacks and restrictions using:
33-
34-
- API splitting, see above.
35-
36-
- the binding of some [Spring framework engines](https://spring.io/projects/spring-framework) with [AspectJ](https://en.wikipedia.org/wiki/AspectJ).
37-
38-
# How to use
39-
40-
It is easy.
41-
42-
```java
43-
import io.appium.java_client.events.api.general.AlertEventListener;
44-
45-
public class AlertListener implements AlertEventListener {
46-
...
47-
}
48-
49-
...
50-
import io.appium.java_client.events.api.general.ElementEventListener;
51-
52-
public class ElementListener implements ElementEventListener {
53-
...
54-
}
55-
56-
//and so on
57-
...
58-
import io.appium.java_client.events.EventFiringWebDriverFactory;
59-
import io.appium.java_client.events.api.Listener;
60-
...
61-
62-
AndroidDriver driver = new AndroidDriver(parameters);
63-
driver = EventFiringWebDriverFactory.getEventFiringWebDriver(driver, new AlertListener(),
64-
new ElementListener());
65-
66-
//or
67-
AndroidDriver driver2 = new AndroidDriver(parameters);
68-
List<Listener> listeners = new ArrayList<>();
69-
listeners.add(new AlertListener());
70-
listeners.add(new ElementListener());
71-
driver = EventFiringWebDriverFactory.getEventFiringWebDriver(driver2, listeners);
72-
```
73-
74-
## What if there are listeners which used everywhere by default.
75-
76-
In order to avoid the repeating actions an end user is free to do these things:
77-
78-
- create folders `/META-INF/services` and put the file `io.appium.java_client.events.api.Listener` there. Please read about
79-
[SPI](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html).
80-
81-
![image](https://cloud.githubusercontent.com/assets/4927589/16731325/24eab680-4780-11e6-8551-a3c72d4b9c38.png)
82-
83-
- define the list of default listeners at the `io.appium.java_client.events.api.Listener`
84-
85-
![image](https://cloud.githubusercontent.com/assets/4927589/16731509/2734a4e0-4781-11e6-81cb-ab64a5924c35.png)
86-
87-
And then it is enough
5+
This feature allows end user to organize the event logging on the client side.
6+
Also this feature may be useful in a binding with standard or custom reporting
7+
frameworks. The feature has been introduced first since Selenium API v4.
888

89-
```java
90-
91-
//and so on
92-
...
93-
import io.appium.java_client.events.EventFiringWebDriverFactory;
94-
...
95-
96-
AndroidDriver driver = new AndroidDriver(parameters);
97-
driver = EventFiringWebDriverFactory.getEventFiringWebDriver(driver);
98-
```
99-
100-
If there are listeners defined externally when this collection is merged with default set of listeners.
101-
102-
# How to reuse customized WebDriverEventListener
103-
104-
If an end user has their own `org.openqa.selenium.support.events.WebDriverEventListener` implementation then in order to
105-
make it compatible with this engine it is enough to do the following.
106-
107-
108-
```java
109-
import org.openqa.selenium.support.events.WebDriverEventListener;
110-
import io.appium.java_client.events.api.general.AppiumWebDriverEventListener;
111-
112-
public class UsersWebDriverEventListener implements WebDriverEventListener, AppiumWebDriverEventListener {
113-
...
114-
}
115-
```
116-
117-
or just
118-
119-
```java
120-
import io.appium.java_client.events.api.general.AppiumWebDriverEventListener;
121-
122-
public class UsersWebDriverEventListener implements AppiumWebDriverEventListener {
123-
...
124-
}
125-
```
126-
# Also
127-
128-
As soon as Appium java client has *Java 8-style* API (methods with default implementation) there was provided the ability to get objects created by these interfaces (anonymous types) listenable. Also there is an option to make some objects (some single element that has been found, for example) listenable too.
9+
# The API
12910

11+
There are two main entities used to implement events firing logic:
12+
- [org.openqa.selenium.support.events.EventFiringDecorator](https://github.com/SeleniumHQ/selenium/blob/trunk/java/src/org/openqa/selenium/support/events/EventFiringDecorator.java) class
13+
- [org.openqa.selenium.support.events.WebDriverListener](https://github.com/SeleniumHQ/selenium/blob/trunk/java/src/org/openqa/selenium/support/events/WebDriverListener.java) interface
14+
15+
## WebDriverListener
16+
17+
Classes that implement this interface are intended to be used with EventFiringDecorator.
18+
This interface provides empty default implementation for all methods that do nothing.
19+
You could easily extend that interface to add more methods that you'd like to listen to.
20+
The strategy to add new/custom event listeners is the following. Let say there is a public `setOrientation`
21+
method in the target WebDriver instance. Then you'd have to add `beforeSetOrientation` and/or
22+
`afterSetOrientation` methods to your WebDriverListener descendant accepting single argument
23+
of `WebDriver` type. If the target method accepts one or more arguments then these arguments
24+
should also be added to the event listeners in the same order they are accepted by the original method,
25+
but the very first argument should still be the firing WebDriver instance.
26+
27+
_Important_: Make sure that your implementation of WebDriverListener class is public
28+
and that event listener methods are also public.
29+
30+
## EventFiringDecorator
31+
32+
This decorator creates a wrapper around an arbitrary WebDriver instance that notifies
33+
registered listeners about events happening in this WebDriver and derived objects,
34+
such as WebElements and Alert.
35+
Listeners should implement WebDriverListener. It supports three types of events:
36+
- "before"-event: a method is about to be called;
37+
- "after"-event: a method was called successfully and returned some result;
38+
- "error"-event: a method was called and thrown an exception.
39+
40+
To use this decorator you have to prepare a listener, create a decorator using this listener,
41+
decorate the original WebDriver instance with this decorator and use the new WebDriver instance
42+
created by the decorator instead of the original one:
13043
```java
131-
import static io.appium.java_client.events.EventFiringObjectFactory.getEventFiringObject;
132-
...
133-
134-
AppiumDriver<AndroidElement> appiumDriver = new AppiumDriver<AndroidElement>(parameters);
135-
FindsByAndroidUIAutomator<AndroidElement> findsByAndroidUIAutomator =
136-
new FindsByAndroidUIAutomator<AndroidElement>() {
137-
138-
@Override
139-
public AndroidElement findElement(String by, String using) {
140-
return appiumDriver.findElement(String by, String using);
141-
}
142-
143-
@Override
144-
public List<AndroidElement> findElements(String by, String using) {
145-
return appiumDriver.findElements(by, using);
146-
}
147-
};
148-
149-
findsByAndroidUIAutomator =
150-
getEventFiringObject(findsByAndroidUIAutomator, appiumDriver, listeners);
44+
WebDriver original = new AndroidDriver();
45+
// it is expected that MyListener class implements WebDriverListener
46+
// interface or its descendant
47+
WebDriverListener listener = new MyListener();
48+
WebDriver decorated = new EventFiringDecorator(listener).decorate(original);
49+
// the next call is going to fire:
50+
// - beforeAnyCall
51+
// - beforeAnyWebDriverCall
52+
// - beforeGet
53+
// - afterGet
54+
// - afterAnyWebDriverCall
55+
// - afterAnyCall
56+
// events in the listener instence (in this order)
57+
decorated.get("http://example.com/");
58+
// the next call is going to fire:
59+
// - beforeAnyCall
60+
// - beforeAnyWebDriverCall
61+
// - beforeFindElement
62+
// - afterFindElement
63+
// - afterAnyWebDriverCall
64+
// - afterAnyCall
65+
// events in the listener instence (in this order)
66+
WebElement header = decorated.findElement(By.tagName("h1"));
67+
// if an error happens during any of these calls the the onError event is fired
15168
```
69+
The instance of WebDriver created by the decorator implements all the same interfaces
70+
as the original driver. A listener can subscribe to "specific" or "generic" events (or both).
71+
A "specific" event correspond to a single specific method, a "generic" event correspond to any
72+
method called in a class or in any class. To subscribe to a "specific" event a listener should
73+
implement a method with a name derived from the target method to be watched. The listener methods
74+
for "before"-events receive the parameters passed to the decorated method. The listener
75+
methods for "after"-events receive the parameters passed to the decorated method as well as the
76+
result returned by this method.

src/main/java/io/appium/java_client/events/DefaultAspect.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
import java.util.Collection;
4040
import java.util.List;
4141

42+
/**
43+
* Deprecated. Use EventFiringDecorator and WebDriverListener instead.
44+
*/
45+
@Deprecated
4246
@SuppressWarnings("unused")
4347
@Aspect
4448
class DefaultAspect {

src/main/java/io/appium/java_client/events/DefaultBeanConfiguration.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
import java.util.ArrayList;
2929
import java.util.List;
3030

31+
/**
32+
* Deprecated. Use EventFiringDecorator and WebDriverListener instead.
33+
*/
34+
@Deprecated
3135
@Configuration
3236
@EnableAspectJAutoProxy(proxyTargetClass = true)
3337
class DefaultBeanConfiguration {

src/main/java/io/appium/java_client/events/DefaultListener.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
import java.util.Collection;
4343
import java.util.List;
4444

45+
/**
46+
* Deprecated. Use EventFiringDecorator and WebDriverListener instead.
47+
*/
48+
@Deprecated
4549
class DefaultListener
4650
implements Listener, AppiumWebDriverEventListener, ListensToException, SearchingEventListener,
4751
NavigationEventListener, JavaScriptEventListener, ElementEventListener, AlertEventListener,

src/main/java/io/appium/java_client/events/EventFiringObjectFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
import java.util.List;
1313
import java.util.ServiceLoader;
1414

15+
/**
16+
* Deprecated. Use EventFiringDecorator and WebDriverListener instead.
17+
*/
18+
@Deprecated
1519
public class EventFiringObjectFactory {
1620

1721
/**

src/main/java/io/appium/java_client/events/EventFiringWebDriverFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323

2424
import java.util.Collection;
2525

26+
/**
27+
* Deprecated. Use EventFiringDecorator and WebDriverListener instead.
28+
*/
29+
@Deprecated
2630
public class EventFiringWebDriverFactory {
2731

2832
/**

src/main/java/io/appium/java_client/events/ListenerInvocationHandler.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
import java.lang.reflect.Method;
2424
import java.util.List;
2525

26+
/**
27+
* Deprecated. Use EventFiringDecorator and WebDriverListener instead.
28+
*/
29+
@Deprecated
2630
class ListenerInvocationHandler implements InvocationHandler {
2731

2832
private final List<Listener> listeners;

src/main/java/io/appium/java_client/events/api/Listener.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
/**
2020
* This interface just marks event listeners.
21+
* Deprecated. Use EventFiringDecorator and WebDriverListener instead.
2122
*/
23+
@Deprecated
2224
public interface Listener {
2325
}

src/main/java/io/appium/java_client/events/api/general/AlertEventListener.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
import org.openqa.selenium.Alert;
2121
import org.openqa.selenium.WebDriver;
2222

23+
/**
24+
* Deprecated. Use EventFiringDecorator and WebDriverListener instead.
25+
*/
26+
@Deprecated
2327
public interface AlertEventListener extends Listener {
2428

2529
/**

src/main/java/io/appium/java_client/events/api/general/AppiumWebDriverEventListener.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
import io.appium.java_client.events.api.Listener;
2020
import org.openqa.selenium.support.events.WebDriverEventListener;
2121

22+
/**
23+
* Deprecated. Use EventFiringDecorator and WebDriverListener instead.
24+
*/
25+
@Deprecated
2226
public interface AppiumWebDriverEventListener extends Listener, WebDriverEventListener, ListensToException,
2327
SearchingEventListener, NavigationEventListener,
2428
JavaScriptEventListener, ElementEventListener {

0 commit comments

Comments
 (0)