Building large scale JavaScript applications in a monorepo in an optimised way — Part 2

Veena Desai
5 min readJun 14, 2021

--

An image that says if we could get that unit test report that would be great!

Thank you for viewing this article. Do checkout the Part-1 of this post where I have articulated about what a monorepo is and how to optimise auth, install and build stages of the development lifecycle. In this article, I would like to share how to test the changes with respect to a single package/module in a monorepo and generate a single coverage report specific to modified package and upload to Codecov, a tool to compare coverage reports without resulting in erroneous coverage.

-> Unit tests and code coverage —Unit tests are a prerequisite for the Extreme Programming methodology. Extreme programming is essentially a “test-everything-that-can-possibly-break” strategy. It’s very useful to know at the active coding stage if a particular line will ever be executed or you if can remove it. Writing unit tests with this methodology makes development and code refactoring simpler & feature integrations easier.

If you are working on a JavaScript or TypeScript applications, chances are that you are already familiar with Jest, a JavaScript testing framework designed to ensure correctness of any JavaScript codebase. It allows you to write tests with an approachable, familiar and feature-rich API that gives you results quickly. It is well documented and focuses on simplicity. (You can get started here!)

Jest provides code coverage reports out of the box. If you have valid unit tests, you can have coverage metrics on hand right away with Jest coverage options.

If you tend to install Jest locally within your project as a dependency, the command to get coverage might look like this —

yarn jest --coverage

If you installed Jest globally, the below command should work —

jest --coverage

A picture with Jest coverage report

You can also get a detailed coverage report in HTML format using the below command —

yarn jest --coverage --config='{ "coverageReporters": ["html"] }'

All the above mentioned steps work great when you are running and testing your code locally. But in order to you ensure coverage on every commit, pull requests or deployment, we need to integrate tools to group, merge, archive and compare coverage reports.
Codecov gives us actionable coverage insights when and where we need them to ensure we are shipping quality code.

If you are working on a monorepo, every time you make a change you end up running all the test suites present in my monorepo, thus increasing the overall build time.
In order to optimise the build time at the unit testing and coverage stages, you can implement the below steps -

1) Run the test suite only for the modified package.
Jest provides --changedSince CLI option that allows you to run tests related to the changes since the provided branch or commit hash.

yarn jest --changedSince=master

You can also use --onlyChanged but only works if you’re running tests in a git/hg repository at the moment and requires a static dependency graph.

Note — If you are using Jest version < v26.0, then changedSince might not work as expected. Here is a bug fix by the jest community for the same.

2) Generate the coverage report only for the modified package.
One of the important feature that codecov provides is Flags and Carryforward flags to categorise reports in a single repository.

-> Flags allow you to isolate and categorise coverage reports for different tests and features in your project. Specifically, if you are employing a monorepo setup where you’d like to encapsulate each project’s test coverage independently, flags are a great way to do that. For example, consider a project say Monorepo X with multiple packages as shown below —

Monorepo X     
/component1
/component2
/component3
.
.

You can upload separate coverage reports and flag them per package in the monorepo. For example, in a CI run for the Monorepo X project, assume that coverage for component1is written to

tests/component1/output/coverage.xml

Then that report would be uploaded as follows:

bash <(curl https://codecov.io/bash) -t <token> -f tests/Component1/output/coverage.xml -F component1

Passing -F parameter indicates you want to upload the coverage report to Codecov. -f indicates Codecov to write to the path followed by it.

Note —

  1. Flags must be lowercase, alphanumeric, periods, or hyphens and not exceed 45 characters
  2. You will need to assign a flag to each coverage report uploaded. Do not use multiple flags on the same report. Instead, upload the report twice.
bash <(curl -s https://codecov.io/bash) -f tests/Component1/output/coverage.xml -F component1
bash <(curl -s https://codecov.io/bash) -f tests/Component2/output/coverage.xml -F component2

-> Carryforward Flags are best used for monorepos with multiple applications/languages and iterative/partial/delta testing setups, etc. If you do not test all of your repo code on each commit, Codecov uses a feature called Carryforward Flags to help only update coverage on tests that were run. Carryforward Flags is built on top of basic Flags. They can be used for any project that do not upload total coverage for every commit.

Here is how the carryforward flags work -

1. Carryforward flags works commit to commit.

2. If the carryforward flag is true, the coverage is pulled from previous commit report that exists. If there are no coverage reports uploaded earlier, a new reported is generated and uploaded to codecov the very first time.

Codecov carry forward flag example

3. Every time the coverage changes, a new report is generated and uploaded to Codecov as a reference for the future commits.

4. If the carryforward flag is false, no coverage is carry forwarded and the coverage report shows 0% coverage for the untested files.

Coverage  is not carry forwarded if the flag value is false.

By identifying the changed files and running the test suites for the modified projects in your monorepo, you can optimise the time taken by the testing stage in your build pipeline which in return reduces the overall build time.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Veena Desai
Veena Desai

Written by Veena Desai

Senior Software Engineer | Women's Network Bay Area Co-Chair @ Intuit. https://www.linkedin.com/in/veenadesai333/

No responses yet

Write a response