Skip to content

Commit

Permalink
Added conditional resolver.
Browse files Browse the repository at this point in the history
  • Loading branch information
danielduarte committed Aug 30, 2019
1 parent b5e866e commit 9403b9b
Show file tree
Hide file tree
Showing 7 changed files with 237 additions and 9 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions src/engine/flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ export class Flow {
}

protected setExpectedResults(expectedResults: string[] = []) {

// Check expected results that cannot be fulfilled
const missingExpected = expectedResults.filter(r => !this.taskProvisions.includes(r));
if (missingExpected.length > 0) {
Expand Down Expand Up @@ -298,8 +297,10 @@ export class Flow {
this.runStatus.runningTasks.splice(this.runStatus.runningTasks.indexOf(task.getCode()), 1);

for (const resultName of taskProvisions) {
const result = taskResults[resultName];
this.supplyResult(resultName, result);
if (taskResults.hasOwnProperty(resultName)) {
const result = taskResults[resultName];
this.supplyResult(resultName, result);
}
}

const stopExecution = error && stopFlowExecutionOnError;
Expand Down
5 changes: 4 additions & 1 deletion src/engine/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,10 @@ export class Task {
const results: GenericValueMap = {};

for (const resolverResultName in this.spec.resolver.results) {
if (this.spec.resolver.results.hasOwnProperty(resolverResultName)) {
if (
this.spec.resolver.results.hasOwnProperty(resolverResultName) &&
resolverResults.hasOwnProperty(resolverResultName)
) {
const taskResultName = this.spec.resolver.results[resolverResultName];
// noinspection UnnecessaryLocalVariableJS
const resolverResult = resolverResults[resolverResultName];
Expand Down
6 changes: 6 additions & 0 deletions src/resolver-library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,10 @@ export class RepeaterResolver {
}
}

export class ConditionalResolver {
public async exec(params: GenericValueMap): Promise<GenericValueMap> {
return params.condition ? { onTrue: params.trueResult } : { onFalse: params.falseResult };
}
}

// @todo add ThrowErrorResolver
216 changes: 216 additions & 0 deletions test/resolver-library.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { expect } from 'chai';
import { debug as rawDebug } from 'debug';
import { GenericValueMap } from '../src';
import { FlowManager } from '../src/engine';
Expand Down Expand Up @@ -158,4 +159,219 @@ describe('the ResolverLibrary', () => {
},
);
});

it('runs conditional resolver', async () => {
class TrueTask {
public async exec(params: GenericValueMap): Promise<GenericValueMap> {
return { msg: `This is the TRUE branch: ${params.text}` };
}
}

class FalseTask {
public async exec(params: GenericValueMap): Promise<GenericValueMap> {
return { msg: `This is the FALSE branch: ${params.text}` };
}
}

const runFlow = async (testCondition: boolean) => {
return await FlowManager.run(
{
tasks: {
if: {
requires: ['condition', 'true-text', 'false-text'],
provides: ['on-true', 'on-false'],
resolver: {
name: 'if',
params: { condition: 'condition', trueResult: 'true-text', falseResult: 'false-text' },
results: { onTrue: 'on-true', onFalse: 'on-false' },
},
},
trueTask: {
requires: ['on-true'],
provides: ['true-msg'],
resolver: {
name: 'true',
params: { text: 'on-true' },
results: { msg: 'true-msg' },
},
},
falseTask: {
requires: ['on-false'],
provides: ['false-msg'],
resolver: {
name: 'false',
params: { text: 'on-false' },
results: { msg: 'false-msg' },
},
},
},
},
{
condition: testCondition,
'true-text': '(YES)',
'false-text': '(NO)',
},
['on-true', 'on-false', 'true-msg', 'false-msg'],
{
if: ResolverLibrary.ConditionalResolver,
true: TrueTask,
false: FalseTask,
},
);
};

const resultTrue = await runFlow(true);
expect(resultTrue).to.be.eql({
'on-true': '(YES)',
'true-msg': 'This is the TRUE branch: (YES)',
});

const resultFalse = await runFlow(false);
expect(resultFalse).to.be.eql({
'on-false': '(NO)',
'false-msg': 'This is the FALSE branch: (NO)',
});
});

it('runs conditional resolver with the same result name', async () => {
class TrueTask {
public async exec(params: GenericValueMap): Promise<GenericValueMap> {
return { msg: `This is the TRUE branch: ${params.text}` };
}
}

class FalseTask {
public async exec(params: GenericValueMap): Promise<GenericValueMap> {
return { msg: `This is the FALSE branch: ${params.text}` };
}
}

const runFlow = async (testCondition: boolean) => {
return await FlowManager.run(
{
tasks: {
if: {
requires: ['condition', 'true-text', 'false-text'],
provides: ['on-true', 'on-false'],
resolver: {
name: 'if',
params: { condition: 'condition', trueResult: 'true-text', falseResult: 'false-text' },
results: { onTrue: 'on-true', onFalse: 'on-false' },
},
},
trueTask: {
requires: ['on-true'],
provides: ['msg'],
resolver: {
name: 'true',
params: { text: 'on-true' },
results: { msg: 'msg' },
},
},
falseTask: {
requires: ['on-false'],
provides: ['msg'],
resolver: {
name: 'false',
params: { text: 'on-false' },
results: { msg: 'msg' },
},
},
},
},
{
condition: testCondition,
'true-text': '(YES)',
'false-text': '(NO)',
},
['msg'],
{
if: ResolverLibrary.ConditionalResolver,
true: TrueTask,
false: FalseTask,
},
);
};

const resultTrue = await runFlow(true);
expect(resultTrue).to.be.eql({
msg: 'This is the TRUE branch: (YES)',
});

const resultFalse = await runFlow(false);
expect(resultFalse).to.be.eql({
msg: 'This is the FALSE branch: (NO)',
});
});

it('runs conditional resolver with missing conditional results', async () => {
class TrueTask {
public async exec(params: GenericValueMap): Promise<GenericValueMap> {
return { msg: `This is the TRUE branch: ${params.text}` };
}
}

class FalseTask {
public async exec(params: GenericValueMap): Promise<GenericValueMap> {
return { msg: `This is the FALSE branch: ${params.text}` };
}
}

const runFlow = async (testCondition: boolean) => {
return await FlowManager.run(
{
tasks: {
if: {
requires: ['condition'],
provides: ['on-true', 'on-false'],
resolver: {
name: 'if',
params: { condition: 'condition', trueResult: 'true-text', falseResult: 'false-text' },
results: { onTrue: 'on-true', onFalse: 'on-false' },
},
},
trueTask: {
requires: ['on-true'],
provides: ['msg'],
resolver: {
name: 'true',
params: { text: 'on-true' },
results: { msg: 'msg' },
},
},
falseTask: {
requires: ['on-false'],
provides: ['msg'],
resolver: {
name: 'false',
params: { text: 'on-false' },
results: { msg: 'msg' },
},
},
},
},
{
condition: testCondition,
},
['msg'],
{
if: ResolverLibrary.ConditionalResolver,
true: TrueTask,
false: FalseTask,
},
);
};

const resultTrue = await runFlow(true);
expect(resultTrue).to.be.eql({
msg: 'This is the TRUE branch: undefined',
});

const resultFalse = await runFlow(false);
expect(resultFalse).to.be.eql({
msg: 'This is the FALSE branch: undefined',
});
});
});

// @todo add test to check error thrown on non resolver set in flow spec (check src/engine/flow.ts method startReadyTasks around line 190)
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"pretty": true,
"removeComments": true,
"resolveJsonModule": true,
"noUnusedLocals": true
"noUnusedLocals": true,
"sourceMap": true
},
"include": ["src"],
"exclude": ["node_modules"]
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"pretty": true,
"removeComments": true,
"resolveJsonModule": true,
"noUnusedLocals": true
"noUnusedLocals": true,
"sourceMap": true
},
"include": ["test"],
"exclude": ["node_modules"]
Expand Down

0 comments on commit 9403b9b

Please sign in to comment.