UNPKG

noflo

Version:

Flow-Based Programming environment for JavaScript

388 lines (361 loc) 15.3 kB
if typeof process isnt 'undefined' and process.execPath and process.execPath.match /node|iojs/ chai = require 'chai' unless chai noflo = require '../src/lib/NoFlo.coffee' shippingLanguage = 'coffeescript' path = require 'path' root = path.resolve __dirname, '../' urlPrefix = './' else noflo = require 'noflo' shippingLanguage = 'javascript' root = 'noflo' urlPrefix = '/' class Split extends noflo.Component constructor: -> @inPorts = in: new noflo.Port @outPorts = out: new noflo.ArrayPort @inPorts.in.on 'connect', (data) => @outPorts.out.connect() @inPorts.in.on 'data', (data) => @outPorts.out.send data @inPorts.in.on 'disconnect', => @outPorts.out.disconnect() Split.getComponent = -> new Split Merge = -> inst = new noflo.Component inst.inPorts.add 'in', (event, payload, instance) -> method = event method = 'send' if event is 'data' instance.outPorts[method] 'out', payload inst.outPorts.add 'out' inst describe 'ComponentLoader with no external packages installed', -> l = new noflo.ComponentLoader root it 'should initially know of no components', -> chai.expect(l.components).to.be.null it 'should not initially be ready', -> chai.expect(l.ready).to.be.false it 'should not initially be processing', -> chai.expect(l.processing).to.be.false it 'should not have any packages in the checked list', -> chai.expect(l.checked).to.be.empty describe 'normalizing names', -> it 'should return simple module names as-is', -> normalized = l.getModulePrefix 'foo' chai.expect(normalized).to.equal 'foo' it 'should return empty for NoFlo core', -> normalized = l.getModulePrefix 'noflo' chai.expect(normalized).to.equal '' it 'should strip noflo-', -> normalized = l.getModulePrefix 'noflo-image' chai.expect(normalized).to.equal 'image' it 'should strip NPM scopes', -> normalized = l.getModulePrefix '@noflo/foo' chai.expect(normalized).to.equal 'foo' it 'should strip NPM scopes and noflo-', -> normalized = l.getModulePrefix '@noflo/noflo-image' chai.expect(normalized).to.equal 'image' it 'should be able to read a list of components', (done) -> @timeout 60 * 1000 ready = false l.once 'ready', -> ready = true chai.expect(l.ready, 'should have the ready bit').to.equal true l.listComponents (err, components) -> return done err if err chai.expect(l.processing, 'should have stopped processing').to.equal false chai.expect(l.components, 'should contain components').not.to.be.empty chai.expect(components, 'should have returned the full list').to.equal l.components chai.expect(l.ready, 'should have been set ready').to.equal true chai.expect(ready, 'should have emitted ready').to.equal true done() unless noflo.isBrowser() # Browser component registry can be synchronous chai.expect(l.processing, 'should have started processing').to.equal true describe 'after listing components', -> it 'should have the Graph component registered', -> chai.expect(l.components.Graph).not.to.be.empty describe 'loading the Graph component', -> instance = null it 'should be able to load the component', (done) -> l.load 'Graph', (err, inst) -> return done err if err chai.expect(inst).to.be.an 'object' chai.expect(inst.componentName).to.equal 'Graph' instance = inst done() it 'should contain input ports', -> chai.expect(instance.inPorts).to.be.an 'object' chai.expect(instance.inPorts.graph).to.be.an 'object' it 'should have "on" method on the input port', -> chai.expect(instance.inPorts.graph.on).to.be.a 'function' it 'it should know that Graph is a subgraph', -> chai.expect(instance.isSubgraph()).to.equal true it 'should know the description for the Graph', -> chai.expect(instance.description).to.be.a 'string' it 'should be able to provide an icon for the Graph', -> chai.expect(instance.getIcon()).to.be.a 'string' chai.expect(instance.getIcon()).to.equal 'sitemap' describe 'loading a subgraph', -> l = new noflo.ComponentLoader root file = "#{urlPrefix}spec/fixtures/subgraph.fbp" it 'should remove `graph` and `start` ports', (done) -> l.listComponents (err, components) -> return done err if err l.components.Merge = Merge l.components.Subgraph = file l.components.Split = Split l.load 'Subgraph', (err, inst) -> return done err if err chai.expect(inst).to.be.an 'object' inst.once 'ready', -> chai.expect(inst.inPorts.ports).not.to.have.keys ['graph','start'] chai.expect(inst.inPorts.ports).to.have.keys ['in'] chai.expect(inst.outPorts.ports).to.have.keys ['out'] done() it 'should not automatically start the subgraph if there is no `start` port', (done) -> l.listComponents (err, components) -> return done err if err l.components.Merge = Merge l.components.Subgraph = file l.components.Split = Split l.load 'Subgraph', (err, inst) -> return done err if err chai.expect(inst).to.be.an 'object' inst.once 'ready', -> chai.expect(inst.started).to.equal(false) done() it 'should also work with a passed graph object', (done) -> noflo.graph.loadFile file, (err, graph) -> return done err if err l.listComponents (err, components) -> return done err if err l.components.Merge = Merge l.components.Subgraph = graph l.components.Split = Split l.load 'Subgraph', (err, inst) -> return done err if err chai.expect(inst).to.be.an 'object' inst.once 'ready', -> chai.expect(inst.inPorts.ports).not.to.have.keys ['graph','start'] chai.expect(inst.inPorts.ports).to.have.keys ['in'] chai.expect(inst.outPorts.ports).to.have.keys ['out'] done() describe 'loading the Graph component', -> instance = null it 'should be able to load the component', (done) -> l.load 'Graph', (err, graph) -> return done err if err chai.expect(graph).to.be.an 'object' instance = graph done() it 'should have a reference to the Component Loader\'s baseDir', -> chai.expect(instance.baseDir).to.equal l.baseDir describe 'loading a component', -> it 'should return an error on an invalid component type', (done) -> l.components['InvalidComponent'] = true l.load 'InvalidComponent', (err, c) -> chai.expect(err).to.be.instanceOf Error chai.expect(err.message).to.equal 'Invalid type boolean for component InvalidComponent.' done() describe 'register a component at runtime', -> class Split extends noflo.Component constructor: -> @inPorts = in: new noflo.Port @outPorts = out: new noflo.Port Split.getComponent = -> new Split instance = null l.libraryIcons.foo = 'star' it 'should be available in the components list', -> l.registerComponent 'foo', 'Split', Split chai.expect(l.components).to.contain.keys ['foo/Split', 'Graph'] it 'should be able to load the component', (done) -> l.load 'foo/Split', (err, split) -> return done err if err chai.expect(split).to.be.an 'object' instance = split done() it 'should have the correct ports', -> chai.expect(instance.inPorts).to.have.keys ['in'] chai.expect(instance.outPorts).to.have.keys ['out'] it 'should have inherited its icon from the library', -> chai.expect(instance.getIcon()).to.equal 'star' it 'should emit an event on icon change', (done) -> instance.once 'icon', (newIcon) -> chai.expect(newIcon).to.equal 'smile' done() instance.setIcon 'smile' it 'new instances should still contain the original icon', (done) -> l.load 'foo/Split', (err, split) -> return done err if err chai.expect(split).to.be.an 'object' chai.expect(split.getIcon()).to.equal 'star' done() it 'after setting an icon for the Component class, new instances should have that', (done) -> Split::icon = 'trophy' l.load 'foo/Split', (err, split) -> return done err if err chai.expect(split).to.be.an 'object' chai.expect(split.getIcon()).to.equal 'trophy' done() it 'should not affect the original instance', -> chai.expect(instance.getIcon()).to.equal 'smile' describe 'reading sources', -> before -> # getSource not implemented in webpack loader yet return @skip() if noflo.isBrowser() it 'should be able to provide source code for a component', (done) -> l.getSource 'Graph', (err, component) -> return done err if err chai.expect(component).to.be.an 'object' chai.expect(component.code).to.be.a 'string' chai.expect(component.code.indexOf('noflo.Component')).to.not.equal -1 chai.expect(component.code.indexOf('exports.getComponent')).to.not.equal -1 chai.expect(component.name).to.equal 'Graph' chai.expect(component.library).to.equal '' chai.expect(component.language).to.equal shippingLanguage done() it 'should return an error for missing components', (done) -> l.getSource 'foo/BarBaz', (err, src) -> chai.expect(err).to.be.an 'error' done() it 'should return an error for non-file components', (done) -> l.getSource 'foo/Split', (err, src) -> chai.expect(err).to.be.an 'error' done() it 'should be able to provide source for a graph file component', (done) -> file = "#{urlPrefix}spec/fixtures/subgraph.fbp" l.components.Subgraph = file l.getSource 'Subgraph', (err, src) -> return done err if err chai.expect(src.code).to.not.be.empty chai.expect(src.language).to.equal 'json' done() it 'should be able to provide source for a graph object component', (done) -> file = "#{urlPrefix}spec/fixtures/subgraph.fbp" noflo.graph.loadFile file, (err, graph) -> return done err if err l.components.Subgraph2 = graph l.getSource 'Subgraph2', (err, src) -> return done err if err chai.expect(src.code).to.not.be.empty chai.expect(src.language).to.equal 'json' done() describe 'writing sources', -> describe 'with working code', -> before -> # setSource not implemented in webpack loader yet return @skip() if noflo.isBrowser() workingSource = """ var noflo = require('noflo'); exports.getComponent = function() { var c = new noflo.Component(); c.inPorts.add('in', function(packet, outPorts) { if (packet.event !== 'data') { return; } // Do something with the packet, then c.outPorts.out.send(packet.data); }); c.outPorts.add('out'); return c; };""" it 'should be able to set the source', (done) -> @timeout 10000 unless noflo.isBrowser() workingSource = workingSource.replace "'noflo'", "'../src/lib/NoFlo'" l.setSource 'foo', 'RepeatData', workingSource, 'js', (err) -> return done err if err done() it 'should be a loadable component', (done) -> l.load 'foo/RepeatData', (err, inst) -> return done err if err chai.expect(inst).to.be.an 'object' chai.expect(inst.inPorts).to.contain.keys ['in'] chai.expect(inst.outPorts).to.contain.keys ['out'] done() describe 'with non-working code', -> before -> # setSource not implemented in webpack loader yet return @skip() if noflo.isBrowser() nonWorkingSource = """ var noflo = require('noflo'); var notFound = require('./this_file_does_not_exist.js'); exports.getComponent = function() { var c = new noflo.Component(); c.inPorts.add('in', function(packet, outPorts) { if (packet.event !== 'data') { return; } // Do something with the packet, then c.outPorts.out.send(packet.data); }); c.outPorts.add('out'); return c; };""" it 'should be able to set the source', (done) -> unless noflo.isBrowser() nonWorkingSource = nonWorkingSource.replace "'noflo'", "'../src/lib/NoFlo'" l.setSource 'foo', 'NotWorking', nonWorkingSource, 'js', (err) -> chai.expect(err).to.be.an 'error' done() it 'should not be a loadable component', (done) -> l.load 'foo/NotWorking', (err, inst) -> chai.expect(err).to.be.an 'error' chai.expect(inst).to.be.an 'undefined' done() describe 'ComponentLoader with a fixture project', -> l = null before -> return @skip() if noflo.isBrowser() it 'should be possible to instantiate', -> l = new noflo.ComponentLoader path.resolve __dirname, 'fixtures/componentloader' it 'should initially know of no components', -> chai.expect(l.components).to.be.a 'null' it 'should not initially be ready', -> chai.expect(l.ready).to.be.false it 'should be able to read a list of components', (done) -> ready = false l.once 'ready', -> chai.expect(l.ready).to.equal true ready = l.ready l.listComponents (err, components) -> return done err if err chai.expect(l.processing).to.equal false chai.expect(l.components).not.to.be.empty chai.expect(components).to.equal l.components chai.expect(l.ready).to.equal true chai.expect(ready).to.equal true done() chai.expect(l.processing).to.equal true it 'should be able to load a local component', (done) -> l.load 'componentloader/Output', (err, instance) -> chai.expect(err).to.be.a 'null' chai.expect(instance.description).to.equal 'Output stuff' chai.expect(instance.icon).to.equal 'cloud' done() it 'should be able to load a component from a dependency', (done) -> l.load 'example/Forward', (err, instance) -> chai.expect(err).to.be.a 'null' chai.expect(instance.description).to.equal 'Forward stuff' chai.expect(instance.icon).to.equal 'car' done() it 'should be able to load a dynamically registered component from a dependency', (done) -> l.load 'example/Hello', (err, instance) -> chai.expect(err).to.be.a 'null' chai.expect(instance.description).to.equal 'Hello stuff' chai.expect(instance.icon).to.equal 'bicycle' done() it 'should be able to load core Graph component', (done) -> l.load 'Graph', (err, instance) -> chai.expect(err).to.be.a 'null' chai.expect(instance.icon).to.equal 'sitemap' done() it 'should fail loading a missing component', (done) -> l.load 'componentloader/Missing', (err, instance) -> chai.expect(err).to.be.an 'error' done()