3
3
import TeamControlium .Utilities .Logger ;
4
4
5
5
import TeamControlium .Utilities .TestData ;
6
+ import org .apache .commons .io .FilenameUtils ;
6
7
import org .apache .commons .lang3 .time .StopWatch ;
7
8
import org .openqa .selenium .By ;
8
9
import org .openqa .selenium .JavascriptExecutor ;
9
10
import org .openqa .selenium .WebDriver ;
10
11
import org .openqa .selenium .WebElement ;
11
-
12
+ import org .openqa .selenium .chrome .ChromeDriver ;
13
+ import org .openqa .selenium .chrome .ChromeDriverService ;
14
+ import org .openqa .selenium .chrome .ChromeOptions ;
15
+ import org .openqa .selenium .edge .EdgeDriver ;
16
+ import org .openqa .selenium .edge .EdgeDriverService ;
17
+ import org .openqa .selenium .edge .EdgeOptions ;
18
+ import org .openqa .selenium .ie .InternetExplorerDriver ;
19
+ import org .openqa .selenium .ie .InternetExplorerDriverLogLevel ;
20
+ import org .openqa .selenium .ie .InternetExplorerDriverService ;
21
+ import org .openqa .selenium .ie .InternetExplorerOptions ;
22
+
23
+ import javax .swing .text .Utilities ;
24
+ import java .io .File ;
25
+ import java .nio .file .Files ;
26
+ import java .nio .file .Path ;
27
+ import java .nio .file .Paths ;
12
28
import java .time .Duration ;
13
29
import java .util .ArrayList ;
30
+ import java .util .Arrays ;
14
31
import java .util .List ;
15
32
import java .util .concurrent .TimeUnit ;
16
33
@@ -40,6 +57,10 @@ public class SeleniumDriver {
40
57
private Browsers _browser =null ;
41
58
private Devices _device =null ;
42
59
private String seleniumHost ;
60
+ private boolean isLocalSelenium =true ;
61
+ private String seleniumServerFolder =null ;
62
+ private boolean seleniumDebugMode =false ;
63
+ private String seleniumLogFilename =null ;
43
64
44
65
public SeleniumDriver (String seleniumHost ,String device ,String browser ) {
45
66
commonConstructs ();
@@ -58,19 +79,49 @@ public SeleniumDriver(String device,String browser) {
58
79
Browsers .SetTestBrowser (browser );
59
80
Devices .SetTestDevice (device );
60
81
setSeleniumHost (seleniumHost );
82
+ startOrConnectToSeleniumServer ();
61
83
}
62
84
public SeleniumDriver () {
63
85
commonConstructs ();
64
86
Browsers .SetTestBrowser ();
65
87
Devices .SetTestDevice ();
66
88
setSeleniumHost (null );
89
+ startOrConnectToSeleniumServer ();
67
90
}
68
91
69
92
private void commonConstructs () {
70
93
// Initialise defaults
71
94
setFindTimeout (Duration .ofMillis (defaultTimeout ));
72
95
setPollInterval (Duration .ofMillis (defaultPollInterval ));
73
96
setPageLoadTimeout (Duration .ofMillis (defaultTimeout ));
97
+
98
+ // Selenium Parameters
99
+ try {
100
+ seleniumServerFolder = TestData .getItem (String .class , SeleniumServerFolder [0 ], SeleniumServerFolder [1 ]);
101
+ }
102
+ catch (Exception e ){
103
+ Logger .WriteLine (Logger .LogLevels .TestDebug , "Selenium Server Folder not set in TestData (%s.%s). Defaulting to local" ,SeleniumServerFolder [0 ], SeleniumServerFolder [1 ]);
104
+ seleniumServerFolder = System .getProperty ("user.dir" );
105
+ }
106
+ Logger .WriteLine (Logger .LogLevels .TestInformation , "Selenium Server Folder [%s]" ,seleniumServerFolder );
107
+
108
+ try {
109
+ seleniumDebugMode = TeamControlium .Utilities .General .IsValueTrue (TestData .getItem (String .class , SeleniumDebugMode [0 ], SeleniumDebugMode [1 ]));
110
+ }
111
+ catch (Exception e ){
112
+ Logger .WriteLine (Logger .LogLevels .TestDebug , "Selenium Server debug mode not set in TestData (%s.%s). Defaulting to off" ,SeleniumDebugMode [0 ], SeleniumDebugMode [1 ]);
113
+ seleniumDebugMode =false ;
114
+ }
115
+ Logger .WriteLine (Logger .LogLevels .TestInformation , "Selenium Debug Mode: [%s]" ,seleniumDebugMode ?"on" :"off" );
116
+
117
+ try {
118
+ seleniumLogFilename = TestData .getItem (String .class , SeleniumLogFilename [0 ], SeleniumLogFilename [1 ]);
119
+ }
120
+ catch (Exception e ){
121
+ Logger .WriteLine (Logger .LogLevels .TestDebug , "Selenium Log filename not set in TestData (%s.%s). Defaulting to stdio (console)" ,SeleniumLogFilename [0 ], SeleniumLogFilename [1 ]);
122
+ seleniumLogFilename =null ;
123
+ }
124
+ Logger .WriteLine (Logger .LogLevels .TestInformation , "Selenium Log filename: [%s]" ,seleniumLogFilename ==null ?"stdio (console)" :seleniumLogFilename );
74
125
}
75
126
76
127
@@ -223,27 +274,6 @@ public HTMLElement findElement(HTMLElement parentElement,ObjectMapping objectMap
223
274
return clauseResults .get (0 );
224
275
}
225
276
226
- private List <HTMLElement > getHtmlElements (HTMLElement parentElement , ObjectMapping objectMapping , boolean allowMultipleMatches , boolean waitUntilSingle , boolean showMultiFound , long totalTimeoutMillis , long pollIntervalMillis , StopWatch timer ) {
227
- List <HTMLElement > clauseResults = new ArrayList <HTMLElement >();
228
- while (clauseResults .size () == 0 || (clauseResults .size () != 1 && !allowMultipleMatches && waitUntilSingle )) {
229
- clauseResults = findElements (parentElement , objectMapping );
230
- if (clauseResults .size () == 0 || (clauseResults .size () != 1 && !allowMultipleMatches && waitUntilSingle )) {
231
- if (clauseResults .size () > 0 && showMultiFound ) {
232
- Logger .WriteLine (Logger .LogLevels .TestDebug , "Found %d elements matching [%s]. Waiting until only a single element is found..." , clauseResults .size (), objectMapping .getActualFindLogic ());
233
- showMultiFound = false ;
234
- }
235
- try {
236
- Thread .sleep (pollIntervalMillis );
237
- } catch (Exception e ) {
238
- Logger .WriteLine (Logger .LogLevels .Error , "Thread.sleep threw an exception after %s so aborting" , durationFormatted (timer .getTime ()));
239
- throw new RuntimeException (String .format ("Exception thrown while thread sleeping during Find Element (for [%s]) poll interval!" , objectMapping .getFriendlyName ()));
240
- }
241
- if (timer .getTime () >= totalTimeoutMillis ) break ;
242
- }
243
- }
244
- return clauseResults ;
245
- }
246
-
247
277
public List <HTMLElement > findElements (HTMLElement parentElement , ObjectMapping mapping ) {
248
278
249
279
List <WebElement > foundElements ;
@@ -336,7 +366,13 @@ public void executeJavaScriptNoReturnData(String script, Object[] args)
336
366
Object dummy = executeJavaScript (Object .class ,script ,args );
337
367
}
338
368
339
- public static void resetSettings () {
369
+
370
+ private void startOrConnectToSeleniumServer () {
371
+ if (isLocalSelenium ) {
372
+ setupLocalRun ();
373
+ } else {
374
+ throw new RuntimeException ("Remote server execution mot yet implemented!" );
375
+ }
340
376
}
341
377
342
378
private void setSeleniumHost (String host ) {
@@ -356,6 +392,174 @@ private void setSeleniumHost(String host) {
356
392
}
357
393
seleniumHost ="localhost" ;
358
394
}
395
+ isLocalSelenium = (seleniumHost .equalsIgnoreCase ("localhost" ) || seleniumHost .equals ("127.0.0.1" ));
396
+ }
397
+
398
+ private void setupLocalRun () {
399
+ Logger .WriteLine (Logger .LogLevels .FrameworkDebug , "Running Selenium locally" );
400
+
401
+ try {
402
+ if (Browsers .isInternetExplorer ()) {
403
+ //
404
+ // See https://code.google.com/p/selenium/issues/detail?id=4403
405
+ //
406
+ String executable ="IEDriver.exe" ;
407
+ InternetExplorerOptions IEO = new InternetExplorerOptions ();
408
+ IEO .destructivelyEnsureCleanSession ();
409
+
410
+ setPathToDriverIfExistsAndIsExecutable (seleniumServerFolder , InternetExplorerDriverService .IE_DRIVER_EXE_PROPERTY ,executable );
411
+ if (seleniumDebugMode )
412
+ System .setProperty (InternetExplorerDriverService .IE_DRIVER_LOGLEVEL_PROPERTY , "INFO" );
413
+
414
+
415
+ if (seleniumLogFilename != null ) {
416
+ Logger .WriteLine (Logger .LogLevels .FrameworkInformation , "Writing Selenium Server Output to: %s" , seleniumLogFilename );
417
+ System .setProperty (InternetExplorerDriverService .IE_DRIVER_LOGFILE_PROPERTY , CheckAndPreparSeleniumLogFile (seleniumLogFilename ));
418
+ } else {
419
+ Logger .WriteLine (Logger .LogLevels .FrameworkInformation , "Writing Selenium Server Output to console" );
420
+ }
421
+
422
+ InternetExplorerDriverService service = InternetExplorerDriverService .createDefaultService ();
423
+
424
+ IEO .setCapability ("INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS" , (boolean ) true ); // Enabling this as part of #ITSD1-1126 - If any issues come back to request
425
+ Logger .WriteLine (Logger .LogLevels .TestInformation , "IE Browser being used. Setting INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS active. #ITSD1-1126" );
426
+ webDriver = new InternetExplorerDriver (service , IEO );
427
+ }
428
+ else if (Browsers .isChrome ()) {
429
+ String executable = "ChromeDriver.exe" ;
430
+ ChromeOptions options = new ChromeOptions ();
431
+
432
+
433
+
434
+ setPathToDriverIfExistsAndIsExecutable (seleniumServerFolder , ChromeDriverService .CHROME_DRIVER_EXE_PROPERTY ,executable );
435
+ if (seleniumDebugMode ) System .setProperty (ChromeDriverService .CHROME_DRIVER_VERBOSE_LOG_PROPERTY , "true" );
436
+
437
+ if (seleniumLogFilename != null ) {
438
+ Logger .WriteLine (Logger .LogLevels .FrameworkInformation , "Writing Selenium Server Output to: %s" , seleniumLogFilename );
439
+ System .setProperty (ChromeDriverService .CHROME_DRIVER_LOG_PROPERTY , CheckAndPreparSeleniumLogFile (seleniumLogFilename ));
440
+ } else {
441
+ Logger .WriteLine (Logger .LogLevels .FrameworkInformation , "Writing Selenium Server Output to console" );
442
+ }
443
+
444
+ webDriver = new ChromeDriver (ChromeDriverService .createDefaultService (), options );
445
+ }
446
+ else if (Browsers .isEdge ()) {
447
+ String executable = "EdgeDriver.exe" ;
448
+ EdgeOptions options = new EdgeOptions ();
449
+
450
+ setPathToDriverIfExistsAndIsExecutable (seleniumServerFolder , EdgeDriverService .EDGE_DRIVER_EXE_PROPERTY ,executable );
451
+ if (seleniumDebugMode ) System .setProperty (EdgeDriverService .EDGE_DRIVER_VERBOSE_LOG_PROPERTY , "true" );
452
+
453
+ if (seleniumLogFilename != null ) {
454
+ Logger .WriteLine (Logger .LogLevels .FrameworkInformation , "Writing Selenium Server Output to: %s" , seleniumLogFilename );
455
+ System .setProperty (EdgeDriverService .EDGE_DRIVER_LOG_PROPERTY , CheckAndPreparSeleniumLogFile (seleniumLogFilename ));
456
+ } else {
457
+ Logger .WriteLine (Logger .LogLevels .FrameworkInformation , "Writing Selenium Server Output to console" );
458
+ }
459
+
460
+ webDriver = new EdgeDriver (EdgeDriverService .createDefaultService (), options );
461
+ }
462
+ else {
463
+ throw new RuntimeException (String .format ("Browser [%s] not yet implemented!" ,Browsers .getBrowserType ().name ()));
464
+ }
465
+ } catch (Exception e ) {
466
+ throw new RuntimeException (String .format ("Error instantiating [%s] (%s)" , Browsers .isChrome () ? "Chrome" : Browsers .isEdge () ? "Edge" : Browsers .isInternetExplorer () ? "Internet Explorer" : Browsers .isSafari () ? "Safari" : "UNKNOWN!" , seleniumServerFolder ));
467
+ }
468
+ }
469
+
470
+ private List <HTMLElement > getHtmlElements (HTMLElement parentElement , ObjectMapping objectMapping , boolean allowMultipleMatches , boolean waitUntilSingle , boolean showMultiFound , long totalTimeoutMillis , long pollIntervalMillis , StopWatch timer ) {
471
+ List <HTMLElement > clauseResults = new ArrayList <HTMLElement >();
472
+ while (clauseResults .size () == 0 || (clauseResults .size () != 1 && !allowMultipleMatches && waitUntilSingle )) {
473
+ clauseResults = findElements (parentElement , objectMapping );
474
+ if (clauseResults .size () == 0 || (clauseResults .size () != 1 && !allowMultipleMatches && waitUntilSingle )) {
475
+ if (clauseResults .size () > 0 && showMultiFound ) {
476
+ Logger .WriteLine (Logger .LogLevels .TestDebug , "Found %d elements matching [%s]. Waiting until only a single element is found..." , clauseResults .size (), objectMapping .getActualFindLogic ());
477
+ showMultiFound = false ;
478
+ }
479
+ try {
480
+ Thread .sleep (pollIntervalMillis );
481
+ } catch (Exception e ) {
482
+ Logger .WriteLine (Logger .LogLevels .Error , "Thread.sleep threw an exception after %s so aborting" , durationFormatted (timer .getTime ()));
483
+ throw new RuntimeException (String .format ("Exception thrown while thread sleeping during Find Element (for [%s]) poll interval!" , objectMapping .getFriendlyName ()));
484
+ }
485
+ if (timer .getTime () >= totalTimeoutMillis ) break ;
486
+ }
487
+ }
488
+ return clauseResults ;
489
+ }
490
+
491
+
492
+ private void setPathToDriverIfExistsAndIsExecutable (final String pathToDriver , final String driverExeProperty ,String executable ) {
493
+ final File driver = new File (pathToDriver ,executable );
494
+ if (driver .exists () && driver .canExecute ()) {
495
+ System .setProperty (driverExeProperty , driver .getAbsolutePath ());
496
+ } else {
497
+ throw new IllegalArgumentException (String .format ("Driver not found or is not executable in %s" , pathToDriver ));
498
+ }
499
+ }
500
+
501
+ private String CheckAndPreparSeleniumLogFile (String SeleniumDebugFile ) {
502
+ String seleniumDebugFile = SeleniumDebugFile ;
503
+ String pathAndFile = "" ;
504
+
505
+ if (seleniumDebugFile ==null || seleniumDebugFile .isEmpty ())
506
+ return null ;
507
+ else
508
+ {
509
+ //
510
+ // If path is relative, make it absolute..
511
+ //
512
+ final File debugFile = new File (seleniumDebugFile );
513
+ String seleniumDebugFileFolder = debugFile .getAbsolutePath ();
514
+
515
+ // File path/name is passed on CMD line so remove all spaces
516
+ String seleniumDebugFileName = FilenameUtils .removeExtension (seleniumDebugFile );
517
+ String seleniumDebugFileExt = FilenameUtils .getExtension (seleniumDebugFile );
518
+ Logger .WriteLine (Logger .LogLevels .FrameworkDebug , "SeleniumDebugFile: [%s]" ,seleniumDebugFile );
519
+ Logger .WriteLine (Logger .LogLevels .FrameworkDebug , "seleniumDebugFileFolder: [%s]" ,seleniumDebugFileFolder );
520
+ Logger .WriteLine (Logger .LogLevels .FrameworkDebug , "seleniumDebugFileName: [%s]" ,seleniumDebugFileName );
521
+ Logger .WriteLine (Logger .LogLevels .FrameworkDebug , "seleniumDebugFileExt: [%s]" ,seleniumDebugFileExt );
522
+
523
+
524
+ if (seleniumDebugFileFolder ==null || seleniumDebugFileFolder .isEmpty ()) seleniumDebugFileFolder = System .getProperty ("user.dir" );
525
+
526
+ try
527
+ {
528
+ int TotalPathLength = seleniumDebugFileFolder .length () + seleniumDebugFileName .length () + seleniumDebugFileExt .length () + 2 ;
529
+ Logger .WriteLine (Logger .LogLevels .FrameworkDebug , "Selenium Debug File - [%s %s.%s]" , seleniumDebugFileFolder , seleniumDebugFileName , seleniumDebugFileExt );
530
+ Logger .WriteLine (Logger .LogLevels .FrameworkDebug , "Selenium Debug File TotalPathLength = %d" , TotalPathLength );
531
+ if (TotalPathLength > 248 )
532
+ {
533
+ //
534
+ // Max path length is 248, so we need to fiddle....
535
+ //
536
+ if ((seleniumDebugFileFolder .length () - seleniumDebugFileName .length () - seleniumDebugFileExt .length () -2 ) > 248 )
537
+ {
538
+ // Ok, we cant do it so bomb out.
539
+ Logger .WriteLine (Logger .LogLevels .FrameworkDebug , "seleniumDebugFileFolder length %d so cannot fix path length by truncating seleniumDebugFileName" , seleniumDebugFileFolder .length ());
540
+ throw new RuntimeException (String .format ("Cannot Selenium Debug file. Full path [%d] would have been too long (Max 248 chars)" ,TotalPathLength ));
541
+ }
542
+ else
543
+ {
544
+ Logger .WriteLine (Logger .LogLevels .FrameworkDebug , "Reducing path length by truncating seleniumDebugFileName (length currently %d)" , seleniumDebugFileName .length ());
545
+ // Ok, we can do it. Just truncate the TestID the required length...
546
+ seleniumDebugFileName = seleniumDebugFileName .substring (0 , seleniumDebugFileName .length () - (TotalPathLength - 248 ));
547
+ Logger .WriteLine (Logger .LogLevels .FrameworkDebug , "Reduced to length %d" , seleniumDebugFileName .length ());
548
+ }
549
+ }
550
+
551
+ pathAndFile = Paths .get (seleniumDebugFileFolder ,(seleniumDebugFileName + seleniumDebugFileExt )).toString ();
552
+
553
+ (new File (pathAndFile )).mkdirs ();
554
+
555
+ Files .write (Paths .get (pathAndFile ), Arrays .asList ("TeamControlium Selenium Debug File" ));
556
+ return pathAndFile ;
557
+ }
558
+ catch (Exception ex )
559
+ {
560
+ throw new RuntimeException (String .format ("Error creating Selenium Debug information file (%s): %s" , pathAndFile ,ex .getMessage ()));
561
+ }
562
+ }
359
563
}
360
564
361
565
private String durationFormatted (Duration duration ) {
0 commit comments