This article will be useful for young QA specialists, as well as those who are interested in the features and capabilities of such popular testing frameworks as Selenide and Selenoid. Here we will look into some a basic Selenium project. I will describe how to connect Selenium and TestNG to the project and will see a Page Object example with the description of page elements and the methods used. The next step is the acquaintance with Selenide: we will see into the framework itself, look through its main features and advantages of usage. Will learn how to add Selenide to a testing project, how to work with elements, assertions, and waits available in Selenide. And finally, I will connect the Selenoid framework to the project to run tests in the Docker container and outside it. 1. Selenium + TestNG. Selenium Maven We are considering a project build on the builder, so we can find the project structure description in the file. To order use , we should add appropriate dependencies to file. You can observe them between the tags below: Maven pom.xml Selenium+TestNG pom.xml dependencies <?xml version= encoding= ?> <modelVersion>4.0.0</modelVersion> <groupId>test</groupId> <artifactId>test</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>3.141.59</version> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.14.3</version> <scope>test</scope> </dependency> </dependencies> "1.0" "UTF-8" < = = = > project xmlns "http://maven.apache.org/POM/4.0.0" xmlns:xsi "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" </ > project Here is an example of the Page Object: ... public { private WebDriver driver; public SignUpPage(WebDriver driver) { .driver = driver; } private By emailField = cssSelector( ); private By confirmEmailField = cssSelector( ); private By passwordField = cssSelector( ); private By displayNameField = cssSelector( ); private By monthDropDown = cssSelector( ); private By dayField = cssSelector( ); private By yearField = cssSelector( ); private By shareCheckbox = cssSelector( ); private By registerButton = cssSelector( ); public SignUpPage typeEmail( email) { driver.findElement(emailField).sendKeys(email); ; } public SignUpPage typeConfirmEmailField( email) {...} public SignUpPage typePassword( password) {...} public SignUpPage typeName( name) {...} public SignUpPage setMonth( month) {...} public SignUpPage typeDay( day) {...} public SignUpPage typeYear( year) {...} import class SignUpPage this "#register-email" "#register-confirm-email" "#register-password" "#register-displayname" "#register-dob-month" "#register-dob-day" "#register-dob-year" "#register-thirdparty" "#register-button-email-submit" String return this String String String String String String As we can see, there is a description of variables with locators for the elements of the registration page at the top of the java file. There are methods directly for interacting with elements of our page below the variable section. Let’s open the tests themselves: private WebDriver driver; private SignUpPage page; @BeforeMethod public setUp() { System.setProperty( , ); driver = FirefoxDriver(); driver.manage().timeouts().impicitlyWait( , TimeUnit.SECONDS); driver.get( ); } void "webdriver.gecko.driver" "C:\\Users\\Nikita\\IdeaProjects\\autotests_examples\\drivers\\geckodriver.exe" new 10 "https://www.spotify.com/us/signup/" As we can see, in the annotation we describe what will have before each method. @BeforeMethod @Test public typeInvalidYear() { page = SignUpPage(driver); page.setMonth( ); .typeDay( ) .typeYear( ) .setShare( ); Assert.assertTrue(page.isErrorVisible( )); void new "December" "20" "85" true "Please enter a valid year." The annotation provides code for test methods. @Test @AfterMethod public tearDown() { driver.quit(); } void The annotation contains the code that should be executed after each method. When running tests using Selenium, the following will happen: @AfterMethod Opening a separate browser window Following the url Test code execution Closing browser session after each test case When running the next test the same things will happen. It should be mentioned that running tests on Selenium is rather a resource-consuming process. 2. Selenide: what, where, and how So what is Selenide itself? What are its main features and advantages? In short, is a wrapper around Selenium WebDriver that makes it quick and easy to use when writing tests. At its core, Selenide is a tool for automating user actions in a browser, focused on the convenience and ease of implementing business logic in autotests in the user’s language, without being distracted by the technical details of working with the “browser driver”. For example, we do not need to focus on working with the waiting for elements in the process of automating testing of dynamic web applications, as well as on the implementation of high-level actions on elements. Key and main advantages of Selenide: Selenide Concise jQuery-style syntax Automatic handling of most problems with Ajax, waitings and timeouts Automatic handling of browser lifecycle Automatic creation of screenshots The purpose of Selenide is to of tests and not “waste” mental energy on technical details. focus on business logic Getting started with the Selenide To get started with the Selenide we need to add the Selenide dependency to the file. Since we no longer need the Selenium dependency, we simply remove it. pom.xml <dependency> <artifactId>selenide< version> com.codeborne < > groupId </ > groupId /artifactId> <version>5.2.8</ </ > dependency In order to start using Selenide in our project, we also need to make some imports. Here are the examples of import required classes: import static com.codeborne.selenide.Selenide.*; import static com.codeborne.selenide.Selectors.*; import static com.codeborne.selenide.Condition.*; import static com.codeborne.selenide.CollectionCondition.*; For more information on how to connect Selenide using the rest of the project builders, see the section of Selenide documentation. Quick start Working with elements, assertions, and waits Let’s move on to the Selenide elements and consider the assertions and waits available in Selenide. ... public { private SignUpPage page; @BeforeClass public setUp() { baseurl = ; browser = ; } import class SignUpTest static void "https://www.spotify.com" "chrome" We replace the annotation with the annotation in the test file since we no longer need it. Selenide eliminates the need to write and methods as Selenide takes care of the function. We only have the annotation left to register a pair of properties. BeforeMethod BeforeClass Before After AfterMethod BeforeClass We registered the , which is in the and in the BeforeClass annotation and it will be the base url. Therefore, the that we used in our Selenium tests is no longer needed. We set the browser on which we will run our tests in the . property baseurl configuration class driver.get property browser We can completely abandon the Selenium driver in our test project, Selenide will take care of all the work, encapsulating it in its classes. We will only have to focus on the logic of the tests themselves. Let’s proceed to using Selenide on our page: public SignUpPage open() { Selenide.open (relativeOrAbsoluteUrl: ); ; } public SignUpPage typeEmail( email) { $(emailField).sendKeys(email); ; } "/us/signup/" return this String return this When invoking the open method, Selenide itself starts a browser session and opens a web page. Selenide also makes sure the browser is closed at the end. Within Selenide. we can write either the whole url path, or we can write a . Since we indicated an absolute path as a , within the Selenide. method it’s enough to indicate just “/”. open http relative url baseurl open public SignUpPage typeEmail( email) { $(emailField.sendKeys(email); ; } public SignUpPage typeConfirmEmailField( email) { $(confirmEmailField).setValue(email); ; } String return this String return this In order to find an element using Selenide, we should indicate instead of command used in Selenium. I.e using a one-character method we can find directly the element itself. The search method is accepted as a string, similar to the jQuery JavaScript library by default. $ driver.findElement In order to find a list of elements using Selenide, we should indicate $$ characters. Instead of , we write the command that is already extended with additional methods. List <WebElement> ElementsCollection To work with elements we can use both standard Selenium methods and method or its short version . (sendKeys()) setValue() vаl() As you can see, Selenide methods are more understandable. Method remains the same, though Selenide has several click() methods: (right mouse button imitation) ( imitation of double click on element ) and so on. Having a certain element found, we can continue the search using other locators. click() contextClick() doubleClick() The difference between Selenide method and Selenium is that Selenide can immediately receive CSS selectors and operate with the Selenide elements, not the Web elements. Basically, Selenide-elements are a more “smart” alternative to Selenium web elements. find() driver.findElement(By) find() Selenide already contains those methods, which would have to be done through an class or some other way. Selenide allows writing brief and “nice” methods that are understandable for everybody. Selenide is also rather flexible, and due to that, we can use standard Selenium features. action You can find more information about Selenide methods in the . official documentation Let’s look into wider and more understandable verification examples provided by Selenide: page.getError( ).shouldBe(Condition.visible); page.getError( ).shouldNotBe(Condition.visible); page.getErrors().shouldHave(CollectionCondition.size( )); page.getErrorByNumber( ).shouldHave(Condition.text( )); "Please enter a valid year." "When were you born?" 6 3 "Please enter your birth month." Selenide verification scheme allows us to take any element, find it and use the following assertions for it: should, shouldBe, shouldHave, shouldNot, shouldNotBe and shouldNotHave. Depending on the logic and our needs, we use certain . When we want to check if the element exists, we use . When we want to check if the element is visible, we use shouldBe(visible) method and so on. In fact, we use only three assertions: should, shouldBe, shouldHave, or opposite to them shouldNot, shouldNotBe, shouldNotHave. “should-methods” should(exist) Verifications of elements and element collections on Selenide are carried out with the help of methods (assertions) described above. They play role of explicit waits in Selenide: they wait for a condition for a certain element to be satisfied. Formulations in Selenide are quite logical and understandable. We can write our methods either using the development environment hints or using our logical assumptions. And of course, we can always take a look at the code for implementing the necessary methods described in the documentation, or we can look through the implementing of the method itself. Automatic screenshots in tests For : In order to take a screenshot automatically after each failed test, we can make an import and indicate the Rule. JUnit com.codeborne.selenide.junit.ScreenShooter; @Rule public ScreenShooter makeScreenshotOnFailure = ScreenShooter.failedTests(); import But in fact, it’s a rudiment, since Selenide has been taking screenshots automatically when tests fail for quite a while. It’s very convenient for error analyzing. Selenide saves all the screenshot to a folder by default. build/reports/tests In order to take a screenshot automatically of each test (even succeeded), we use the following command: @Rule public ScreenShooter makeScreenshotOnFailure = ScreenShooter.failedTests().succeededTests(); For we also make an import: TestNG com.codeborne.selenide.testng.ScreenShooter; @Listeners({ ScreenShooter.class}) import In order to take screenshots automatically after succeeded test, we invoke the following command before running tests: ScreenShooter.captureSuccessfulTests = ; true We can also make a screenshot with a single line of code at any moment: com.codeborne.selenide.Selenide.screenshot; screenshot( ); import static "my_file_name" Thus, Selenide will create two files: and my_file_name.png my_file_name.html 3. Docker: features and advantages of usage Let’s proceed to Docker itself and its advantages: Rapid Deployment. There is no need to set up additional tools, we can run them in containers Convenient encapsulation of applications Clean monitoring Easy scaling When we talk about Docker, the following things should be clarified: a running instance that encapsulates required software. It consists of images. And it can easily be deleted and created again within a short period of time. Container is is the basic element of each container. Container image is the main public Docker repository provided by Docker Inc. It stores a lot of container images. The service is a source of “official” images made by the Docker team or created in collaboration with developers. Docker Hub Docker installing To install Docker for Windows, we open the and download the app for Windows or MacOS. https://hub.docker.com Docker Desktop To install Docker for Ubuntu Linux, we need the command. sudo apt install docker.io Then we need to run Docker and configure it to start automatically when the system boots by executing the following commands: sudo systemctl start docker sudo systemctl enable docker 4. Selenoid: features and advantages Advantages of Selenoid usage: Single environment for a parallel launch of automated tests Isolated environment: Selenoid allows running each browser in a separate container, which enables full isolation of the browser environment Scalability: Selenoid environment does not affect qualitative and continuous testing Resources consumption and utilization: Selenoid enables to maintain a high load without additional waste of resources; in addition, all inactive containers are removed at the end of each session. Thus, the level of free memory is always appropriate Installation: Selenoid requires little time and effort. And in fact it is done with the help of one command Simultaneous support of multiple browser versions: this option is only available if you use Selenoid; several containers with the appropriate browsers are to be built Focus: challenges may emerge if multiple browsers are run on the same machine within the Selenium Grid. Due to the OS-specific nature, the focus can contain only one window. Therefore, windows can compete for it. Selenoid allows running each test in a separate container. Thus, this problem is eliminated User interface and logs: all available logs are accessed easily in Selenoid. There is also the possibility of integration with the stack for faster collection and analysis of current log files ELK Selenoid installation Before installing Selenoid you need: Make sure you have recent Docker version installed (further we look into the usage of Selenoid together with Docker) The easiest way to install Selenoid is to download that is used for automatic installation of Aerokube products. Selenoid is such a product Configuration Manager Rename the downloaded file to cm.exe (for easy interaction) Run the following commands to start Selenoid: ./cm.exe selenoid start --vnc ./cm.exe selenoid-ui start The command will download the latest Selenoid version, browser container images, web driver binaries, generate configuration files and finally start Selenoid. The command installs and starts . It is a user interface to track what’s happening during the test execution. Selenoid runs on standard Selenium 4444 port by default. We can redefine the port using the key. ./cm.exe selenoid start -- vnc ./cm.exe selenoid-ui start Selenoid UI --port Stats and sessions in Selenoid UI Selenoid UI is available at the link: http://localhost:8080/ Here we can see the current quota usage, pending browsers and the queue itself. Selenoid UI gets updates via SSE, so there is no need to renew the browser to see what is going on. It will reconnect automatically after any temporary failure. If we talk about simultaneous testing on different devices, e.g: we have a cross-platform web app with a real-life chat function, we can simultaneously test the interaction between them, that is obviously comfortable. Selenoid UI capabilities Selenoid UI has the following capabilities: You can choose a browser from available browsers and UI will provide a setup example with the right capabilities. We can see from the screenshot that examples are available for several languages. With the selection of the browser, it could be launched manually right in the interface. While executing tests, we can connect to vnc port in real-time regime, get access to the browser and even intervene in the process of autotests execution. Logs and VNC If you use capability, you can see a list of the available statistics. VNC allows to see and interact with the browser while the log will reflect all browser actions. enableVNC=true VNC session: VNC fullscreen mode: You can also see logs of the docker container for each session even without vnc. It means, if you didn’t use — vnc flag, you’ll see logs only. We can also view recorded videos of our tests. We can access them by opening or by going to the “Videos” tab in Selenoid UI. http://localhost:4444/video/ Adding Selenoid to run tests within Docker container In order to add Selenoid into the annotation we need to do the following configuration: @BeforeClass Configuration.remote = ; Configuration.browser = ; Configuration.browserSize = ; DesiredCapabilities capabilities = DesiredCapabilities(); capabilities.setCapability(capabilityName: , : ); capabilities.setCapability(capabilityName: , : ); Configuration.browserCapabilities = capabilities; "http://localhost:4444/wd/hub" "chrome" "1920x1080" new "enableVNC" value true "enableVideo" value true Since now we have the property, we delete which defined the browser for running our tests: Configuration.browser = “chrome” Property baseurl @BeforeClass public setUp() { Configuration.remote = ; Configuration.browser = ; Configuration.browserSize = ; DesiredCapabilities capabilities = DesiredCapabilities(); capabilities.setCapability(capabilityName: , : ); capabilities.setCapability(capabilityName: , : ); Configuration.browserCapabilities = capabilities; static void "http://10.0.75.1:4444/wd/hub" "chrome" "1920x1080" new "enableVNC" value true "enableVideo" value true Selenoid advanced capabilities Data storage in RAM: Selenoid stores all temporary files in . It is a temporary file repository that allows storing files in RAM. As we know, access to RAM is performed much faster than to the file system of the hard drive. Tmpfs Various screen resolution types: we can configure the appropriate screen resolution for a running container on their own by setting the required parameters in the Browser Capabilities. Video recording of tests: it’s possible to record the video of the tests performed. For instance, the activation in the Google Chrome browser is implemented by setting the parameter in the true Browser Capabilities: ChromeOptions options = new ChromeOptions (); options.setCapability (“enableVideo”, true); Using Selenoid without Docker Selenoid uses containers to run browsers, but there are cases when it’s not possible to run a browser within a container. For example, in Windows we have Internet Explorer, that can not be run inside the container. Selenoid can be used as a lightweight Selenium server replacement to run IE, Firefox or Chrome on Windows. For example to use Selenoid with IE. To do it we need: 1. Download latest archive and unpack it to some directory (C:\ in this example) IEDriverServer 2. Download latest binary Selenoid 3. Create configuration file: browsers.json { : { : , : { : { : [ , ] } } } } "internet explorer" "default" "11" "versions" "11" "image" "C:\\IEDriverServer.exe" "--log-level=DEBUG" 4. Start Selenoid: ./selenoid_win_amd64.exe -conf ./browsers.json -disable-docker 5. Run the tests, using endpoint with the following capabilities: http://localhost:4444/wd/hub = internet explorer = browserName version 11 6. To start , just download binary and modify browsers.json accordingly Chrome Chromedriver 7. Selenoid does not process launched driver logs by default. So we need to launch Selenoid with the flag to append driver logs for each session into the main log -capture-driver-logs Summarizing Solution on the basis of Selenide + Selenoid in Docker container demonstrates high flexibility for configuration of the runtime environment. The stability of this solution, significant time savings when using it and a number of additional features allow us to optimize the process and ensure high-quality software products in a short time. As a result, it is easy to give preference to the above solutions, since they allow us to perform testing automation tasks quickly and accurately. Previously published at https://intexsoft.com/