Front-End Architecture: Tests
By: Caio Vaccaro
Tags: Front End Development, JavaScript, Software Development, Testing

Unit

What it is

As the name says, it refers to the units, and, as the word suggest, it means that it is something that cannot be divided, since it is the smallest possible part. When referring to software, it means that they are functions that only do one thing. Unit tests are responsible for attesting that such functions (or units) are behaving properly. As we are talking about Front-End, these functions are written in Javascript or any other language that compiles to it.

Whether using the TDD process or not, it is difficult for a developer to take into account all possible scenarios, especially when programming such functions. Writing unit tests can help you to prepare your code for situations that are not “optimal”. In addition, they can make sure that during the life of the project, the “little guys” (unit tests) will complain before you notice such errors, in case something goes out of the established format or architecture,. By writing them, you are creating an army of robots with a life of their own, whose only mission is to observe their functions and ensure that they are correct.

An example, in the case of a function that formats dates, would be to guarantee the outputs, for practically all types of input — which happens when someone uses a date in different formats, invalid dates, and so on, including how the function handles errors and exceptions.

When to use it

The project has a considerable amount of logic

There are many functions that are reused in many places

You have a business rule or a code that is crucial to the success of how the business flow goes

It is a product or project with a long life

It is an open-source project with contributors

Note: How can you tell when it’s a logic code or not? Logic, most of the time, is pure Javascript — that is, if you are accessing the DOM, changing classes or animating, this is already the consequence of logic, or, in other words, it is a side effect of a decision. Usually, logical functions are composed of conditionals (if-else, switch) and loops.

Pros

Bugs are found faster

Run-time errors are treated preventively

More confidence in deploys

It makes it easier the use of refactor (rewriting functions while keeping the same inputs and outputs)

Cons

More time spent in developing

More time spent with the project

It is difficult to rewrite. Unlike the refactor, if a function or module has been poorly designed and needs to be redone, the test will need to be rewritten as well

Tools

Tape

Jasmine

Jest

Mocha

Ava (assertion and runner)

Karma (runner)

Extras: Chai, Sinon

Coverage

This is a controversial point. When using unit tests as a synonym for more stability and security, it is very common to compromise or require some “coverage”, usually measured in percentage. At first, the more of your Javascript files, functions, lines, conditions — in short, the more operation is covered by tests, the better. But there is “too much testing”. A happy medium would be to manually choose critical files, with a business rule or logic, and measure their coverage, instead of doing that with all files.

Integration

What is it

There are a lot of gifs on the internet exemplifying the difference between unit and integration tests. It basically means testing units together. While in unit tests it is often necessary to mock (simulate data locally, removing the need for external integrations) parameters, data and dependencies, in the integration test the “real units” are used as much as possible.

Here’s an example, in the case of dates. You would probably have at least one function to format dates and another to format time (hours of the day). And here’s the question: would a simple integration test be sufficient to verify what would happen, for example, if the date and time formats are different — even if the date and time formatting works in isolation? Will the output be the date in the format of a specific country and will the time be in the format of another one — or is that an exception?

When to use it

The word “integration” in this context means a lot. Basically, these tests aim to answer the question that still remains: how do two units tested together work together? However, in this case, unity can have several meanings:

To test two or more functions, when one is used by the other and the unit test was solved by the mock

To test functions or modules that use external dependencies (like NPM packages) and the unit test was solved by mock

To connect APIs or external services to tests that were previously mocked

On microservice architectures, to test functions or modules from different repositories that work together

Pros

It provides you even more security in the application, mainly as a validation before deploying

It quickly warns you of any failures as a result of a refactor, either from your own code or from the others, which otherwise might only be caught in production

Cons

Depending on the stack and the architecture of the project, it might take some considerable setup time, specially when provisioning instances in the cloud, including setup and teardown services

It can be slow, increasing the build time considerably

Tools

The same as for unit tests, but depending on the architecture of the project you may need to run a browser to access some specific functionalities.

End-to-end

What is it

It is what the name says: “from end to end”. We are talking about “applications”, which have data, logic and interface, so “end-to-end” tests must encompass all three. They are focused on the interface as a way to automatically test behaviors, interactions and flows, whether they contain data and logic or not.

An example: through this option, it would be to possible to automate an interface test in which the user accesses a calendar and chooses dates, and in another column he/she would be able to choose the hours of the day, attesting that the correct options are shown, that the success and error messages appear and so on.

When to use it

Whenever you and your team find yourselves performing the same interface test dozens of times and there is time to schedule automated tests. The most important question that defines whether this is the case or not is: how long will these tests continue to be done, or how long will this project take? If the answer is at least a few months, it is certainly the case.

Pros

It shortens considerably the time you spend doing manual tests

If configured correctly, it makes it easier to find cross-browser divergences

Cons

It demands considerable time to schedule tests

Drivers, browsers headless and different browsers have an unstable behavior when it comes to automated tests, leading to many exceptions that must be skipped and retested manually

Tools

Regression

What is it

All integration and end-to-end (unit) tests have much more value when monitored over time. It is possible to configure them to use a log that clearly shows what has been successful or failed. If you are on a well-structured project, it is possible that there are dedicated QA professionals — and, in this case, they are probably doing exploratory manual tests as well, and writing down the test results over time.

While the uses mentioned above focus primarily on the layer of data and the logic of an application, there is another use, perhaps one of the most useful for large-scale projects. For example, to observe automatically the interface differences during the lifetime of a product or project, using past references. This is extremely useful in a project with hundreds or thousands of pages, since it would take several days or weeks to certify that everything is okay if you check it manually. So it is valid to use regression testing.

When to use it

In complex software where there is a well-used design system, that is, a component system with some consistent design rules. In such systems, it is possible to infer through automated scripts that changes that are poorly made in design are likely to be a break in the design system. In addition, it is possible to have too many pages to remember, especially when considering all multiple releases and timelines.

Pros

It can help you to ensure that new releases conform to the previous ones that were successful.

Cons

It requires end-to-end testing to be effective.

It requires considerable setup time.

Depending on your compatibility matrix, it may not remove the need for excessive manual testing.

There is no perfect solution yet, since it’s problematic to deal with responsiveness, threshold proportionality and screenshots of all possible interactions.

Tools

Note: In addition to the tests mentioned above, there are also specific test tools for you to use with a framework, such as Protractor from Angular and Enzyme for React.