acdc
Version:
JavaScript object transformation
353 lines (329 loc) • 14.7 kB
JavaScript
/* eslint-disable no-undef */
var assert = require('assert')
var acdc = require('..')
var flow = require('../lib/tasks/flow')
var property = require('../lib/tasks/property')
var string = require('../lib/tasks/string')
var logic = require('../lib/tasks/logic')
var collection = require('../lib/tasks/collection')
var dsl = require('../lib/dsl')
var async = require('async')
describe('AC/DC', function() {
[flow.run, flow.domain].forEach(function(runner) {
describe(runner.fn.name, function() {
it('should execute a task', function(done) {
var executed = false
acdc(runner).run(function(dsl, cb) {
cb({
task: {
fn: function dummy(input, ctx, cb) {
executed = true
cb()
}
}
})
}).done(function(err) {
assert.ifError(err)
assert.ok(executed)
done()
})
})
it('should yield a result', function(done) {
acdc(runner).run(function(dsl, cb) {
cb({
task: {
fn: function dummy(input, ctx, cb) {
cb(null, 123)
}
}
})
}).done(function(err, result) {
assert.ifError(err)
assert.equal(result, 123)
done()
})
})
it('should yield errors', function(done) {
acdc(runner).run(function(dsl, cb) {
cb({
task: {
fn: function dummy(input, ctx, cb) {
cb(new Error('nothing to see here'))
}
}
})
}).done(function(err, result) {
assert.ok(err)
assert.equal(err.message, 'nothing to see here')
done()
})
})
it('should support complex conversion flows', function(done) {
acdc(runner).run(function(dsl, cb) {
cb({
task: flow.sequence,
params: {
tasks: [
{
task: flow.output,
params: {
value: { a: 'x', b: 'y' }
}
},
{
task: flow.fork,
params: {
tasks: {
a: {
task: property.get,
params: {
path: 'a'
}
},
b: {
task: property.get,
params: {
path: 'b'
}
}
}
}
},
{
task: {
fn: function slash(input, ctx, cb) {
cb(null, input.a + '/' + input.b)
}
}
},
{
task: logic.choose,
params: {
options: [
{
task: logic.when,
params: {
condition: {
task: logic.eq,
params: {
value: 'does not match'
}
},
task: {
task: {
fn: function err(input, ctx, cb) {
cb(new Error('wrong condition'))
}
}
}
}
},
{
task: logic.when,
params: {
condition: {
task: logic.eq,
params: {
value: 'x/y'
}
},
task: {
task: {
fn: function err(input, ctx, cb) {
cb(null, 'oh yeah!')
}
}
}
}
}
]
}
}
]
}
})
}).done(function(err, result) {
assert.ifError(err)
assert.equal(result, 'oh yeah!')
done()
})
})
it('should support shorthand syntax', function(done) {
acdc(runner)
.bind(flow).alias({ seq: 'sequence' })
.bind(dsl)
.bind(property)
.bind(string)
.bind(logic)
.run(function(dsl, cb) {
with (dsl) {
cb(seq([
output({ a: 'x', b: 'y' }),
fork({
a: get('a'),
b: get('b')
}),
task(function slash(input, ctx, cb) {
cb(null, input.a + '/' + input.b)
}),
choose([
when(eq('y/x'), output('oh no!')),
when(eq('x/y'), output('oh yeah!'))
]),
set('z'),
copy('z', 'z2'),
transform('z2', uppercase(), 'Z2')
]))
}
})
.done(function(err, result) {
assert.ifError(err)
assert.equal(result.Z2, 'OH YEAH!')
assert.equal(typeof sequence, 'undefined')
assert.equal(typeof fork, 'undefined')
assert.equal(typeof get, 'undefined')
assert.equal(typeof set, 'undefined')
assert.equal(typeof copy, 'undefined')
assert.equal(typeof transform, 'undefined')
assert.equal(typeof task, 'undefined')
done()
})
})
it('should reject shorthand functions with too many arguments', function(done) {
try {
acdc(runner)
.run(function(dsl, cb) {
cb(flow.sequence(1, 2))
})
} catch(err) {
assert.equal(err.message, 'Task sequence has 2 arguments but only takes 1 parameters')
done()
}
})
it('should support aliased task functions', function(done) {
acdc(runner)
.bind(flow.sequence).alias('seq')
.run(function(dsl, cb) {
with (dsl) {
cb(seq([
]))
}
})
.done(done)
})
it('should reject duplicate task function aliases', function(done) {
try {
acdc(runner).bind(flow.sequence).alias('seq').alias('seq')
} catch(err) {
assert.ok(err)
assert.equal(err.message, 'seq has already been bound')
done()
}
})
it('should support aliased task objects', function(done) {
acdc(runner)
.bind(flow).alias({ seq: 'sequence' })
.run(function(dsl, cb) {
with (dsl) {
cb(seq([
]))
}
})
.done(done)
})
it('should reject duplicate task objects aliases', function(done) {
try {
acdc(runner).bind(flow).alias({ seq: 'sequence' }).alias({ seq: 'sequence' })
} catch(err) {
assert.ok(err)
assert.equal(err.message, 'seq has already been bound')
done()
}
})
it('should not cause maximum call stack size exceeded errors', function(done) {
this.timeout(60000)
var executed = 0
var items = []
for (var i = 0; i < 50000; i++) {
items.push(i)
}
acdc(runner)
.run(function(dsl, cb) {
cb(flow.sequence([
flow.output(items),
{
task: collection.map,
params: {
task: {
task: {
fn: function dummy(input, ctx, cb) {
executed++
cb()
}
}
}
}
}
]))
}).done(function(err) {
assert.ifError(err)
assert.equal(executed, 50000)
done()
})
})
if (runner === flow.domain) {
it('should yield thrown errors', function(done) {
acdc(flow.domain).run(function(dsl, cb) {
cb({
task: {
fn: function dummy(input, ctx, cb) {
throw new Error('nothing to see here')
}
}
})
}).done(function(err, result) {
assert.ok(err)
assert.equal(err.message, 'nothing to see here')
done()
})
})
it('should yield thrown errors in async code', function(done) {
acdc(flow.domain).run(function(dsl, cb) {
cb({
task: {
fn: function dummy(input, ctx, cb) {
setImmediate(function() {
throw new Error('nothing to see here')
})
}
}
})
}).done(function(err, result) {
assert.ok(err)
assert.equal(err.message, 'nothing to see here')
done()
})
})
it('should yield errors thrown from synchronous code wrapped by async', function(done) {
acdc(flow.domain).run(function(dsl, cb) {
cb({
task: {
fn: function dummy(input, ctx, cb) {
async.series([
function() {
throw new Error('nothing to see here')
}
])
}
}
})
}).done(function(err, result) {
assert.ok(err)
assert.equal(err.message, 'nothing to see here')
done()
})
})
}
})
})
})