2014-09-17 20:47:30 +04:00
|
|
|
ViewRegistry = require '../src/view-registry'
|
|
|
|
|
2015-07-23 21:03:11 +03:00
|
|
|
describe "ViewRegistry", ->
|
2014-09-17 20:47:30 +04:00
|
|
|
registry = null
|
|
|
|
|
|
|
|
beforeEach ->
|
|
|
|
registry = new ViewRegistry
|
|
|
|
|
2015-07-21 21:09:23 +03:00
|
|
|
afterEach ->
|
|
|
|
registry.clearDocumentRequests()
|
|
|
|
|
2014-09-17 20:47:30 +04:00
|
|
|
describe "::getView(object)", ->
|
|
|
|
describe "when passed a DOM node", ->
|
|
|
|
it "returns the given DOM node", ->
|
|
|
|
node = document.createElement('div')
|
|
|
|
expect(registry.getView(node)).toBe node
|
|
|
|
|
2015-08-18 22:38:00 +03:00
|
|
|
describe "when passed an object with an element property", ->
|
|
|
|
it "returns the element property if it's an instance of HTMLElement", ->
|
|
|
|
class TestComponent
|
|
|
|
constructor: -> @element = document.createElement('div')
|
|
|
|
|
|
|
|
component = new TestComponent
|
|
|
|
expect(registry.getView(component)).toBe component.element
|
|
|
|
|
2016-03-01 18:56:03 +03:00
|
|
|
describe "when passed an object with a getElement function", ->
|
|
|
|
it "returns the return value of getElement if it's an instance of HTMLElement", ->
|
|
|
|
class TestComponent
|
|
|
|
getElement: ->
|
|
|
|
@myElement ?= document.createElement('div')
|
|
|
|
|
|
|
|
component = new TestComponent
|
|
|
|
expect(registry.getView(component)).toBe component.myElement
|
|
|
|
|
2014-09-17 20:47:30 +04:00
|
|
|
describe "when passed a model object", ->
|
2014-09-17 20:58:46 +04:00
|
|
|
describe "when a view provider is registered matching the object's constructor", ->
|
2014-12-02 04:53:03 +03:00
|
|
|
it "constructs a view element and assigns the model on it", ->
|
|
|
|
class TestModel
|
2014-09-17 20:58:46 +04:00
|
|
|
|
2014-12-02 04:53:03 +03:00
|
|
|
class TestModelSubclass extends TestModel
|
2014-09-17 20:58:46 +04:00
|
|
|
|
2014-12-02 04:53:03 +03:00
|
|
|
class TestView
|
|
|
|
initialize: (@model) -> this
|
2014-09-17 20:58:46 +04:00
|
|
|
|
2014-12-02 04:53:03 +03:00
|
|
|
model = new TestModel
|
2014-09-17 20:58:46 +04:00
|
|
|
|
2014-12-02 04:53:03 +03:00
|
|
|
registry.addViewProvider TestModel, (model) ->
|
|
|
|
new TestView().initialize(model)
|
2014-09-17 20:58:46 +04:00
|
|
|
|
2014-12-02 04:53:03 +03:00
|
|
|
view = registry.getView(model)
|
|
|
|
expect(view instanceof TestView).toBe true
|
|
|
|
expect(view.model).toBe model
|
2014-09-17 20:58:46 +04:00
|
|
|
|
2014-12-02 04:53:03 +03:00
|
|
|
subclassModel = new TestModelSubclass
|
|
|
|
view2 = registry.getView(subclassModel)
|
|
|
|
expect(view2 instanceof TestView).toBe true
|
|
|
|
expect(view2.model).toBe subclassModel
|
2014-09-20 01:25:35 +04:00
|
|
|
|
2015-11-20 02:54:47 +03:00
|
|
|
describe "when a view provider is registered generically, and works with the object", ->
|
|
|
|
it "constructs a view element and assigns the model on it", ->
|
|
|
|
model = {a: 'b'}
|
|
|
|
|
|
|
|
registry.addViewProvider (model) ->
|
|
|
|
if model.a is 'b'
|
|
|
|
element = document.createElement('div')
|
|
|
|
element.className = 'test-element'
|
|
|
|
element
|
|
|
|
|
|
|
|
view = registry.getView({a: 'b'})
|
|
|
|
expect(view.className).toBe 'test-element'
|
|
|
|
|
|
|
|
expect(-> registry.getView({a: 'c'})).toThrow()
|
|
|
|
|
2014-09-17 20:47:30 +04:00
|
|
|
describe "when no view provider is registered for the object's constructor", ->
|
2015-09-04 02:24:18 +03:00
|
|
|
it "throws an exception", ->
|
|
|
|
expect(-> registry.getView(new Object)).toThrow()
|
2014-09-20 00:44:25 +04:00
|
|
|
|
|
|
|
describe "::addViewProvider(providerSpec)", ->
|
2014-09-20 01:20:35 +04:00
|
|
|
it "returns a disposable that can be used to remove the provider", ->
|
2014-09-20 00:44:25 +04:00
|
|
|
class TestModel
|
|
|
|
class TestView
|
2014-12-02 04:53:03 +03:00
|
|
|
initialize: (@model) -> this
|
|
|
|
|
|
|
|
disposable = registry.addViewProvider TestModel, (model) ->
|
|
|
|
new TestView().initialize(model)
|
2014-09-20 00:44:25 +04:00
|
|
|
|
|
|
|
expect(registry.getView(new TestModel) instanceof TestView).toBe true
|
|
|
|
disposable.dispose()
|
|
|
|
expect(-> registry.getView(new TestModel)).toThrow()
|
2015-02-20 00:26:39 +03:00
|
|
|
|
|
|
|
describe "::updateDocument(fn) and ::readDocument(fn)", ->
|
|
|
|
frameRequests = null
|
|
|
|
|
|
|
|
beforeEach ->
|
|
|
|
frameRequests = []
|
|
|
|
spyOn(window, 'requestAnimationFrame').andCallFake (fn) -> frameRequests.push(fn)
|
|
|
|
|
|
|
|
it "performs all pending writes before all pending reads on the next animation frame", ->
|
|
|
|
events = []
|
|
|
|
|
|
|
|
registry.updateDocument -> events.push('write 1')
|
|
|
|
registry.readDocument -> events.push('read 1')
|
|
|
|
registry.readDocument -> events.push('read 2')
|
|
|
|
registry.updateDocument -> events.push('write 2')
|
|
|
|
|
|
|
|
expect(events).toEqual []
|
|
|
|
|
|
|
|
expect(frameRequests.length).toBe 1
|
|
|
|
frameRequests[0]()
|
|
|
|
expect(events).toEqual ['write 1', 'write 2', 'read 1', 'read 2']
|
|
|
|
|
|
|
|
frameRequests = []
|
|
|
|
events = []
|
|
|
|
disposable = registry.updateDocument -> events.push('write 3')
|
|
|
|
registry.updateDocument -> events.push('write 4')
|
|
|
|
registry.readDocument -> events.push('read 3')
|
|
|
|
|
|
|
|
disposable.dispose()
|
|
|
|
|
|
|
|
expect(frameRequests.length).toBe 1
|
|
|
|
frameRequests[0]()
|
|
|
|
expect(events).toEqual ['write 4', 'read 3']
|
|
|
|
|
2015-04-21 06:59:13 +03:00
|
|
|
it "performs writes requested from read callbacks in the same animation frame", ->
|
|
|
|
spyOn(window, 'setInterval').andCallFake(fakeSetInterval)
|
|
|
|
spyOn(window, 'clearInterval').andCallFake(fakeClearInterval)
|
|
|
|
events = []
|
|
|
|
|
|
|
|
registry.updateDocument -> events.push('write 1')
|
|
|
|
registry.readDocument ->
|
|
|
|
registry.updateDocument -> events.push('write from read 1')
|
|
|
|
events.push('read 1')
|
|
|
|
registry.readDocument ->
|
|
|
|
registry.updateDocument -> events.push('write from read 2')
|
|
|
|
events.push('read 2')
|
|
|
|
registry.updateDocument -> events.push('write 2')
|
|
|
|
|
|
|
|
expect(frameRequests.length).toBe 1
|
|
|
|
frameRequests[0]()
|
|
|
|
expect(frameRequests.length).toBe 1
|
|
|
|
|
|
|
|
expect(events).toEqual [
|
|
|
|
'write 1'
|
|
|
|
'write 2'
|
|
|
|
'read 1'
|
|
|
|
'read 2'
|
|
|
|
'write from read 1'
|
|
|
|
'write from read 2'
|
|
|
|
]
|
|
|
|
|
2015-10-24 03:13:30 +03:00
|
|
|
describe "::getNextUpdatePromise()", ->
|
|
|
|
it "returns a promise that resolves at the end of the next update cycle", ->
|
|
|
|
updateCalled = false
|
|
|
|
readCalled = false
|
|
|
|
|
|
|
|
waitsFor 'getNextUpdatePromise to resolve', (done) ->
|
|
|
|
registry.getNextUpdatePromise().then ->
|
|
|
|
expect(updateCalled).toBe true
|
|
|
|
expect(readCalled).toBe true
|
|
|
|
done()
|
|
|
|
|
|
|
|
registry.updateDocument -> updateCalled = true
|
|
|
|
registry.readDocument -> readCalled = true
|