@@ -34,7 +34,18 @@ public class RemoteWebDriverAdvice {
3434
3535 // LambdaTest-specific keys that should ONLY be in lt:options, not at W3C top level
3636 // These keys cause W3C validation errors in Selenium 4 if set at top level
37- private static final Set <String > LT_SPECIFIC_KEYS = Set .of ("build" , "name" , "projectName" , "resolution" );
37+ private static final Set <String > LT_SPECIFIC_KEYS = Set .of (
38+ "build" , "name" , "projectName" , "resolution" ,
39+ "buildTags" , "driver_version" , "tags"
40+ );
41+
42+ // Selenium 3 capabilities that should be moved to lt:options when using Selenium 4
43+ // These are legacy capabilities that Selenium 4 rejects at top level
44+ private static final Set <String > SELENIUM3_LEGACY_KEYS = Set .of (
45+ "version" , "commandLog" , "systemLog" , "network.http2" ,
46+ "DisableXFHeaders" , "network.debug" , "ignoreFfOptionsArgs" ,
47+ "updateBuildStatusOnSuccess" , "lambda:loadExtension"
48+ );
3849
3950 /**
4051 * Static method to enhance capabilities that can be called from ASM bytecode.
@@ -112,6 +123,20 @@ public static void enhanceCapabilities(MutableCapabilities capabilities) {
112123 continue ;
113124 }
114125
126+ // Selenium 3 legacy capabilities should be moved to lt:options when using Selenium 4
127+ // (Selenium 4 rejects these at top level)
128+ if (SELENIUM3_LEGACY_KEYS .contains (key )) {
129+ // Skip empty string values (e.g., lambda:loadExtension: "")
130+ if (value instanceof String && ((String ) value ).trim ().isEmpty ()) {
131+ continue ;
132+ }
133+ // Move to lt:options instead of top level
134+ if (!ltOptions .containsKey (key )) {
135+ ltOptions .put (key , value );
136+ }
137+ continue ;
138+ }
139+
115140 // Add valid W3C capabilities to top level
116141 if (!userCapMap .containsKey (key )) {
117142 capabilities .setCapability (key , value );
@@ -127,8 +152,60 @@ public static void enhanceCapabilities(MutableCapabilities capabilities) {
127152 if (!ltOptions .containsKey (ltKey )) {
128153 ltOptions .put (ltKey , ltValue );
129154 }
155+ // Remove from top level by setting to null (safer than remove on potentially unmodifiable map)
156+ try {
157+ capabilities .setCapability (ltKey , (Object ) null );
158+ } catch (Exception e ) {
159+ // If setCapability with null doesn't work, try to remove from map
160+ try {
161+ if (capabilities .asMap () instanceof java .util .Map ) {
162+ ((java .util .Map <String , Object >) capabilities .asMap ()).remove (ltKey );
163+ }
164+ } catch (Exception e2 ) {
165+ // Ignore - capability might already be removed or map is unmodifiable
166+ }
167+ }
168+ }
169+ }
170+
171+ // Clean up: Remove Selenium 3 legacy capabilities from top level (Selenium 4 rejects them)
172+ // Move them to lt:options instead
173+ for (String legacyKey : SELENIUM3_LEGACY_KEYS ) {
174+ if (capabilities .asMap ().containsKey (legacyKey )) {
175+ Object legacyValue = capabilities .getCapability (legacyKey );
176+ // Skip empty string values
177+ if (legacyValue instanceof String && ((String ) legacyValue ).trim ().isEmpty ()) {
178+ // Just remove from top level, don't add to lt:options
179+ try {
180+ capabilities .setCapability (legacyKey , (Object ) null );
181+ } catch (Exception e ) {
182+ try {
183+ if (capabilities .asMap () instanceof java .util .Map ) {
184+ ((java .util .Map <String , Object >) capabilities .asMap ()).remove (legacyKey );
185+ }
186+ } catch (Exception e2 ) {
187+ // Ignore
188+ }
189+ }
190+ continue ;
191+ }
192+ // Ensure it's in lt:options
193+ if (!ltOptions .containsKey (legacyKey )) {
194+ ltOptions .put (legacyKey , legacyValue );
195+ }
130196 // Remove from top level
131- capabilities .asMap ().remove (ltKey );
197+ try {
198+ capabilities .setCapability (legacyKey , (Object ) null );
199+ } catch (Exception e ) {
200+ // If setCapability with null doesn't work, try to remove from map
201+ try {
202+ if (capabilities .asMap () instanceof java .util .Map ) {
203+ ((java .util .Map <String , Object >) capabilities .asMap ()).remove (legacyKey );
204+ }
205+ } catch (Exception e2 ) {
206+ // Ignore - capability might already be removed or map is unmodifiable
207+ }
208+ }
132209 }
133210 }
134211
0 commit comments