Types of Automated Tests in Frontend Applications
Production-ready software requires testing before it goes into production. As the methodology of software development matured, software testing approaches have matured too. Instead of having a huge number of manual software testers, development teams have moved towards automating the biggest portion of their testing efforts. Automating their tests allows teams to know whether their software is broken in a matter of seconds and minutes instead of days and weeks.
The drastically shortened feedback loop fuelled by automated tests goes hand in hand with agile development practices, continuous delivery, and DevOps culture. Having an effective software testing approach allows teams to move fast with confidence.
This article explores the different types of automated tests that are written in frontend applications (the examples are written in Vue.js). We’ll also get into the details of writing those automated tests and we’ll cover multiple scenarios in each type of test.
What are Automated Tests Exactly?
They are pieces of code written to cover the actual application code on different levels and from different perspectives to make sure that it’s always behaving as intended after applying changes.
The goal of automated tests is to reduce the number of test cases that have to be run manually.
Once created, automated tests can be run over and over again at no additional cost.
Types of Automated Tests
There are three main types of automated tests:
- Unit Tests.
- Component Tests.
- E2E Tests.
Unit Tests
What is Unit Testing?
Unit testing is testing the smallest testable unit of an application in isolation, typically a function, and it’s done by mocking all the other parts of the application that interacts with that function (unit).
Usually, a few unit tests are written for each tested unit to cover all the possible code flows in that unit. The idea of unit tests is that they are a lot of small, lightweight tests that can run very fast to determine if the application code has any problem.
How to write Unit Tests using Jest in a Vue.js application
In the following examples, we’ll be using the Jestjs library to demonstrate the different ideas.
Usually, the test files are placed in the __tests__/unit/specs/
folder and they have the extension .spec.{j,t}s
and you can configure these settings in the jest.config.js
file in the project root.
In unit tests for a Vue.js application, we can cover the component’s methods, computed properties, watcher handlers, and mixin methods.
Writing the tests:
In the following examples, we will have a look at writing unit tests for the different parts that make up a Vue component.
Testing a method:
ShallowMount()
mounts the required component without its child components.component.vm
, gives us access to the actual component object as we would have when usingthis
inside the component’s code.
Testing a computed property:
- Notice how we are using the
describe()
method to structure our test file. - When you have multiple test cases you can use the
beforeEach()
method to execute common code that is shared in the samedescribe()
block. - Notice how we used the
setData()
method to modify the component’s state.
Testing a watcher handler:
- As you can see, by changing the data that the watcher is bound to, we can trigger the corresponding handler.
- For testing watcher handlers, we must wait for the DOM to be updated for our assertions to work, hence the
$nextTick()
. - Jest provides us with access to the
emitted()
method to be able to assert event emitting and event data.
Testing a mixin method:
- Testing a mixin method is similar to testing a component’s method, the only difference is that for mixin methods we don’t need to mount any actual component, we only need a generic component to host our mixin methods and this is what
MockComponent
is doing. - You can pass the whole mixin object to your component or just the method you’re interested in testing.
Mocking in Unit Test:
As we stated before, in Unit Tests we need mocking, so in the following examples, we will have a look at how we can mock the different parts in a Vue component.
Mocking a method:
For mocking any logic in Jest we use the jest.fn()
function and for the component methods. We can override the method implementation by assigning the mock implementation.
Mocking a computed property:
- Unlike component methods, a computed property’s implementation cannot be changed after mounting the component so we have to pass the mock implementation when mounting.
- Notice how we can pass any implementation we want to the mocked method/computed property as an argument to the
fn()
function. - For mocked computed properties, we can’t expect the calls on them as we do for mocked methods.
Mocking a mixin method:
- You can use a similar way to what we did for the methods but here is an alternative way that uses the spy technique provided by Jest to assert calls.
toHaveBeenCalledWith()
is used to assert arguments passed to a function call.
Mocking an external library:
A common use case of an external library is issuing HTTP requests, so in the following example, we’ll have a look at mocking the Axios
HTTP library.
You can mock any method at any level in the describe()
structure to suit your needs.
How to run Unit Tests written in Jest in a Vue.js application
You can use the vue-cli-service test:unit
command to run unit tests.
For convenience, you can define a script to run unit tests in your package.json
file. You can also run individual tests using your IDE by clicking the play button next to the test code. You can add a breakpoint to your code and run the test in debug mode.
Component Tests
What is Component Testing?
As the name suggests, component tests are written to test the application components (Vue.js components in our case) and like unit tests, component tests are done in isolation for the tested component, but the difference here is that we don’t just test the logic of the component, but also its rendered template. We test the component by interacting with the component’s HTML elements and expecting certain results or changes on those elements. In components’ tests, we only mock the services that take time to deliver results such as HTTP requests and file system interactions.
Usually, the number of component tests is less than unit tests and they take more time to run.
How to write Component Tests using Cypress in a Vue.js application
Cypress is an E2E testing library but it also supports Component Testing by configuring it.
Usually, the test files are placed in the __tests__/component/specs/
folder and they have the extension .spec.{j,t}s
and you can configure these settings in the __tests__/e2e/plugins/index.js
file.
In the following examples, we’ll have a look at some of the important aspects of component testing.
First, let’s look at the structure of the test:
As you can see, the structure is very similar to the Unit test structure, now after mounting the component, we can start adding our assertions.
You can use the cy
object to write your assertions, and all the modifiers are passed as strings to the should()
method.
Targeting the elements is done by using CSS selectors.
Asserting the existence and visibility of an element:
You can add not
in front of any modifier to reverse its function.
Asserting the value of an element:
For asserting the value, you need to target HTML elements that can have a value attribute, like form elements.
Asserting the content of an element:
Asserting options text of a dropdown:
Intercepting an outgoing HTTP request:
- Notice how we used the
*
in the query section of the URL, this is a wildcard and it means any variation of that request will be intercepted. - You should always wait for the request to be fulfilled before starting your assertions.
How to run Component Tests written in Cypress in a Vue.js application
There are two modes of running component tests:
- Browser Mode
- Headless Mode
In browser mode, a browser window is opened where you can choose to run a specific component test in a specific browser and you can see the changes on the page as the tests are running.
This mode is useful for development.
To run component tests in the browser mode, you can run npx cypress open-ct
.
In headless mode, no browser window is opened, and you can only see the failing or passing tests without many details. In this mode, you can run all the component tests at once.
This mode is useful for CI/CD pipelines.
To run component tests in the headless mode, you can run npx cypress run-ct
.
E2E Tests
E2E or End-to-End Tests (aka Integration Tests) are similar to component tests but in these tests, instead of loading an individual component in isolation, we test the application by visiting its pages.
The idea of E2E tests is that they simulate a real user visiting our application and interacting with it. In addition to what we check in the component tests, in E2E tests, we also check that our components on the same page are communicating as we intended. In E2E tests it’s better to not mock any service so that our tests are like real-life scenarios.
How to write E2E Tests using Cypress in a Vue.js application
Usually, the test files are placed in the __tests__/e2e/specs/
folder and they have the extension .spec.{j,t}s
and you can configure these settings in the __tests__/e2e/plugins/index.js
file.
Since we are using the same library for both component and E2E tests, all the concepts covered in the component tests section are applicable for E2E tests, the only difference is in loading the page.
In E2E tests we visit a URL instead of loading a specific component.
How to run E2E Tests written in Cypress in a Vue.js application
Like Component Tests, in E2E tests there are two modes of running the tests:
- Browser Mode
- Headless Mode
To run E2E tests in the browser mode, you can run vue-cli-service test:e2e
.
To run E2E tests in the headless mode, you can run vue-cli-service test:e2e — headless
.
Conclusion
Automated Tests are an essential part of any well-written software and they are critical especially for projects that will grow and will be maintained over the years, but keep in mind to maintain a good balance between the E2E/Component Tests cases coverage and the effort and time needed to write those cases.