What tools and approaches to use for front-end testing

SHARE
Software-Development-Strategies

Testing is a fairly reliable way to trap errors at the development stage and save nerves during the operation of the software. In this article, experts will tell you what tools and approaches for front-end testing they recommend for a web developer and tester to use.

Lead Software Engineer

It seems to me that the development community is somewhere in the phase of understanding that only designs that promise to live for a long time without changes can be “concreted” with tests. At the same time, we see the widespread use of Agile approaches to development, hinting to us that the mobility, flexibility of a product in every sense is one of the key factors for its survival in the market.

TDD (test-driven development or development through testing) sounds cheerful when you do laboratory work, and not at all when you find yourself on the market and lose the tender just because you have priced tests that will hardly live up to release date. The obvious contradiction between an abstract ideal code and a business that wants cheap, reliable and by yesterday is resolved in this compromise: you can have a lot of cheap tests, but few expensive ones. The more functionality is covered by a test, the more expensive such a test is usually.

This is how we enter the classics of the test pyramid: Jest, Mocha, Jasmine and others in unit and integration tests; Karma, Protractor, Phantom, etc. for UI component tests (which, with the easy introduction of the Angular team, began to be called E2E tests, although this is not always the case), and Pact as testing the performance of a contract between a provider and a consumer.

It is worth mentioning separately security testing (Fortify is used on my current project), performance testing (Lighthouse), CSS regression testing (Hermione).

Frontend-developer

Each programmer is responsible for the quality of the code he writes, and one of the most important characteristics of quality is code coverage with tests. In practice, this area is often neglected due to lack of time or deadlines, giving preference to writing new functionality and leaving this task to testers. As a result, weekly sprints are marked with pain called “bug fixing” due to unforeseen errors in the code, and the beloved Agile gradually turns into a waterfall model.

When building a large SPA with a complex architecture, writing tests is an integral part of the development process. Depending on the specifics of the application, test coverage can be focused on working with data or on the area of ​​working with the DOM. If the module represents a simple block for rendering data associated with an API (form, list, modal window, or table), it is worth concentrating on describing the functions responsible for changing data, such as working with state or data storage, by tests. The more complex the visual part of the application, the more attention deserves the process of rendering the DOM tree.

The main types of testing for the frontend are Unit testing, integration testing and end-to-end (E2E) testing. A unit test tests the operation of one unit (function, object, class, module) in isolation from other parts of the application. Integration tests test several related modules. Most often for the frontend, this means checking the performance of parts of the application related to the outside world (working with localStorage or cookies, working with API), or simulating events on the page and transitions between modules. In end-to-end testing, the entire application is loaded and the user’s work with the application is simulated.

To determine the number of tests for each of the groups, there is a testing pyramid that groups the necessary tests into different levels of implementation (many Unit tests, fewer integration tests, and a little E2E). In practice, this pyramid is not always the best approach. The fact is that in a rapidly developing application, functionality often changes, business requirements expand, while affecting previously written modules, and some features may not even reach deployment in production. Therefore, it does not always make sense to cover all the functionality of an application with tests. The pyramid in this case can be placed upside down.

In development, I pay the most attention to writing integration tests, in particular working with APIs. This is not the most dynamic part of the code, but improving fault tolerance when working with the server is one of the most important goals for front-end testing.

To implement effective testing, there are TDD (Test Driven Development) and BDD (Behavior Driven Development). These are special extreme programming techniques, when first the developer writes tests, and then the code that will satisfy the underlying technical requirements or user scenarios. In real life, this approach is effective but difficult to maintain and implement, for instance, if you have a development team with distributed duties.

Popular testing libraries for front-end developers are Jest for integration and unit testing, and Puppeteer or Cypress for end-to-end testing. To work with Angular, Karma and Jasmine are most often used to write tests, together with Protractor for end-to-end one. In addition to common libraries, each framework has specific approaches to testing. For example, React contains test-utils that make component testing easier. When choosing a tool, it is recommended to study the approaches and documentation for testing your framework.

Head of Software Lifecycle Management

We create most load tests and functional autotests of web applications using LoadRunner from MicroFocus. This tool is also considered optimal by many external IT teams who come to us for expertise in the development of automated tests.

By the way, few people know about the possibilities of LoadRunner in the field of functional testing, as they are used to perceiving it solely as a load tool. Here you can create functional tests for applications using the TrueClient protocol, and then convert them into load tests. A very convenient thing, but it requires certain knowledge and a thoughtful approach to the solution.

In fact, LoadRunner is a huge professional studio that does a lot of work for you, for example, it helps you quickly create load scripts using autocorrelation. With its help, when developing functional tests, you can quickly and efficiently create locators for objects, embed your code in various programming languages ​​into autotests. The ability to include your own libraries is one of the strengths of this tool. And everything that LoadRunner cannot do, you can write yourself in C or JavaScript. For example, this was useful when, in a load test, we needed to test a system where each report sent to the server must be accompanied by an electronic signature. There is a lot of information regarding LoadRunner on the thematic forums, as well as video presentations on YouTube. Usually an hour is enough to connect a new person to create or maintain autotests.

Previously, LoadRunner was completely purchasable, but now it is free for a load of 50 users, while the TrueClient protocol is generally free. Usually fifty users are enough to show developers their weaknesses in the code, but you can always slightly increase the load using virtualization.

Testing engineer

When it comes to automating front-end testing, the most obvious tool is Selenium. Although, if the project is short-termed, it is worth considering Selenide or another wrapper as an alternative. This will significantly speed up the start of the project and will help you avoid writing custom functions for basic interaction. Then it is very important to create a convenient infrastructure where all manual operations can be minimized, and test results can be visualized. For example, a bunch of Allure, Jenkins and Selenoid can help you with this. Allure can be used both for general statistics and for displaying all steps and actions of tests in a report. To do this, you just need to provide the code with the necessary annotations. Selenoid is needed to remotely run your UI tests, since after a certain point it becomes unacceptable to run them locally in time. And finally, Jenkins serves as a link and allows you to easily set up tests to run at a certain time or after the next build of the front.

As a general approach when writing tests, I can advise maximum fragmentation. There is no need to try to test everything in one test. On the contrary, it is worth splitting them into small tests, checking one or two business functions at a time. And as practice shows, in complex applications it is very convenient to prepare test data before the UI test by automating work with the database or with the API application.

And as a piece of advice to beginners who decide to learn front-end testing automation using Selenium, I can recommend learning Xpath rather than trying to use programs to automatically find locators, and learn the programming language of your choice as best as possible, because in complex systems and complex tests work with data occupies the first place, and you will not be able to get by even with excellent knowledge of Selenium alone.
Let’s sum up everything we’ve covered in the article.

So, what and for what tests is used when testing the front-end?

  • Unit and integration tests: Jest, Mocha, Jasmine;
  • UI-testing: Selenium, Karma, Protractor;
  • Layout testing for CSS-regression: Hermione, PhantomCSS;
  • End-to-end tests: Puppeteer, Cypress, Webdrive.io;
  • Performance testing: Lighthouse;
  • Cross-browser testing on real devices: BrowserStack;
  • Tools for creating test infrastructure: Allure, Jenkins, Selenoid.