'use strict'; const Grafn = require('..'); const Tap = require('tap'); Tap.beforeEach((done, t) => { t.graph = new Grafn(); t.verticesRan = 0; done(); }); Tap.test(async (t) => { await t.rejects(t.graph.run('nonExisting'), 'It throws an error if you try to run a non-existing vertex'); }); Tap.test(async (t) => { t.graph.vertex({ name: 'root', action() { t.verticesRan++; } }); await t.graph.run('root'); t.equal(t.verticesRan, 1, 'It runs a vertex if no dependencies are defined'); }); Tap.test(async (t) => { t.graph.vertex({ name: 'unfulfilled', dependencies: ['nonExisting'], action() { t.verticesRan++; } }); await t.graph.run('unfulfilled'); t.equal(t.verticesRan, 0, 'It does not run a vertex if it has unfulfilled dependencies'); }); Tap.test(async (t) => { t.graph.vertex({ name: 'root', action() { } }); t.graph.vertex({ name: 'firstDependent', dependencies: ['root'], action() { t.verticesRan++; } }); t.graph.vertex({ name: 'secondDependent', dependencies: ['root'], action() { t.verticesRan += 2; } }); await t.graph.run('root'); t.equal(t.verticesRan, 3, 'It runs dependent vertices on completion of a vertex\'s action'); }); Tap.test(async (t) => { t.graph.vertex({ name: 'root', action() { } }); t.graph.vertex({ name: 'firstDependent', dependencies: ['root'], action() { return 1; } }); t.graph.vertex({ name: 'secondDependent', dependencies: ['root'], action() { return 2; } }); t.graph.vertex({ name: 'final', dependencies: ['firstDependent', 'secondDependent'], action(state) { t.verticesRan = state.firstDependent + state.secondDependent; } }); await t.graph.run('root'); t.equal(t.verticesRan, 3, 'It ensures dependencies state is available before running dependents'); }); Tap.test(async (t) => { t.graph.vertex({ name: 'root', action() { return 101; } }); t.graph.vertex({ name: 'stateDependent', dependencies: ['root'], action(state) { t.verticesRan = state.root; } }); await t.graph.run('root'); t.equal(t.verticesRan, 101, 'It gives dependent vertices a state including their dependencies\' results'); }); Tap.test(async (t) => { t.graph.vertex({ name: 'root', action() { throw new Error('Unexpected root problem'); } }); await t.rejects(t.graph.run('root'), 'It throws an error if a vertex throws an error'); }); Tap.test(async (t) => { t.graph.vertex({ name: 'root', action() { t.verticesRan++; return 1; } }); await t.graph.run('root'); await t.graph.run('root'); t.equal(t.verticesRan, 1, 'It runs a vertex only once'); }); Tap.test( (t) => { t.graph.vertex({ name: 'root', action() {} }); t.graph.vertex({ name: 'firstDependent', dependencies: ['root'], action() {} }); t.graph.vertex({ name: 'secondDependent', dependencies: ['root'], action() {} }); t.graph.vertex({ name: 'final', dependencies: ['firstDependent', 'secondDependent'], action() {} }); t.matchSnapshot(t.graph.toString(), 'It can convert to a string representing the graph in graphviz format'); t.end(); }); Tap.test('It colorizes the graph based on execution results', async (t) => { t.graph.vertex({ name: 'root', action() {} }); t.graph.vertex({ name: 'firstDependent', dependencies: ['root'], action() {} }); t.graph.vertex({ name: 'secondDependent', dependencies: ['root'], action() { throw new Error('Second dependent has failed'); } }); t.graph.vertex({ name: 'final', dependencies: ['firstDependent', 'secondDependent'], action() {} }); await t.rejects(t.graph.run('root'), 'It throws an error if a sub-step fails'); t.matchSnapshot(t.graph.toString(), 'It adds the right colors according to execution'); });