Contact us

🌍 All

About us

Digitalization

News

Startups

Development

Design

Front-end Testing: Static vs Unit vs Integration vs E2E

Mateusz Wójcik

Jul 20, 20205 min read

Software testing

Table of Content

  • What is static testing?

  • Front-end unit testing

  • Front-end testing: the integration tests

  • Front-end testing: End-to-End tests

  • Last words on front-end testing

Front-end testing is a big part of development. The benefits of adding tests to our apps are clear, but it can be confusing. There are a lot of test types, and their definitions may vary depending on who you ask, the tools you use, and the ways we can test code. The internet provides a few examples of "roadmaps” for testing front-end, like the testing pyramid or the testing dorito. But the Testing Trophy by Kent C. Dodds is the one that caught my eye. Let’s go through each segment of this testing trophy and see its pros and cons.

What is static testing?

Static tests should be the base of front-end testing. They consist of linters (e.g. ESlint) and static type checking (e.g. Typescript).

Static testing with ESlint

You may already be familiar with ESlint as it's trendy in the Javascript ecosystem. It's a tool that scans your code and finds potential problems in it; for example, you are trying to use a variable you didn't declare yet, or maybe you didn't import a function, but you are still trying to run it. ESlint can automatically fix some of these problems. It's easy to configure, and there are already existing configs to help you get up and running, like eslint:recommended or eslint-config-react-app. 

Installing the required packages takes only a few minutes. It's a good idea to tweak your IDE to run ESlint on every save or to use some tools like Husky and Lint-Staged to run it on every commit. This way, you make sure that every line of code that goes into a remote repository is checked and hopefully fixed by ESlint.

Static testing with Typescript

Typescript, on the other hand, requires a little bit more work. This is because it is a superset of Javascript that can extend JS capabilities. We are talking mostly about static type checking, which is available in a lot of programming languages but unfortunately not in JavaScript. 

It allows you to set the type of variable or function parameters. For instance, in a function function 

sum(a: number, b: number): number { return a + b; }

we specify that the parameters 'a' and 'b' should be numbers, and that our function will return a number.

In this example, we are saying that the parameters "a" and "b" should be numbers and also that our function will return a number. So whenever you try to pass a string as a function argument, Typescript will catch it and throw an error. Using Typescript is the most challenging part of static testing as it requires developers to learn some new syntax.

Front-end unit testing

Unit tests are pretty simple because their focus is to test separated parts of the app. No external dependencies, no software frameworks. 

They can even test a single function. For instance, we can add a unit test for the function 'sum' as follows: 

test('sum function', () => { expect(sum(1, 3)).toBe(4); });

 In this test, we're expecting that the sum of 1 and 3 will result in 4.

Unit tests are pretty simple and can be read as standard English: "Expect that sum with arguments 1 and 3 will result in 4." According to the Testing Trophy, they are a good starting point for more complex tests. If you are interested in this kind of test, take a look at the Jest library. It doesn't require a lot of configs and generally works great, provided you have enough helpers to test everything you need. You can also create more complex test cases with mocking API requests and responses.

As part of your product development, you should focus on testing the crucial parts of the application as well as its logic. Otherwise, you might find yourself testing implementation details, and that's unnecessary. So far, your code is covered by static tests, and some parts of your app have their own unit tests. Let’s see the next type of tests, that is, the integration.

Front-end testing: the integration tests

Integration tests ensure that various parts of the app work together. They’re crucial from a business viewpoint. Remember that users don't care if a single function of your app works. They are interested in knowing if they can use the whole application, and that's where integrations tests shine. 

The React Testing Library is a go-to resource for integration tests. Its main goal is to allow for testing the way your users will use the app and avoid testing implementation details. RTL offers a ton of utils to make testing more straightforward and more maintainable. 

Let's consider a simple React component. The component consists of a label connected with an input field, a button to show a message, and a paragraph element to display the message. The label is tied to the input field through the 'htmlFor' property, and the button has an onClick event handler that changes the state of the message.

This simple component consists of a label connected with its input, a button to show the message, and a paragraph in which we will display it.

Now let's add a test for it: we first render the component, select the elements we need to interact with or inspect, simulate user input and button click, and then check if the expected message shows up in the paragraph. This test would look something like this:

test('user interaction test', () => {
    const { getByLabelText, getByText } = render(<MyComponent />);
    const input = getByLabelText('message-input');
    const button = getByText('Show Message');
    const messageContainer = getByText('');
    
    expect(messageContainer.textContent).toBe('');
    
    fireEvent.change(input, { target: { value: 'Hello World' } });
    fireEvent.click(button);
    expect(messageContainer.textContent).toBe('Hello World');
});

Let's go through this example:

1. We import a few helpers provided by RTL alongside the component to be tested.
2. We create a new test and name it.
3. We use the render method from RTL to render the component. This method provides so-called queries that will let us select the elements needed in the test.
4. We use the provided queries to select the input, the button, and the paragraph where the message is displayed. We can choose the elements in different ways even when they show up asynchronously, and we can use regexp (like here, case-insensitive). The most interesting is "getByLabelText" because we can select the input by first choosing the label connected to it. We can also check if our inputs are accessible.
5. There shouldn't be any message in it, so we test for that.
6. We are using a helper to simulate the user’s input.
7. We simulate another event: click on the button.
8. We add another expectation to see if the message container contains the provided value.

Hopefully, our test passes!

Front-end testing: End-to-End tests

The last part of the Testing Trophy is End-to-End tests. E2E tests are different from other types of tests because they run in a real browser. We write test cases as step-by-step instructions for the automated browser to go through the parts of the app we want to test. 

One of the most popular tools for End-to-End tests is Cypress. It's easy to set up and to use, on top of being fast. 

Here's an example of an end-to-end test for a registration form using Cypress:

it('tests user registration', () => {
    cy.visit('https://mywebsite.com/register');

    cy.get('input[name="username"]').type('testUser');
    cy.get('input[name="password"]').type('password123');
    cy.get('button').contains('Register').click();

    cy.url().should('include', '/login');
});

In this test, we navigate to the registration page, fill in the username and password fields, click the register button, and then check if we're redirected to the login page.

1. We create our test
2. We tell Cypress to visit the URL with the registration form.
3. We take proper inputs and type some values.
4. We look for a button with a "Register" text, and we click on it
5. After successfully registering, we should be redirected to the "/login" page, so we test for that.

When we run this test, a browser window pops up, so we can see the test runner perform each step. If something goes wrong, Cypress lets us know.

Usually, End-to-End tests take longer to write than the unit or integration tests. They also take longer to run as they communicate with a real API, so you should only write them for the most critical flows in the application.

Last words on front-end testing

The Testing Trophy is a great guideline. We can start with static tests, then move on to unit tests, and finish with integration tests. We can leverage the power of end-to-end tests to automate the testing of the app’s most critical routes. Drop us a line to learn more about front-end testing or write to

Front-end Testing: Static vs Unit vs Integration vs E2E

Published on July 20, 2020

Share


Mateusz Wójcik JavaScript Developer

Don't miss a beat - subscribe to our newsletter
I agree to receive marketing communication from Startup House. Click for the details

You may also like...

How AI-Powered Testing Tools are Revolutionising QA/QC
Software testingQuality Assurance

How AI-Powered Testing Tools are Revolutionising QA/QC

AI-powered testing tools are transforming quality assurance and control with automation, efficiency, and accuracy. Explore their impact on QA/QC processes, popular tools, and future trends.

Marek Pałys

Dec 03, 20247 min read

The Ultimate Guide to App Maintenance for Peak Performance
Software developmentSoftware testingQuality Control

The Ultimate Guide to App Maintenance for Peak Performance

Effective app maintenance is key to ensuring optimal performance and user satisfaction. This guide covers essential maintenance practices, from regular software updates and bug fixes to security enhancements and functionality improvements. It outlines the importance of understanding app maintenance, identifying areas for improvement, and implementing strategies for peak performance, thereby ensuring apps remain reliable, efficient, and competitive in the fast-evolving digital landscape.

Marek Majdak

Jan 16, 202412 min read

Quality Assurance In Mobile App Development
Software testingSoftware development

Quality Assurance In Mobile App Development

Quality assurance (QA) plays a pivotal role in mobile app development, ensuring apps function seamlessly across devices. From functional to security testing, rigorous QA processes prevent costly post-launch corrections and elevate user trust. Dive into the world of QA and understand why it's indispensable in today's competitive app market.

Marek Majdak

Nov 23, 20225 min read

Let's talk
let's talk

Let's build

something together

Startup Development House sp. z o.o.

Aleje Jerozolimskie 81

Warsaw, 02-001

VAT-ID: PL5213739631

KRS: 0000624654

REGON: 364787848

Contact us

Follow us

logologologologo

Copyright © 2025 Startup Development House sp. z o.o.

EU ProjectsPrivacy policy