Each programmer is responsible for the quality of the code written by him, and one of the most important quality characteristics is the coverage of the code with tests. In practice, this area is often neglected due to lack of time or deadlines, preferring to write new functionality and skipping this task for testers. As a result, a weekly sprint is superimposed with a pain seal called “bug fixes” due to unforeseen errors in the code, and the beloved Agile is gradually turning into a waterfall model.
When creating 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 directed to work with data or to the area of work with the DOM. If the module represents a simple block for rendering data related to the API (form, list, modal window or table), it is worthwhile to concentrate on the description by the tests of the functions responsible for changing the data – work with the state or data store. The more complex the visual part of the application, the more attention is paid to the process of rendering the DOM tree.
The main types of testing for frontend are Unit testing, integration testing, end-to-end (E2E) testing. Unit test tests the operation of one unit (function, object, class, module) in isolation from other parts of the application. Integration tests test several interconnected modules. Most often for the frontend, this means checking the health of the parts of the application related to the outside world (working with localStorage or cookies, working with the 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 test pyramid that groups the necessary tests by 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, the functionality often changes, business requirements expand, while affecting the modules written before, and some features may not even reach the deployment in production. Therefore, covering all the functionality of an application with tests does not always make sense. The pyramid in this case can stand upside down.
In development, I pay most attention to writing integration tests, in particular, working with the API. This is not the most dynamic part of the code, but increasing fault tolerance when working with the server is one of the most important goals of testing the frontend.
To implement effective testing, there are TDD (Test Driven Development) and BDD (Behavior Driven Development). These are special extreme programming techniques, when the developer first writes the tests, and then the code that will satisfy the technical requirements or user scripts. In real life, this approach is effective, but difficult to maintain and implement, for example, if you have a distributed development team.
Popular test libraries for front-end developers are Jest for integration and unit tests, and Puppeteer or Cypress for end-to-end testing. When working with Angular, Karma and Jasmine, as well as Protractor for end-to-end, are most often used to write tests. In addition to shared libraries, each framework has specific testing approaches. For example, React contains test-utils that simplify component testing. When choosing a tool, it is recommended that you study the approaches and documentation for testing your framework.