Send your request Join Sii

Component testing is a relatively new concept introduced in Cypress on June 1, 2022, in version 10.0.0. We had previously encountered the implementation of component tests, but at a different level than it is today.

In this article, I will describe component tests, present an example from the past, and discuss the current implementation using Cypress. Additionally, I will discuss the pros and cons of these solutions.

If you are interested in Cypress, I warmly invite you to read my previous article about waits in Cypress: Testy automatyczne Cypress czeka aż – wprowadzenie do waitów, as well as an article by my colleague Michał, introducing this testing tool: Cypress – dlaczego warto zainteresować się tym frameworkiem.

What are component tests?

Component tests in front-end testing involve checking individual components or units of a web application in isolation. The main goal is to ensure that each component works as expected at an early stage of development.

Components are usually smaller, independent user interface parts, such as:

  • buttons,
  • forms,
  • or custom UI elements.

For example, a popular “date-picker” fits perfectly into this definition and is an excellent subject for testing on your own keyboard.

Benefits of component tests

These tests bring several benefits, including:

  • Isolation testing – this means we don’t need actual working software, service, website, or server to conduct the test. It saves time and increases test stability.
  • Small and fast tests – we conduct component tests almost like unit tests. This lets us detect irregularities quickly, resulting in quick and relatively inexpensive fixes.
  • Easy and readable code – using this practice, we introduce ease of code maintenance and increase its clarity. The application is divided into smaller parts, which are then tested by these component tests.
  • Automation and integration – these tests can be easily automated and integrated into continuous integration tools. We can also run them locally on a Docker container, particularly useful when starting the journey with automated tests.

But why do we need component tests?

To answer this question, we need to understand the necessity and essence of automated tests. An automated test is part of the process of checking test scenarios using automation tools or scripts. However, it’s important to remember the testing basics, as they are crucial when creating test cases. In my opinion, a good automated test should consist of three elements:

  1. Test data,
  2. Steps,
  3. One assertion.

I touch on a rather controversial topic by emphasizing the last point as a critical criterion. In my view, a test that checks many things is unreliable, difficult to maintain, and complicated to verify.

Let’s consider a situation where we want to write a test that submits a user registration form. We fill in all the fields and click the “submit” button using cy.contains(“submit”). However, a question arises – what happens if our button has different text, for instance, due to issues displaying special characters? We get a negative result in a test that creates a user even though the string (commonly known as a “string”) we are searching for is different.

What can we do in this situation? We should write a better test! We can use the cy.get() method and provide our unique identifier (cy-data locator) here. This method eliminates the need to search for elements by a specific string and instead refers to the locator. However, we sometimes use the cy.contains() method because it is more convenient and effective than cy.get().

But what if we had a component test that generates this element with the expected string, simultaneously checking its text, behavior, and CSS styles? Our continuous integration tool would only allow further tests to run if we fixed what produced a negative result. Thanks to early error detection, we can quickly and cheaply fix it. Additionally, this prevents false negatives in other tests where the component is at fault, not the logic of the code itself.

Component testing vs. the Testing Pyramid

The Testing Pyramid is a “design pattern” that outlines the hierarchy and quantity of tests. According to generally accepted standards, it is divided into three levels, stacked one on top of the other, in order of creation/maintenance cost or execution time.

The Testing Pyramid depicts the three main levels of tests
Fig. 1 The Testing Pyramid depicts the three main levels of tests

Unit tests

Developers usually write these and aim to verify a method/function/module at a unit level. They should have the highest, realistic code coverage. Unit tests are represented as the foundation of the testing pyramid because:

  • They are independent of external services.
  • They are extremely quick to write and execute.
  • They are inexpensive to maintain and create.

They can also serve as a form of project documentation.

Integration tests

At the next level are integration tests, which include system, functional, and integration tests. These tests verify whether individual modules communicate with each other using both test and real data. These tests are primarily written and executed by testers, but this also depends on team agreements and project approach. Depending on complexity, they may rely on external services but are certainly cheaper and faster than end-to-end tests (E2E).

End-to-end tests

These tests verify business paths from user creation to purchasing items in an online store. However, they have the following disadvantages:

  • They are unstable.
  • They are costly to create and maintain.
  • They cover a minimal portion of code.
  • Their execution time is much longer compared to unit or integration tests.

Where do component tests fit into the testing pyramid?

Based on what we’ve read about both component tests and the Testing Pyramid, they sit between the unit and integration layers. This is precisely where I place them.

Testing Pyramid with placement of component tests
Fig. 2 Testing Pyramid with placement of component tests

Who should write/create component tests?

Here, we encounter a situation similar to that of unit tests. Internet sources claim that developers are responsible for component tests. However, I know from experience that most developers focus more on code implementation than writing tests. This is also a debatable topic related to the definition of done, project approach, and team dynamics.

In my opinion, writing component tests is an ideal task for a tester who wants to start their journey with automated testing. These tests are easy to write and maintain, and their results are clear, reliable, and transparent.

Component tests in practice

Here, I will discuss two approaches: the old and the new way of creating component tests using JavaScript with Cypress.

Old-fashion way

This approach is encountered in Cypress and other testing frameworks where we cannot currently display components. Knowing these limitations, let’s proceed with implementation.

We want our test to verify if our website’s “Click me” button meets our expectations. We need to check the button on our locally running software version at http://localhost:4200/.

Verification of the operation of the “Click me” button
Fig. 3 Verification of the operation of the “Click me” button

We create test cases and check if it works.

  1. Check if the button has the label “Click me.”
  2. Verify if the button has a red background color.
  3. Ensure the button correctly displays the text “1!2#45.”
  4. Confirm if the button displays the color changed to blue correctly.
code

The presented code looks neat and readable. Using the Page-Object design pattern and pulling recurring elements into variables can make it even clearer. Its drawback is undoubtedly the execution time, which, with four tests, is only 809 ms or as much as 809 ms.

Here, we need to note that we access the button immediately after loading “localhost.” It does not require any additional interaction, allowing us to achieve an acceptable time for four test cases. However, it becomes more complicated to extract individual elements, for example, from the third page of the user edit form to reach the reset button, which only appears after editing any field.

Suddenly, your test looks like this:

code

Acquiring this element can take a lot of time, leading to a significant increase in code and dependence on other services. What if we were to test the button on the “production” server? It took me 12 seconds to execute these four tests.

What can we do to make our test better and faster?

  1. If we have Storybook or similar tools, let’s write tests there. We may encounter inconveniences with iframes, but the scale of these inconveniences is drastically smaller compared to the time it takes to run these tests, and they are very close to component tests themselves.
  2. Combine all assertions into one test using so-called “Soft assertions” (an assertion that does not immediately fail the test upon occurrence) to save time when visiting the page or element. This idea can be beneficial, especially with the right reporter, which can really pay off. (This is a potential anti-pattern because a test should ideally consist of a single assertion, but… that’s a topic for another post). I managed to achieve a time of 358 ms.
  3. Do not refresh the page and perform assertions in separate tests (anti-pattern because tests depend on each other) – time: 278 ms.
  4. Use the cy.mount() method to utilize Cypress’s component testing!
code

With this method, we can generate the component individually by importing it and passing it to the mount() method. It saves time on writing and execution, keeps the code clear, and ensures reliable tests. The time I achieved was 162 ms! This is the best result so far.

Component testing
Fig. 4 Component testing

If not Cypress, then what?

Component testing is not limited to Cypress alone. There are several alternative tools, such as

  • Jest,
  • Enzyme,
  • Vue Test Utils,

which can also be effectively used for this practice.

These diverse options allow developers to tailor tools to specific project needs, which becomes particularly important in situations where Cypress, for various reasons, does not meet expectations.

***

Learn more about Cypress in other articles by our experts.

5/5 ( votes: 9)
Rating:
5/5 ( votes: 9)
Author
Avatar
Piotr Flis

His adventure with tests began in 2015 working with Silk Test and Python. Currently working on test automation in Cypress with the use of JavaScript and TypeScript. He is the founder of a sport shooting group Sii-ła Magnum in Sii. After work puts emphasis on personal development in the test automation area and shooting practice. In all likelihood, he can be found at the largest IPSC competitions in Poland, in the Standard Shotgun category

Leave a comment

Your email address will not be published. Required fields are marked *

You might also like

More articles

Don't miss out

Subscribe to our blog and receive information about the latest posts.

Get an offer

If you have any questions or would like to learn more about our offer, feel free to contact us.

Send your request Send your request

Natalia Competency Center Director

Get an offer

Join Sii

Find the job that's right for you. Check out open positions and apply.

Apply Apply

Paweł Process Owner

Join Sii

SUBMIT

Ta treść jest dostępna tylko w jednej wersji językowej.
Nastąpi przekierowanie do strony głównej.

Czy chcesz opuścić tę stronę?