cypress-load-balancer
Cypress is an automation testing framework with great support for handling comprehensive tests against frontend applications. Before creating this plugin, I was tasked with speeding up component test pipelines executed on code checks. Cypress only offers load balancing as part of its paid Cypress Cloud suite, when wasn’t being used by the organization at that time. Therefore, I set out to build this as an open-source package as a way to contribute to the community, and also use across my own personal projects. I also wrote two articles originally posted on Dev.to:
- Load balancing Cypress tests without Cypress Cloud
- Optimizing a load balancing algorithm to minimize the runtime of a static process
A developer would add this to a Cypress configuration, add some parameters to their test script, and declare how many parallelized processes to use within a continuous delivery pipeline. At first, it employed a round-robin algorithm, which was good enough for component tests that take under 10 minutes to run when divided up. However, a round-robin approach isn’t optimized for a speedy total duration, since there can be big variations where the longest running job is the shortest possible time for the whole pipeline to run. Later that year, there was a new need to add it to an end-to-end test suite that could take multiple hours when not parallelized, and I learned fairly quickly a more efficient approach was needed.
Thus, I learned I needed to optimize for the shortest runtime possible when a given number of parallelized processes exist. After a lot of long nights with a notepad and various scribblings of napkin math algorithms, I found a way to balance all runners to be nearly equal in execution time, which is the best possible solution for this problem.
Key points of this plugin include multiple ways to customize this for a Cypress suite, as well as taking an object-oriented, class-based approach to writing it so it easy easier to mock inside of JavaScript unit test frameworks. JavaScript is not easy to mock due to oddities with module imports, so the code underneath is a little more structured like a legacy project with a lot of static methods. I’ve found it easy to understand whenever I return to work with the code.
Working on this was a rare journey. It was the most scientific project I’ve had to work on in a long while, so was particularly fun to optimize something with mathematics. It wasn’t until much later I learned that a separate plugin already existed, and I honestly borrowed the smallest bit from it (making sure pipelines don’t fail when there are empty test sets). In its second article I demonstrated that both plugins were equally efficient. I’m proud of the work put in here, and still recommend it to others since it has been a huge help.