Saturday, September 26, 2020

Selenium Grid - 4 Tutorial - Standalone:

Selenium Grid allows the execution of WebDriver scripts on remote machines (virtual or real) by routing commands sent by the client to remote browser instances. It aims to provide an easy way to run tests in parallel on multiple machines.

Selenium Grid allows us to run tests in parallel on multiple machines, and to manage different browser versions and browser configurations centrally (instead of in each individual test).


Purpose and functionalities of Grid: 


we can use grid to achieve following purposes & Functionalities.

  • Central entry point for all tests
  • Management and control of the nodes / environment where the browsers run
  • Scaling
  • Running tests in parallel
  • Cross platform testing
  • Load balancing

When to use Grid:

  • To run your tests against multiple browsers, multiple versions of browser, and browsers running on different operating systems.
  • To reduce the time it takes for the test suite to complete a test pass.

Grid is used to speed up the execution of a test pass by using multiple machines to run tests in parallel. For example, if you have a suite of 100 tests, but you set up Grid to support 4 different machines (VMs or separate physical machines) to run those tests, your test suite will complete in (roughly) one-fourth the time as it would if you ran your tests sequentially on a single machine. For large test suites, and long-running test suite such as those performing large amounts of data-validation, this can be a significant time-saver. Some test suites can take hours to run. Another reason to boost the time spent running the suite is to shorten the turnaround time for test results after developers check-in code for the AUT. Increasingly software teams practicing Agile software development want test feedback as immediately as possible as opposed to wait overnight for an overnight test pass.


Grid is also used to support running tests against multiple runtime environments, specifically, against different browsers at the same time. For example, a ‘grid’ of virtual machines can be setup with each supporting a different browser that the application to be tested must support. So, machine 1 has Internet Explorer 8, machine 2, Internet Explorer 9, machine 3 the latest Chrome, and machine 4 the latest Firefox. When the test suite is run, Selenium-Grid receives each test-browser combination and assigns each test to run against its required browser.


In addition, one can have a grid of all the same browser, type and version. For instance, one could have a grid of 4 machines each running 3 instances of Firefox 70, allowing for a ‘server-farm’ (in a sense) of available Firefox instances. When the suite runs, each test is passed to Grid which assigns the test to the next available Firefox instance. In this manner one gets test pass where conceivably 12 tests are all running at the same time in parallel, significantly reducing the time required to complete a test pass.


Grid is very flexible. These two examples can be combined to allow multiple instances of each browser type and version. A configuration such as this would provide both, parallel execution for fast test pass completion and support for multiple browser types and versions simultaneously.



Grid 4:


Selenium Grid 4 is a fresh implementation and does not share the codebase the previous version had.

Grid 4 has an approach to take advantage of a number of new technologies in order to facilitate scaling up, while still allowing local execution.


In selenium Grid 4, many changes happened - Concept, commands, URLs and many more things have changed.


There are three ways to run Selenium Grid

  • Standalone
  • Classical Grid (Hub and node)
  • Fully Distributed (Session, Distributor etc)


Grid 4 Architecture:





Components:


1.  Router

The Router takes care of forwarding the request to the correct component.

It is the entry point of the Grid, all external requests will be received by it. The Router behaves differently depending on the request. If it is a new session request, the Router will forward it to the Distributor (where the new session creation will be handled). If the request belongs to an existing session, the Router will send the session id to the Session Map, and the Session Map will return the Node where the session is running. After this, the Router will forward the request to the Node.

The Router aims to balance the load in the Grid by sending the requests to the component that is able to handle them better, without overloading any component that is not needed in the process.


2.  Distributor

The Distributor is aware of all the Nodes and their capabilities. Its main role is to receive a new session request and find a suitable Node where the session can be created. After the session is created, the Distributor stores in the Session Map the relation between the session id and Node where the session is being executed.


3.  Node

A Node can be present several times in a Grid. Each Node takes care of managing the slots for the available browsers of the machine where it is running.

The Node registers itself to the Distributor through the Event Bus, and its configuration is sent as part of the registration message.

By default, the Node auto-registers all browser drivers available on the path of the machine where it runs. It also creates one slot per available CPU for Chromium based browsers and Firefox. For Safari and Internet Explorer, only one slot is created. Through a specific configuration, it can run sessions in Docker containers. 



4.  Session Map

The Session Map is a data store that keeps the information of the session id and the Node where the session is running. It serves as a support for the Router in the process of forwarding a request to the Node. The Router will ask the Session Map for the Node associated to a session id. When starting the Grid in its fully distributed mode, the Session Map is the first component that should be started.


5.  Event Bus

The Event Bus serves as a communication path between the Nodes, Distributor, and Session Map. The Grid does most of its internal communication through messages, avoiding expensive HTTP calls.


6.  Roles in Grid

In Grid 3, the components were Hub and Node, and it was possible to run them together by starting the Grid in Standalone mode. The same concept is available in Grid 4, it is possible to run a Hub by grouping some of the components described above, and it is also possible to run all components together in a Standalone mode.


7.  Hub

Hub is the union of the following components:

  •  Router
  •  Distributor
  •  Session Map
  •  Event Bus

It enables the classic Hub & Node(s) setup.


8.  Standalone

As mentioned before, Standalone is the union of all components, and to the user’s eyes, they are executed as one. This includes all the components which are part of the Hub, plus one Node. A fully functional Grid of one is available after starting it in the Standalone mode.



Now let’s understand how to use Standalone Selenium Grid with examples:


How to download selenium server jar:


Navigate to https://www.selenium.dev/downloads/ and download selenium-server version 4 jar


Copy your selenium server jar to folder and navigate to that path, form there open terminal or command prompt.


Run Selenium Grid 4:

Let’s add our first driver (chrome driver) into a folder. Then add this folder to the computer’s PATH and run the below command. If you don’t place Chrome or Firefox drivers in a folder you will not be able to execute test on those browsers


java -jar selenium-server-4.0.0-alpha-1.jar standalone



You will see an output like below. As you can see Chrome Driver is registered into our Grid.



Mahanteshs-MacBook-Pro:Grid mahanteshhadimani$ java -jar selenium-server-4.0.0-alpha-6.jar standalone

18:27:30.061 INFO [LoggingOptions.getTracer] - Using OpenTelemetry for       tracing

18:27:30.062 INFO [LoggingOptions.createTracer] - Using OpenTelemetry for tracing

18:27:30.094 INFO [EventBusOptions.createBus] - Creating event bus: org.openqa.selenium.events.local.GuavaEventBus

18:27:35.584 INFO [NodeOptions.report] - Adding Chrome for {"browserName": "chrome"} 16 times

18:27:35.585 INFO [NodeOptions.report] - Adding Firefox for {"browserName": "firefox"} 16 times

18:27:35.586 INFO [NodeOptions.report] - Adding Safari for {"browserName": "safari"} 1 times

18:27:35.616 INFO [LocalDistributor.add] - Added node a84b0c2b-12ac-44a1-960d-b2734c118b67.

18:27:35.617 INFO [Host.lambda$new$0] - Changing status of node a84b0c2b-12ac-44a1-960d-b2734c118b67 from DOWN to UP. Reason: http://192.168.1.3:4444 is ok

18:27:40.853 INFO [Standalone.execute] - Started Selenium standalone 4.0.0-alpha-6 (revision 5f43a29cfc): http://localhost:4444/


Then navigate to http://localhost:4444/status



You will see your driver registered with 16 instances. Safari driver is automatically registered as I am using a MacBook.


{

  "value": {

    "ready": true,

    "message": "Selenium Grid ready.",

    "nodes": [

      {

        "id": "a84b0c2b-12ac-44a1-960d-b2734c118b67",

        "uri": "http:\u002f\u002f192.168.1.3:4444",

        "maxSessions": 33,

        "stereotypes": [

          {

            "capabilities": {

              "browserName": "safari"

            },

            "count": 1

          },

          {

            "capabilities": {

              "browserName": "chrome"

            },

            "count": 16

          },

          {

            "capabilities": {

              "browserName": "firefox"

            },

            "count": 16

          }

        ],

        "sessions": [

        ]

      }

    ]

  }

}








Run a Test:


Now, you can implement your first test. You just need to point your RemoveWebDriver to http://localhost:4444/ instead of http://localhost:4444/wd/hub which is the relevant URL for Selenium Grid 2.



package sampleTests;



import java.net.MalformedURLException;

import java.net.URI;



import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.WebElement;

import org.openqa.selenium.chrome.ChromeOptions;

import org.openqa.selenium.remote.CapabilityType;

import org.openqa.selenium.remote.DesiredCapabilities;

import org.openqa.selenium.remote.RemoteWebDriver;

import org.testng.annotations.Test;



public class GridExample {



 @Test

   public void remoteTest(){

     ChromeOptions chromeOptions = new ChromeOptions();

     DesiredCapabilities caps = new DesiredCapabilities();

     caps.setCapability(CapabilityType.BROWSER_NAME,"chrome");

  

     caps.setCapability(ChromeOptions.CAPABILITY, chromeOptions);

     WebDriver driver = null;

     try {

       driver = new RemoteWebDriver(URI.create("http://localhost:4444/").toURL(), caps);

     } catch (MalformedURLException e) {

       e.printStackTrace();

     }

     driver.navigate().to("https://mahantesh-hadimani.blogspot.com/");

  

     WebElement header = driver.findElement(By.xpath("//h1"));

  

     System.out.println(header.isDisplayed());

   }



}
After the execution, if you navigate to http://localhost:4444/status you’ll be able to see the session details.


{

  "value": {

    "ready": true,

    "message": "Selenium Grid ready.",

    "nodes": [

      {

        "id": "a84b0c2b-12ac-44a1-960d-b2734c118b67",

        "uri": "http:\u002f\u002f192.168.1.3:4444",

        "maxSessions": 33,

        "stereotypes": [

          {

            "capabilities": {

              "browserName": "safari"

            },

            "count": 1

          },

          {

            "capabilities": {

              "browserName": "chrome"

            },

            "count": 16

          },

          {

            "capabilities": {

              "browserName": "firefox"

            },

            "count": 16

          }

        ],

        "sessions": [

          {

            "sessionId": "428e4a037fc94e23364a95f87f22dc41",

            "stereotype": {

              "browserName": "chrome"

            },

            "currentCapabilities": {

              "acceptInsecureCerts": false,

              "browserName": "chrome",

              "browserVersion": "85.0.4183.121",

              "chrome": {

                "chromedriverVersion": "85.0.4183.87 (cd6713ebf92fa1cacc0f1a598df280093af0c5d7-refs\u002fbranch-heads\u002f4183@{#1689})",

                "userDataDir": "\u002fvar\u002ffolders\u002f28\u002fbnw3p1vs3kx08zs6bq84sj3w0000gn\u002fT\u002f.com.google.Chrome.FB6KPX"

              },

              "goog:chromeOptions": {

                "debuggerAddress": "localhost:49916"

              },

              "networkConnectionEnabled": false,

              "pageLoadStrategy": "normal",

              "platformName": "mac os x",

              "proxy": {

              },

              "se:options": {

                "cdp": "http:\u002f\u002flocalhost:49916"

              },

              "setWindowRect": true,

              "strictFileInteractability": false,

              "timeouts": {

                "implicit": 0,

                "pageLoad": 300000,

                "script": 30000

              },

              "unhandledPromptBehavior": "dismiss and notify",

              "webauthn:virtualAuthenticators": true

            }

          },

          {

            "sessionId": "68efb58b1d81845b00ea8b15674060d4",

            "stereotype": {

              "browserName": "chrome"

            },

            "currentCapabilities": {

              "acceptInsecureCerts": false,

              "browserName": "chrome",

              "browserVersion": "85.0.4183.121",

              "chrome": {

                "chromedriverVersion": "85.0.4183.87 (cd6713ebf92fa1cacc0f1a598df280093af0c5d7-refs\u002fbranch-heads\u002f4183@{#1689})",

                "userDataDir": "\u002fvar\u002ffolders\u002f28\u002fbnw3p1vs3kx08zs6bq84sj3w0000gn\u002fT\u002f.com.google.Chrome.AfmYTG"

              },

              "goog:chromeOptions": {

                "debuggerAddress": "localhost:49602"

              },

              "networkConnectionEnabled": false,

              "pageLoadStrategy": "normal",

              "platformName": "mac os x",

              "proxy": {

              },

              "se:options": {

                "cdp": "http:\u002f\u002flocalhost:49602"

              },

              "setWindowRect": true,

              "strictFileInteractability": false,

              "timeouts": {

                "implicit": 0,

                "pageLoad": 300000,

                "script": 30000

              },

              "unhandledPromptBehavior": "dismiss and notify",

              "webauthn:virtualAuthenticators": true

            }

          }

        ]

      }

    ]

  }

}



Console Output:


[TestNG] Running:

  /private/var/folders/28/bnw3p1vs3kx08zs6bq84sj3w0000gn/T/testng-eclipse-594231446/testng-customsuite.xml



Sep 23, 2020 6:37:10 PM org.openqa.selenium.remote.ProtocolHandshake createSession

INFO: Detected dialect: W3C

true

PASSED: remoteTest



===============================================

    Default test

    Tests run: 1, Failures: 0, Skips: 0

===============================================





===============================================

Default suite

Total tests run: 1, Failures: 0, Skips: 0

===============================================



[TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 1 ms

[TestNG] Time taken by org.testng.reporters.jq.Main@7ce69770: 31 ms

[TestNG] Time taken by org.testng.reporters.XMLReporter@7e057f43: 2 ms

[TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@6440112d: 13 ms

[TestNG] Time taken by org.testng.reporters.JUnitReportReporter@7c137fd5: 5007 ms

[TestNG] Time taken by org.testng.reporters.EmailableReporter2@70ed52de: 3 ms









Friday, September 4, 2020

How to handle Camera, Mic & Show notification permission request Pop-ups | Selenium Automation

How to handle Camera, Mic & Show notification permission request Pop-ups | Selenium Automation

 

In this post will learn how to handle camera permission pop-up, mic permission pop up & show notification popup in your browser using selenium.

 


How to handle camera Permission pop-up & Mic permission pop up :


When browser try to take picture or use camera for video call, it will ask you to give permission. These pop-ups are different than user message pop-up displays regularly and we cannot handle these by switching. We need to provide do settings in browser profile to handle it.

 

Let’s see some examples for camera & Mic permission request Pop-ups:


Camera permission request popup



How to handle Mic permission request popup using selenium


The below full code, lets you automate to allow mic and camera permission request:

 

package practise;

 

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.chrome.ChromeDriver;

import org.openqa.selenium.chrome.ChromeOptions;

 

public class CameraMicrophonePermission {

    

     public static WebDriver driver;

 

     public static void main(String[] args) throws InterruptedException {

         

           ChromeOptions option = new ChromeOptions();

           option.addArguments("use-fake-device-for-media-stream"); // this argument for accepting permissions

           option.addArguments("use-fake-ui-for-media-stream");    // this argument for accepting permissions

         driver = new ChromeDriver(option);

        

        //WebCam Permission Test

         driver.get("https://webcamtests.com/check");

         Thread.sleep(5000);

         driver.findElement(By.id("webcam-launcher")).click();

         Thread.sleep(2000);

 

         //Mic permission test

         driver.get("https://www.vidyard.com/mic-test/");

         Thread.sleep(2000);

         driver.findElement(By.xpath("(//a[@id='start-test'])[1]")).click();

         Thread.sleep(2000);

 

         driver.quit();

 

     }

 

}


 

Handling web Show Notification popup:

 

Many times we come across handling permission request for showing notifications on browser during our automation scripts:


Show notification permission request popup


 

Using “managed_default_content_settings” we can handle it:

 

We need to set “notifications” as 1 to “Allow

                 set “notifications” as 1 to “Block

                 set “notifications” as 1 to “Default

 

       

  // SET CHROME OPTIONS

  // 0 - Default, 1 - Allow, 2 - Block

  contentSettings.put("notifications", 1);

  profile.put("managed_default_content_settings", contentSettings);

 

 

The below full code, lets you automate an ‘Allow’ or ‘Block’ interaction when your web app requests permission to show notifications:

 


package practise;

 

import java.util.HashMap;

import java.util.Map;

 

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.chrome.ChromeDriver;

import org.openqa.selenium.chrome.ChromeOptions;

 

public class WebNotificationExample

{

    

     public static WebDriver driver;

 

     public static void main(String[] args) throws InterruptedException {

         

 

          // INIT CHROME OPTIONS

         ChromeOptions options = new ChromeOptions();

         Map<String, Object> prefs = new HashMap<String, Object>();

         Map<String, Object> profile = new HashMap<String, Object>();

         Map<String, Object> contentSettings = new HashMap<String, Object>();

 

         // SET CHROME OPTIONS

         // 0 - Default, 1 - Allow, 2 - Block

         contentSettings.put("notifications", 1);

         profile.put("managed_default_content_settings", contentSettings);

         prefs.put("profile", profile);

         options.setExperimentalOption("prefs", prefs);

         driver = new ChromeDriver(options);

    

         driver.get("https://web-push-book.gauntface.com/demos/notification-examples/");

         driver.findElement(By.xpath("//input[@class='c-toggle js-example-toggle']")).click();

         Thread.sleep(5000);

         driver.quit();

 

     }

 

}


Do let me know if any issues/feedback in the comment section. 

 

 

Tuesday, September 1, 2020

How to Click Home Button in Appium| Mobile Automation

 

How to Click Home Button in Appium| Mobile Automation

 

In this post will learn how to get click Home button when we are using other app and want to go back Home Page.

 

 We can automate this functionality using PressKey command.

 

Command:


((PressesKey) driver).pressKey(new KeyEvent(AndroidKey.HOME));

 

Now lets write one sample program and lets see how we can click Home button:

 

package tests;

 

import java.io.IOException;

import java.net.URL;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.remote.DesiredCapabilities;

import io.appium.java_client.MobileElement;

import io.appium.java_client.android.AndroidDriver;

import io.appium.java_client.android.nativekey.AndroidKey;

import io.appium.java_client.android.nativekey.KeyEvent;

import io.appium.java_client.android.nativekey.PressesKey;

 

public class turnOnWifi {

 

       public static AndroidDriver<MobileElement> driver;

 

       public static void main(String args[]) throws InterruptedException, IOException {

 

              DesiredCapabilities cap = new DesiredCapabilities();

              cap.setCapability("deviceName", "emulator-5554"); // your device name from adb devices

              cap.setCapability("udid", "emulator-5554");// your udid from adb devices

              cap.setCapability("appActivity", "com.android.calculator2.Calculator");

              cap.setCapability("appPackage", "com.google.android.calculator");

              cap.setCapability("platformName", "Android");

              cap.setCapability("platformVersion", "R"); // your device platform version

              driver = new AndroidDriver<MobileElement>(new URL("http://0.0.0.0:4723/wd/hub"), cap);

              driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);

              Thread.sleep(5000);

 

              ((PressesKey) driver).pressKey(new KeyEvent(AndroidKey.HOME));

 

       }

 

}

 

 


 

Recorded Output:

 

 






Saturday, August 29, 2020

Screen Recording in Appium for Appium Tests | Appium Tests Screen Recorder

Recording Screen in Appium Test Execution

 

One of the best feature in Appium is Screen Recording for Appium Tests, we can record our Appium script execution and store it in local path.

 

Screen Recording in Appium is inbuilt unlike configuring things externally like how we do with Selenium.

 

We can record a complete session of Appium and recorded files can be saved to local drive.

 

 



Start Recording Screen:

 

To record the screen, we need to call the startRecordingScreen() method from the respective class.

 

driver.startRecordingScreen();


 

this above can be called without passing recording options like width, height and duration.


driver.startRecordingScreen(new BaseStartScreenRecordingOptions(....));





this above method, we need to use when we have specific requirement like width and height and duration of the recording.

 

Where

 

Video Size : The video size  of the generated media file. The format is WIDTHxHieght. The Default value is the device’s native display resolution(if supported). If not 1280x720.

 

Duration: The maximum recording time. The default and maximum value is 180 seconds(3 minutes).

 Setting values greater than this or less than zero(0) will cause an exception. The minimum time resolution unit is one second.

 

Since Appium 1.8.2 version, the time limit can be up to 1800 seconds (30 minutes). Appium automatically try to merge the 3-minutes chunks recorded, however, this requires FFMEG utility to be installed and available in PATH on server machine. If the utility is not present then the most recent screen recording chunk is going to be returned as result

 

 



                            

 

Example:

driver.startRecordingScreen(

                  new AndroidStartScreenRecordingOptions()

                      .withVideoSize("1280x720") .withTimeLimit(Duration.ofSeconds(200)));

 

In above example, we are setting width as 1280 and height as 720 and duration of the recording is 200 seconds.

 

Stopping Screen record:

 

 

In order to stop the recording, we need to call the stopRecordingScreen() method from the respective classes.

 

Driver.stopRecordingScreen();


 

 

The stopRecordingScreen() method returns a Base64 String. Using this string we need to build our video. There are many ways to do it, I have used methods from Java FileUtils and Base64 Decoder.

 

String video =driver.stopRecordingScreen();

           byte[] decode = Base64.getDecoder().decode(video);

           FileUtils.writeByteArrayToFile(new File("appiumRecorded.mp4"), decode);

Now Let’s see the example by writing full program and see the result:

 

Program:

 

package tests;

 

import java.io.File;

import java.io.IOException;

import java.net.URL;

import java.util.Base64;

import java.util.concurrent.TimeUnit;

import org.apache.commons.io.FileUtils;

import org.openqa.selenium.By;

import org.openqa.selenium.remote.DesiredCapabilities;

import io.appium.java_client.android.AndroidDriver;

import io.appium.java_client.android.AndroidStartScreenRecordingOptions;

import java.time.Duration;

 

public class ScreenRecordExample {

 

         public static AndroidDriver driver;

 

         public static void main(String args[]) throws InterruptedException, IOException {

 

                  DesiredCapabilities cap = new DesiredCapabilities();

                  cap.setCapability("deviceName", "emulator-5554"); // your device name from adb devices

                  cap.setCapability("udid", "emulator-5554");// your udid from adb devices

                  cap.setCapability("appActivity", "com.android.calculator2.Calculator");

                  cap.setCapability("appPackage", "com.google.android.calculator");

                  cap.setCapability("platformName", "Android");

                  cap.setCapability("platformVersion", "R"); // your device platform version

                  driver = new AndroidDriver(new URL("http://0.0.0.0:4723/wd/hub"), cap);

                  driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);

                  Thread.sleep(5000);

 

                  try {

 

                           // driver.startRecordingScreen();

                           driver.startRecordingScreen(new AndroidStartScreenRecordingOptions().withVideoSize("1280x720")

                                             .withTimeLimit(Duration.ofSeconds(200)));

                           driver.findElement(By.id("com.google.android.calculator:id/digit_8")).click();

                           driver.findElement(By.id("com.google.android.calculator:id/op_add")).click();

                           driver.findElement(By.id("com.google.android.calculator:id/digit_2")).click();

                           driver.findElement(By.id("com.google.android.calculator:id/eq")).click();

                           Thread.sleep(5000);

 

                  } catch (Exception ex) {

                           ex.printStackTrace();

                           System.out.println(driver.getPageSource());

 

                  }

 

                  finally {

 

                           String video = driver.stopRecordingScreen();

                           byte[] decode = Base64.getDecoder().decode(video);

                           FileUtils.writeByteArrayToFile(new File("appiumRecorded.mp4"), decode);

                           driver.quit();

                  }

 

         }

 

}

 

Output: this recorded file will be stored in your project main folder.





If any issues encountered let me know in the comment section: