DEV Community

Cover image for Generate All Possible Combinations in JavaScript Using Combinate
Nick Scialli (he/him)
Nick Scialli (he/him)

Posted on • Originally published at typeofnan.dev

Generate All Possible Combinations in JavaScript Using Combinate

Please give this post a πŸ’“, πŸ¦„, or πŸ”– if it you found it interesting!

One challenge we often face when creating apps is combinatoric complexity. Today, we're going to use a handy helper npm package I created to list all possible permutations of variables we're interested in. This can be especially handy for generating tests for every possible data scenario!

The Problem

Let's say we have an app that has has some user-set color value, a variable that indicates whether the user is an admin, and a light or dark theme mode.

The following represents the possible values for each variable:

color = "red" | "blue" | "green"
admin = true | false
mode = "light" | "dark"
Enter fullscreen mode Exit fullscreen mode

This assumes our possible values for color are "red", "blue", or "green", our possible values for admin are true or false, and our possible values for mode are "light" and "dark".

We'd like to test our app using each possible combination of these variables. In this case, there are 3 x 2 x 2 = 12 combinations. We could write out all these test cases individually, but that would be a pain. Also, in a real application, you would likely end up with many more than 12 combinations.

Using Combinate

Let's solve this problem with the combinate package I created!

First, let's get combinate install. We can do this with npm or yarn.

npm i combinate
Enter fullscreen mode Exit fullscreen mode

or

yarn add combinate
Enter fullscreen mode Exit fullscreen mode

Next, let's create an object that represents all the possible options for each variable:

const options = {
  color: ["red", "blue", "green"],
  admin: [true, false],
  mode:  ["light", "dark"],
}
Enter fullscreen mode Exit fullscreen mode

Finally, we just have to pass this to our combinate function, and we'll get an array of all of the possible combinations! let's see it in action.

import combinate from "combinate";

const options = {
  color: ["red", "blue", "green"],
  admin: [true, false],
  mode:  ["light", "dark"],
}

const combinations = combinate(options);

console.log(combinations);

/*
[
  {"admin": true, "color": "red", "mode": "light"},
  {"admin": true, "color": "blue", "mode": "light"},
  {"admin": true, "color": "green", "mode": "light"},
  {"admin": false, "color": "red", "mode": "light"},
  {"admin": false, "color": "blue", "mode": "light"},
  {"admin": false, "color": "green", "mode": "light"},
  {"admin": true, "color": "red", "mode": "dark"},
  {"admin": true, "color": "blue", "mode": "dark"},
  {"admin": true, "color": "green", "mode": "dark"},
  {"admin": false, "color": "red", "mode": "dark"},
  {"admin": false, "color": "blue", "mode": "dark"},
  {"admin": false, "color": "green", "mode": "dark"}
]
*/
Enter fullscreen mode Exit fullscreen mode

Using in a Test

Getting all combinations is great and all, but what's actual use case for doing this?

One way I've used this is frontend storyshot generation using a tool like Storybook. Using Storybook in conjunction with combinate, you can generate visual tests for every possible combination quickly.

A super barebones example, if you're familiar with Storybook, would look something like this:

// Get all combinations
const options = {
  color: ["red", "blue", "green"],
  admin: [true, false],
  mode:  ["light", "dark"],
}
const combinations = combinate(options);

// Create main story section
const navbarStories = storiesOf('Navbar', module);

// Add a story for each combination
combinatons.forEach(({color, admin, mode}) => {
  navbarStories.add(`${color} - ${admin} - ${mode}`, () => (
    <Navbar color={color} admin={admin} mode={mode} />
  ));
})
Enter fullscreen mode Exit fullscreen mode

Conclusion

Hopefully this little utility saves you some time writing our different app state combinations for things like testing! Would love to hear what you think!

Top comments (7)

Collapse
 
bytebodger profile image
Adam Nathaniel Davis

A handy utility, but I would just point out that, depending upon the range of potential inputs/values, devs should think very carefully about whether they want to - or whether they even should - test all possible inputs. The theoretical, brute-force approach is to say, "I'll write the best code by testing ALL THE THINGS!!! But you can end up with unit tests that take 15 minutes to run on every save. And for most functions, it's sufficient to say, "There are a million possible combinations that can be input to this function, and once I see that a few hundred combinations have passed, it's reasonable to assume that the function is sound."

Collapse
 
farzadbagheri profile image
farzadbagheri

Problem cases like this make me think, how often should I resort to a module and how often should I just write a function myself? Cool example though

Collapse
 
nas5w profile image
Nick Scialli (he/him) • Edited

Yeah, you’re absolutely right. It’s just something that I’ve written so often for different projects I figured I’d wrap it up as an npm package. There’s some level or DRYness to able to just import something like this rather than rolling the function for each project.

Collapse
 
dieguezz profile image
Diego Segura

I like it a lot, this is something i had already thought of but never implemented, because as some comments say, i thought it might be a bit overkill. Anyway, i think there are cool use cases (specially for testing) where might be very useful. Used wisely :)

Collapse
 
nas5w profile image
Nick Scialli (he/him)

I do some machine learning engineering too and got my idea from grid search. I assume anyone using ML in JS could use this for parameter turning

Collapse
 
kloshar4o profile image
Alexandr Plesca • Edited

Ok, that was kinda dumb :D I was working on the same solution, creating combination indexes by calculating all possible outcomes via rowLenght to the power of columnLenght and just after being so close I found this post :D

The only difference that I had is using different data structure:

const values = [
  { key: 'color', values: ['red', 'blue', 'green'] },
  { key: 'admin', values: [true, false] },
  { key: 'mode', values: ['light', 'dark'] },
];
Enter fullscreen mode Exit fullscreen mode

Instead of:

const values = {
  color: ["red", "blue", "green"],
  admin: [true, false],
  mode: ["light", "dark"],
};
Enter fullscreen mode Exit fullscreen mode

Great tool! Thank you for sharing! πŸ™

Collapse
 
briancodes profile image
Brian

This is really cool πŸ‘