Installation
Quick Take
Purpose
It’s used to generate an array of all possible combinations of options object boolean settings.
detergent has 12 boolean toggles — that’s 2^12 = 4096 variations to test for each input. This program generates those options variations.
string-collapse-white-space has 6 boolean toggles — that’s 2^6 = 64 variations to test for each input.
And so on.
API — mixer()
The main function mixer() is imported like this:
It’s a function which takes two input arguments:
| Input argument | Type | Description | 
|---|---|---|
refType: A plain object or something falsy  | ||
ref | A plain object or something falsy | Plain object with “pinned” values (each will reduce the generated combinations count by 1) | 
defaultsObjType: A plain object  | ||
defaultsObj | A plain object | Put the default options object here. | 
Function will return an array of zero or more plain objects.
By the way. The order of the arguments seems backward because typically you want to export a wrapper around the mixer(), with defaults set, so that you can save time and omit the second argument, defaults. See an example below, with import { mixer as testMixer } from "text-mixer";, then export const mixer = (ref) => testMixer(ref, opts);, then prepped mixer() is one-argument function, ready for use.
API — version
You can import version:
In practice
Let’s say, we test detergent. It has the following default options:
{
  fixBrokenEntities: true,
  removeWidows: true,
  convertEntities: true,
  convertDashes: true,
  convertApostrophes: true,
  replaceLineBreaks: true,
  removeLineBreaks: false,
  useXHTML: true,
  dontEncodeNonLatin: true,
  addMissingSpaces: true,
  convertDotsToEllipsis: true,
  stripHtml: true,
  eol: "lf",
  stripHtmlButIgnoreTags: ["b", "strong", "i", "em", "br", "sup"],
  stripHtmlAddNewLine: ["li", "/ul"],
  cb: null,
}
Imagine, we’re testing how detergent strips HTML, setting, opts.stripHtml.
// 😱 eleven other boolean opts settings were left out, 2^12 - 1 = 4095 other combinations!
import tap from "tap";
import { det } from "detergent";
tap.test(`01`, (t) => {
  t.equal(
    det(t, n, `text <a>text</a> text`, {
      stripHtml: true,
    }).res,
    "text text text"
  );
  t.end();
});
Here’s the proper way:
// ✅
import tap from "tap";
import { det, opts } from "detergent";
import { mixer as testMixer } from "text-mixer";
// we create a wrapper to skip writing the second input argument again and again
const mixer = (ref) => testMixer(ref, opts);
tap.test(`01`, (t) => {
  // 2^11 = 2048 variations:
  mixer({
    stripHtml: false, // <--- will be the same across all generated objects
  }).forEach((opt, n) => {
    t.equal(
      det(t, n, `text <a>text</a> text`, opt).res,
      `text <a>text</a> text`,
      JSON.stringify(opt, null, 4)
    );
  });
  // another 2^11 = 2048 variations:
  mixer({
    stripHtml: true,
  }).forEach((opt, n) => {
    t.equal(
      det(t, n, `text <a>text</a> text`, opt).res,
      `text text text`,
      JSON.stringify(opt, null, 4)
    );
  });
  t.end();
});