1+ package com .testsigma .addons .mobileweb ;
2+
3+ import com .testsigma .sdk .ApplicationType ;
4+ import com .testsigma .sdk .WebAction ;
5+ import com .testsigma .sdk .annotation .Action ;
6+ import com .testsigma .sdk .annotation .TestData ;
7+ import com .testsigma .sdk .Result ;
8+ import lombok .Data ;
9+ import org .apache .commons .lang3 .exception .ExceptionUtils ;
10+ import org .openqa .selenium .NoSuchElementException ;
11+ import org .openqa .selenium .WebDriver ;
12+ import org .openqa .selenium .chromium .ChromiumDriver ;
13+ import org .openqa .selenium .devtools .Command ;
14+ import org .openqa .selenium .devtools .ConverterFunctions ;
15+ import org .openqa .selenium .devtools .DevTools ;
16+ import org .openqa .selenium .devtools .HasDevTools ;
17+ import org .openqa .selenium .remote .Augmenter ;
18+ import org .openqa .selenium .remote .RemoteWebDriver ;
19+
20+ import java .lang .reflect .Method ;
21+ import java .util .HashMap ;
22+ import java .util .Map ;
23+
24+ @ Data
25+ @ Action (
26+ actionText = "Switch Location to coordinates latitude: lat-val , longitude: long-val , accuracy: acc-val" ,
27+ description = "Overrides geolocation using Chrome DevTools" ,
28+ applicationType = ApplicationType .MOBILE_WEB ,
29+ useCustomScreenshot = false
30+ )
31+ public class MockGeoLocationAction extends WebAction {
32+
33+ @ TestData (reference = "lat-val" )
34+ private com .testsigma .sdk .TestData latVal ;
35+
36+ @ TestData (reference = "long-val" )
37+ private com .testsigma .sdk .TestData longVal ;
38+
39+ @ TestData (reference = "acc-val" )
40+ private com .testsigma .sdk .TestData accVal ;
41+
42+ @ Override
43+ public Result execute () throws NoSuchElementException {
44+ Result result = Result .SUCCESS ;
45+
46+ try {
47+ // Input Validation
48+ double latitude , longitude , accuracy ;
49+ try {
50+ latitude = Double .parseDouble (latVal .getValue ().toString ());
51+ logger .info ("Parsed latitude: " + latitude );
52+ } catch (NumberFormatException e ) {
53+ setErrorMessage ("Invalid latitude format. Must be a number. Value provided: " + latVal .getValue ());
54+ return Result .FAILED ;
55+ }
56+
57+ try {
58+ longitude = Double .parseDouble (longVal .getValue ().toString ());
59+ logger .info ("Parsed longitude: " + longitude );
60+ } catch (NumberFormatException e ) {
61+ setErrorMessage ("Invalid longitude format. Must be a number. Value provided: " + longVal .getValue ());
62+ return Result .FAILED ;
63+ }
64+
65+ try {
66+ accuracy = Double .parseDouble (accVal .getValue ().toString ());
67+ if (accuracy < 0 ) {
68+ setErrorMessage ("Invalid accuracy value. Must be a non-negative number. Value provided: " + accuracy );
69+ return Result .FAILED ;
70+ }
71+ logger .info ("Parsed accuracy: " + accuracy );
72+ } catch (NumberFormatException e ) {
73+ setErrorMessage ("Invalid accuracy format. Must be a number. Value provided: " + accVal .getValue ());
74+ return Result .FAILED ;
75+ }
76+
77+ Map <String , Object > coordinates = new HashMap <>();
78+ coordinates .put ("latitude" , latitude );
79+ coordinates .put ("longitude" , longitude );
80+ coordinates .put ("accuracy" , accuracy );
81+
82+ try {
83+ // Enhance the driver to support DevTools
84+ logger .info ("Augmenting driver to support DevTools..." );
85+ WebDriver driver1 = new Augmenter ().augment (this .driver );
86+
87+ // Initialize DevTools and create a session
88+ logger .info ("Initializing DevTools..." );
89+ DevTools devTool = ((HasDevTools ) driver1 ).getDevTools ();
90+ devTool .createSessionIfThereIsNotOne ();
91+ logger .info ("DevTools session successfully created." );
92+
93+ devTool .send (new Command <>("Emulation.setGeolocationOverride" , coordinates , ConverterFunctions .empty ()));
94+ logger .info ("Geolocation override applied successfully using DevTools." );
95+ } catch (Exception e ) {
96+ logger .info ("DevTools usage failed (" + e .getClass ().getSimpleName () + "), attempting fallback..." );
97+
98+ if (this .driver instanceof org .openqa .selenium .chromium .HasCdp ) {
99+ ((org .openqa .selenium .chromium .HasCdp ) this .driver ).executeCdpCommand ("Emulation.setGeolocationOverride" ,
100+ coordinates );
101+ logger .info ("Fallback to HasCdp (Chrome/Edge) execution successful." );
102+ } else if (this .driver instanceof ChromiumDriver ) {
103+ ((ChromiumDriver ) this .driver ).executeCdpCommand ("Emulation.setGeolocationOverride" , coordinates );
104+ logger .info ("Fallback to ChromiumDriver (Chrome/Edge) execution successful." );
105+ } else if (this .driver instanceof RemoteWebDriver ) {
106+ // Reflection hack for RemoteWebDriver to bypass HasDevTools/Augmenter
107+ Method execute = RemoteWebDriver .class .getDeclaredMethod ("execute" , String .class , Map .class );
108+ execute .setAccessible (true );
109+ Map <String , Object > params = new HashMap <>();
110+ params .put ("cmd" , "Emulation.setGeolocationOverride" );
111+ params .put ("params" , coordinates );
112+ execute .invoke (this .driver , "executeCdpCommand" , params );
113+ logger .info ("Fallback to RemoteWebDriver execution successful." );
114+ } else {
115+ throw e ; // Rethrow if no fallback is possible
116+ }
117+ }
118+
119+ } catch (Exception e ) {
120+ logger .warn ("Failed to override geolocation. Error: " + ExceptionUtils .getStackTrace (e ));
121+ setErrorMessage ("Failed to override geolocation. Error: " + ExceptionUtils .getMessage (e ));
122+ result = Result .FAILED ;
123+ }
124+
125+ return result ;
126+ }
127+ }
0 commit comments