@danielkalen/simplybind
Version:
Magically simple, framework-less one-way/two-way data binding for frontend/backend in ~5kb.
1,530 lines (1,117 loc) • 105 kB
text/coffeescript
mocha.setup('bdd')
expect = chai.expect
should = chai.should()
describe "SimplyBind", ()->
before ()->
startSandbox()
window.server = sinon.fakeServer.create()
server.respondWith '/local', ''
server.respondWith '/get/some/data.json', [
200
{ 'Content-Type': 'application/json' }
JSON.stringify('prop': 'externalValues': 'it works :)')
]
server.respondWith '/get/some/data2.json', [
200
{ 'Content-Type': 'application/json' }
JSON.stringify('prop': 'externalValues': 'it works :)')
]
server.respondWith '/get/nonexistent', ''
server.respondWith '/set/some/data.json', [
200
{ 'Content-Type': 'application/json' }
JSON.stringify('prop': 'externalValues': 'it works too :)')
]
server.respondWith '/set/some/data2.json', [
200
{ 'Content-Type': 'application/json' }
JSON.stringify('prop': 'externalValues': 'it works too :)')
]
server.autoRespond = true
server.autoRespondAfter = 0
it "should return an options list when calling SimplyBind.options", ()->
options = SimplyBind.options
expect(options.silent).not.to.be.undefined
expect(options.placeholderStart).not.to.be.undefined
expect(options.placeholderEnd).not.to.be.undefined
expect(options.liveProps).not.to.be.undefined
expect(options.ignoreCase).not.to.be.undefined
expect(options.dispatchEvents).not.to.be.undefined
expect(options.updateEvenIfUndefined).not.to.be.undefined
expect(options.updateEvenIfSame).not.to.be.undefined
expect(options.mutateInherited).not.to.be.undefined
expect(options.mutateArrayMethods).not.to.be.undefined
expect(options.invokeOnBind).not.to.be.undefined
it "should set a new value for a single option when calling SimplyBind.setOption()", ()->
expect(SimplyBind.options.silent).to.equal false
SimplyBind.setOption 'silent', true
expect(SimplyBind.options.silent).to.equal true
SimplyBind.setOption 'silent', false
it "should set new values for a all the options passed when calling SimplyBind.setOptions()", ()->
expect(SimplyBind.options.silent).to.equal false
expect(SimplyBind.options.liveProps).to.equal true
SimplyBind.setOptions
'silent': true
'liveProps': false
expect(SimplyBind.options.silent).to.equal true
expect(SimplyBind.options.liveProps).to.equal false
SimplyBind.setOptions
'silent': false
'liveProps': true
SimplyBind.setOptions {}
expect(SimplyBind.options.silent).to.equal false
expect(SimplyBind.options.liveProps).to.equal true
it "should not add non-existing options when they are added via .setOptions", ()->
SimplyBind.setOptions
placeholderStart: '{{'
placeholderEnd: '}}'
youtube: 'yea!'
expect(SimplyBind.options.placeholderStart).to.equal '{{'
expect(SimplyBind.options.placeholderEnd).to.equal '}}'
expect(SimplyBind.options.youtube).to.be.undefined
it 'should apply input-simplybind polyfill', (done)->
$inputA.one 'input-simplybind', ()->
expect(true).to.equal true
done()
$inputA.trigger 'input-simplybind'
it "should only accept a param value with the constructor of String, Number, Function, or SimplyBounded", ()->
symbol = ()->
SimplyBind Symbol('5')
expect(symbol).to.throw()
it "should only accept a param value with the constructor of String or SimplyBounded that isn't empty", ()->
emptyString = ()-> SimplyBind ''
numberZero = ()-> SimplyBind 0
expect(emptyString).to.throw()
expect(numberZero).not.to.throw()
it "should not accept null subjects in .of()", ()->
fn = ()-> SimplyBind('prop').of null
expect(fn).to.throw()
it "should not accept undefined subjects in .of()", ()->
fn = ()-> SimplyBind('prop').of undefined
expect(fn).to.throw()
it "should not accept string, number, or boolean subjects in .of()", ()->
fn = ()-> SimplyBind('prop').of 'string'
fn2 = ()-> SimplyBind('prop').of 3
fn3 = ()-> SimplyBind('prop').of true
expect(fn).to.throw()
expect(fn2).to.throw()
expect(fn3).to.throw()
it "should not accept non-object subjects in .of()", ()->
fn = ()-> SimplyBind('prop').of Symbol('test')
expect(fn).to.throw()
it "should throw a warning when binding a property of a jQuery element with multiple els", ()->
origLog = console.log
console.log = chai.spy()
SimplyBind('value').of $('input[type="text"]')
expect(console.log).to.have.been.called()
console.log = origLog
it "should throw a warning when binding a property of an empty NodeList/HTMLCollection", ()->
origLog = console.log
console.log = chai.spy()
SimplyBind('value').of document.querySelectorAll('nonexistent')
expect(console.log).to.have.been.called()
SimplyBind('value').of document.getElementsByTagName('nonexistent')
expect(console.log).to.have.been.called()
console.log = origLog
it "should throw a warning when binding a property of an empty jQuery element", ()->
origLog = console.log
console.log = chai.spy()
SimplyBind('value').of $('input[type="nonexistent"]')
expect(console.log).to.have.been.called()
console.log = origLog
it "should throw a warning when creating a binding with a non-function object using the .transform or .transformAll method.", ()->
origLog = console.log
console.log = chai.spy()
SimplyBind('prop1').of(objectA).to('prop1').of(objectB).transform []
expect(console.log).to.have.been.called()
SimplyBind('prop1').of(objectA).to('prop1').of(objectB).transformAll []
expect(console.log).to.have.been.called()
console.log = origLog
restartSandbox()
it "should\'t throw warnings if errors are suppressed, but should throw errors regardless", ()->
emptyString = ()->
SimplyBind ''
SimplyBind.setOption 'silent', true
origLog = console.log
console.log = chai.spy()
SimplyBind('value').of $('input[type="text"]')
expect(console.log).not.to.have.been.called()
expect(emptyString).to.throw()
console.log = origLog
SimplyBind.setOption 'silent', false
describe "Bound Object", ()->
before ()->
restartSandbox()
it "should have the proper methods depending on its stage", ()->
bound = ()-> SimplyBind '1'
expect(()-> bound().of objectA).not.to.throw()
expect(()-> bound().ofEvent objectA).not.to.throw()
expect(()-> bound().ofExternal '/local').not.to.throw()
expect(()-> bound().to 'prop2').to.throw()
expect(()-> bound().toExternal '/local').to.throw()
expect(()-> bound().and 'prop2').to.throw()
expect(()-> bound().set 'value').to.throw()
expect(()-> bound().get()).to.throw()
expect(()-> bound().transform ()->).to.throw()
expect(()-> bound().transformAll ()->).to.throw()
expect(()-> bound().bothWays()).to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).to.throw()
expect(()-> bound().unBind()).to.throw()
expect(()-> bound().chainTo ()->).to.throw()
expect(()-> bound().updateDepsOnEvent 'a').to.throw()
expect(()-> bound().removeEvent 'a').to.throw()
bound = ()->
SimplyBind('1').of objectA
expect(()-> bound().of objectA).to.throw()
expect(()-> bound().ofEvent objectA).to.throw()
expect(()-> bound().ofExternal '/local').to.throw()
expect(()-> bound().to 'prop2').not.to.throw()
expect(()-> bound().toExternal '/local').not.to.throw()
expect(()-> bound().and 'prop2').to.throw()
expect(()-> bound().set 'value').not.to.throw()
expect(()-> bound().get()).not.to.throw()
expect(()-> bound().transform ()->).to.throw()
expect(()-> bound().transformAll ()->).to.throw()
expect(()-> bound().bothWays()).to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).to.throw()
expect(()-> bound().unBind()).to.throw()
expect(()-> bound().chainTo ()->).to.throw()
expect(()-> bound().updateDepsOnEvent 'a').to.throw()
expect(()-> bound().removeEvent 'a').to.throw()
bound = ()->
SimplyBind('1').ofEvent 'click'
expect(()-> bound().of objectA).not.to.throw()
expect(()-> bound().ofEvent objectA).to.throw()
expect(()-> bound().ofExternal '/local').to.throw()
expect(()-> bound().to 'prop2').to.throw()
expect(()-> bound().toExternal '/local').to.throw()
expect(()-> bound().and 'prop2').to.throw()
expect(()-> bound().set 'value').to.throw()
expect(()-> bound().get()).to.throw()
expect(()-> bound().transform ()->).to.throw()
expect(()-> bound().transformAll ()->).to.throw()
expect(()-> bound().bothWays()).to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).to.throw()
expect(()-> bound().unBind()).to.throw()
expect(()-> bound().chainTo ()->).to.throw()
expect(()-> bound().updateDepsOnEvent 'a').to.throw()
expect(()-> bound().removeEvent 'a').to.throw()
bound = ()->
SimplyBind('1').ofEvent('click').of inputA
expect(()-> bound().of objectA).to.throw()
expect(()-> bound().ofEvent objectA).to.throw()
expect(()-> bound().ofExternal '/local').to.throw()
expect(()-> bound().to 'prop2').not.to.throw()
expect(()-> bound().toExternal '/local').not.to.throw()
expect(()-> bound().and 'prop2').to.throw()
expect(()-> bound().set 'value').not.to.throw()
expect(()-> bound().get()).not.to.throw()
expect(()-> bound().transform ()->).to.throw()
expect(()-> bound().transformAll ()->).to.throw()
expect(()-> bound().bothWays()).to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).to.throw()
expect(()-> bound().unBind()).to.throw()
expect(()-> bound().chainTo ()->).to.throw()
expect(()-> bound().updateDepsOnEvent 'a').to.throw()
expect(()-> bound().removeEvent 'a').to.throw()
bound = ()->
SimplyBind('1').of(objectA).to 'prop1'
expect(()-> bound().of objectA).not.to.throw()
expect(()-> bound().ofEvent objectA).to.throw()
expect(()-> bound().ofExternal '/local').to.throw()
expect(()-> bound().to 'prop2').to.throw()
expect(()-> bound().toExternal '/local').to.throw()
expect(()-> bound().and 'prop2').to.throw()
expect(()-> bound().set 'value').to.throw()
expect(()-> bound().get()).to.throw()
expect(()-> bound().transform ()->).to.throw()
expect(()-> bound().transformAll ()->).to.throw()
expect(()-> bound().bothWays()).to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).to.throw()
expect(()-> bound().unBind()).to.throw()
expect(()-> bound().chainTo ()->).to.throw()
expect(()-> bound().updateDepsOnEvent 'a').to.throw()
expect(()-> bound().removeEvent 'a').to.throw()
bound = ()->
SimplyBind('1').of(objectA).to('prop1').of objectB
expect(()-> bound().of objectA).to.throw()
expect(()-> bound().ofEvent objectA).to.throw()
expect(()-> bound().ofExternal '/local').to.throw()
expect(()-> bound().to 'prop2').to.throw()
expect(()-> bound().toExternal '/local').to.throw()
expect(()-> bound().and 'prop2').not.to.throw()
expect(()-> bound().set 'value').not.to.throw()
expect(()-> bound().get()).not.to.throw()
expect(()-> bound().transform ()->).not.to.throw()
expect(()-> bound().transformAll ()->).not.to.throw()
expect(()-> bound().bothWays()).not.to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
expect(()-> bound().unBind()).not.to.throw()
expect(()-> bound().chainTo ()->).not.to.throw()
expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
expect(()-> bound().removeEvent 'a').not.to.throw()
bound = ()->
SimplyBind('1').of(objectA).to('prop1').of(objectB).and 'prop2'
expect(()-> bound().of objectA).not.to.throw()
expect(()-> bound().ofEvent objectA).to.throw()
expect(()-> bound().ofExternal '/local').to.throw()
expect(()-> bound().to 'prop2').to.throw()
expect(()-> bound().toExternal '/local').to.throw()
expect(()-> bound().and 'prop2').to.throw()
expect(()-> bound().set 'value').to.throw()
expect(()-> bound().get()).to.throw()
expect(()-> bound().transform ()->).to.throw()
expect(()-> bound().transformAll ()->).to.throw()
expect(()-> bound().bothWays()).to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).to.throw()
expect(()-> bound().unBind()).to.throw()
expect(()-> bound().chainTo ()->).to.throw()
expect(()-> bound().updateDepsOnEvent 'a').to.throw()
expect(()-> bound().removeEvent 'a').to.throw()
bound = ()->
SimplyBind('1').of(objectA).to('prop1').of(objectB).and('prop2').of objectB
expect(()-> bound().of objectA).to.throw()
expect(()-> bound().ofEvent objectA).to.throw()
expect(()-> bound().ofExternal '/local').to.throw()
expect(()-> bound().to 'prop2').to.throw()
expect(()-> bound().toExternal '/local').to.throw()
expect(()-> bound().and 'prop2').not.to.throw()
expect(()-> bound().set 'value').not.to.throw()
expect(()-> bound().get()).not.to.throw()
expect(()-> bound().transform ()->).not.to.throw()
expect(()-> bound().transformAll ()->).not.to.throw()
expect(()-> bound().bothWays()).not.to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
expect(()-> bound().unBind()).not.to.throw()
expect(()-> bound().chainTo ()->).not.to.throw()
expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
expect(()-> bound().removeEvent 'a').not.to.throw()
bound = ()->
SimplyBind('1').of(objectA).to('prop1').of(objectB).bothWays()
expect(()-> bound().of objectA).to.throw()
expect(()-> bound().ofEvent objectA).to.throw()
expect(()-> bound().ofExternal '/local').to.throw()
expect(()-> bound().to 'prop2').to.throw()
expect(()-> bound().toExternal '/local').to.throw()
expect(()-> bound().and 'prop2').not.to.throw()
expect(()-> bound().set 'value').not.to.throw()
expect(()-> bound().get()).not.to.throw()
expect(()-> bound().transform ()->).not.to.throw()
expect(()-> bound().transformAll ()->).not.to.throw()
expect(()-> bound().bothWays()).not.to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
expect(()-> bound().unBind()).not.to.throw()
expect(()-> bound().chainTo ()->).not.to.throw()
expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
expect(()-> bound().removeEvent 'a').not.to.throw()
bound = ()->
SimplyBind('1').of(objectA).to('prop1').of(objectB).transform ()->
expect(()-> bound().of objectA).to.throw()
expect(()-> bound().ofEvent objectA).to.throw()
expect(()-> bound().ofExternal '/local').to.throw()
expect(()-> bound().to 'prop2').to.throw()
expect(()-> bound().toExternal '/local').to.throw()
expect(()-> bound().and 'prop2').not.to.throw()
expect(()-> bound().set 'value').not.to.throw()
expect(()-> bound().get()).not.to.throw()
expect(()-> bound().transform ()->).to.throw()
expect(()-> bound().transformAll ()->).to.throw()
expect(()-> bound().bothWays()).not.to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
expect(()-> bound().unBind()).not.to.throw()
expect(()-> bound().chainTo ()->).not.to.throw()
expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
expect(()-> bound().removeEvent 'a').not.to.throw()
bound = ()->
SimplyBind('1').of(objectA).to('prop1').of(objectB).transformAll ()->
expect(()-> bound().of objectA).to.throw()
expect(()-> bound().ofEvent objectA).to.throw()
expect(()-> bound().ofExternal '/local').to.throw()
expect(()-> bound().to 'prop2').to.throw()
expect(()-> bound().toExternal '/local').to.throw()
expect(()-> bound().and 'prop2').to.throw()
expect(()-> bound().set 'value').not.to.throw()
expect(()-> bound().get()).not.to.throw()
expect(()-> bound().transform ()->).to.throw()
expect(()-> bound().transformAll ()->).to.throw()
expect(()-> bound().bothWays()).to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
expect(()-> bound().unBind()).not.to.throw()
expect(()-> bound().chainTo ()->).not.to.throw()
expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
expect(()-> bound().removeEvent 'a').not.to.throw()
bound = ()->
SimplyBind('1').of(objectA).to('prop1').of(objectB).transform(()->
).and ()->
expect(()-> bound().of objectA).to.throw()
expect(()-> bound().ofEvent objectA).to.throw()
expect(()-> bound().ofExternal '/local').to.throw()
expect(()-> bound().to 'prop2').to.throw()
expect(()-> bound().toExternal '/local').to.throw()
expect(()-> bound().and 'prop2').not.to.throw()
expect(()-> bound().set 'value').not.to.throw()
expect(()-> bound().get()).not.to.throw()
expect(()-> bound().transform ()->).not.to.throw()
expect(()-> bound().transformAll ()->).not.to.throw()
expect(()-> bound().bothWays()).not.to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
expect(()-> bound().unBind()).not.to.throw()
expect(()-> bound().chainTo ()->).not.to.throw()
expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
expect(()-> bound().removeEvent 'a').not.to.throw()
bound = ()->
SimplyBind('1').of(objectA).to('prop1').of(objectB).transform(()->
).and(()->
).chainTo ()->
expect(()-> bound().of objectA).to.throw()
expect(()-> bound().ofEvent objectA).to.throw()
expect(()-> bound().ofExternal '/local').to.throw()
expect(()-> bound().to 'prop2').to.throw()
expect(()-> bound().toExternal '/local').to.throw()
expect(()-> bound().and 'prop2').not.to.throw()
expect(()-> bound().set 'value').not.to.throw()
expect(()-> bound().get()).not.to.throw()
expect(()-> bound().transform ()->).not.to.throw()
expect(()-> bound().transformAll ()->).not.to.throw()
expect(()-> bound().bothWays()).not.to.throw()
expect(()-> bound().stopPolling()).to.throw()
expect(()-> bound().pollEvery(1000).stopPolling()).not.to.throw()
expect(()-> bound().unBind()).not.to.throw()
expect(()-> bound().chainTo ()->).not.to.throw()
expect(()-> bound().updateDepsOnEvent 'a').not.to.throw()
expect(()-> bound().removeEvent 'a').not.to.throw()
it "should have the correct public properties", ()->
bound = SimplyBind('prop1').of(objectA).to('prop2').of(objectB)
expect(bound.ID).not.to.be.undefined
expect(typeof bound.has).to.equal 'object'
expect(bound.has.initBind).not.to.be.undefined
expect(bound.has.tf).not.to.be.undefined
expect(bound.has.massTf).not.to.be.undefined
expect(bound.has.event).not.to.be.undefined
expect(bound.has.interval).not.to.be.undefined
expect(bound.value).not.to.be.undefined
expect(bound.stage).not.to.be.undefined
expect(bound.original).not.to.be.undefined
expect(bound.dependents).not.to.be.undefined
expect(bound._).not.to.be.undefined
it "should return the same SimplyBounded object from cache if in it", ()->
bound1 = SimplyBind('prop1').of(objectA).to('prop1').of(objectB)
bound2 = SimplyBind('prop1').of(objectA).to('prop1').of(objectB)
expect(bound1.ID).to.equal bound2.ID
it "should accept number attributes", ()->
tempObject =
'1': 'text'
'2': 'shmext'
SimplyBind(1).of(tempObject).to(2).of tempObject
expect(tempObject[1]).to.equal 'text'
expect(tempObject[2]).to.equal 'text'
it "should create the passed property on the parent object if undefined", ()->
bound = SimplyBind('prop20').of(objectA).to('prop20').of(objectB)
expect(objectA.prop20).not.to.be.undefined
expect(objectB.prop20).not.to.be.undefined
expect(objectA.prop20).to.be.null
expect(objectB.prop20).to.be.null
bound.set 'new value'
expect(objectA.prop20).to.equal 'new value'
expect(objectB.prop20).to.equal 'new value'
it "should return the appropriate values when using .value prop and .get() method", ()->
tempObject =
'a': 'with'
'b': 'text {{verb}} a placeholder'
SimplyBind('a').of(tempObject).to('b.verb').of tempObject
bound = SimplyBind('b.verb').of(tempObject)
expect(tempObject.b).to.equal 'text with a placeholder'
expect(bound.value).to.equal 'text with a placeholder'
expect(bound.get()).to.equal 'with'
tempObject.a = 'without'
expect(tempObject.b).to.equal 'text without a placeholder'
expect(bound.value).to.equal 'text without a placeholder'
expect(bound.get()).to.equal 'without'
describe "Data Binding", ()->
before ()->
restartSandbox()
describe "Misc.", ()->
it "can make inherited properties live properties if so set in options, otherwise it shouldn\'t", ()->
testArray = []
SimplyBind.setOption 'mutateInherited', true
Array::inherited = 'Hello :)'
SimplyBind('inherited').of(testArray).to('prop1').of objectB
testArray.inherited = 'inherited live prop change :)'
expect(objectB.prop1).to.equal 'inherited live prop change :)'
delete Array::inherited
SimplyBind.setOption 'mutateInherited', false
Array::inherited2 = 'Hello :)'
SimplyBind('inherited2').of(testArray).to('prop2').of objectB
testArray.inherited2 = 'inherited prop shouldn\'t change'
expect(objectB.prop2).not.to.equal 'inherited prop shouldn\'t change'
delete Array::inherited2
SimplyBind.setOption 'mutateInherited', false
it "should invoke the original descriptor\'s setter and getter on a live property (if exists)", ()->
prop7 = 'hey!'
invokeCountGet = 0
invokeCountSet = 0
Object.defineProperty objectA, 'prop7',
enumerable: true
configurable: true
get: ()->
invokeCountGet++
prop7
set: (val)->
invokeCountSet++
prop7 = val
expect(objectA.prop7).to.equal 'hey!'
expect(invokeCountGet).to.equal 1
expect(invokeCountSet).to.equal 0
SimplyBind('prop7').of(objectA).to('prop3').of objectB
objectA.prop7 = 'hello!'
expect(invokeCountGet).to.equal 2
expect(invokeCountSet).to.equal 1
expect(objectA.prop7).to.equal 'hello!'
objectA.prop7 = 'hi!'
expect(invokeCountGet).to.equal 3
expect(invokeCountSet).to.equal 2
it "shouldn\'t change anything if passed a null/undefined value to .to()", ()->
restartSandbox()
bound = SimplyBind('prop1').of(objectA).to(null)
expect(bound.stage).to.equal 1
bound = SimplyBind('prop1').of(objectA).to(undefined)
expect(bound.stage).to.equal 1
if typeof Symbol != 'undefined'
symbol = ()-> SimplyBind('prop1').of(objectA).to Symbol('whatever')
expect(symbol).to.throw()
it "shouldn\'t change anything if passed a null/undefined value to .and()", ()->
restartSandbox()
bound = SimplyBind('prop1').of(objectA).to(()->).and(null)
expect(bound.stage).to.equal 3
bound = SimplyBind('prop1').of(objectA).to(()->).and(undefined)
expect(bound.stage).to.equal 3
it "can accept a SimplyBounded object as an argument for .of()", ()->
bound = SimplyBind('prop3').of(objectA).to('prop3').of(objectB)
bound.set 'standard'
expect(objectA.prop3).to.equal 'standard'
expect(objectB.prop3).to.equal 'standard'
bound2 = SimplyBind('prop4').of(bound).to('prop4').of(objectB)
bound2.set 'ofBounded'
expect(objectA.prop4).to.equal 'ofBounded'
expect(objectB.prop4).to.equal 'ofBounded'
it "should update values and dependents even if it\'s unchanged, if set the updateEvenIfSame option to true", ()->
invokeCount = 0
objectA.prop6 = 'start'
objectB.prop6 = ''
binding = SimplyBind('prop6').of(objectA).to('prop6').of(objectB).transform (value)-> invokeCount++; return value
expect(objectB.prop6).to.equal 'start'
expect(invokeCount).to.equal 1
objectA.prop6 = 'shouldn\'t update'
expect(objectB.prop6).to.equal 'shouldn\'t update'
expect(invokeCount).to.equal 2
objectA.prop6 = 'shouldn\'t update'
expect(objectB.prop6).to.equal 'shouldn\'t update'
expect(invokeCount).to.equal 2
objectA.prop6 = 'shouldn\'t update'
objectA.prop6 = 'shouldn\'t update'
objectA.prop6 = 'shouldn\'t update'
objectA.prop6 = 'shouldn\'t update'
expect(invokeCount).to.equal 2
binding.setOption 'updateEvenIfSame', true
objectA.prop6 = 'should update'
expect(objectB.prop6).to.equal 'should update'
expect(invokeCount).to.equal 3
objectA.prop6 = 'should update'
objectA.prop6 = 'should update'
objectA.prop6 = 'should update'
objectA.prop6 = 'should update'
expect(invokeCount).to.equal 7
binding.setOption 'updateEvenIfSame', false
objectA.prop6 = 'shouldn\'t update'
expect(objectB.prop6).to.equal 'shouldn\'t update'
expect(invokeCount).to.equal 8
objectA.prop6 = 'shouldn\'t update'
objectA.prop6 = 'shouldn\'t update'
objectA.prop6 = 'shouldn\'t update'
objectA.prop6 = 'shouldn\'t update'
expect(invokeCount).to.equal 8
it "can handle complex chainings using the .chainTo() method", ()->
outerstate =
'first': null
'second': null
'third': null
objectA.prop1 = 'Hello World'
SimplyBind('prop1').of(objectA)
.to('prop1').of(objectB)
.and('prop2').of(objectA)
.and (val)-> outerstate.first = val
.transformAll (val)-> val.toUpperCase()
.chainTo('prop2').of(objectB)
.and('prop3').of(objectA)
.transform (val)-> val.toLowerCase()
.chainTo('prop3').of(objectB)
.and('prop4').of(objectA)
.and (val)-> outerstate.second = val
.chainTo('prop4').of(objectB)
.and (val)-> outerstate.third = val.slice(0, 5)
expect(outerstate.first).to.equal 'HELLO WORLD'
expect(outerstate.second).to.equal 'hello world'
expect(outerstate.third).to.equal 'hello'
expect(objectA.prop1).to.equal 'Hello World'
expect(objectA.prop2).to.equal 'HELLO WORLD'
expect(objectB.prop1).to.equal 'HELLO WORLD'
expect(objectB.prop2).to.equal 'HELLO WORLD'
expect(objectA.prop3).to.equal 'hello world'
expect(objectB.prop3).to.equal 'hello world'
expect(objectA.prop4).to.equal 'hello world'
expect(objectB.prop4).to.equal 'hello world'
it "should update dependents even if the new value is undefined, if so set in the options", ()->
restartSandbox()
binding = SimplyBind('prop1').of(objectA).to('prop1').of(objectB)
objectA.prop1 = 10
expect(objectB.prop1).to.equal 10
objectA.prop1 = window.nonexistent # undefined value
expect(objectB.prop1).to.equal 10
binding.setOption 'updateEvenIfUndefined', true
objectA.prop1 = 20
expect(objectB.prop1).to.equal 20
objectA.prop1 = window.nonexistent # undefined value
expect(objectB.prop1).to.be.undefined
binding.setOption 'updateEvenIfUndefined', false
it "dependents should update their subdependents when being updated by an independent, even if these dependents are not liveProps", ()->
objectA.prop2 = 0.8
SimplyBind('prop2').of(objectA)
.to('opacity').of regA.style
SimplyBind('opacity').of(regA.style)
.to('font-size').of(regA.style)
.transform (opacity)-> opacity * 20 + 'px'
.and('font-size').of(regB.style)
.transform (opacity)-> opacity * 40 + 'px'
expect(regA.style.opacity.toString()).to.equal '0.8'
expect(regA.style['font-size']).to.equal '16px'
expect(regB.style['font-size']).to.equal '32px'
objectA.prop2 = 0.5
expect(regA.style.opacity.toString()).to.equal '0.5'
expect(regA.style['font-size']).to.equal '10px'
expect(regB.style['font-size']).to.equal '20px'
describe "Polling values in an interval", ()->
it 'can manually poll the subject at a given interval via the .pollEvery method', (done)->
shouldFinish = false
lastValue = undefined
bound = undefined
arr = []
fn = (length)->
if shouldFinish
expect(length).to.equal 2
bound.stopPolling()
done()
else
lastValue = length
bound = SimplyBind('length').of(arr).to(fn)
expect(lastValue).to.equal 0
arr.push 'some value'
arr.push 'and another'
expect(lastValue).to.equal 0
arr = []
bound = SimplyBind('length').of(arr).to(fn).pollEvery(5)
setTimeout ()->
shouldFinish = true
expect(lastValue).to.equal 0
arr.push 'some value'
arr.push 'and another'
expect(lastValue).to.equal 0
, 8
it 'can manually poll the subject at a given interval via the .pollEvery method, even if it\'s an Attr type', (done)->
shouldFinish = false
lastValue = undefined
bound = undefined
h1 = regAH1
fn = (value)->
if shouldFinish
expect(value).to.equal 'and another'
bound.stopPolling()
done()
else
lastValue = value
bound = SimplyBind('attr:data-attr').of(h1).to(fn).pollEvery(5)
bound.set 'initial value'
setTimeout ()->
shouldFinish = true
expect(lastValue).to.equal 'initial value'
h1.setAttribute 'data-attr', 'some value'
h1.setAttribute 'data-attr', 'and another'
expect(lastValue).to.equal 'initial value'
, 8
it 'can manually poll the subject and invoke it if it\'s a function at a given interval via the .pollEvery method', (done)->
shouldFinish = false
timesCalled = 0
bound = undefined
sourceFn = ()-> timesCalled++
fn = (length)->
if shouldFinish
expect(timesCalled).to.equal 9
bound.stopPolling()
done()
else
if timesCalled > 5
shouldFinish = true
bound = SimplyBind(sourceFn).to(fn).pollEvery(5)
expect(timesCalled).to.equal 1
describe "Objects (Standard)", ()->
it "supports live properties", ()->
restartSandbox()
SimplyBind('prop1').of(objectA).to('prop1').of objectB
objectA.prop1 = 'live prop change :)'
expect(objectB.prop1).to.equal 'live prop change :)'
it "should avoid infinite loops", ()->
SimplyBind('prop1').of(objectA).to('prop1').of(objectB).bothWays()
SimplyBind('prop1').of(objectB).to('prop1').of(objectC).bothWays()
SimplyBind('prop1').of(objectC).to('prop1').of(objectA).bothWays()
objectA.prop1 = 'objectA'
expect(objectB.prop1).to.equal 'objectA'
expect(objectC.prop1).to.equal 'objectA'
objectB.prop1 = 'objectB'
expect(objectA.prop1).to.equal 'objectB'
expect(objectC.prop1).to.equal 'objectB'
it "can bind an object\'s property to another\'s", ()->
restartSandbox()
bound = SimplyBind('prop1').of(objectA).to('prop1').of(objectB)
bound.set 'changed'
expect(objectB.prop1).to.equal 'changed'
it "can bind an functions\' property to another\'s", ()->
fn = ()->
fn.prop = 'some value'
bound = SimplyBind('prop').of(fn).to('prop1').of(objectB)
bound.set 'changed'
expect(objectB.prop1).to.equal 'changed'
it "can match case in property names (unless told otherwise via options.ignoreCase)", ()->
restartSandbox()
bound = SimplyBind('PrOp1').of(objectA).to('prOP1').of(objectB)
bound.set 'not changed'
expect(objectB.prop1).not.to.equal 'not changed'
SimplyBind.setOption 'ignoreCase', true
bound = SimplyBind('PrOp2').of(objectA).to('prOP2').of(objectB)
bound.set 'changed'
expect(objectB.prop2).to.equal 'changed'
SimplyBind.setOption 'ignoreCase', false
it "can bind even if the value is falsy", ()->
restartSandbox()
bound = SimplyBind('prop1').of(objectA).to('prop1').of(objectB)
bound.set ''
expect(objectB.prop1).to.equal ''
bound.set 0
expect(objectB.prop1).to.equal 0
bound.set false
expect(objectB.prop1).to.equal false
bound.set undefined
expect(objectB.prop1).to.equal false
it "can bind an object\'s property to multiple other properties", ()->
restartSandbox()
SimplyBind('prop1').of(objectA)
.to('prop1').of(objectB)
.and('prop2').of(objectB)
.and('prop3').of(objectB)
.and('prop4').of(objectB)
objectA.prop1 = 'all at once'
expect(objectB.prop1).to.equal 'all at once'
expect(objectB.prop2).to.equal 'all at once'
expect(objectB.prop3).to.equal 'all at once'
expect(objectB.prop4).to.equal 'all at once'
it "can bind two objects\' properties both ways", ()->
restartSandbox()
SimplyBind('prop2').of(objectA).to('prop2').of(objectB).bothWays()
objectA.prop2 = 'changed from objectA'
expect(objectB.prop2).to.equal 'changed from objectA'
objectB.prop2 = 'changed from objectB'
expect(objectA.prop2).to.equal 'changed from objectB'
it "can bind multiple bindings and apply the .bothWays() method only to the last binding.", ()->
restartSandbox()
SimplyBind('prop1').of(objectA).to('prop1').of(objectB).bothWays().and('prop2').of(objectB).and('prop3').of(objectB).bothWays().and('prop4').of objectB
objectA.prop1 = 'all at once'
expect(objectB.prop1).to.equal 'all at once'
expect(objectB.prop2).to.equal 'all at once'
expect(objectB.prop3).to.equal 'all at once'
expect(objectB.prop4).to.equal 'all at once'
objectB.prop1 = 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
expect(objectA.prop1).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
expect(objectB.prop2).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
expect(objectB.prop3).to.equal 'all at once'
expect(objectB.prop4).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
objectB.prop3 = 'just a few'
expect(objectA.prop1).to.equal 'just a few'
expect(objectB.prop1).to.equal 'almost all as well since objectA.prop1 gets updated and updates all of its decendents'
expect(objectB.prop2).to.equal 'just a few'
expect(objectB.prop4).to.equal 'just a few'
it "can unbind all bindings", ()->
restartSandbox()
modified = false
bound = SimplyBind('prop1').of(objectA)
.to('prop1').of(objectB).bothWays()
.and('prop2').of(objectB).bothWays()
.and('prop1').of(objectC).bothWays()
.and('prop2').of(objectC).bothWays()
.and('value').of(textarea).bothWays()
.and ()-> modified = true
expect(objectB.prop1).to.equal 'some string'
expect(objectB.prop2).to.equal 'some string'
expect(objectC.prop1).to.equal 'some string'
expect(objectC.prop2).to.equal 'some string'
expect(textarea.value).to.equal 'some string'
expect(modified).to.equal true
modified = false
bound.unBind()
objectA.prop1 = 'should change'
expect(modified).to.equal false
expect(objectB.prop1).to.equal 'should change'
expect(objectB.prop2).to.equal 'should change'
expect(objectC.prop1).to.equal 'should change'
expect(objectC.prop2).to.equal 'should change'
expect(textarea.value).to.equal 'should change'
SimplyBind.unBindAll objectA
objectA.prop1 = 'shouldn\'t change'
expect(objectB.prop1).to.equal 'should change'
expect(objectB.prop2).to.equal 'should change'
expect(objectC.prop1).to.equal 'should change'
expect(objectC.prop2).to.equal 'should change'
expect(textarea.value).to.equal 'should change'
describe "Placeholders", ()->
it "can bind an object\'s property to another\'s with a placeholder", ()->
restartSandbox()
objectB.prop1 = 'The size of this shirt is {{size}}, man!'
bound = SimplyBind('prop1').of(objectA).to('prop1.size').of(objectB)
bound.set 'Medium'
expect(objectB.prop1).to.equal 'The size of this shirt is Medium, man!'
it "shouldn\'t perform any changes if trying to update a placeholder that doesn\'t exist", ()->
restartSandbox()
objectB.prop1 = 'The size of this shirt is _____, man!'
bound = SimplyBind('prop1').of(objectA).to('prop1.size').of(objectB)
bound.set 'Medium'
expect(objectB.prop1).to.equal 'The size of this shirt is _____, man!'
it "can bind even if the value is not a string", ()->
restartSandbox()
objectB.prop1 = 'The size of this shirt is {{size}}, man!'
bound = SimplyBind('prop1').of(objectA).to('prop1.size').of(objectB)
bound.set false
expect(objectB.prop1).to.equal 'The size of this shirt is false, man!'
bound.set null
expect(objectB.prop1).to.equal 'The size of this shirt is null, man!'
bound.set {}
expect(objectB.prop1).to.equal 'The size of this shirt is [object Object], man!'
it "can bind even when the selector has extra dot-notations", ()->
restartSandbox()
objectB.prop1 = 'The size of this shirt is {{size.tedious}}, man!'
bound = SimplyBind('prop1').of(objectA).to('prop1.size.tedious').of(objectB)
bound.set 'Medium'
expect(objectB.prop1).to.equal 'The size of this shirt is Medium, man!'
it "can bind with a custom placeholder", ()->
restartSandbox()
SimplyBind.setOption 'placeholderStart', '^^'
SimplyBind.setOption 'placeholderEnd', '$$'
$inputA.val 'The size of this shirt is ^^size$$, man!'
bound = SimplyBind('prop1').of(objectA).to('value.size').of(inputA)
bound.set 'XXS'
expect($inputA.val()).to.equal 'The size of this shirt is XXS, man!'
SimplyBind.setOption 'placeholderStart', '{{'
SimplyBind.setOption 'placeholderEnd', '}}'
it "can bind multiple values to a string that has multiple placeholders", ()->
restartSandbox()
objectA.prop1 = 'The following text is {{verb}} {{nounOne}} and {{nounTwo}}'
sampleObject =
'verb': 'not'
'nounOne': 'small'
'nounTwo': 'pretty'
SimplyBind('verb').of(sampleObject).to('prop1.verb').of objectA
SimplyBind('nounOne').of(sampleObject).to('prop1.nounOne').of objectA
SimplyBind('nounTwo').of(sampleObject).to('prop1.nounTwo').of objectA
expect(objectA.prop1).to.equal 'The following text is not small and pretty'
sampleObject.verb = 'very'
sampleObject.nounOne = 'big'
sampleObject.nounTwo = 'ugly'
expect(objectA.prop1).to.equal 'The following text is very big and ugly'
sampleObject.verb = 'not'
sampleObject.nounOne = 'small'
sampleObject.nounTwo = 'pretty'
expect(objectA.prop1).to.equal 'The following text is not small and pretty'
it "can bind multiple values to a string that has multiple placeholders + transforms", ()->
restartSandbox()
objectA.prop1 = 'The following text is {{verbOne}} ({{verbTwo}}) {{nounOne}} and {{nounTwo}}'
caseMethod = 'toUpperCase'
sampleObject =
'verb': 'not'
'nounOne': 'small'
'nounTwo': 'pretty'
SimplyBind('verb').of(sampleObject)
.to('prop1.verbOne').of(objectA).transform (value)-> value[caseMethod]()
SimplyBind('verb').of(sampleObject)
.to('prop1.verbTwo').of(objectA).transform (value)-> value.toLowerCase()
SimplyBind('nounOne').of(sampleObject)
.to('prop1.nounOne').of(objectA).transform (value)-> value[caseMethod]()
SimplyBind('nounTwo').of(sampleObject)
.to('prop1.nounTwo').of(objectA).transform (value)-> value[caseMethod]()
expect(objectA.prop1).to.equal 'The following text is NOT (not) SMALL and PRETTY'
sampleObject.verb = 'Very'
sampleObject.nounOne = 'Big'
sampleObject.nounTwo = 'Ugly'
expect(objectA.prop1).to.equal 'The following text is VERY (very) BIG and UGLY'
caseMethod = 'toLowerCase'
sampleObject.verb = 'Not'
sampleObject.nounOne = 'Small'
sampleObject.nounTwo = 'Pretty'
expect(objectA.prop1).to.equal 'The following text is not (not) small and pretty'
describe "Transforms", ()->
it "can bind an object\'s property to another\'s with a transform", ()->
objectA.prop2 = 'current'
bound = SimplyBind('prop2').of(objectA).to('prop2').of(objectB).transform((newValue, currentValue)->
newValue+'+'+currentValue
)
expect(objectB.prop2).to.equal 'current+current'
objectA.prop2 = 'new'
expect(objectB.prop2).to.equal 'new+current+current'
objectA.prop2 = 'new'
expect(objectB.prop2).to.equal 'new+current+current'
objectA.prop2 = 'newer'
expect(objectB.prop2).to.equal 'newer+new+current+current'
it "can bind an object\'s property to another\'s with a promise transform that resolves async", (done)->
restartSandbox()
objectA.prop2 = 'current'
bound = SimplyBind('prop2', {'promiseTransforms':true}).of(objectA)
.to('prop2').of(objectB)
.transform (newValue, currentValue)-> new Promise (resolve)-> resolve(newValue+'+'+currentValue)
setTimeout ()->
expect(objectB.prop2).to.equal 'current+current'
objectA.prop2 = 'new'
setTimeout ()->
expect(objectB.prop2).to.equal 'new+current+current'
done()
, 0
, 0
it "can bind with a transform both ways", ()->
restartSandbox()
objectA.prop2 = 'current'
bound = SimplyBind('prop2').of(objectA).to('prop2').of(objectB).transform((newValue, currentValue)->
newValue+'+'+currentValue
).bothWays()
expect(objectB.prop2).to.equal 'current+current'
objectA.prop2 = 'new'
expect(objectB.prop2).to.equal 'new+current+current'
objectA.prop2 = 'new'
expect(objectB.prop2).to.equal 'new+current+current'
objectB.prop2 = 'new'
expect(objectA.prop2).to.equal 'new+new'
objectB.prop2 = 'newer'
expect(objectA.prop2).to.equal 'newer+new+new'
it "can bind with multiple transforms in a single chain", ()->
restartSandbox()
objectA.prop1 = 'CuRRent'
SimplyBind('prop1').of(objectA).to('prop1').of(objectB).and('prop2').of(objectB).transform((value)->
value.toUpperCase()
).and('prop3').of(objectB).transform((value)->
value.toLowerCase()
).and('prop4').of(objectB).transform (value)->
value.slice 0, 4
expect(objectA.prop1).to.equal 'CuRRent'
expect(objectB.prop1).to.equal 'CuRRent'
expect(objectB.prop2).to.equal 'CURRENT'
expect(objectB.prop3).to.equal 'current'
expect(objectB.prop4).to.equal 'CuRR'
it "can apply a single transform to all bindings in a chain", ()->
restartSandbox()
SimplyBind('prop1').of(objectA).to('prop1').of(objectB).and('prop2').of(objectB).transformAll (value)->
value.toUpperCase()
SimplyBind('prop1').of(objectA).to('prop3').of(objectB).and('prop4').of objectB
objectA.prop1 = 'all at once'
expect(objectB.prop1).to.equal 'ALL AT ONCE'
expect(objectB.prop2).to.equal 'ALL AT ONCE'
expect(objectB.prop3).to.equal 'all at once'
expect(objectB.prop4).to.equal 'all at once'
describe "Arrays", ()->
describe "As property value", ()->
it "supports live properties", ()->
restartSandbox()
SimplyBind(0).of(arrayA).to(0).of arrayB
arrayA[0] = 'live prop change :)'
expect(arrayB[0]).to.equal 'live prop change :)'
it "should avoid infinite loops", ()->
restartSandbox()
# ==== Standard objects =================================================================================
SimplyBind(0).of(arrayA).to(0).of(arrayB).bothWays()
SimplyBind(0).of(arrayB).to(0).of(arrayC).bothWays()
SimplyBind(0).of(arrayC).to(0).of(arrayA).bothWays()
arrayA[0] = 'arrayA'
expect(arrayB[0]).to.equal 'arrayA'
expect(arrayC[0]).to.equal 'arrayA'
arrayB[0] = 'arrayB'
expect(arrayA[0]).to.equal 'arrayB'
expect(arrayC[0]).to.equal 'arrayB'
it "can bind an array\'s property to another\'s", ()->
restartSandbox()
bound = SimplyBind(0).of(arrayA).to(0).of(arrayB)
bound.set 'changed'
expect(arrayB[0]).to.equal 'changed'
it "can bind an object\'s property to another\'s even if the value is falsy", ()->
restartSandbox()
bound = SimplyBind(1).of(arrayA).to(1).of(arrayB)
bound.set ''
expect(arrayB[1]).to.equal ''
bound.set 0
expect(arrayB[1]).to.equal 0
bound.set false
expect(arrayB[1]).to.equal false
bound.set undefined
expect(arrayB[1]).to.equal false
it "can bind an object\'s property to multiple other properties", ()->
restartSandbox()
SimplyBind(0).of(arrayA).to(0).of(arrayB).and(1).of(arrayB).and(2).of(arrayB).and(3).of arrayB
arrayA[0] = 'all at once'
expect(arrayB[0]).to.equal 'all at once'
expect(arrayB[1]).to.equal 'all at once'
expect(arrayB[2]).to.equal 'all at once'
expect(arrayB[3]).to.equal 'all at once'
it "can unbind all bindings", ()->
restartSandbox()
arrayA[0] = 'some string'
modified = false
bound = SimplyBind(0).of(arrayA).to('prop1').of(objectB).bothWays().and('prop2').of(objectB).bothWays().and('prop1').of(objectC).bothWays().and('prop2').of(objectC).bothWays().and('value').of(textarea).bothWays().and(()->
modified = true
)
expect(objectB.prop1).to.equal 'some string'
expect(objectB.prop2).to.equal 'some string'
expect(objectC.prop1).to.equal 'some string'
expect(objectC.prop2).to.equal 'some string'
expect(textarea.value).to.equal 'some string'
expect(modified).to.equal true
modified = false
bound.unBind()
arrayA[0] = 'should change'
expect(modified).to.equal false
expect(objectB.prop1).to.equal 'should change'
expect(objectB.prop2).to.equal 'should change'
expect(objectC.prop1).to.equal 'should change'
expect(objectC.prop2).to.equal 'should change'
expect(textarea.value).to.equal 'should change'
SimplyBind.unBindAll arrayA
arrayA[0] = 'shouldn\'t change'
expect(objectB.prop1).to.equal 'should change'
expect(objectB.prop2).to.equal 'should change'
expect(objectC.prop1).to.equal 'should change'
expect(objectC.prop2).to.equal 'should change'
expect(textarea.value).to.equal 'should change'
describe "As direct array", ()->
# it("should avoid infinite loops", function(){
# restartSandbox();
# SimplyBind(0).of(arrayA).to(0).of(arrayB).bothWays();
# SimplyBind(0).of(arrayB).to(0).of(arrayC).bothWays();
# SimplyBind(0).of(arrayC).to(0).of(arrayA).bothWays();
# arrayA[0] = 'arrayA';
# expect(arrayB[0]).to.be('arrayA');
# expect(arrayC[0]).to.be('arrayA');
# arrayB[0] = 'arrayB';
# expect(arrayA[0]).to.be('arrayB');
# expect(arrayC[0]).to.be('arrayB');
# });
it "can bind an array to anything and update dependents even when calling the .push, .pop, .shift, .unshift, .splice, .reverse, and .sort methods", ()->
sampleArray = [1,2,3,4,5,6,7,8,9,10]
mutations = 0
SimplyBind(sampleArray).to('prop4').of(objectB).and ()-> mutations++
expect(objectB.prop4.length).to.equal 10
expect(mutations).to.equal 1
sampleArray.push 11
expect(objectB.prop4.length).to.equal 11
expect(mutations).to.equal 2
sampleArray.shift()
sampleArray.shift()
expect(objectB.prop4.length).to.equal 9
expect(mutations).to.equal 4
sampleArray.unshift 2
sampleArray.unshift 1
expect(objectB.prop4.length).to.equal 11
expect(mutations).to.equal 6
sampleArray.pop()
sampleArray.pop()
expect(objectB.prop4.length).to.equal 9
expect(mutations).to.equal 8
sampleArray.splice 0, 5
expect(objectB.prop4.length).to.equal 4
expect(mutations).to.equal 9
sampleArray.reverse()
expect(objectB.prop4.length).to.equal 4
expect(mutations).to.equal 10
sampleArray.sort()
expect(objectB.prop4.length).to.equal 4
expect(mutations).to.equal 11
sampleArray.sort ()->
1
expect(objectB.prop4.length).to.equal 4
expect(mutations).to.equal 12
it "it\'s impossible to replace the array object in an array binding.", ()->
sampleArray = [1,2,3,4,5,6,7,8,9,10]
mutations = 0
SimplyBind(sampleArray).to('prop4').of(objectB).and ()-> mutations++
expect(objectB.prop4.length).to.equal 10
expect(mutations).to.equal 1
SimplyBind(sampleArray).set [1,2,3,4,5,6,7,8,9,10]
# Replace array. If it were to replace it, the mutations count will increase by one.
SimplyBind(sampleArray).set [1,2,3,4,5,6,7,8,9,10]
SimplyBind(sampleArray).set [1,2,3,4,5,6,7,8,9,10]
sampleArray.push 11
expect(objectB.prop4.length).to.equal 11
expect(mutations).to.equal 2
sampleArray.shift()
sampleArray.shift()
expect(objectB.prop4.length).to.equal 9
expect(mutations).to.equal 4
sampleArray.unshift 2
sampleArray.unshift 1
expect(objectB.prop4.length).to.equal 11
expect(mutations).to.equal 6
sampleArray.pop()
sampleArray.pop()
expect(objectB.prop4.length).to.equal 9
expect(mutations).to.equal 8
sampleArray.splice 0, 5
expect(objectB.prop4.length).to.equal 4
expect(mutations).to.equal 9
it "will update dependents when its children get modified if specified via the trackArrayChildren option", ()->
sampleArray = [1,2,3,4,5,6,7,8,9,10]
sampleArray2 = [1,2,3,4,5,6,7,8,9,10]
mutations = 0
SimplyBind(sampleArray).to('prop5').of(objectA).and ()-> mutations++
expect(objectA.prop5).to.equal sampleArray
sampleArray[0] = 100
sampleArray[1] = 200
sampleArray[2] = 300
expect(objectA.prop5[0]).to.equal 100
expect(objectA.prop5[1]).to.equal 200
expect(objectA.prop5[2]).to.equal 300
expect(mutations).to.equal 1
mutations = 0
SimplyBind(sampleArray2, 'trackArrayChildren': true).to('prop6').of(objectA).and ()-> mutations++
expect(objectA.prop6).to.equal sampleArray2
sampleArray2[0] = 100
sampleArray2[1] = 200
sampleArray2[2] = 300
expect(objectA.prop6[0]).to.equal 100
expect(objectA.prop6[1]).to.equal 200
expect(objectA.prop6[2]).to.equal 300
expect(mutations).to.equal 4
it "will update dependents even when there is a sepearate binding on a reference of the same array", ()->
sampleArrayA = [1,2,3,4,5,6,7,8,9,10]
sampleArrayB = sampleArrayA
sampleArrayC = null
mutationsA = 0
mutationsB = 0
mutationsC = 0
SimplyBind(sampleArrayA)
.to('prop6').of(objectA)
.and ()-> mutationsA++
SimplyBind(sampleArrayB)
.to('prop6').of(objectB)
.and (arr)-> sampleArrayC = arr unless sampleArrayC
.a