123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- import t from 'tap';
- import {compositeFrom, continuationSymbol, input} from '#composite';
- import {isString} from '#validators';
- t.test(`compositeFrom: basic behavior`, t => {
- t.plan(2);
- const composite = compositeFrom({
- annotation: `myComposite`,
- compose: false,
- steps: [
- {
- dependencies: ['foo'],
- compute: (continuation, {foo}) =>
- continuation({'#bar': foo * 2}),
- },
- {
- dependencies: ['#bar', 'baz', 'suffix'],
- compute: ({'#bar': bar, baz, suffix}) =>
- baz.repeat(bar) + suffix,
- },
- ],
- });
- t.match(composite, {
- annotation: `myComposite`,
- flags: {expose: true, compose: false, update: false},
- expose: {
- dependencies: ['foo', 'baz', 'suffix'],
- compute: Function,
- transform: null,
- },
- update: null,
- });
- t.equal(
- composite.expose.compute({
- foo: 3,
- baz: 'ba',
- suffix: 'BOOM',
- }),
- 'babababababaBOOM');
- });
- t.test(`compositeFrom: input-shaped step dependencies`, t => {
- t.plan(2);
- const composite = compositeFrom({
- compose: false,
- steps: [
- {
- dependencies: [
- input.myself(),
- input.updateValue(),
- ],
- transform: (updateValue1, {
- [input.myself()]: me,
- [input.updateValue()]: updateValue2,
- }) => ({me, updateValue1, updateValue2}),
- },
- ],
- });
- t.match(composite, {
- expose: {
- dependencies: ['this'],
- transform: Function,
- compute: null,
- },
- });
- const myself = {foo: 'bar'};
- t.same(
- composite.expose.transform('banana', {
- this: myself,
- pomelo: 'delicious',
- }),
- {
- me: myself,
- updateValue1: 'banana',
- updateValue2: 'banana',
- });
- });
- t.test(`compositeFrom: dependencies from inputs`, t => {
- t.plan(3);
- const composite = compositeFrom({
- annotation: `myComposite`,
- compose: true,
- inputMapping: {
- foo: input('bar'),
- pomelo: input.value('delicious'),
- humorous: input.dependency('#mammal'),
- data: input.dependency('albumData'),
- ref: input.updateValue(),
- },
- inputDescriptions: {
- foo: input(),
- pomelo: input(),
- humorous: input(),
- data: input(),
- ref: input(),
- },
- steps: [
- {
- dependencies: [
- input('foo'),
- input('pomelo'),
- input('humorous'),
- input('data'),
- input('ref'),
- ],
- compute: (continuation, {
- [input('foo')]: foo,
- [input('pomelo')]: pomelo,
- [input('humorous')]: humorous,
- [input('data')]: data,
- [input('ref')]: ref,
- }) => continuation.exit({foo, pomelo, humorous, data, ref}),
- },
- ],
- });
- t.match(composite, {
- expose: {
- dependencies: [
- input('bar'),
- '#mammal',
- 'albumData',
- ],
- transform: Function,
- compute: null,
- },
- });
- const exitData = {};
- const continuation = {
- exit(value) {
- Object.assign(exitData, value);
- return continuationSymbol;
- },
- };
- t.equal(
- composite.expose.transform('album:bepis', continuation, {
- [input('bar')]: 'squid time',
- '#mammal': 'fox',
- 'albumData': ['album1', 'album2'],
- }),
- continuationSymbol);
- t.same(exitData, {
- foo: 'squid time',
- pomelo: 'delicious',
- humorous: 'fox',
- data: ['album1', 'album2'],
- ref: 'album:bepis',
- });
- });
- t.test(`compositeFrom: update from various sources`, t => {
- t.plan(3);
- const match = {
- flags: {update: true, expose: true, compose: false},
- update: {
- validate: isString,
- default: 'foo',
- },
- expose: {
- transform: Function,
- compute: null,
- },
- };
- t.test(`compositeFrom: update from composition description`, t => {
- t.plan(2);
- const composite = compositeFrom({
- compose: false,
- update: {
- validate: isString,
- default: 'foo',
- },
- steps: [
- {transform: (value, continuation) => continuation(value.repeat(2))},
- {transform: (value) => `Xx_${value}_xX`},
- ],
- });
- t.match(composite, match);
- t.equal(composite.expose.transform('foo'), `Xx_foofoo_xX`);
- });
- t.test(`compositeFrom: update from step dependencies`, t => {
- t.plan(2);
- const composite = compositeFrom({
- compose: false,
- steps: [
- {
- dependencies: [
- input.updateValue({
- validate: isString,
- default: 'foo',
- }),
- ],
- compute: ({
- [input.updateValue()]: value,
- }) => `Xx_${value.repeat(2)}_xX`,
- },
- ],
- });
- t.match(composite, match);
- t.equal(composite.expose.transform('foo'), 'Xx_foofoo_xX');
- });
- t.test(`compositeFrom: update from inputs`, t => {
- t.plan(3);
- const composite = compositeFrom({
- inputMapping: {
- myInput: input.updateValue({
- validate: isString,
- default: 'foo',
- }),
- },
- inputDescriptions: {
- myInput: input(),
- },
- steps: [
- {
- dependencies: [input('myInput')],
- compute: (continuation, {
- [input('myInput')]: value,
- }) => continuation({
- '#value': `Xx_${value.repeat(2)}_xX`,
- }),
- },
- {
- dependencies: ['#value'],
- transform: (_value, continuation, {'#value': value}) =>
- continuation(value),
- },
- ],
- });
- let continuationValue = null;
- const continuation = value => {
- continuationValue = value;
- return continuationSymbol;
- };
- t.match(composite, {
- ...match,
- flags: {update: true, expose: true, compose: true},
- });
- t.equal(
- composite.expose.transform('foo', continuation),
- continuationSymbol);
- t.equal(continuationValue, 'Xx_foofoo_xX');
- });
- });
- t.test(`compositeFrom: dynamic input validation from type`, t => {
- t.plan(2);
- const composite = compositeFrom({
- inputMapping: {
- string: input('string'),
- number: input('number'),
- boolean: input('boolean'),
- function: input('function'),
- object: input('object'),
- array: input('array'),
- },
- inputDescriptions: {
- string: input({null: true, type: 'string'}),
- number: input({null: true, type: 'number'}),
- boolean: input({null: true, type: 'boolean'}),
- function: input({null: true, type: 'function'}),
- object: input({null: true, type: 'object'}),
- array: input({null: true, type: 'array'}),
- },
- outputs: {'#result': '#result'},
- steps: [
- {compute: continuation => continuation({'#result': 'OK'})},
- ],
- });
- const notCalledSymbol = Symbol('continuation not called');
- let continuationValue;
- const continuation = value => {
- continuationValue = value;
- return continuationSymbol;
- };
- let thrownError;
- try {
- continuationValue = notCalledSymbol;
- thrownError = null;
- composite.expose.compute(continuation, {
- [input('string')]: 123,
- });
- } catch (error) {
- thrownError = error;
- }
- t.equal(continuationValue, notCalledSymbol);
- t.match(thrownError, {
- });
- });
|