Commit 15cd074f authored by Daniel Shumway's avatar Daniel Shumway

initial commit with dependencies

parents
image: node
before_script:
- npm install
test:
script:
- npm test
\ No newline at end of file
node_modules/*
\ No newline at end of file
This diff is collapsed.
{
"_from": "@latinfor/distilled",
"_id": "@latinfor/distilled@1.0.4",
"_inBundle": false,
"_integrity": "sha512-Q+g1KbnPiewSx4BFC3PYqvaMn9Hd+RwKU71yTTGh2LPZRqHVa+6GboZwsZSKB3WNCgXoZC9IspMEMIOTsFisfQ==",
"_location": "/@latinfor/distilled",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "@latinfor/distilled",
"name": "@latinfor/distilled",
"escapedName": "@latinfor%2fdistilled",
"scope": "@latinfor",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/@latinfor/distilled/-/distilled-1.0.4.tgz",
"_shasum": "316d77dbf6dedf91a3423d1190bd175a2a5f5e1b",
"_spec": "@latinfor/distilled",
"_where": "/media/danshumway/files/Code/site",
"author": {
"name": "danShumway"
},
"bugs": {
"url": "https://gitlab.com/distilled/distilled/issues"
},
"bundleDependencies": false,
"dependencies": {
"distilled-reporters-checklist": "0.0.1"
},
"deprecated": false,
"description": "An aggressively elegant testing framework, inspired by ideals of simplicity, flexibility, and consistency",
"devDependencies": {
"tape": "^4.6.3"
},
"homepage": "https://gitlab.com/distilled/distilled#README",
"keywords": [
"unit",
"test",
"distilled",
"carbination",
"mineral"
],
"license": "MIT",
"main": "src/node_modules/Distilled.js",
"name": "@latinfor/distilled",
"repository": {
"type": "git",
"url": "git+ssh://git@gitlab.com/distilled/distilled.git"
},
"scripts": {
"test": "node src/tests/distilled.js && node src/tests/tape.js"
},
"version": "1.0.4"
}
var STATUS = require('constants/status');
var MESSAGES = require('constants/messages').en;
var REPORTERS = Object.freeze({
dot : require('reporters/dot'),
checklist : require('distilled-reporters-checklist'),
});
(function () {
if (!Promise) {
console.log(MESSAGES.promiseMissing());
}
});
var uniqueId = (function (i) {
return function () { return Math.random() + '' + (++i); };
}(0));
var Suite = (function () {
var PRIVATE = uniqueId();
function Suite(options) {
options = options || {};
var that = this;
var _that = this[PRIVATE] = {
//---------------INTERNAL STATE---------------------------
assertion : options.assertion || Promise.resolve(),
suite : null,
finally : null,
//-----------------USER OPTIONS----------------------------
attachPostResolve : !!options.attachPostResolve, //Can you call `test` on a suite that's already finished?
reporter : options.reporter, //Default `then` that fires off after every other `then` is done.
//---------USER-FACING INFORMATION-------------------------
parent : options.parent || null,
children : [],
label : options.label || null,
status : STATUS.PENDING,
error : null,
//-----------------MISC (should be kept small)--------------
callbacks : [], //List of callbacks attached to `then`
};
_that[PRIVATE] = _that;
/* Chain result place so status will always be set on resolution. */
_that.assertion = _that.assertion.then(function () {
_that.status = STATUS.PASSED;
}, function (error) {
if (_that.status !== STATUS.SKIPPED) {
_that.status = STATUS.FAILED;
_that.error = error;
}
return Promise.reject(error);
});
/* Resolve suites once all children have finished. */
_that.suite = new Promise(function (resolve) {
/* When the assertion finishes, check children. */
_that.assertion.then(checkSuite, checkSuite);
function checkSuite(size) {
size = size || 0;
if (size === _that.children.length) {
resolve(); /* If no new children have been added, resolve */
return;
}
/* Otherwise repeat, including the new children */
var map = _that.children.map(function (child) {
var _child = child[PRIVATE];
return _child.finally;
});
Promise.all(map).then(checkSuite.bind(null, _that.children.length));
}
});
_that.finally = new Promise(function (resolve) {
/* When the suite finishes, check callbacks. */
_that.suite.then(checkFinally, checkFinally);
function checkFinally(size) {
size = size || 0;
if (size === _that.callbacks.length) {
resolve(); /* If no new callbacks have been added, resolve */
return;
}
/* Otherwise repeat, including the new callbacks */
Promise.all(_that.callbacks).then(checkFinally.bind(null, _that.callbacks.length));
}
});
/* Errors are handled elsewhere, so blindly catch any remaining assertion failures */
_that.assertion.catch(function () {});
//Make sure suite resolves correctly.
that.then(function () {}); // @huh: Is this still necessary? You should make `finally` resolve cleaner.
/* And attach reporter */
_that.finally.then(function () {
_that.reporter.call(that, that);
});
}
Suite.prototype = {
constructor : Suite,
get error() { return this[PRIVATE].error; },
get status() { return this[PRIVATE].status; },
get label() { return this[PRIVATE].label; },
get parent() { return this[PRIVATE].parent; },
get children() {
//Wrapper to prevent tampering with the array
return Object.create(this[PRIVATE].children);
},
get STATUS () { return STATUS },
get REPORTERS () { return REPORTERS },
get MESSAGES () { return MESSAGES },
assert : function (assertion) {
var that = this;
var _that = this[PRIVATE];
return (function promisify (assertion) {
if (assertion == null) {
return Promise.resolve();
}
if (assertion instanceof Promise) {
return assertion.then(function (resolution) {
return promisify(resolution);
});
}
if (typeof assertion === 'function') {
//For the API to be completely, 100% consistent, allow recursion.
return Promise.resolve().then(function () {
return promisify(assertion.call(that, that));
});
}
return assertion ? Promise.resolve() : Promise.reject();
}(assertion));
},
test : function (label, assertion) {
var that = this;
var _that = this[PRIVATE];
/*
* Prevent the user from attaching new tests after a suite has resolved.
*
* A suite is considered "finished" if:
* - it isn't pending
* - it has no unresolved `then` calls
* - the user hasn't turned off the "finished" state
*/
if(!_that.status === STATUS.PENDING &&
!_that.pendingCallbacks &&
!_that.attachPostResolve) {
assertion = Promise.reject(new Error(MESSAGES.attachPostResolve));
}
/*
* Be careful to use the attached constructor. This makes it easier to write extensions.
*/
var test = Object.create(that.constructor.prototype);
Suite.call(test, {
label : label,
parent : that,
reporter : _that.reporter, //@huh: Still not sure what the best way is to handle this.
attachPostResolve : _that.attachPostResolve,
assertion : _that.assertion.then(function () {
return test.assert(assertion);
}, function (error) {
test[PRIVATE].status = STATUS.SKIPPED; //@huh: possibly an encapsulation violation here.
throw error;
})
});
_that.children.push(test); // basic attachment
return test;
},
then : function (callback) {
var that = this,
_that = this[PRIVATE];
//For now (?) allow passing in blank callbacks.
callback = callback || function () {};
callback = callback.bind(that, that);
//Polyfill while waiting for https://github.com/nodejs/node/pull/8217
var promise = _that.suite.then(callback, callback).catch(function (err) {
console.log(MESSAGES.callbackError, err);
//TODO: should this break?
});
_that.callbacks.push(promise);
return that;
},
};
return Suite;
}());
function Distilled(reporter, options) {
options = options || {};
Suite.call(this, {
label : null,
assertion : null,
parent : null,
attachPostResolve : options.attachPostResolve,
reporter : reporter || REPORTERS.checklist,
});
}
Distilled.prototype = Suite.prototype;
Distilled.prototype.constructor = Suite;
Distilled.STATUS = STATUS;
Distilled.REPORTERS = REPORTERS;
Distilled.MESSAGES = MESSAGES;
Distilled.prototype.STATUS = STATUS;
Distilled.prototype.REPORTERS = REPORTERS;
Distilled.prototype.MESSAGES = MESSAGES;
module.exports = Distilled;
module.exports = {
en : {
attachPostResolve: function () {
return [
"Test attached after the suite has already finished. Usually, this is a mistake.",
"Set `options.attachPostResolve` if you really know what you're doing."
].join("\n");
},
callbackError: function () {
return ["Uncaught error in suite callback:", ""].join("\n");
},
promiseMissing : function () {
return [
"Distilled relies on Promise support or an equivalent polyfill: ",
"Expect to see a LOT of errors soon!"
].join("");
}
}
};
module.exports = Object.freeze({
PASSED : 'passed',
FAILED : 'failed',
PENDING : 'pending',
SKIPPED : 'skipped'
});
var STATUS = require('constants/status');
module.exports = (function () {
var buffer = '';
var log = function (message) {
if (process && process.stdout) {
process.stdout.write(message);
} else if (console.clear) {
buffer = buffer + message;
console.clear();
console.log(buffer);
} else {
console.log(message);
}
};
var failPath = function(suite) {
if (suite.parent == null) {
return suite.label ? '(' + suite.label + ')' : '';
}
return failPath(suite.parent) + '(' + suite.label + ')';
};
var passed = true;
return function (suite) {
if (suite.status === STATUS.PASSED) {
log('.');
} else if (suite.status === STATUS.FAILED) {
log('X');
log('\n\n' + failPath(suite) + ' failed!');
if(suite.error) {
if (typeof suite.error.expected !== 'undefined') {
log('\nExpected: ' + suite.error.expected);
log('\nActual: ' + suite.error.actual);
}
log('\n' + suite.error.stack);
}
log('\n\n');
if(process) {
process.exitCode = 1;
pass = false;
}
}
if (suite.parent == null) {
log('\nTests finished: ' +
(passed ? 'passed' : 'failed') + '\n');
}
};
}());
console.log('Distilled self-test: ');
require('./distilled/test.js');
require('./distilled/then.js');
require('./distilled/callback.js');
require('./distilled/assertions.js');
var Distilled = require('Distilled');
var show = require('../helpers/show.js');
show('The `assert` method: ', function (console) {
var suite = new Distilled(function () {});
console.log('Tests/suites expose an `assert` method: ', typeof suite.assert === 'function');
console.log('Calling assert returns a promise: ', suite.assert() instanceof Promise);
});
show('Basic assertion types: ', function (console) {
var suite = new Distilled(function () {});
suite.assert(null).then(function () {
console.log('Asserting `null` passes.');
});
suite.assert(undefined).then(function () {
console.log('Asserting `undefined` passes.');
});
suite.assert(true).then(function () {
console.log('Asserting `true` passes.');
});
suite.assert(false).catch(function () {
console.log('Asserting `false` fails.');
});
});
show('Recursion using functions: ', function (console) {
var suite = new Distilled(function () {});
suite.assert(function () {
console.log('functions passed into assert are called.');
}).then(function () {
console.log('Because the function returned `undefined`, the assertion passed.');
});
suite.assert(function () {
return false;
}).catch(function () {
console.log('Because the function returned `false`, it failed.');
});
var err = new Error('An exception!');
suite.assert(function () {
throw err;
}).catch(function (result) {
console.log('If an exception is thrown, it gets intercepted as a failure: ', result === err);
});
suite.assert(function (test) {
console.log('Assertion context is passed into functions: ', test === suite);
console.log('Assertion context is set on `this`: ', this === suite);
});
});
show('Recursion using promises: ', function (console) {
var suite = new Distilled(function () {});
suite.assert(Promise.resolve()).then(function () {
console.log('Because the promise resolved to `undefined`, the assertion passed.');
});
suite.assert(Promise.reject()).catch(function () {
console.log('Because the promise was rejected, the assertion failed.');
});
suite.assert(Promise.resolve(false)).catch(function () {
console.log('Because the promise resolved to `false` the assertion failed.');
});
});
show('Advanced recursion: ', function (console) {
var suite = new Distilled(function () {});
suite.assert(function () {
return Promise.resolve(function () {
return Promise.resolve(function (test) {
console.log('Promises and functions can be infinitely nested.');
console.log('Nested functions still have the correct context.', test === suite && this === suite);
return Promise.resolve(false);
});
});
}).catch(function () {
console.log('Because the nested promises and functions eventually returned false, the test failed.');
});
suite.assert(function () {
return function () {
return function () {
return Promise.resolve(
Promise.resolve(function () {
return Promise.resolve(function () {
console.log('Promises can be nested in promises and functions in functions.');
});
})
);
};
};
}).then(function () {
console.log('Because the assertion eventually resolved to `undefined`, it passed.');
});
});
show('Bug #9: ', function (console) {
var suite = new Distilled(function () {});
var error = new Error('error');
suite.assert(function () {
return Promise.resolve(function () {
throw error;
});
}).catch(function (err) {
console.log('Exceptions from recursively called functions are still thrown: ', err === error);
});
});
var Distilled = require('Distilled');
var assert = require('assert');
var suite = Distilled.suite;
function deferred () {
var result = {};
result.promise = new Promise(function (res, rej) {
result.resolve = res;
result.reject = rej;
});
return result;
}
var Distilled = require('Distilled');
var show = require('../helpers/show.js');
/*
* CALLBACK TESTS
*-----------------------------------------------------------
*
* Whenever a test resolves, a callback is called:
* - this is primarily a place to do reporting and logging
* - it can also be adapted into a harness runner
* - it can also be used to extend Distilled and add new features
*
* You don't need to understand how Promises work to use Distilled:
* - but, if you do understand Promises, that will probably make you better
* - tests are executed as promises, and when they resolve, the callback is called
*/
show('The callback', function (console) {
var suite = new Distilled(function (test) {
console.log('Callback is passed the finished test/suite as a parameter:', test === suite);
console.log('`this` is set to the finished test/suite:', this === suite);
});
});
show('Callback on multiple/chained tests', function (console) {
var calls = [];
var suite = new Distilled(function (test) {
calls.push(test.label);
if (test === suite) {
console.log('All tests/suites called in the correct order:', '_a-_b-a-b-A-B-' === calls.join('-'));
}
});
suite.test('A').test('a').test('_a');
suite.test('B').test('b').test('_b');
});
show('Test status within callbacks', function (console) {
var suite = new Distilled(function (test) {
if (test === passed) {
console.log('Labels set correctly for passed tests:', test.label === 'passed');
console.log('`status` is set to `STATUS.PASSED`:', test.status === Distilled.STATUS.PASSED);
console.log('there is no error:', test.error == null);
}
if (test === failed) {
console.log('Labels set correctly for failed tests:', test.label === 'failed');
console.log('`status is set to `STATUS.FAILED`:', test.status === Distilled.STATUS.FAILED);
console.log('Error is set:', test.error === error);
}
});
var passed = suite.test('passed', true);
var error = new Error('error');
var failed = suite.test('failed', Promise.reject(error));
});
show('Skipped tests are logged (if already attached)', function (console) {
var suite = new Distilled(function (test) {
if (test === a) {
console.log('Status is set to `STATUS.SKIPPED`:', test.status === Distilled.STATUS.SKIPPED);
}
});
var A = suite.test('A', false),
a = A.test('a');
});
var Distilled = require('Distilled');
var show = require('../helpers/show.js');
show('The `test` method', function (console) {
var suite = new Distilled(function () {});
console.log('Tests/suites expose a `test` method: ', typeof suite.test === 'function');
var test = suite.test();
console.log('Calling `test` returns a new test/suite of the same type: ', Object.getPrototypeOf(test) === Object.getPrototypeOf(suite));
});
show('`test` is a wrapper around `assert`', function (console) {
function Extension () {
Distilled.apply(this, arguments);
}
Extension.prototype = Object.create(Distilled.prototype);
Extension.prototype.constructor = Extension;
var assertion = function () {};
Extension.prototype.assert = function (claim) {
console.log('tests are passed into the child assert', claim === assertion);
return Distilled.prototype.assert.apply(suite, arguments);
};
var suite = new Extension(function () {});
suite.test('', assertion);
});
show('Child tests are chained off of their parents', function (console) {
var suite = new Distilled(function () {});
var assertions = [];
suite.test('A', function () {
assertions.push('A');
}).test('a', function () {
assertions.push('a');
console.log('Parent tests are resolved before child assertions are called', this.parent.status === Distilled.STATUS.PASSED);
});
suite.test('B', function () {
assertions.push('B');
});
console.log('Tests are marked as unresolved before they are called', suite.status === Distilled.STATUS.PENDING);
suite.then(function () {
console.log('Tests are called in the correct order', assertions.join('-') === 'A-B-a');
});