3939 * Then the {@code stereotype} must contain the same values.
4040 * </ul>
4141 *
42- * <p>One thing to note is that extension capabilities are not considered when matching slots, since
43- * the matching of these is implementation-specific to each driver.
42+ * <p>Note that extension capabilities are considered for slot matching, with the following exceptions:
43+ *
44+ * <ul>
45+ * <li>Extension capabilities with these prefixes:
46+ * <ul>
47+ * <li>"goog:" - Google
48+ * <li>"moz:" - Mozilla
49+ * <li>"ms:" - Microsoft
50+ * <li>"se:" - Selenium
51+ * </ul>
52+ * <li>Extension capabilities with these suffixes:
53+ * <ul>
54+ * <li>"options"
55+ * <li>"Options"
56+ * <li>"loggingPrefs"
57+ * <li>"debuggerAddress"
58+ * </ul>
59+ * </ul>
4460 */
4561public class DefaultSlotMatcher implements SlotMatcher , Serializable {
4662
@@ -51,6 +67,13 @@ public class DefaultSlotMatcher implements SlotMatcher, Serializable {
5167 private static final List <String > EXTENSION_CAPABILITIES_PREFIXES =
5268 Arrays .asList ("goog:" , "moz:" , "ms:" , "se:" );
5369
70+ /*
71+ List of extension capability suffixes we never should try to match, they should be
72+ matched in the Node or in the browser driver.
73+ */
74+ private static final List <String > EXTENSION_CAPABILITY_SUFFIXES =
75+ Arrays .asList ("Options" , "options" , "loggingPrefs" , "debuggerAddress" );
76+
5477 @ Override
5578 public boolean matches (Capabilities stereotype , Capabilities capabilities ) {
5679
@@ -76,14 +99,14 @@ public boolean matches(Capabilities stereotype, Capabilities capabilities) {
7699
77100 // At the end, a simple browser, browserVersion and platformName match
78101 boolean browserNameMatch =
79- (capabilities .getBrowserName () == null || capabilities .getBrowserName ().isEmpty ())
102+ capabilities .getBrowserName () == null
103+ || capabilities .getBrowserName ().isEmpty ()
80104 || Objects .equals (stereotype .getBrowserName (), capabilities .getBrowserName ());
81105 boolean browserVersionMatch =
82- (capabilities .getBrowserVersion () == null
83- || capabilities .getBrowserVersion ().isEmpty ()
84- || Objects .equals (capabilities .getBrowserVersion (), "stable" ))
85- || browserVersionMatch (
86- stereotype .getBrowserVersion (), capabilities .getBrowserVersion ());
106+ capabilities .getBrowserVersion () == null
107+ || capabilities .getBrowserVersion ().isEmpty ()
108+ || Objects .equals (capabilities .getBrowserVersion (), "stable" )
109+ || browserVersionMatch (stereotype .getBrowserVersion (), capabilities .getBrowserVersion ());
87110 boolean platformNameMatch =
88111 capabilities .getPlatformName () == null
89112 || Objects .equals (stereotype .getPlatformName (), capabilities .getPlatformName ())
@@ -102,21 +125,17 @@ private Boolean initialMatch(Capabilities stereotype, Capabilities capabilities)
102125 .filter (name -> !name .contains (":" ))
103126 // Platform matching is special, we do it later
104127 .filter (name -> !"platformName" .equalsIgnoreCase (name ))
105- .map (
128+ .filter (name -> capabilities .getCapability (name ) != null )
129+ .allMatch (
106130 name -> {
107- if (capabilities .getCapability (name ) instanceof String ) {
108- return stereotype
109- .getCapability (name )
110- .toString ()
111- .equalsIgnoreCase (capabilities .getCapability (name ).toString ());
112- } else {
113- return capabilities .getCapability (name ) == null
114- || Objects .equals (
115- stereotype .getCapability (name ), capabilities .getCapability (name ));
116- }
117- })
118- .reduce (Boolean ::logicalAnd )
119- .orElse (true );
131+ if (stereotype .getCapability (name ) instanceof String
132+ && capabilities .getCapability (name ) instanceof String ) {
133+ return ((String ) stereotype .getCapability (name ))
134+ .equalsIgnoreCase ((String ) capabilities .getCapability (name ));
135+ }
136+ return Objects .equals (
137+ stereotype .getCapability (name ), capabilities .getCapability (name ));
138+ });
120139 }
121140
122141 private Boolean managedDownloadsEnabled (Capabilities stereotype , Capabilities capabilities ) {
@@ -140,13 +159,11 @@ private Boolean platformVersionMatch(Capabilities stereotype, Capabilities capab
140159 */
141160 return capabilities .getCapabilityNames ().stream ()
142161 .filter (name -> name .contains ("platformVersion" ))
143- .map (
162+ .allMatch (
144163 platformVersionCapName ->
145164 Objects .equals (
146165 stereotype .getCapability (platformVersionCapName ),
147- capabilities .getCapability (platformVersionCapName )))
148- .reduce (Boolean ::logicalAnd )
149- .orElse (true );
166+ capabilities .getCapability (platformVersionCapName )));
150167 }
151168
152169 private Boolean extensionCapabilitiesMatch (Capabilities stereotype , Capabilities capabilities ) {
@@ -156,23 +173,25 @@ private Boolean extensionCapabilitiesMatch(Capabilities stereotype, Capabilities
156173 of the new session request contains that specific extension capability.
157174 */
158175 return stereotype .getCapabilityNames ().stream ()
176+ // examine only extension capabilities
159177 .filter (name -> name .contains (":" ))
160- . filter ( name -> capabilities . asMap (). containsKey ( name ))
178+ // ignore special extension capability prefixes
161179 .filter (name -> EXTENSION_CAPABILITIES_PREFIXES .stream ().noneMatch (name ::contains ))
162- .map (
180+ // ignore special extension capability suffixes
181+ .filter (name -> EXTENSION_CAPABILITY_SUFFIXES .stream ().noneMatch (name ::endsWith ))
182+ // ignore capabilities not specified in the request
183+ .filter (name -> capabilities .getCapability (name ) != null )
184+ .allMatch (
163185 name -> {
164- if (capabilities .getCapability (name ) instanceof String ) {
165- return stereotype
166- .getCapability (name )
167- .toString ()
168- .equalsIgnoreCase (capabilities .getCapability (name ).toString ());
169- } else {
170- return capabilities .getCapability (name ) == null
171- || Objects .equals (
172- stereotype .getCapability (name ), capabilities .getCapability (name ));
173- }
174- })
175- .reduce (Boolean ::logicalAnd )
176- .orElse (true );
186+ // evaluate capabilities with String values
187+ if (stereotype .getCapability (name ) instanceof String
188+ && capabilities .getCapability (name ) instanceof String ) {
189+ return ((String ) stereotype .getCapability (name ))
190+ .equalsIgnoreCase ((String ) capabilities .getCapability (name ));
191+ }
192+ // evaluate capabilities with non-String values
193+ return Objects .equals (
194+ stereotype .getCapability (name ), capabilities .getCapability (name ));
195+ });
177196 }
178197}
0 commit comments