visit
We are considering a project build on the builder, so we can find the project structure description in the pom.xml file. To order use Selenium+TestNG, we should add appropriate dependencies to pom.xml file. You can observe them between the dependencies tags below:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0"
xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
<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>
</project>
import...
public class SignUpPage {
private WebDriver driver;
public SignUpPage(WebDriver driver) { this.driver = driver; }
private By emailField = cssSelector("#register-email");
private By confirmEmailField = cssSelector("#register-confirm-email");
private By passwordField = cssSelector("#register-password");
private By displayNameField = cssSelector("#register-displayname");
private By monthDropDown = cssSelector("#register-dob-month");
private By dayField = cssSelector("#register-dob-day");
private By yearField = cssSelector("#register-dob-year");
private By shareCheckbox = cssSelector("#register-thirdparty");
private By registerButton = cssSelector("#register-button-email-submit");
public SignUpPage typeEmail(String email) {
driver.findElement(emailField).sendKeys(email);
return this;
}
public SignUpPage typeConfirmEmailField(String email) {...}
public SignUpPage typePassword(String password) {...}
public SignUpPage typeName(String name) {...}
public SignUpPage setMonth(String month) {...}
public SignUpPage typeDay(String day) {...}
public SignUpPage typeYear(String year) {...}
private WebDriver driver;
private SignUpPage page;
@BeforeMethod
public void setUp() {
System.setProperty("webdriver.gecko.driver", "C:\\Users\\Nikita\\IdeaProjects\\autotests_examples\\drivers\\geckodriver.exe");
driver = new FirefoxDriver();
driver.manage().timeouts().impicitlyWait(10, TimeUnit.SECONDS);
driver.get("//www.spotify.com/us/signup/");
}
As we can see, in the @BeforeMethod annotation we describe what will have before each method.
@Test
public void typeInvalidYear() {
page = new SignUpPage(driver);
page.setMonth("December");
.typeDay("20")
.typeYear("85")
.setShare(true);
Assert.assertTrue(page.isErrorVisible("Please enter a valid year."));
The @Test annotation provides code for test methods.
@AfterMethod
public void tearDown() {
driver.quit();
}
The @AfterMethod annotation contains the code that should be executed after each method.
When running tests using Selenium, the following will happen:
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:
The purpose of Selenide is to focus on business logic of tests and not “waste” mental energy on technical details.
Getting started with the Selenide
To get started with the Selenide we need to add the Selenide dependency to the pom.xml file. Since we no longer need the Selenium dependency, we simply remove it.
<dependency>
<groupId>com.codeborne</groupId>
<artifactId>selenide</artifactId>
<version>5.2.8</version>
</dependency>
Working with elements, assertions, and waits
Let’s move on to the Selenide elements and consider the assertions and waits available in Selenide.import...
public class SignUpTest {
private SignUpPage page;
@BeforeClass
public static void setUp() {
baseurl = "//www.spotify.com";
browser = "chrome";
}
We replace the BeforeMethod annotation with the BeforeClass annotation in the test file since we no longer need it. Selenide eliminates the need to write Before and After methods as Selenide takes care of the AfterMethod function. We only have the BeforeClass annotation left to register a pair of properties.
We registered the property baseurl, which is in the configuration class and in the BeforeClass annotation and it will be the base url. Therefore, the driver.get 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 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: "/us/signup/");
return this;
}
public SignUpPage typeEmail(String email) {
$(emailField).sendKeys(email);
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.open we can write either the whole http url path, or we can write a relative url. Since we indicated an absolute path as a baseurl, within the Selenide.open method it’s enough to indicate just “/”.
public SignUpPage typeEmail(String email) {
$(emailField.sendKeys(email);
return this;
}
public SignUpPage typeConfirmEmailField(String email) {
$(confirmEmailField).setValue(email);
return this;
}
In order to find an element using Selenide, we should indicate $ instead of driver.findElement 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.
In order to find a list of elements using Selenide, we should indicate $$ characters. Instead of List <WebElement>, we write the ElementsCollection command that is already extended with additional methods.
To work with elements we can use both standard Selenium methods (sendKeys()) and setValue() method or its short version vаl().
As you can see, Selenide methods are more understandable. Method click() remains the same, though Selenide has several click() methods: contextClick() (right mouse button imitation) doubleClick() ( imitation of double click on element ) and so on. Having a certain element found, we can continue the search using other locators.
The difference between Selenide find() method and Selenium driver.findElement(By) is that Selenide find() 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.
Selenide already contains those methods, which would have to be done through an action 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.
You can find more information about Selenide methods in the .Let’s look into wider and more understandable verification examples provided by Selenide:page.getError("Please enter a valid year.").shouldBe(Condition.visible);
page.getError("When were you born?").shouldNotBe(Condition.visible);
page.getErrors().shouldHave(CollectionCondition.size(6));
page.getErrorByNumber(3).shouldHave(Condition.text("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 “should-methods”. When we want to check if the element exists, we use should(exist). 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.
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 JUnit:
In order to take a screenshot automatically after each failed test, we can make an import and indicate the Rule.
import com.codeborne.selenide.junit.ScreenShooter;
@Rule
public ScreenShooter makeScreenshotOnFailure = ScreenShooter.failedTests();
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 build/reports/tests folder by default.
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 TestNG we also make an import:
import com.codeborne.selenide.testng.ScreenShooter;
@Listeners({ ScreenShooter.class})
ScreenShooter.captureSuccessfulTests = true;
import static com.codeborne.selenide.Selenide.screenshot;
screenshot("my_file_name");
Thus, Selenide will create two files: my_file_name.png and my_file_name.html
Container is 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 image is the basic element of each container.
Docker Hub 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 installing
To install Docker for Windows, we open the and download the Docker Desktop app for Windows or MacOS.
To install Docker for Ubuntu Linux, we need the sudo apt install docker.io command.
Then we need to run Docker and configure it to start automatically when the system boots by executing the following commands:
Selenoid installation
./cm.exe selenoid start --vnc
./cm.exe selenoid-ui start
The ./cm.exe selenoid start -- vnc command will download the latest Selenoid version, browser container images, web driver binaries, generate configuration files and finally start Selenoid.
The ./cm.exe selenoid-ui start command installs and starts Selenoid UI. 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 --port key.
Stats and sessions in Selenoid UI
Selenoid UI capabilities
Selenoid UI has the following capabilities:Logs and VNC
If you use enableVNC=true 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.
VNC session:Adding Selenoid to run tests within Docker container
In order to add Selenoid into the @BeforeClass annotation we need to do the following configuration:
Configuration.remote = "//localhost:4444/wd/hub";
Configuration.browser = "chrome";
Configuration.browserSize = "1920x1080";
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(capabilityName: "enableVNC", value: true);
capabilities.setCapability(capabilityName: "enableVideo", value: true);
Configuration.browserCapabilities = capabilities;
Since now we have the Configuration.browser = “chrome” property, we delete Property baseurl which defined the browser for running our tests:
@BeforeClass
public static void setUp() {
Configuration.remote = "//10.0.75.1:4444/wd/hub";
Configuration.browser = "chrome";
Configuration.browserSize = "1920x1080";
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(capabilityName: "enableVNC", value: true);
capabilities.setCapability(capabilityName: "enableVideo", value: true);
Configuration.browserCapabilities = capabilities;
Selenoid advanced capabilities
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)2. Download latest binary3. Create browsers.json configuration file:
{
"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
browserName = internet explorer
version = 11
7. Selenoid does not process launched driver logs by default. So we need to launch Selenoid with the -capture-driver-logs flag to append driver logs for each session into the main log