It's often desirable to get all combinations of an object's properties. One of the cases where I use this most is testing: I want to try a function of component with every permutation of data it might receive.
A Simple Example: React Navbar
Let's say we have a React navbar that takes the following props: name
, displayMode
, and timezone
. name
can either be a string or null
(if there's no logged-in user), displayMode
can be "dark"
or "light"
, and timezone
can be "ET"
, "CT"
, "MT"
, or "PT"
.
We would like to do snapshot testing of our navbar in each possible state. We could manually write out each state, but that ends up being 2 * 2 * 4 = 16 combinations. If we had even more props, this would get out of hand fast! Instead, let's write a quick script that produces all possible combinations:
const navBarProps = {
name: ["John Doe", null],
displayMode: ["dark", "light"],
timezone: ["ET", "CT", "MT", "PT"],
};
function allCombinations(obj) {
let combos = [{}];
Object.entries(obj).forEach(([key, values]) => {
let all = [];
values.forEach((value) => {
combos.forEach((combo) => {
all.push({ ...combo, [key]: value });
});
});
combos = all;
});
return combos;
}
console.log(allCombinations(navBarProps));
/*
[ { name: 'John Doe', displayMode: 'dark', timezone: 'ET' },
{ name: null, displayMode: 'dark', timezone: 'ET' },
{ name: 'John Doe', displayMode: 'light', timezone: 'ET' },
{ name: null, displayMode: 'light', timezone: 'ET' },
{ name: 'John Doe', displayMode: 'dark', timezone: 'CT' },
{ name: null, displayMode: 'dark', timezone: 'CT' },
{ name: 'John Doe', displayMode: 'light', timezone: 'CT' },
{ name: null, displayMode: 'light', timezone: 'CT' },
{ name: 'John Doe', displayMode: 'dark', timezone: 'MT' },
{ name: null, displayMode: 'dark', timezone: 'MT' },
{ name: 'John Doe', displayMode: 'light', timezone: 'MT' },
{ name: null, displayMode: 'light', timezone: 'MT' },
{ name: 'John Doe', displayMode: 'dark', timezone: 'PT' },
{ name: null, displayMode: 'dark', timezone: 'PT' },
{ name: 'John Doe', displayMode: 'light', timezone: 'PT' },
{ name: null, displayMode: 'light', timezone: 'PT' }
*/
And that's it! Now, if we wanted to generate some components based on these combinations, we can just loop over the array we created.
const tests = allCombinations(navBarProps).map(props => {
return <Navbar {...props} />;
});
Top comments (3)
At first I assumed it doing this requires a recursive-like algorithm, never thought of doing it that way!
Using
flatMap
, we can further reduce this down to 8 lines:ooo that's fancy!
or even shorter :
thanks for the inspiration :)