Testing
First in line for testing, we have fbp-spec
Just add a fbpspec.coffee
file in /spec
directory
Important to note, you cannot send brackets or do any sort of special operations using fbp-spec. To get around that, you will have to write components exclusively for testing, and fbp graphs as fixtures.
The command we use for noflo, and the flags can be found at noflo-nodejs flags
fbpspec = require 'fbp-spec'
nodeRuntime =
label: "NoFlo node.js"
description: ""
type: "noflo"
protocol: "websocket"
secret: 'notasecret'
address: "ws://localhost:3333"
id: "7807f4d8-63e0-4a89-a577-2770c14f8106"
command: './node_modules/.bin/noflo-nodejs --verbose --catch-exceptions=false --secret notasecret --port=3333 --host=localhost --register=false --capture-output=true --debug=true'
fbpspec.mocha.run nodeRuntime, './spec',
fixturetimeout: 20000
starttimeout: 100000
Then, for each test, just add a yaml
file in the /spec
directory, each yaml
file in /spec
is loaded by the fbp-spec
.
topic: "canadianness/FindWords"
name: "Find words fbpspec"
cases:
-
name: 'content eh'
assertion: 'should be find one `eh`'
inputs:
word: 'eh'
surrounding: false
content: 'eh'
expect:
matches:
equals: 'eh'
Then traditional: (as you would any other mocha test)
noflo = require 'noflo'
# if you want to run your tests on the browser builds using phantom
unless noflo.isBrowser()
chai = require 'chai'
path = require 'path'
baseDir = path.resolve __dirname, '../'
else
baseDir = 'canadianness'
describe 'FindWords component', ->
# we scope the instance of the component or graph
# as well as the sockets we attach to the ports
# because we load it inside of the `before`
# and use it inside of the actual test
c = null
word = null
surrounding = null
content = null
matches = null
before (done) ->
@timeout 4000
loader = new noflo.ComponentLoader baseDir
loader.load 'canadianness/FindWords', (err, instance) ->
return done err if err
c = instance
word = noflo.internalSocket.createSocket()
content = noflo.internalSocket.createSocket()
surrounding = noflo.internalSocket.createSocket()
c.inPorts.word.attach word
c.inPorts.content.attach content
c.inPorts.surrounding.attach surrounding
done()
# before each test we want to attach all of the outports
# and we want to detach the outports after each,
# otherwise the event listeners in the test that ran before
# would get triggered again
beforeEach ->
matches = noflo.internalSocket.createSocket()
c.outPorts.matches.attach matches
afterEach ->
c.outPorts.matches.detach matches
describe 'with content eh', ->
it 'should be find one `eh`', (done) ->
# we listen to the port events, receive the data
# and do our assertions
matches.on 'data', (data) ->
chai.expect(data).to.eql 'eh'
done()
word.send 'eh'
surrounding.send false
content.send 'eh'
describe 'with content that has no `eh`s', ->
it 'should send an empty array', (done) ->
matches.on 'data', (data) ->
chai.expect(data).to.eql []
done()
word.send 'eh'
surrounding.send false
content.send 'A string without it is a sad string.'
describe 'with content that has multiple `eh`s', ->
it 'should send an array of ehs', (done) ->
expect = ['Eh...', 'eh?', 'EH!']
matches.on 'ip', (ip) ->
if ip.type is 'data'
chai.expect(ip.data).to.eql expect.shift()
if ip.type is 'closeBracket'
done()
word.send 'eh'
surrounding.send true
content.send 'Eh... eh? EH!'
And finally, noflo-tester (as you would any other mocha test):
Tester = require 'noflo-tester'
chai = require 'chai'
describe 'FindWords component', ->
t = new Tester 'canadianness/FindWords'
before (done) ->
t.start (err, instance) ->
return throw err if err
done()
describe 'with content eh', ->
it 'should be find one `eh`', (done) ->
# will only listen once and trigger after disconnect
t.receive 'matches', (data) ->
chai.expect(data).to.eql 'eh'
done()
t.ins.word.send 'eh'
t.ins.surrounding.send false
t.ins.content.send 'eh'
describe 'with content that has no `eh`s', ->
it 'should send an empty array', (done) ->
t.receive 'matches', (data) ->
chai.expect(data).to.eql []
done()
t.ins.word.send 'eh'
t.ins.surrounding.send false
t.ins.content.send 'A string without it is a sad string.'
describe 'with content that has multiple `eh`s', ->
it 'should send an array of ehs', (done) ->
expect = ['Eh...', 'eh?', 'EH!']
t.outs.matches.on 'ip', (ip) ->
if ip.type is 'data'
chai.expect(ip.data).to.eql expect.shift()
if ip.type is 'closeBracket'
done()
t.ins.word.send 'eh'
t.ins.surrounding.send true
t.ins.content.send 'Eh... eh? EH!'
Loading Components inline
Components can be also defined and loaded in one file: Components and graphs can be loaded using the ComponentLoader Say you were using a database query, querying a list of names from people
noflo = require 'noflo'
unless noflo.isBrowser()
chai = require 'chai'
path = require 'path'
baseDir = path.resolve __dirname, '../'
else
baseDir = 'canadianness'
fetchPeople = ->
new noflo.Component
inPorts:
eh:
datatype: 'all'
outPorts:
out:
datatype: 'object'
description: 'random data'
error:
datatype: 'object'
description: 'if something goes horribly wrong'
forwardBrackets:
eh: ['out', 'error']
process: (input, output) ->
eh = input.getData 'eh'
output.send out: new noflo.IP 'openBracket'
output.send out: eh
output.send out: new noflo.IP 'closeBracket'
output.done()
log = ->
c = new noflo.Component
inPorts:
in:
datatype: 'all'
description: 'data to log'
outPorts:
out:
datatype: 'all'
description: 'when finished'
# we don't want to automatically forward from `in` so we set it to empty
c.forwardBrackets = {}
c.process (input, output) ->
return unless input.hasStream 'in'
# the stream will contain all the forwarded openBrackets
console.log input.getStream 'in'
output.sendDone out: true
loader = new noflo.ComponentLoader baseDir
loader.listComponents (err) ->
return throw err if err
loader.registerComponent 'processapi', 'Log', log
loader.registerComponent 'processapi', 'FetchPeople', fetchPeople
fbpData = "
INPORT=FetchPeople.EH:EH
OUTPORT=Log.OUT:OUT
FetchPeople(processapi/FetchPeople) OUT -> IN Log(processapi/Log)
"
noflo.graph.loadFBP fbpData, (err, g) ->
return throw err if err
loader.registerComponent 'processapi', 'Connected', g
loader.load 'processapi/Connected', (err, instance) ->
return throw err if err
# instance of the graph we defined in `fbpData`
c = instance
# create and attach sockets
eh = noflo.internalSocket.createSocket()
out = noflo.internalSocket.createSocket()
c.inPorts.eh.attach eh
c.outPorts.out.attach out
# will be openBracket, data, closeBracket
# and those will be forwarded to Log `in` port
# which will wrap the brackets that FetchPeople itself sends
eh.send new noflo.IP 'openBracket'
eh.send 'message'
eh.send new noflo.IP 'closeBracket'
out.on 'data', (data) ->
console.log 'done!'