Automated Testing with Jest on AWS

Cloud Native App Dev
Infrastructure & DevOps Modernization
Cloud Technology

Learn how to automate testing and safeguard your JavaScript apps using Jest with AWS CodeBuild and CodePipeline.

If you’re coming across this article, you likely have a good understanding of why automated testing is so crucial to the success of your business. However, if you’re unfamiliar with the benefits, automated testing will save you money and time, increase application reliability, and increase team productivity. In some extreme yet real-world scenarios, it could even save you from losing hundreds of thousands of dollars in revenue by detecting a fatal bug before it makes its way into production. Reaping the benefits of automated testing is easier than you might think. Here in this blog, I’ll show you just how simple it is to safeguard your JavaScript application utilizing the Jest testing framework, AWS CodeBuild, and AWS CodePipeline.

Benefits of Jest

Jest is a lightweight, simple JavaScript testing framework. It's open-source and written by the same Facebook open-source team that brought us React. It's straightforward and intuitive to use, allowing developers to focus more on building business logic rather than an intricate and hard-to-manage testing framework. It can be used to test applications written in JavaScript, TypeScript, Vue, Angular, and more, but most importantly, for our use case, React.

  • Jest is incredibly simple to set up. We'll get into how exactly to do this in more detail below.
  • Jest is fast and efficient. It runs the slowest tests first to maximize core utilization and uses advanced caching techniques and parallelization. Looking at a real-world example, Airbnb switched from Mocha to Jest, and were able to reduce their tests run time to take only ⅓ of the time, improving from 45 mins to 15 mins. 
  • Jest provides an easy-to-understand API that enables engineers to write tests in an intuitive, human-readable way.
  • Jest offers comprehensive, up-to-date documentation that simplifies learning and mastery.
  • Jest has a vast user base that shares ideas, best practices, and troubleshooting assistance.

Capabilities of Jest

Jest is a truly robust tool that, if used right, will dramatically improve application reliability and the developer experience. It does more than simply allowing users to write unit and integration tests. Jest has a plethora of baked-in capabilities and features that allow developers to get the most out of their time when writing tests. The following are some of the most important capabilities of Jest that truly make a difference when it comes to safeguarding your application's reliability and user experience:

  • Robust and straightforward configuration. Jest’s out-of-the-box config is sensible and works great for most projects, but if you need more customization there are over 70 different configuration options to craft a version of Jest that perfectly meets your project’s requirements.
  • A long, helpful list of built-in matchers. These matchers allow developers to easily check conditions in an easy human-readable way. For example, checking if a variable is true is as simple as writing the following:

  • Built-in snapshot testing. Snapshots allow developers to capture the output of components or data structures and save it as a snapshot file. Then, when the tests are run again, after that initial snapshot is saved, they will compare the output of the current test to the saved snapshot file. They are incredibly useful in many scenarios, but one of the most impactful is determining that your underlying code changes didn’t have any unintended UI changes. Writing snapshot tests is as simple as rendering a component with a library like React Test Renderer and calling the Jest snapshot checker function. The following code snippet shows how simple it is:
  • Robust mocks. Jest allows developers to mock functions, modules, and external dependencies. This can be crucial for isolating components that you want to test, ensuring that they are evaluated in isolation without relying on actual external resources. This can also speed up testing in cases where a developer doesn’t want to wait for an expensive call out to external dependencies when they know what the return will look like. If you don’t want to explore the documentation but want more ideas or code examples, the following blog is a good place to start.
  • Function spying. Spying on functions allows developers to track function calls and track how they are used in execution. For an example, look at the following code snippet:
  • Asynchronous testing support. Jest allows developers to seamlessly test asynchronous code. They can use built-in JavaScript asynchronous standards like async/await and promises or take advantage of Jest's automatic resolution of promises, even further simplifying the testing of asynchronous behavior.
  • Code coverage analysis. After running tests, Jest will generate a detailed coverage report that indicates which lines of code were executed during the tests. This allows developers to identify areas of code that are not adequately tested and improve the overall code quality. This can be displayed in the command line, but developers can also choose to generate a renderable html file that outlines test coverage with an easy-to-use UI.
  • Watch mode. When this valuable productivity feature is enabled, Jest monitors file changes and re-runs only the relevant tests impacted by those changes. This real-time feedback allows developers to iterate quickly during development without running the entire test suite each time. Developers could also just run a test file individually, but this could lead them to miss tests they are unaware of that are impacted by their code changes.
  • Impressive plugin and extension support. Jest's ecosystem includes numerous plugins and extensions that enhance its functionality. You can view a list of valuable plugins here. A great example is jest-email-reporter which can send emails when a test fails, which could be used with CICD to notify developers when tests are failing in a deployment to the production environment.

Writing a Jest Test For a React Component

Consider a simple React component rendering that displays a name passed in as a prop. We want to verify that the name is making its way into the component and rendering correctly in the Document Object Model (DOM). The following steps show how simple it is to set up a test with Jest to mimic this behavior. Keep in mind these libraries are ever-changing, and this tutorial will reference only a few of the libraries you may want to explore. This overview will give you an idea of how easy it is to write Jest tests and you can then pursue more complex examples based on your testing needs and goals. For complete documentation, check out the official Jest framework guides

  1. Installing Dependencies

First, we need to install the following dependencies to make things work: React, React DOM, React Testing Library, and Jest. To do this, run the following commands in the terminal at your project directory.

  1. Creating a React Component

We first create a React component that takes in a name and displays it after "Your name is:" if the name is defined. If the name is undefined, it renders, "You have no name!". Lastly, we give the component a test id to easily access it within our tests.

  1. Writing a Jest Test

Typically Jest testing files are denoted with ‘.test.’ or ‘.spec.’. They can be placed in the same folder as the page or component you are testing or in a separate test folder. All of this can be configured within your Jest configuration file

First, we will import the React component DisplayName and React Testing Library. We will use React Testing Library to render our component DisplayName. React Testing Library provides lightweight utility functions that we can call on top of React DOM to test our components.

We will then use Jest to describe and configure the test. In the test, we will use functions from React Testing Library and Jest to check if the component displays the name correctly. We will also write a second test that checks the condition where the name is undefined.

The first string passed to test( ) will be displayed in the console when running the tests with Jest. In the case of a test failure, this provides a way to know which test failed.

Capabilities and Benefits of AWS CodeBuild & AWS CodePipeline

AWS CodeBuild is a fully managed build service in the cloud meaning you don’t have to configure any of the underlying resources, AWS does it all for you. It takes the hassle out of compiling source code, running unit tests, and generating deployment-ready artifacts. By removing the burden of provisioning, managing, and scaling your own build servers, CodeBuild allows developers to focus solely on writing code and accelerating the software delivery lifecycle. The following are just some of the benefits and capabilities of AWS CodeBuild:

  • Extensive language and platform support. It offers a slew of pre-configured build environments and allows developers to create custom build environments tailored to the specific requirements of their application.
  • CodeBuild seamlessly integrates with other AWS services. This lends to easy monitoring and automated deployments, which we will explore further later. This can be especially beneficial if your application is already on AWS.
  • Builds are secure and isolated, with each build being run in a new container minimizing potential security risks.
  • CodeBuild build specs allow developers to define their build steps with YAML alongside their code in their version control system, reducing complexity. It allows developers to easily roll back changes, keep things consistent between builds, and even reuse configuration files on similar projects.
  • CodeBuild supports multiple inputs sources and multiple output artifacts, allowing developers to build multiple resources in tandem.
  • Your secret keys stay within the AWS ecosystem. You don't need to expose them to an external repository or provider to trigger a build. 
  • CodeBuild uses the pay-as-you-go model, meaning you only pay for what you use. There are no upfront introductory fees or commitments. If you have a small application or POC, your usage might even fall under AWS Free Tier.

AWS CodePipeline is a powerful continuous integration and deployment tool that seamlessly orchestrates the entire software release process. CodePipeline automates the building, testing, and deployment of your applications, leading to quicker and more reliable application and infrastructure updates. Automation, as discussed in the introduction, is crucial for modern-day projects and businesses, and CodePipeline makes it easy to implement. The following explains some of the benefits and capabilities of AWS CodePipeline:

  • CodePipeline, just like Codebuild, is also a managed service, meaning that you do not need to worry about any underlying infrastructure to run CodePipeline. AWS automatically scales and creates resources as needed.
  • CodePipeline integrates with multiple AWS services and 3rd party tools, creating a seamless CI/CD experience for developers. For instance, you can use AWS Identity Access Management service roles to access AWS resources—no need to use or manage keys.
  • CodePipeline allows for real-time monitoring and advanced logging to provide valuable insights into pipeline health and progress.
  • CodePipeline automates your deployment, but still allows for manual approval on critical steps that need human oversight.
  • CodePipeline also uses the pay-as-you-go mode like CodeBuild.
  • CodePipeline supports multiple deployment strategies for CI/CD, such as blue/green deployments, ensuring smooth and seamless rollouts with minimal downtime and user disruption.

Automating your Jest tests with AWS CodeBuild & AWS CodePipeline

Now that we have a Jest test setup, we’ll want to automate it within our application build pipeline. That's where CodeBuild and CodePipeline come in. The following guide shows how easy it is to set up automated Jest testing in CodeBuild and CodePipeline. There can be some nuances in setup depending on where the repository is kept, such as in AWS CodeCommit, GitLab, or GitHub. You may also see subtle differences based on the application's architecture, different build steps the application may have, and more, so keep in mind that each application will likely have slightly different setup steps. Jest has many other configuration options like generating coverage reports, excluding certain file types and paths in your directory, setting up global variables, and more, which could warrant its own blog post. Additionally, there are multiple ways to configure CodeBuild and CodePipeline. You can use the console with an interactive UI or set things up programmatically using AWS CLI, SDKs, or CloudFormation. There is a flavor combination to meet any need and comfort level. This guide isn't meant to be an all-encompassing tutorial, but the example below will show how simple automated Jest testing is to set up from scratch or drop into your existing CodeBuild and CodePipeline configuration.

  1. Git Repository

Create or utilize an existing Git repository that stores the React application code.

  1. Jest Configuration and Tests

Install and configure Jest in the React application. Write at least one test and manually run it locally to ensure it works as intended. Add the test script to package.json. Below is an example of the scripts in package.json for a NextJS React application with Jest. The "test" script would be used locally, and "test:ci" will be used in CodeBuild.

  1. Configure Build Specifications

Create a buildspec.yml file in the root of your project directory. This file contains the build instructions for CodeBuild. It gives commands to install dependencies, build the React application, and run Jest tests. Below is an example buildspec.yml file:

  1. Configure AWS CodeBuild

Create a CodeBuild project in the AWS Management Console. Configure the source code settings to connect to the Git repository and specify the build environment, including the operating system and runtime. Elect to use the buildspec.yml file that was created in step 3. Enable CloudWatch logs or S3 logs to allow logging for your build. The logs are where we see the output of the build, for instance, the output from Jest indicating all passing and failing tests.

  1. Create a new pipeline using CodePipeline

Create a pipeline using CodePipeline in the AWS Management Console. As shown in the screenshots below, name your pipeline, create a new service role, specify the source as your Git repository, and configure the CodeBuild project created in step 3 as the build stage action. Once completed, a source stage will pull the code into the pipeline and build stage, where the application is built and tested. We will skip the deploy stage in this tutorial, but this is where you would put your application on a host to make it accessible to users.

  1. Trigger the pipeline

Trigger the CodePipeline to start the build and test process. Either manually trigger the pipeline to see it in action or configure it to trigger on every code commit or other events automatically.

  1. Monitor the results

Monitor the CodePipeline for the build and test results. If any test fails then the pipeline will fail, which prevents you from releasing potentially buggy code. To view CodePipeline logs, click on your build project and navigate to the build logs tab. You should see something similar to the following Jest output. It details the results of all test suites, individual tests, and snapshots run along with the time it took to complete towards the end of your logs.

Coupling AWS’s offerings with Jest makes for an efficient and powerful solution to start running automated tests on your application. Jest’s lightweight nature, user-friendly API, comprehensive documentation, and impressive speed and efficiency, demonstrated by real-world examples like Airbnb's significant reduction in test run time, makes it the go-to framework for automating Javascript tests. The ease of configuration, management, and monitoring provided by AWS CodePipeline and AWS CodeBuild CI/CD solutions makes automating your Jest tests a walk in the park.

As we discussed, automated testing can be vital for the success of your business. Now you know how simple it is to set up automated testing to improve and safeguard your business. If you don’t already have automated testing set up for your Javascript or React application, give it a try. If you get stuck or want to avoid dealing with implementation, give Caylent a call! Our brilliant engineers can tackle this and anything else you throw our way.

Cloud Native App Dev
Infrastructure & DevOps Modernization
Cloud Technology
Tristan Weeden

Tristan Weeden

Tristan is a Senior Cloud Software Engineer at Caylent, helping customers build the most performant user-centric cloud-native applications on AWS. Tristan grew up in Milwaukee, Wisconsin, and graduated from Milwaukee Area Technical College. He holds both AWS Solutions Architect Associate and AWS Certified Developer Associate certifications. When he isn’t developing top-tier applications for our customers, he enjoys traveling, tinkering with cars, getting outside with his dog, and his freshwater aquariums.

View Tristan's articles

Related Services

Caylent Services

Cloud Native App Dev

Deliver high-quality, scalable, cloud native, and user-friendly applications that allow you to focus on your business needs and deliver value to your end users faster.

Caylent Services

AWS Foundations & Migrations

From rehosting to replatforming to rearchitecting, Caylent will help you leverage AWS to its fullest potential to meet your business objectives.

Accelerate your cloud native journey

Leveraging our deep experience and patterns

Get in touch

Related Blog Posts

Optimizing Media Management on Amazon S3

Learn how we helped a media company optimize the management of their video assets on Amazon S3.

Infrastructure & DevOps Modernization

Optimizing AWS Data Pipelines for Compliance in Digital Advertising

Learn how we helped an advertising customer setup automated, cost-effective pipelines to ensure compliance for sensitive data in their existing processes.

Infrastructure & DevOps Modernization

re:Invent 2023 AI/ML Session Summaries

Get up to speed on all the GenAI, AI, and ML focused 300 and 400 level sessions from re:Invent 2023!

Cloud Technology
Artificial Intelligence & MLOps