getting started
Distilled is one of the nicest, friendliest testing libraries that you will ever use, so getting up to speed is pretty quick. If at any point you think of an experiment you'd like to try out, all of the code examples below are editable.
Running Distilled is easy. Create a new instance, and then just start adding tests. You can create as many instances of Distilled as you'd like, anywhere in your project.
var suite = new Distilled();suite.test('An introduction to Distilled');When I'm starting out a new project, I like to add my tests to the same file as my prototype code. Then once I have a better grasp of how my code will be structured, I'll copy and paste my tests into another, more permanent file.
Writing Tests
The test method is how you add tests to a suite.
var suite = new Distilled();suite.test('There\'s only one method you need to remember', function () { this.test('And you\'ll quickly find', function () { this.test('it\'s') .test('super') .test('flexible'); }); this.test('!!!', true);});Tests in Distilled are hierarchical. This means that you can infinitely nest or chain tests as much as you want. Use tests to organize your tests!
Child tests will only be executed if their parents pass. This speeds up you testing suite by allowing you to abort tests early if a piece of setup or a pre-test fails.
Testing Harnesses
Distilled's API is designed to be simple and transparent. Just from the above code, you may already have some idea of how you could set up a dead-simple, custom testing harness for your next project.
xxxxxxxxxxvar suite = new Distilled();/* Exposing a singleton is a quick way to share suites between files. Your * existing test framework is probably already doing something similar, just * behind the scenes where you can't see it. */Distilled.suite = suite;/* Adapt imports to whatever environment you're using (node, webpack, browser, etc...) */overviewTests();regressions();/* ------- In Separate Files ------ */function overviewTests() { var suite = Distilled.suite || new Distilled(); suite = suite.test('Overview Tests'); /* continue adding actual tests. */}/* --------- In Separate Files ------*/function regressions() {For a fun challenge, try extending the above code so that you can conditionally run only certain parts of your test suite based on a flag or config setting.
The above example illustrates one of Distilled's important, underlying philosophies: testing harnesses and runners are easy to reason about if their underlying logic isn't obscured. In fact, becoming comfortable thinking about your tests this way opens the door for you to build creative things and to adapt Distilled to each project's unique testing needs.
Check out the full documentation for when and how tests are executed!
How Tests Pass or Fail
Of course, the test method isn't just for organization. It also runs
tests.
xxxxxxxxxxvar suite = new Distilled();suite.test('Passing', true);suite.test('and');suite.test('failing', false);suite.test('tests', Promise.resolve());suite.test('is', Promise.reject());suite.test('just', function () { });suite.test('as', function () { return false; });suite.test('flexible', function () { return true; });suite.test('as', function () { return Promise.reject(); });suite.test('organizing', function () { return Promise.resolve(); });suite.test('them', function () { throw new Error('Danger, Will Robinson!');});Distilled is designed to accept a wide variety of assertion formats because different APIs call for different testing styles. In keeping with the theme of simplicity and extensibility, this also makes it easy to build new helper methods and wrappers around Distilled.
Because Distilled listens for standard exceptions inside of its test methods, it's also compatible out-of-the-box with most modern assertion libraries.
xxxxxxxxxx/* Disable the reporter for cleaner logging. Don't worry, we'll get to * building custom reporters in just a minute. */var suite = new Distilled(function () {});var order = '';suite.test('asynchronous test', function () { order += 'B'; console.log('I\'m called second: ', order === 'AB');});order += 'A';console.log('I\'m called first: ', order === 'A');Tests in Distilled are always executed asynchronously. Period.
This is a decision made with experts in mind. Most well-written Javascript code is asynchronous. Therefore, Distilled is optimized for asynchronous code first and foremost.
A lot of work has gone into making sure that Distilled tests act like native Promises and resolve consistently with the native Promise chaining behavior that you're already used to. If you like using Promises and Async functions, Distilled is one of the nicest coding environments out there. No more jumping through hoops just to write clean async unit tests!
Because Distilled is focused on being as flexible as possible, tests can also be
nested by chaining, via a parameter (handy for arrow functions), or
through the this keyword.
xxxxxxxxxxvar suite = new Distilled(function () {});var child = suite.test('', function (me) { console.log('`this` and `me` both point at the currently executing test: ', me === this); console.log('`me` and the returned value both point at the same test: ', me === child);});Another trick that you'll quickly learn to love is recursively resolving assertions in your tests.
xxxxxxxxxxvar suite = new Distilled();suite.test('foo', function () { return new Promise(function (res) { setTimeout(function () { res(function () { console.log('I get called'); return true; //And the test passes. }); }, 100); });});Recursively resolving assertions are the power-user feature that you never knew you wanted. They make it even easier to extend Distilled on-the-fly in powerful ways.
If you want to dig deeper into how Distilled resolves tests,
check out the documentation for assert.
If you're ready to start extending Distilled and adding your own custom
features, check out the documentation for then. This will allow you to
run custom logic whenever a test finishes.
Custom Test Reporters
Distilled makes it easy to build custom test reporters. Distilled can be extended to stream test results as they finish, to pipe results across network requests, or to set up new criteria for whether or not a suite can be considered passed.
xxxxxxxxxxvar results = [];var suite = new Distilled(function (result) { var label = result.label || 'Suite'; results.push(label + '-' + result.status); /* Possible statuses are attached to the Distilled constructor for easier reference. */ if (result.status === Distilled.STATUS.FAILED) { console.log('Test failed: ', result.error.message === 'B failed!'); } /* The root suite has no label. When it's called, the test suite is finished. */ if (result.label == null) { var expected = 'C-passed, B-failed, A-passed, Suite-passed'; var actual = results.join(', '); console.log('Test suite finished: ', expected === actual); }});suite.test('A').test('B', Promise.reject(new Error('B failed!')));suite.test('C');A reporter is a function that you pass into Distilled at initialization. Distilled's reporter will get called once per-test.
If you're curious about learning more about how to make your own reporters, take a look at the documentation.
Summing up
And that's it! You're now equipped to start using Distilled in your own projects.
xxxxxxxxxxfunction fibonacci (index) { if (index <=1) return 1; return fibonacci(index - 1) + fibonacci(index - 2);}var suite = new Distilled();suite.test('fibonacci', function () { this.test('0', fibonacci(0) === 1); this.test('1', fibonacci(1) === 1); this.test('2', fibonacci(2) === 2); this.test('3', fibonacci(3) === 3); this.test('5', fibonacci(5) === 8); this.test('Error handling', function () { this.test('-1', fibonacci(-1) === -1); });});