<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: IntexSoft</title>
    <description>The latest articles on DEV Community by IntexSoft (@intexsoft).</description>
    <link>https://dev.to/intexsoft</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F495572%2F530b5fa3-4d3e-4f64-96bb-0b4365c4572d.jpg</url>
      <title>DEV Community: IntexSoft</title>
      <link>https://dev.to/intexsoft</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/intexsoft"/>
    <language>en</language>
    <item>
      <title>Container Orchestration: What Is Kubernetes</title>
      <dc:creator>IntexSoft</dc:creator>
      <pubDate>Wed, 23 Dec 2020 07:47:17 +0000</pubDate>
      <link>https://dev.to/intexsoft/container-orchestration-what-is-kubernetes-4fed</link>
      <guid>https://dev.to/intexsoft/container-orchestration-what-is-kubernetes-4fed</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;First of all, i would like to thank my colleague Dzmitry Iliushyn for helping with this article.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With the boom of horizontal scalability and microservice architecture, the world observed the “container deployment era”. Containers have been in use for more than ten years. Today at least a quarter of leading IT companies use container solutions in a big production, and this number is likely to grow further.&lt;/p&gt;

&lt;p&gt;Many market solutions provide container runtimes and orchestration, such as Docker Swarm, Mesos and others. However, more than half of the users choose Kubernetes as an infrastructure standard. Here we'll talk about the Kubernetes as a widespread and rapidly-developing solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why containers?
&lt;/h2&gt;

&lt;p&gt;Let’s start with container peculiarities and advantages first.&lt;/p&gt;

&lt;p&gt;As Docker developers would say: "a container is a standard unit of software that packs an application with all the dependencies it needs to run - application code, runtime, system tools, libraries, and settings." Compared to Virtual Machines, containers, in essence, are not full-fledged independent OSes, but configured spaces isolated within the same OS that use the host's Linux kernel to access hardware resources, as well as host’s memory and storage. Therefore, containers require significantly fewer resources to start and run, which positively impacts the project's performance and budget.&lt;/p&gt;

&lt;p&gt;Lightweight, high-speed of startup and great performance, delegation of hardware and OS maintenance to the provider (in case of -as-a-Service solutions), are the advantages of containers, which reduce the costs of development and maintenance of applications making solutions based on containers so attractive for businesses.&lt;/p&gt;

&lt;p&gt;As for advantages for technical specialists, containers allow them to pack an application along with its runtime environment, thereby solving the problem of dependencies in different environments. For example, differences between software package versions on the developer's laptop and the subsequent staging or production environments will sooner or later lead to failures. So it will at least require efforts to get with them: to analyze and fix bugs edged into production. Using containers eliminates the "everything-worked-on-my-machine" problem.&lt;/p&gt;

&lt;p&gt;Containers also reduce app development time and simplify its management in production due to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;easy setup and changing the configuration;&lt;/li&gt;
&lt;li&gt;versioning the configuration along with the application code;&lt;/li&gt;
&lt;li&gt;creating an easily reproducible environment for implementing CI/CD processes;&lt;/li&gt;
&lt;li&gt;convenient orchestration tools allowing to scale the infrastructure quickly.
Besides, the absence of binding containers to the hosting platform gives tremendous flexibility when choosing or changing a provider. One can run them without fundamental differences on a personal computer, bare metal servers, or cloud services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Py0zjYMs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1608708676465/zdHPXHatd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Py0zjYMs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1608708676465/zdHPXHatd.png" alt="deployment-evolution-1600.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Containers are a great way to bundle and run applications. In a production environment, DevOps engineers need to manage the containers that run the applications and ensure that there is no downtime. To withstand the estimated load, the number of application containers should be certain or not less than minimum required. So here some mechanism is required which will start new copies of the app containers if load will become higher or some of them fail for any reason. And this process is easier when such a behavior is handled by the system like an “orchestrator” for these containers. All this leads to Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  About Kubernetes
&lt;/h2&gt;

&lt;p&gt;Kubernetes (also known as K8s) is a platform implementing orchestration of containers in a cluster environment. Previously, it was mainly used for Docker containers as they were highly popular and wide-spread . But, in the latest Kubernetes versions, Docker is listed as deprecated while Container Runtime Interface (CRI) is stated as the native container mechanism.&lt;/p&gt;

&lt;p&gt;Kubernetes significantly expands container capabilities, making it easier to manage deployment, network routing, resource consumption, load balancing, and fault tolerance of running applications. This platform is now widely offered by Cloud providers within the -as-a-Service model. At the same time, nothing stops you from installing it on a set of physical or virtual machines whether in cloud or on-premise.&lt;/p&gt;

&lt;p&gt;Kubernetes is a new step in the IT industry that allows simplifying the delivery of apps including the environment where these apps will run. With Kubernetes, it is possible to abstract the description of this environment from the hardware configuration.&lt;/p&gt;

&lt;p&gt;K8s allows us to create a cluster based on several physical or virtual machines. This cluster works as a single environment and consists of two types of nodes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Master&lt;/strong&gt; nodes that manages the cluster (for high availability best practice there should be at least 2 master nodes);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Worker nodes&lt;/strong&gt; that are the machines to run the applications (2 or more as for full-fledged cluster depending on load).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lsVp6hT---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1608708740009/x6rHikREW.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lsVp6hT---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1608708740009/x6rHikREW.png" alt="k8s-clusters-1600.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you deploy your applications in K8s, you alert the master to launch app containers. The master node schedules containers to run on the working nodes. Each working node communicates with the master. For that Kubernetes has the &lt;a href="https://kubernetes.io/docs/concepts/overview/kubernetes-api/"&gt;API&lt;/a&gt;, which can be used for direct management using REST calls as well.&lt;/p&gt;

&lt;p&gt;To get started with Kubernetes developers can use a lightweight implementation - Minikube. Minikube is a tool available as a cross-platform solution. It creates a simple single-node cluster on a local machine.&lt;/p&gt;

&lt;p&gt;To work with a Kubernetes cluster and to run an app in such an environment, one needs certain instructions to determine the desired state of the app. Such instructions are Kubernetes Manifests that describe what and how you want to run the containerized code in a cluster. Basic manifests could be relatively simple. They are code in YAML/JSON format, so for a developer it would not be a problem to write a simple manifest, also Manifests can be handled using the GitOps model. But when we are moving from simple manifests in development to production, the problem is that the level of K8s abstraction is so high that one should have a good understanding of how things work under the hood of a cluster.&lt;/p&gt;

&lt;p&gt;Kubernetes has a lot of Kinds that describe and manage the behavior of containers inside a cluster. K8s itself is primarily a Container Orchestrator and therefore its parts are containers as well. This fact leads us to 2 main peculiarities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The components of the platform do not affect each other. If one goes down, then all others continue to operate.&lt;/li&gt;
&lt;li&gt;These components work according to a pull model. There is no central component, a commander who rules everyone. Each component carries out and performs its own function.If the component fails, then it's actions will not be performed.&lt;/li&gt;
&lt;li&gt;Kubernetes model is focused on maintaining the desired number of working containers: it restarts the containers that go down, or don't respond to a user-defined health check, replacing them.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Core Kinds of Kubernetes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Node&lt;/strong&gt;&lt;br&gt;
A node is a component part of the Kubernetes cluster. The Master node (there can be several of those) controls the cluster through the scheduler and controller manager, provides an interface for interacting with users through the API server, and contains the etcd repository with cluster configuration, statuses of its objects, and metadata. The working nodes are intended exclusively for launching and working with containers; for this, two Kubernetes services are installed on it - a network router and a scheduler agent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Namespace&lt;/strong&gt;&lt;br&gt;
A structural object that allows you to divide cluster resources between environments, users and teams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pod&lt;/strong&gt;&lt;br&gt;
This is the smallest unit in Kubernetes - a group of one or more containers that work as one service or application, assembled for joint deployment on a node. It makes sense to group containers of different types in a Pod when they depend on each other and, therefore, must run on the same node to reduce the response time when they interact. An example: containers with a web application and a caching service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ReplicaSet&lt;/strong&gt;&lt;br&gt;
An object that describes and controls the correspondence of the number of Pod replicas running on the cluster. Setting the number of replicas to more than one is required to improve the application's fault tolerance and scalability. Deployment kind provides more capabilities and is used more often for apps, but in some particular cases ReplicaSet is enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment&lt;/strong&gt;&lt;br&gt;
An object that declaratively describes Pods, the number of replicas, and the strategy for their replacement during update. Deployment allows updating different Pods according to declared rules. This makes the update of services or applications that have been released as much smooth and painless as possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;StatefulSet&lt;/strong&gt;&lt;br&gt;
StatefulSet allows you to describe and save Pods' state: unique network address and their disk storage while restarting, thus implementing the stateful application model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DaemonSet&lt;/strong&gt;&lt;br&gt;
It's a kind that provides control over what will be launched on each (or several selected) node according to a specified Pod instance. It is used to run cluster storage, logs collecting or node monitoring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Job and CronJob&lt;/strong&gt;&lt;br&gt;
Kind that launch the specified Pod once (or regularly on a schedule in case of CronJob) and monitor the result of its execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Service&lt;/strong&gt;&lt;br&gt;
A virtual kind for publishing an application as a network service, which also implements load balancing between application Pods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CRD&lt;/strong&gt;&lt;br&gt;
K8s is not limited only by its basic functionality, but can also be extended with Custom Resource Definitions (CRD). CRD allows us to inject or even “invent” new custom kinds in addition to out-of-the-box ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros and Cons of Kubernetes
&lt;/h2&gt;

&lt;p&gt;The K8s in essence is a great abstraction tool: there is no need to think deeply about technologies, hardware resources or its maintenance, etc. Let’s look a bit deeper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;+Abstraction from hardware&lt;/strong&gt;&lt;br&gt;
First of all, there is no need to deep dive into hardware characteristics and parameters, despite the project itself not requiring some specific needs. In case of any custom solutions, developers or DevOps engineers indicate these custom adjustments in the manifests or probably even add checks for them.&lt;/p&gt;

&lt;p&gt;For example, if your project uses a database and it’s not a cloud database -as-a-Service, you should have one or several nodes a bit more improved then the others (they should have more memory and fast storage) and you should just “tell” via manifests for database pods to be run on exactly these improved nodes.&lt;/p&gt;

&lt;p&gt;Moreover, you are able to limit all the needed resources (RAM, CPU, etc) yourself. The lack of processing capacities can be compensated by cluster monitoring plus node scaling. If talking about the Cloud, this process can even be automated with a &lt;a href="https://kubernetes.io/blog/2016/07/autoscaling-in-kubernetes/"&gt;Cluster Autoscaler&lt;/a&gt; which scales the target cluster up or down, so it can satisfy any changing demands of the workloads on top.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mo51WwZ3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1608708889200/9hhZyWR8W.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mo51WwZ3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1608708889200/9hhZyWR8W.png" alt="clusters-autoscaling-1600.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Autoscaling is a great solution when you don’t know exactly what will be the load and how many resources the app needs to keep such load. As an example: selling the tickets for a football match, when the requests traffic increases within a short period of time. So with Cluster Autoscaler, the cluster expands automatically to cope with the load and returns back after load decrease.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;+Resource isolation&lt;/strong&gt;&lt;br&gt;
With the help of namespaces, you can isolate several projects or different stages of one project - non-prod and prod environments - from each other in one cluster. With RBAC you can also configure restriction of access to valuable resources based on the role the user holds. All this provides us with predictable application security.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;+ Safe update of microservice systems&lt;/strong&gt;&lt;br&gt;
All we know, that microservice architecture is widespread now. For example,if we have a website divided into modules that operate separately, the failure of one will not affect the whole system. Moreover, there is a possibility to update each separate module with Deployment so that any problems with the update do not engage the whole audience but nobody or a small part of them. And, eventually, if something goes wrong, versioning will help us to roll the update back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;+Uniformity&lt;/strong&gt;&lt;br&gt;
There is no actual OS dependency, you just have an integrated interface you interact via standard commands or API with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;+Integration with third-party software&lt;/strong&gt;&lt;br&gt;
Integration with monitoring systems, CI/CD systems, secret storages and many more . As for the secrets: if you don’t want secrets to be placed in a cluster, there is an opportunity to integrate K8s with systems storing secrets in order to have them in a secret storage, while K8s can access them securely when needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;+-Open-source&lt;/strong&gt;&lt;br&gt;
K8s was created by Google and has been published as open-source. It’s an advantage and disadvantage at the same time as we can face a problem of technical support. In case of an urgent Kubernetes platform issue, there is no opportunity to address it to experts responsible to fix it. So, whoever uses K8s, should understand that for now just the open-source community supports it.&lt;/p&gt;

&lt;p&gt;But business needs support for software platforms. So there were the companies who decided to release Kubernetes as a commercial product. One of them is RedHat - a company that provides supported open-source software products to enterprises. They released their own container orchestration platform based on Kubernetes named OpenShift with enterprise lifecycle support.&lt;/p&gt;

&lt;p&gt;It is also worth mentioning Rancher that offers the functionality of commercial K8s distribution in an open-source package. It is quite popular now since it allows to easily create clusters on bare metal with Rancher Kubernetes Engine as well as on hosting providers such as AKS and GKE. Rancher is not a redesign of Kubernetes, but rather a platform that makes deployment and use of it easier even in multi-cluster environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- High entry threshold&lt;/strong&gt;&lt;br&gt;
Kubernetes interface is implemented as a number of rather complex Manifests, or descriptions for each abstracted kind. To understand all the peculiarities and to have the ability to configure and debug such systems, one should have a good understanding of microservice architecture and containerization principles, and, therefore, should have a good knowledge of Linux itself as a basis. So if it’s a small or mid-sized project, it would be a tough start for a developer to work with Kubernetes from the scratch without a fair knowledge of the technologies mentioned.&lt;/p&gt;

&lt;p&gt;As for the projects, there are cases when startups hope for the fast start and high load of their systems, and eventually, their expectations fall short, which means there were spent extra efforts and resources for implementing microservices and orchestration, and as the result - overhead. This point leads us to the question below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it always Kubernetes?
&lt;/h2&gt;

&lt;p&gt;Since Kubernetes has been on the hype for the last several years, it’s a common practice when a client with a small-sized project requests Kubernetes to be used from the very beginning.&lt;/p&gt;

&lt;p&gt;But Kubernetes must be used consciously. Working with Kubernetes should be considered when you have a really large number of microservices, when there are certain requirements for the level of availability of your project/system, when several teams are working on the application, or when infrastructure is needed to automate deployments and tests more efficiently. At this point, it's really worth thinking about Kubernetes.&lt;/p&gt;

&lt;p&gt;If you are a small company or if you have a monolithic app which will be hard to split to microservices, Kubernetes is definitely not the best decision.&lt;/p&gt;

&lt;p&gt;In the case of a microservice solution, Kubernetes is rather a blessing. Gradually, the application becomes overgrown with logic, and there are more and more microservices. And Docker itself is already becoming insufficient. Plus to everything, the clients probably also want some kind of fault tolerance.&lt;/p&gt;

&lt;p&gt;Gradually, the company bumps into the ceiling when they need a fresh and highly productive solution. And here, of course, you need a container orchestrator. K8s is a type of software that manages all microservices, looks after them, repairs, transfers within a cluster, builds networks and routes their traffic, and, in general, is such an entry point to the entire infrastructure of the project.&lt;/p&gt;

&lt;p&gt;Summarizing&lt;br&gt;
The IT industry is highly flexible and changeable. The software is more and more complex each year. To keep up to date, businesses need to use the newest tools and solutions.&lt;/p&gt;

&lt;p&gt;If we look at this issue in terms of deployment, a couple of years ago using containers in production was considered as an unreliable solution. However, time does not stand still, the industry evaluated and appreciated the prospects of containers. Now the variety of solutions based on containers is more and more convenient and attractive for businesses.&lt;/p&gt;

&lt;p&gt;As for the Kubernetes, if implemented and maintained correctly, it offers developers, DevOps engineers, and business owners great benefits: scalability, workload portability, improved app development/deployment efficiencies, effort and cost optimization.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>docker</category>
    </item>
    <item>
      <title>Node.js vs Java: Why Compare?</title>
      <dc:creator>IntexSoft</dc:creator>
      <pubDate>Fri, 11 Dec 2020 13:10:49 +0000</pubDate>
      <link>https://dev.to/intexsoft/node-js-vs-java-why-compare-1a3n</link>
      <guid>https://dev.to/intexsoft/node-js-vs-java-why-compare-1a3n</guid>
      <description>&lt;p&gt;Recently, my colleagues and I discussed the popularity of a couple of technologies - in particular, Java and node.js. After a brief Internet surfing session, it turned out that these technologies are used by many information giants to develop and maintain their platforms. Below, I will mention only a few of them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Companies using Java:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vPA8r2br--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ocp74uf6jnx050xde4ww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vPA8r2br--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ocp74uf6jnx050xde4ww.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Companies using node.js:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FyYou6Kn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e62z1f8h8mr965hk74x6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FyYou6Kn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e62z1f8h8mr965hk74x6.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One more interesting fact is that according to &lt;a href="https://www.indeed.com/"&gt;indeed.com&lt;/a&gt; (06.28.2019) Java developers (30272 jobs) and node.js developers (7401 jobs) are quite in demand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pUCUvzNF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/drox96keff9s5oc3c3te.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pUCUvzNF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/drox96keff9s5oc3c3te.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why they should be compared
&lt;/h2&gt;

&lt;p&gt;Java is a language, while node.js can be called an ecosystem built on the basis of JS, and, above all, on the basis of Google’s &lt;a href="https://v8.dev/"&gt;V8&lt;/a&gt; engine.&lt;/p&gt;

&lt;p&gt;However, when we talk about Java, we are talking not only about the language but about the Java Virtual Machine (JVM), as well as the entire ecosystem and infrastructure built around this machine. That’s the first reason why we can compare them.&lt;/p&gt;

&lt;p&gt;As a result, &lt;strong&gt;in both cases, we have the execution environment&lt;/strong&gt;. In the case of Java, it’s a virtual machine. In the case of node.js, this is the V8 engine that presents on most operating systems, such as Windows, Linux, MacOS, and those lesser known. Developers can write code using the same language, and this will work in more or less the same way on different operating systems due to the fact that there is a runtime environment. The execution environment influences how it interacts with the OS. In addition, they can be compared because they are used to &lt;strong&gt;solve a similar range of tasks&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  V8 and JVM
&lt;/h2&gt;

&lt;p&gt;When a JS code enters the V8, it is compiled into a byte code due to the &lt;a href="https://en.wikipedia.org/wiki/Just-in-time_compilation"&gt;just in time&lt;/a&gt;(JIT) compilation that is used in the virtual machine, therefore the JS code runs faster.&lt;br&gt;
Byte code is an intermediate, high-level language, so in a JVM, they write not only in Java but also in Scala and Kotlin.&lt;/p&gt;

&lt;p&gt;There are prerequisites that in the near future for V8 it will be possible to use not only JS but also TypeScript or others. At the moment, a transpiling of these languages ​​in JS is going on. The perspective for the technology will see that, they will probably be supported out of the box, and everything will work much faster.&lt;/p&gt;

&lt;p&gt;Now, when the continuous development of V8 takes place, the emergence of new node.js versions is associated with the appearance of a new version of the V8 engine. They are directly interrelated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros and cons of node.js
&lt;/h2&gt;

&lt;p&gt;Node.js was created by &lt;a href="https://en.wikipedia.org/wiki/Ryan_Dahl"&gt;Ryan Dahl&lt;/a&gt; in 2009.&lt;/p&gt;

&lt;p&gt;The node.js itself includes several key components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;V8 engine;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://libuv.org/"&gt;libuv&lt;/a&gt; library, which is responsible for the central part of node - the event loop, which interacts with the OS, as well as for asynchronous I/O;&lt;/li&gt;
&lt;li&gt;a set of different JS libraries and the JS language itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let us turn to the pros and cons of node.js.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ease and speed of code writing;&lt;/li&gt;
&lt;li&gt;lightness;&lt;/li&gt;
&lt;li&gt;simplicity (in comparison with Java);&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/"&gt;node package manager&lt;/a&gt; (a huge number of libraries that can be installed in one line);&lt;/li&gt;
&lt;li&gt;each library falls into a dependency tree and it's all done easily;&lt;/li&gt;
&lt;li&gt;constant development (TypeScript is being actively developed, which introduces typing into JS, decorators and is used, for example, for Angular).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;flexibility and rapid development also causes disadvantages, due to the need to constantly monitor updates, some things are not tested enough;&lt;/li&gt;
&lt;li&gt;there was a &lt;a href="https://blog.npmjs.org/post/141577284765/kik-left-pad-and-npm"&gt;case&lt;/a&gt; where a developer deleted his library from NPM and many applications using it stopped working;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pros and cons of Java
&lt;/h2&gt;

&lt;p&gt;In contrast, let's consider the main characteristics of Java.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;speed;&lt;/li&gt;
&lt;li&gt;prevalence (Java is taught in universities of many countries);&lt;/li&gt;
&lt;li&gt;huge set of libraries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;heaviness;&lt;/li&gt;
&lt;li&gt;some Java paradigms were created long ago and are already outdated;&lt;/li&gt;
&lt;li&gt;JDK is proprietary, so Java is developing slowly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recently, JS has begun to overtake Java. Java is also leaving the Android world: it is being replaced by Kotlin, which, although using the JVM, is still a different language.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conflict of Oracle and Google
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_EQHCm1d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rvzwn8mqpu5n0ni9q3jk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_EQHCm1d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rvzwn8mqpu5n0ni9q3jk.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Source: giphy.com&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Java was created by &lt;a href="https://www.oracle.com/technetwork/java/javase/overview/javahistory-index-198355.html"&gt;Sun&lt;/a&gt;, which was later acquired by Oracle. For this reason, for many companies, the use of Java causes some issues.&lt;/p&gt;

&lt;p&gt;Google had problems when Oracle started a &lt;a href="https://www.forbes.com/sites/briansolomon/2016/05/26/google-wins-9-billion-android-copyright-case/#77a03be2a3ad"&gt;trial&lt;/a&gt; with them to use Java on Android. Because of this, Google has very actively adopted Kotlin, which appeared independently.&lt;/p&gt;

&lt;p&gt;Java is proprietary. But there is an Oracle virtual machine, as well as an open Java virtual machine (open JVM), which is used in Linux and written in open source. Sometimes there are some incompatibilities, but in recent times these have been fewer.&lt;/p&gt;

&lt;p&gt;By the way, Google could not completely abandon Java. In &lt;a href="https://www.javatpoint.com/dalvik-virtual-machine"&gt;Dalvik&lt;/a&gt;, which is used as the core in Android, JVM is utilized. Perhaps they will change this one day, but it will be very difficult since the entire Android ecosystem is built on Java, specifically on an upgraded JVM. And at some point, this was also the cause of the conflict between Oracle and Google, because Oracle prohibits modernizing the JVM. This is the most important part of Java. However, the language itself can be used with no restrictions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Java vs node.js: performance and resource intensity
&lt;/h2&gt;

&lt;p&gt;First of all, it should be noted that Java performance is much higher than on JS, and, accordingly, node.js.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--grMyiXE---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/s95ivt8snrskwfslkuv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--grMyiXE---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/s95ivt8snrskwfslkuv6.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Performance of node.js and Java&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you run a simple task, like squaring, then in tests the indicators can differ up to 10 times. If you run loops in millions of calculating tasks, Java will almost always exceed node.js.&lt;/p&gt;

&lt;p&gt;Plus, the huge difference between Java and node.js is that node is single-threaded, that may be considered its advantage, and its disadvantage on the other hand.&lt;/p&gt;

&lt;p&gt;Java can work with threads that are supported at the OS level, and it turns out that a program written in Java makes the most of the OS features. And if you need to write a high-load application that will use a large number of calculations, then Java will definitely work better for this.&lt;/p&gt;

&lt;p&gt;The problem is that even a small server written in Java will take up a lot of memory - both on disk and operational.&lt;/p&gt;

&lt;p&gt;Node.js is lightweight due to its event-based architecture. It is built to work as a web server and copes very well with servicing lightweight tasks. For example, a simple query like calculating, or writing to a database happens very quickly. And if there are a lot of requests and we want to scale the system into a node, you can use the Nginx or Apache web server. You can have many identical node instances. Then everything will be distributed through load balancing on &lt;a href="https://www.nginx.com/resources/glossary/round-robin-load-balancing/"&gt;round-robin&lt;/a&gt;. If we run 8 node instances on 16 cores respectively, the OS itself will distribute the instances between the cores. Node does not control this, it will have one thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thread control in Java and node.js
&lt;/h2&gt;

&lt;p&gt;In Java, we can create an application and run 8 threads in it. Due to the fact that there is a closer interaction with the OS, you can distribute the load.&lt;/p&gt;

&lt;p&gt;One of the well-known web servers written in Java is &lt;a href="http://tomcat.apache.org/"&gt;tomcat&lt;/a&gt;. There you can clearly see that when a user makes a request, additional threads are started. And when the request for a node arrives, the event loop will be processed and sent back, then the next request will appear. And, due to the fact that we are not waiting for the results of the first, it will also be picked up. If the requests are lightweight, all is great. However, when a heavy computation is performed, if there is even one instance, the node stops and a timeout occurs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LieNQD_6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xipk44oszrn0mpwpr25j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LieNQD_6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xipk44oszrn0mpwpr25j.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thread control in Java&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In node, you can write literally a few lines of code and get a simple web server. Naturally, for a wider functionality, where there will be notifications, authorizations, logging, etc. It is more difficult to implement, but there are frameworks that allow you to solve such issues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CSB66TYg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8r0lvmh9m1huasah9xmf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CSB66TYg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8r0lvmh9m1huasah9xmf.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thread control in node.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Java has a developed API - &lt;a href="https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/package-summary.html"&gt;concurrency api&lt;/a&gt;, which allows you to work with competitive streams. But at the same time, one of the problems as concurrency is that it is a pretty difficult thing which not every developer understands well enough to be able to implement.&lt;/p&gt;

&lt;p&gt;Web, &lt;a href="https://restfulapi.net/"&gt;REST API&lt;/a&gt; is the node’s thing, and sometimes it is used for that. But if we are dealing with complex calculations, it’s still better to use Java.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Java project
&lt;/h2&gt;

&lt;p&gt;I had an interesting project in Java - a distributed application, where the key task was the processing of large volumes of graphical information for further use in catalogs. When creating a catalog, it is necessary to prepare sets of a large number of images in various resolutions that will be used when creating the catalog. In short, this is an application to automate prepress catalog preparation.&lt;/p&gt;

&lt;p&gt;Previously, photographers had to do everything manually. In the beginning, it was necessary to use some small application in order to upload all the images. Next, the specialist who created the catalog had to develop the catalog structure using another application. Then, in another application, they should create a workflow, which scattered the pictures into the structure that was created beforehand. In general, the process was quite difficult. ImageMagick which is available for Linux, Windows, and MacOS was used. We worked with Linux.&lt;/p&gt;

&lt;p&gt;For example, a .tiff image with a size of 200-300 MB was loaded into the application; it was necessary to make pictures in various resolutions, cut something out, or make a background.&lt;/p&gt;

&lt;p&gt;The first version of the application could not cope with a large load; even a server with a 16-core processor was not enough. We improved the architecture of the application to use several instances at the same time, in order not to radically change the operation of the application. Many instances started up and interacted with each other and each of them processed a piece of the task. It was difficult, but we managed to successfully implement everything in a couple of months. And the system is still working. The process had to deal with competitiveness and various aspects of interaction.&lt;/p&gt;

&lt;p&gt;Something from this project could still be done in node, but some things would still have to be done in Java since there were a lot of different calculations. Basically, we could make parts in node that would call certain parts on Java and use its microservice architecture. We could use a mixed version. But this approach does not always work, because a developer specializing in node may not be a Java expert and vice versa. And finding multi-talented developers is much more difficult.&lt;/p&gt;

&lt;h2&gt;
  
  
  From experience on node.js
&lt;/h2&gt;

&lt;p&gt;There was a project for organizing a large amount of data. Something similar to the project described above. But here we have an uploaded file that contains a large set of information that is subjected to validation through a third-party service (written in Java), several times and according to different rules. It was necessary to process hundreds of gigabytes of information, and node was not intended for this.&lt;/p&gt;

&lt;p&gt;Designing the system architecture was especially interesting since the application consisted of several microservices, including third-party ones. When working with a third-party service that performed validation, we used &lt;a href="https://www.rabbitmq.com/tutorials/tutorial-one-python.html"&gt;RabbitMQ message broker&lt;/a&gt;. We gave the third-party server the necessary information and received a message from RabbitMQ at the end of validation, then the data was processed in sections to avoid an out of memory error.&lt;/p&gt;

&lt;p&gt;If the application initially processed a file containing 10,000 entries, it can now process up to a million. We still managed to solve this problem with the help of node.js, although in Java it could have been solved more simply. The client insisted on using node.js since they needed a single infrastructure and architecture with microservices written in JS. Using node to solve the problem was much more difficult, and took more time, but node.js wins due to its scalability. That is why now we can increase the number of workers and process and more and more data. In Java, this would be more complicated.&lt;/p&gt;

&lt;p&gt;In fact, any problem can be solved both ways, but as I’ve said before, if there are a lot of calculations, then it is better to use Java, if not then use node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results and prospects: can node.js overtake java?
&lt;/h2&gt;

&lt;p&gt;Now there’s a tendency that node.js will often be used as a “wrapper”, and the “stuffing” will be written in other languages. Its shortcomings are already well noted. For example, such a conditional flaw as single-threading has already been fixed. The latest version of node provides the ability to use multiple threads.&lt;/p&gt;

&lt;p&gt;Java was originally created as a lightweight solution replacing C++ and now has become heavyweight. It’s like an evolution. Maybe someday there will be something that will replace node.js as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9mlU2FsW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dtsqfwcz61t2khag68zv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9mlU2FsW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dtsqfwcz61t2khag68zv.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="http://www.modulecounts.com/"&gt;http://www.modulecounts.com/&lt;/a&gt; - Development of Java vs node.js&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At the moment, according to the number of requests, and to my own feelings, node.js has already overtaken Java. JS is actively developing and it will continue to do so. But, at the moment, there is no potential competitor that could replace Java or node.js.&lt;/p&gt;

&lt;p&gt;The problem is that lately Java is developing quite slowly, and node.js is developing at such a rate that it just cannot be replaced in the nearest future.&lt;/p&gt;

&lt;p&gt;Which technology do you use in your work? Share your thoughts, interesting projects and questions in the comments.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Selenide Test Automation: Using Selenoid in the Docker Container
</title>
      <dc:creator>IntexSoft</dc:creator>
      <pubDate>Thu, 19 Nov 2020 15:12:11 +0000</pubDate>
      <link>https://dev.to/intexsoft/selenide-test-automation-using-selenoid-in-the-docker-container-23cb</link>
      <guid>https://dev.to/intexsoft/selenide-test-automation-using-selenoid-in-the-docker-container-23cb</guid>
      <description>&lt;p&gt;Selenide Test Automation: Using Selenoid in the Docker Container&lt;br&gt;
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.&lt;/p&gt;

&lt;p&gt;Here we will look into some 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;And finally, I will connect the Selenoid framework to the project to run tests in the Docker container and outside it.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Selenium + TestNG. Selenium Maven
&lt;/h2&gt;

&lt;p&gt;We are considering a project build on the &lt;a href="https://maven.apache.org/"&gt;Maven&lt;/a&gt; builder, so we can find the project structure description in the pom.xml file. To order use &lt;strong&gt;Selenium+TestNG&lt;/strong&gt;, we should add appropriate dependencies to pom.xml file. You can observe them between the dependencies tags below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;project&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/POM/4.0.0"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;                               
        &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;    
    &lt;span class="nt"&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;    
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0-SNAPSHOT&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;    
        &lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;             
                &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;                       
                      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.seleniumhq.selenium&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;                      
                      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;selenium-java&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;                     
                      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.141.59&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;                 
                &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;           
                &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;                      
                       &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.testing&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;                     
                       &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;testing&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;                     
                       &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;6.14.3&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;                     
                       &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;           
                &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;   
        &lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt; 
&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the example of the Page Object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="nn"&gt;...&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;WebDriver&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SignUpPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WebDriver&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;By&lt;/span&gt; &lt;span class="n"&gt;emailFriend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cssSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#register-email"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;By&lt;/span&gt; &lt;span class="n"&gt;confirmEmailFriend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cssSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#register-confirm-email"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;By&lt;/span&gt; &lt;span class="n"&gt;passwordField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cssSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#register-password"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;By&lt;/span&gt; &lt;span class="n"&gt;displayNameField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cssSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#register-displayname"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;By&lt;/span&gt; &lt;span class="n"&gt;monthDropDown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cssSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#register-dob-month"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;By&lt;/span&gt; &lt;span class="n"&gt;dayField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cssSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#register-dob-day"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;By&lt;/span&gt; &lt;span class="n"&gt;yearField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cssSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#register-dob-year"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;By&lt;/span&gt; &lt;span class="n"&gt;shareCheckbox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cssSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#register-thirdparty"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;By&lt;/span&gt; &lt;span class="n"&gt;registerButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cssSelector&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#register-button-email-submit"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="nf"&gt;typeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emailField&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="nf"&gt;typeConfirmEmailFriend&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{...}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="nf"&gt;typePassword&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nc"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{...}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="nf"&gt;typeName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{...}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="nf"&gt;setMonth&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{...}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="nf"&gt;typeDay&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{...}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="nf"&gt;typeYear&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{...}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;br&gt;
Let’s open the tests themselves:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;WebDriver&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@BeforeMethod&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"webdriver.gecko.driver"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"C:\\Users\\Nikita\\IdeaProjects\\autotests_examples\\drivers\\geckodriver.exe"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FirefoxDriver&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
       &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;timeouts&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;impicitlyWait&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
       &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://www.spotify.com/us/signup/"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, in the &lt;strong&gt;@BeforeMethod&lt;/strong&gt; annotation we describe what will have before each method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;typeInvalidYear&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
     &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setMonth&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"December"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;typeDay&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"20"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;typeYear&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"85"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                 &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setShare&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="nc"&gt;Assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isErrorVisible&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please enter a valid year."&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;&lt;a class="comment-mentioned-user" href="https://dev.to/test"&gt;@test&lt;/a&gt;
&lt;/strong&gt; annotation provides code for test methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AfterMethod&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;tearDown&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;quit&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;@AfterMethod&lt;/strong&gt; annotation contains the code that should be executed after each method.&lt;br&gt;
When running tests using Selenium, the following will happen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Opening a separate browser window&lt;/li&gt;
&lt;li&gt;Following the url&lt;/li&gt;
&lt;li&gt;Test code execution&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  2. Selenide: what, where, and how
&lt;/h2&gt;

&lt;p&gt;So what is Selenide itself? What are its main features and advantages?&lt;/p&gt;

&lt;p&gt;In short, &lt;a href="https://selenide.org/index.html"&gt;Selenide&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;Key and main advantages of Selenide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Concise jQuery-style syntax&lt;/li&gt;
&lt;li&gt;Automatic handling of most problems with Ajax, waitings and timeouts&lt;/li&gt;
&lt;li&gt;Automatic handling of browser lifecycle&lt;/li&gt;
&lt;li&gt;Automatic creation of screenshots&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The purpose of Selenide is to focus on business logic of tests and not “waste” mental energy on technical details.&lt;/p&gt;
&lt;h3&gt;
  
  
  Getting started with the Selenide
&lt;/h3&gt;

&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.codeborne&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;selenide&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;                             
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;5.2.8&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to start using Selenide in our project, we also need to make some imports. Here are the examples of import required classes:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;import static com.codeborne.selenide.Selenide.*&lt;/em&gt;;&lt;br&gt;
&lt;em&gt;import static com.codeborne.selenide.Selectors.*&lt;/em&gt;;&lt;br&gt;
&lt;em&gt;import static com.codeborne.selenide.Condition.*&lt;/em&gt;;&lt;br&gt;
&lt;em&gt;import static com.codeborne.selenide.CollectionCondition.*&lt;/em&gt;;&lt;/p&gt;

&lt;p&gt;For more information on how to connect Selenide using the rest of the project builders, see the &lt;a href="https://selenide.org/quick-start.html"&gt;Quick start&lt;/a&gt; section of Selenide documentation.&lt;/p&gt;

&lt;p&gt;Working with elements, assertions, and waits&lt;/p&gt;

&lt;p&gt;Let’s move on to the Selenide elements and consider the assertions and waits available in Selenide.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="nn"&gt;...&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SignUpTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="nd"&gt;@BeforeClass&lt;/span&gt;
   &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;baseurl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://www.spotify.com"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"chrome"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We replace the &lt;strong&gt;BeforeMethod&lt;/strong&gt; annotation with the &lt;strong&gt;BeforeClass&lt;/strong&gt; 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 &lt;em&gt;AfterMethod&lt;/em&gt; function. We only have the &lt;strong&gt;BeforeClass&lt;/strong&gt; annotation left to register a pair of properties.&lt;/p&gt;

&lt;p&gt;We registered the &lt;em&gt;property baseurl&lt;/em&gt;, which is in the &lt;em&gt;configuration&lt;/em&gt; 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 &lt;em&gt;property browser&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Let’s proceed to using Selenide on our page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

         &lt;span class="nc"&gt;Selenide&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;open&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;relativeOrAbsoluteUrl:&lt;/span&gt; &lt;span class="s"&gt;"/us/signup/"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="nf"&gt;typeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nc"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

         &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emailFriend&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;em&gt;http&lt;/em&gt; url path, or we can write a &lt;em&gt;relative url&lt;/em&gt;. Since we indicated an absolute path as a &lt;em&gt;baseurl&lt;/em&gt;, within the Selenide.open method it’s enough to indicate just “/”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="nf"&gt;typeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emailField&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SignUpPage&lt;/span&gt; &lt;span class="nf"&gt;typeConfirmEmailField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;confirmEmailField&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;setValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to find an element using Selenide, we should indicate $ instead of &lt;em&gt;driver.findElement&lt;/em&gt; 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.&lt;/p&gt;

&lt;p&gt;In order to find a list of elements using Selenide, we should indicate $$ characters. Instead of List , we write the &lt;em&gt;ElementsCollection&lt;/em&gt; command that is already extended with additional methods.&lt;/p&gt;

&lt;p&gt;To work with elements we can use both standard Selenium methods &lt;em&gt;(sendKeys())&lt;/em&gt; and &lt;em&gt;setValue()&lt;/em&gt; method or its short version &lt;em&gt;vаl()&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The difference between Selenide &lt;em&gt;find()&lt;/em&gt; method and Selenium &lt;em&gt;driver.findElement(By)&lt;/em&gt; is that Selenide &lt;em&gt;find()&lt;/em&gt; 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;You can find more information about Selenide methods in the &lt;a href="https://selenide.org/documentation.html"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s look into wider and more understandable verification examples provided by Selenide:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please enter a valid year."&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;shouldBe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Condition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visible&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"When were you born?"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;shouldNotBe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Condition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visible&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getErrors&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;shoildHave&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CollectionCondition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getErrorByNumber&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;shouldHave&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Condition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please enter your birth month."&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;strong&gt;“should-methods”&lt;/strong&gt;. When we want to check if the element exists, we use &lt;em&gt;should(exist)&lt;/em&gt;. 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Automatic screenshots in tests&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;JUnit&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;In order to take a screenshot automatically after each failed test, we can make an import and indicate the Rule.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.codeborne.selenide.junit.screenShooter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Rule&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ScreenShooter&lt;/span&gt; &lt;span class="n"&gt;makeScreenshotOnFailure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ScreenShooter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;failledTests&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;em&gt;build/reports/tests&lt;/em&gt; folder by default.&lt;/p&gt;

&lt;p&gt;In order to take a screenshot automatically of each test (even succeeded), we use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Rule&lt;/span&gt; 
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ScreenShooter&lt;/span&gt; &lt;span class="n"&gt;makeScreenshotOnFailure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ScreenShooter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;failedTests&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;succeededTests&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;strong&gt;TestNG&lt;/strong&gt; we also make an import:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.codeborne.selenide.testng.ScreenShooter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Listeners&lt;/span&gt;&lt;span class="o"&gt;({&lt;/span&gt; &lt;span class="nc"&gt;ScreenShooter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to take screenshots automatically after succeeded test, we invoke the following command before running tests:&lt;br&gt;
ScreenShooter.captureSuccessfulTests = true;&lt;br&gt;
We can also make a screenshot with a single line of code at any moment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;codeborne&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;selenide&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;selenide&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;screenshot&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;screenshot("my_file_name");&lt;br&gt;
Thus, Selenide will create two files: my_file_name.png and my_file_name.html&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Docker: features and advantages of usage
&lt;/h2&gt;

&lt;p&gt;Let’s proceed to Docker itself and its advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rapid Deployment. There is no need to set up additional tools, we can run them in containers&lt;/li&gt;
&lt;li&gt;Convenient encapsulation of applications&lt;/li&gt;
&lt;li&gt;Clean monitoring&lt;/li&gt;
&lt;li&gt;Easy scaling&lt;/li&gt;
&lt;li&gt;When we talk about Docker, the following things should be clarified:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Container is&lt;/strong&gt; 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Container image&lt;/strong&gt; is the basic element of each container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Hub&lt;/strong&gt; 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.&lt;/p&gt;
&lt;h3&gt;
  
  
  Docker installing
&lt;/h3&gt;

&lt;p&gt;To install Docker for Windows, we open the &lt;a href="https://hub.docker.com"&gt;https://hub.docker.com&lt;/a&gt; and download the &lt;strong&gt;Docker Desktop&lt;/strong&gt; app for Windows or MacOS.&lt;/p&gt;

&lt;p&gt;To install Docker for Ubuntu Linux, we need the sudo apt install docker.io command.&lt;/p&gt;

&lt;p&gt;Then we need to run Docker and configure it to start automatically when the system boots by executing the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl start docker
sudo systemctl enable docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Selenoid: features and advantages
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aerokube.com/selenoid/latest/"&gt;Selenoid&lt;/a&gt; is a server, that launches isolated browsers within Docker containers.&lt;/p&gt;

&lt;p&gt;Advantages of Selenoid usage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single environment for a parallel launch of automated tests&lt;/li&gt;
&lt;li&gt;Isolated environment: Selenoid allows running each browser in a separate container, which enables full isolation of the browser environment&lt;/li&gt;
&lt;li&gt;Scalability: Selenoid environment does not affect qualitative and continuous testing&lt;/li&gt;
&lt;li&gt;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&lt;/li&gt;
&lt;li&gt;Installation: Selenoid requires little time and effort. And in fact it is done with the help of one command&lt;/li&gt;
&lt;li&gt;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&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;Therefore, windows can compete for it. Selenoid allows running each test in a separate container. Thus, this problem is eliminated&lt;/li&gt;
&lt;li&gt;User interface and logs: all available logs are accessed easily in Selenoid. There is also the possibility of integration with the &lt;a href="https://www.elastic.co/what-is/elk-stack"&gt;ELK&lt;/a&gt; stack for faster collection and analysis of current log files&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Selenoid installation
&lt;/h3&gt;

&lt;p&gt;Before installing Selenoid you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you have recent Docker version installed (further we look into the usage of Selenoid together with Docker)&lt;/li&gt;
&lt;li&gt;The easiest way to install Selenoid is to download &lt;a href="http://aerokube.com/cm/latest/"&gt;Configuration Manager&lt;/a&gt; that is used for automatic installation of Aerokube products. Selenoid is such a product&lt;/li&gt;
&lt;li&gt;Rename the downloaded file to cm.exe (for easy interaction)&lt;/li&gt;
&lt;li&gt;Run the following commands to start Selenoid:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;./cm.exe selenoid start — vnc&lt;/em&gt;&lt;br&gt;
&lt;em&gt;./cm.exe selenoid-ui start&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;./cm.exe selenoid start — vnc&lt;/em&gt; command will download the latest Selenoid version, browser container images, web driver binaries, generate configuration files and finally start Selenoid.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;./cm.exe selenoid-ui start&lt;/em&gt; command installs and starts Selenoid UI. It is a user interface to track what’s happening during the test execution.&lt;/p&gt;

&lt;p&gt;Selenoid runs on standard Selenium 4444 port by default. We &lt;br&gt;
can redefine the port using the — port key.&lt;/p&gt;
&lt;h3&gt;
  
  
  Stats and sessions in Selenoid UI
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kprTtU8d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.intexsoft.com/images/intexsoft/blog/selenide/selenide2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kprTtU8d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.intexsoft.com/images/intexsoft/blog/selenide/selenide2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Selenoid UI is available at the link: &lt;a href="http://localhost:8080/"&gt;http://localhost:8080/&lt;/a&gt;&lt;br&gt;
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.&lt;br&gt;
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.&lt;/p&gt;
&lt;h3&gt;
  
  
  Selenoid UI capabilities
&lt;/h3&gt;

&lt;p&gt;Selenoid UI has the following capabilities:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oKeCj8ef--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.intexsoft.com/images/intexsoft/blog/selenide/selenide3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oKeCj8ef--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.intexsoft.com/images/intexsoft/blog/selenide/selenide3.png" alt=""&gt;&lt;/a&gt;&lt;br&gt;
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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CD_z2w5z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.intexsoft.com/images/intexsoft/blog/selenide/selenide4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CD_z2w5z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.intexsoft.com/images/intexsoft/blog/selenide/selenide4.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;
  
  
  Logs and VNC
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;VNC session:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gZXeSE4m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.intexsoft.com/images/intexsoft/blog/selenide/selenide7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gZXeSE4m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.intexsoft.com/images/intexsoft/blog/selenide/selenide7.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VNC fullscreen mode:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mp96oSY_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.intexsoft.com/images/intexsoft/blog/selenide/selenide5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mp96oSY_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.intexsoft.com/images/intexsoft/blog/selenide/selenide5.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_6ww1J4U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.intexsoft.com/images/intexsoft/blog/selenide/selenide6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_6ww1J4U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.intexsoft.com/images/intexsoft/blog/selenide/selenide6.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also view recorded videos of our tests. We can access them by opening &lt;a href="http://localhost:4444/video/"&gt;http://localhost:4444/video/&lt;/a&gt; or by going to the “Videos” tab in Selenoid UI.&lt;br&gt;
Adding Selenoid to run tests within Docker container&lt;br&gt;
In order to add Selenoid into the @BeforeClass annotation we need to do the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Configuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"http://localhost:4444/wd/hub"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nc"&gt;Configuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"chrome"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nc"&gt;Configuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;browserSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1920x1080"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nc"&gt;DesiredCapabilities&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DesiredCapabilities&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCapability&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;capabilityName:&lt;/span&gt; &lt;span class="s"&gt;"enableVNC"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;value:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCapability&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;capabilityName:&lt;/span&gt; &lt;span class="s"&gt;"enableVideo"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;value:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Configuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;browserCapabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since now we have the Configuration.browser = “chrome” property, we delete Property baseurl which defined the browser for running our tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@BeforeClass&lt;/span&gt; 
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="nc"&gt;Configuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"http://10.0.75.1:4444/wd/hub"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;               
       &lt;span class="nc"&gt;Configuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"chrome"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;          
       &lt;span class="nc"&gt;Configuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;browserSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1920x1080"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;      
       &lt;span class="nc"&gt;DesiredCapabilities&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DesiredCapabilities&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;     
       &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCapability&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;capabilityName:&lt;/span&gt; &lt;span class="s"&gt;"enableVNC"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;value:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;        
       &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCapability&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;capabilityName:&lt;/span&gt; &lt;span class="s"&gt;"enableVideo"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;value:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;      
       &lt;span class="nc"&gt;Configuration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;browserCapabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Selenoid advanced capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Data storage in RAM: Selenoid stores all temporary files in Tmpfs. 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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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 true in the &lt;em&gt;Browser Capabilities:
java
ChromeOptions options = new ChromeOptions ();
options.setCapability (“enableVideo”, true);&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using Selenoid without Docker
&lt;/h3&gt;

&lt;p&gt;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.&lt;br&gt;
To do it we need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download latest &lt;a href="http://www.seleniumhq.org/download/"&gt;IEDriverServer&lt;/a&gt; archive and unpack it to some directory (C:\ in this example)&lt;/li&gt;
&lt;li&gt;Download latest Selenoid binary&lt;/li&gt;
&lt;li&gt;Create browsers.json configuration file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;{&lt;/span&gt;     
   &lt;span class="s"&gt;"internet explorer"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;      
      &lt;span class="s"&gt;"default"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"11"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;      
      &lt;span class="s"&gt;"versions"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;         
         &lt;span class="s"&gt;"11"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;            
            &lt;span class="s"&gt;"image"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"C:\\IEDriverServer.exe"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"--log-level=DEBUG"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;          
            &lt;span class="o"&gt;}&lt;/span&gt;       
        &lt;span class="o"&gt;}&lt;/span&gt;    
    &lt;span class="o"&gt;}&lt;/span&gt; 
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start Selenoid:
./selenoid_win_amd64.exe -conf ./browsers.json -disable-docker&lt;/li&gt;
&lt;li&gt;Run the tests, using endpoint &lt;a href="http://localhost:4444/wd/hub"&gt;http://localhost:4444/wd/hub&lt;/a&gt; with the following capabilities:
browserName = internet explorer
version = 11&lt;/li&gt;
&lt;li&gt;To start &lt;a href="https://www.google.com/chrome/"&gt;Chrome&lt;/a&gt;, just download &lt;a href="https://sites.google.com/a/chromium.org/chromedriver/"&gt;Chromedriver&lt;/a&gt; binary and modify browsers.json accordingly&lt;/li&gt;
&lt;li&gt;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&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Summarizing
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
