PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/test/client.coffee

https://github.com/setdirection/viewjs
CoffeeScript | 478 lines | 410 code | 53 blank | 15 comment | 2 complexity | dff7f445e1d72baf3bae92dd518e5fe5 MD5 | raw file
  1. assert = require 'assert'
  2. {View,Builder,Router,RouteResolver} = require './view.client.js'
  3. {jsdom} = require 'jsdom'
  4. jQuery = require 'jquery'
  5. Backbone = require 'backbone'
  6. global.Backbone = Backbone
  7. array_from = (object) ->
  8. return [] if not object
  9. length = object.length or 0
  10. results = new Array length
  11. while length--
  12. results[length] = object[length]
  13. results
  14. View.extend
  15. env:
  16. set:test: true
  17. document: jsdom '<html><head></head><body></body></html>'
  18. module.exports.parses = ->
  19. assert.ok(true)
  20. module.exports.stack = (before_exit) ->
  21. i = 0
  22. sequence = []
  23. {StackView} = View.create
  24. StackView:
  25. stack:initialize:add: (next) ->
  26. sequence.push 'a'
  27. @a = 'a'
  28. ++i
  29. next()
  30. StackView.extend stack:initialize:add: (next) ->
  31. sequence.push 'b'
  32. @b = 'b'
  33. ++i
  34. next()
  35. StackView.initialize ->
  36. before_exit ->
  37. assert.equal StackView._stack.initialize.stack.length, 3
  38. assert.equal 2, i
  39. assert.equal StackView.a, 'a'
  40. assert.equal StackView.b, 'b'
  41. assert.equal sequence[0], 'a'
  42. assert.equal sequence[1], 'b'
  43. module.exports.envBasics = ->
  44. View.env set:
  45. a: false
  46. b: -> true
  47. call_count = 0
  48. View.env
  49. a: ->
  50. ++call_count
  51. b: ->
  52. ++call_count
  53. assert.equal call_count, 1
  54. View.extend env:set:
  55. a: -> true
  56. b: false
  57. View.env
  58. a: ->
  59. ++call_count
  60. assert.equal call_count, 2
  61. View.env
  62. b: ->
  63. ++call_count
  64. assert.equal call_count, 2
  65. #non-existent env will not be called
  66. View.env c: ->
  67. ++call_count
  68. assert.equal call_count, 2
  69. module.exports.canDeferViewManagerCallback = ->
  70. call_count = 0
  71. View QuantumView: ->
  72. ++call_count
  73. View.create QuantumView: {}
  74. assert.equal call_count, 1
  75. module.exports.canTriggerEvents = ->
  76. {TestView} = View.create TestView: {}
  77. i = 0
  78. TestView.bind 'test', -> ++i
  79. TestView.trigger 'test'
  80. assert.equal i, 1
  81. module.exports.canDetectModel = (before_exit) ->
  82. _model = false
  83. model = new Backbone.Model
  84. model.set key: 'value'
  85. {ModelView} = View.create ModelView:
  86. model: model
  87. initialize: (next) ->
  88. _model = @model
  89. next()
  90. ModelView.initialize -> before_exit ->
  91. assert.equal ModelView.model, model
  92. assert.equal _model, model
  93. module.exports.canDetectCollection = (before_exit) ->
  94. _collection = false
  95. collection = new Backbone.Collection
  96. {CollectionView} = View.create CollectionView:
  97. collection: collection
  98. initialize: (next) ->
  99. _collection = @collection
  100. next()
  101. CollectionView.initialize ->
  102. before_exit ->
  103. assert.equal CollectionView.collection, collection
  104. assert.equal CollectionView.collection, _collection
  105. module.exports.canRender = ->
  106. {BuilderView} = View.create BuilderView: [Builder,
  107. render: ->
  108. @p 'test'
  109. on:ready: ->
  110. assert.equal @[0].firstChild.innerHTML, 'test'
  111. ]
  112. View BuilderView: -> @initialize()
  113. module.exports.canRenderCollection = ->
  114. Item = Backbone.Model.extend()
  115. List = new (Backbone.Collection.extend(model: Item))
  116. render_count = 0
  117. contents = [
  118. {content: 'One'}
  119. {content: 'Two'}
  120. {content: 'Three'}
  121. ]
  122. List.add array_from contents
  123. {ListView} = View.create ListView:
  124. collection: List
  125. element: -> @tag 'ul'
  126. render: (item) ->
  127. ++render_count
  128. @tag 'li', item.get 'content'
  129. ListView.initialize ->
  130. assert.equal @[0].tagName.toLowerCase(), 'ul'
  131. assert.equal render_count, 3
  132. assert.equal ListView[0].childNodes.length, 3
  133. assert.equal ListView[0].firstChild.innerHTML, 'One'
  134. List.remove List.at(0)
  135. assert.equal render_count, 3
  136. assert.equal ListView[0].childNodes.length, 2
  137. assert.equal ListView[0].firstChild.innerHTML, 'Two'
  138. List.add content: 'Four'
  139. assert.equal render_count, 4
  140. assert.equal ListView[0].childNodes.length, 3
  141. assert.equal ListView[0].firstChild.innerHTML, 'Two'
  142. assert.equal ListView[0].childNodes[2].innerHTML, 'Four'
  143. List.refresh contents
  144. assert.equal render_count, 7
  145. assert.equal ListView[0].childNodes.length, 3
  146. assert.equal ListView[0].firstChild.innerHTML, 'One'
  147. assert.equal ListView[0].childNodes[2].innerHTML, 'Three'
  148. module.exports.viewManager = ->
  149. View.create TestView2: key: 'value'
  150. View.create TestView3: key: 'value2'
  151. [TestView2,TestView3] = View ['TestView2', 'TestView3']
  152. assert.equal TestView2.key, 'value'
  153. assert.equal TestView3.key, 'value2'
  154. module.exports.canUseCreateAsCallback = ->
  155. instance = View.create ->
  156. @key = 'value'
  157. assert.equal instance.key, 'value'
  158. module.exports.canDepend = ->
  159. sequence = []
  160. View.create
  161. ParentView:
  162. views: ['ChildView1','ChildView2','ChildView3']
  163. initialize: (next) ->
  164. assert.equal @ChildView1.name, 'ChildView1'
  165. assert.equal @ChildView2.name, 'ChildView2'
  166. assert.equal @ChildView3.name, 'ChildView3'
  167. next()
  168. ChildView1:
  169. name: 'ChildView1'
  170. render: ->
  171. sequence.push 'a'
  172. @document.createElement 'div'
  173. ChildView2:
  174. name: 'ChildView2'
  175. render: ->
  176. sequence.push 'b'
  177. @document.createElement 'div'
  178. ChildView3:
  179. name: 'ChildView3'
  180. render: ->
  181. sequence.push 'c'
  182. @document.createElement 'div'
  183. View ParentView: ->
  184. @initialize()
  185. @on ready: ->
  186. assert.equal sequence[0], 'a'
  187. assert.equal sequence[1], 'b'
  188. assert.equal sequence[2], 'c'
  189. module.exports.canDependAsync = (before_exit) ->
  190. View.create
  191. AsyncParentView: [Builder,
  192. views: ['AsyncChildView1','AsyncChildView2']
  193. initialize: (next) ->
  194. setTimeout next, 50
  195. render: ->
  196. @ul @AsyncChildView1, @AsyncChildView2
  197. ]
  198. AsyncChildView1: [Builder,
  199. initialize: (next) ->
  200. setTimeout next, 1
  201. render: ->
  202. @li 'A'
  203. ]
  204. AsyncChildView2: [Builder,
  205. initialize: (next) ->
  206. setTimeout next, 100
  207. render: ->
  208. @li 'B'
  209. ]
  210. View AsyncParentView: ->
  211. @initialize()
  212. @on ready: ->
  213. before_exit =>
  214. assert.equal jQuery('li:first',@[0]).html(), 'A'
  215. module.exports.canPassViewsToBuilder = ->
  216. {OuterView} = View.create OuterView: [Builder,
  217. initialize: (next) ->
  218. InnerView.on ready: next
  219. InnerView.initialize()
  220. render: ->
  221. @div InnerView, class: 'test'
  222. on:ready: ->
  223. assert.equal @[0].firstChild.firstChild.firstChild.innerHTML, 'test'
  224. ]
  225. {InnerView} = View.create InnerView: [Builder,
  226. render: ->
  227. @p 'test'
  228. ]
  229. OuterView.initialize()
  230. module.exports.canDiscardMixin = ->
  231. View.extend extend:discard: (value,discard) ->
  232. @discard = value
  233. discard()
  234. {DiscardView} = View.create
  235. DiscardView: {}
  236. DiscardView.extend
  237. discard: 'discard'
  238. {DiscardChildView} = DiscardView.create DiscardChildView: {}
  239. assert.equal DiscardView.discard, 'discard'
  240. assert.equal typeof DiscardChildView.discard, 'undefined'
  241. module.exports.canObserveKeyChanges = ->
  242. _a = ''
  243. _b = ''
  244. _c = ''
  245. {KeyChangeView} = View.create KeyChangeView:
  246. on:
  247. change:
  248. a: (a) -> _a = a
  249. b: (b) -> _b = b
  250. KeyChangeView.bind 'change:c', (c) -> _c = c
  251. KeyChangeView.set a: 'a', b: 'b', c: 'c'
  252. assert.equal _a, 'a'
  253. assert.equal _b, 'b'
  254. assert.equal _c, 'c'
  255. module.exports.canHaveDefaults = ->
  256. {DefaultsView} = View.create DefaultsView:
  257. defaults:
  258. key: 'value'
  259. assert.equal DefaultsView.get('key'), 'value'
  260. assert.equal DefaultsView.create().get('key'), 'value'
  261. module.exports.canUseArrayInBuilder = (before_exit) ->
  262. {ArrayBuilderViewA,ArrayBuilderViewB,ArrayBuilderViewC} = View.create
  263. ArrayBuilderViewA:
  264. views: ['ArrayBuilderViewB','ArrayBuilderViewC']
  265. render: ->
  266. @tag 'ul', [@ArrayBuilderViewB,@ArrayBuilderViewC]
  267. ArrayBuilderViewB:
  268. render: ->
  269. @tag 'li', 'b'
  270. ArrayBuilderViewC:
  271. render: ->
  272. @tag 'li', 'c'
  273. ArrayBuilderViewA.initialize ->
  274. before_exit =>
  275. assert.ok @[0].firstChild.firstChild?
  276. assert.equal @[0].firstChild.firstChild.firstChild.innerHTML, 'b'
  277. module.exports.router = (before_exit) ->
  278. #initial call sets
  279. View.extend routes: {
  280. '/': 'IndexView'
  281. '/post/:id?': 'PostView'
  282. '/:a/:b/:c?': 'AlphabetView'
  283. }
  284. View.extend
  285. env:set:
  286. server: -> false
  287. browser: -> false
  288. #views should be auto assigned routes after they are created
  289. #if they didn't exist at the time the router was called
  290. post_view_render_count = 0
  291. index_view_render_count = 0
  292. {PostView,IndexView,ContainerView} = View.create
  293. SidebarView:
  294. render: ->
  295. @tag 'div', class: 'sidebar'
  296. PostView:
  297. on:
  298. change:id: ->
  299. @render()
  300. render: ->
  301. ++post_view_render_count
  302. @tag 'div', 'post'
  303. IndexView:
  304. render: ->
  305. ++index_view_render_count
  306. @tag 'div', 'index'
  307. ContainerView: [Router,
  308. views: ['SidebarView']
  309. render: ->
  310. element = @tag('div'
  311. @SidebarView
  312. @tag('div',
  313. @Router
  314. )
  315. )
  316. element
  317. ]
  318. AlphabetView: {}
  319. #can turn a url into parsed view and params
  320. #can turn an object with params into a url
  321. assert.deepEqual '/post/5', RouteResolver PostView: id: 5
  322. assert.deepEqual {PostView: id: "5"}, RouteResolver '/post/5'
  323. assert.deepEqual '/', RouteResolver IndexView: {}
  324. assert.deepEqual {IndexView: {}}, RouteResolver '/'
  325. assert.deepEqual {AlphabetView: {a:'a',b:'b',c:'c'}}, RouteResolver '/a/b/c'
  326. assert.deepEqual {AlphabetView: {a:'a',b:'b',c:'c'}}, RouteResolver '/a/b/c'
  327. assert.deepEqual '/a/b/', RouteResolver {AlphabetView: {a:'a',b:'b'}}
  328. #router can resolve ordered params
  329. assert.equal '/a/b/c', RouteResolver(AlphabetView: ['a','b','c'])
  330. #view can generate a url for itself
  331. assert.equal '/post/5', PostView.url id: 5
  332. assert.equal '/', IndexView.url()
  333. assert.equal '/post/5', IndexView.url PostView: id: 5
  334. assert.equal '/', RouteResolver 'IndexView'
  335. #should have route auto set
  336. callback_count = 0
  337. ContainerView.initialize ->
  338. #use as dispatcher
  339. RouteResolver '/post/5', (view,params) ->
  340. #callback should only be called after
  341. assert.equal view.get('id'), '5'
  342. assert.ok PostView.element().style.display isnt 'none'
  343. assert.ok IndexView.element().style.display is 'none'
  344. ++callback_count
  345. #dispatcher can take object argument
  346. RouteResolver {IndexView: {}}, (view,params) ->
  347. assert.ok IndexView.element().style.display isnt 'none'
  348. assert.ok PostView.element().style.display is 'none'
  349. ++callback_count
  350. #dispatcher can take ordered param argument
  351. RouteResolver {PostView:['4']}, (view,params) ->
  352. assert.equal view.get('id'), '4'
  353. assert.ok PostView.element().style.display isnt 'none'
  354. assert.ok IndexView.element().style.display is 'none'
  355. ++callback_count
  356. #IndexView should not re-render
  357. RouteResolver {IndexView: {}}, (view,params) ->
  358. assert.ok IndexView.element().style.display isnt 'none'
  359. assert.ok PostView.element().style.display is 'none'
  360. ++callback_count
  361. #default logic of hiding siblings can be disabled
  362. PostView.unbind 'route'
  363. RouteResolver {PostView: id: 4}, (view,params) ->
  364. assert.ok IndexView.element().style.display is 'none'
  365. assert.ok PostView.element().style.display isnt 'none'
  366. ++callback_count
  367. before_exit ->
  368. assert.equal 5, callback_count
  369. assert.equal 4, post_view_render_count
  370. assert.equal 1, index_view_render_count
  371. View.extend
  372. env:
  373. server: -> true
  374. browser: -> false
  375. module.exports.canPassDataInitialize = (before_exit) ->
  376. model = new Backbone.Model
  377. collection = new Backbone.Collection
  378. attributes = {key:'value'}
  379. model_view = View.create()
  380. model_view.initialize model, ->
  381. assert.equal model_view.model, model
  382. collection_view = View.create()
  383. collection_view.initialize collection, ->
  384. assert.equal collection_view.collection, collection
  385. attributes_view = View.create()
  386. attributes_view.initialize attributes, ->
  387. before_exit ->
  388. assert.equal attributes.key, attributes_view.get 'key'
  389. module.exports.canUse$InBuilder = (before_exit) ->
  390. click_count = 0
  391. {$BuilderView} = View.create $BuilderView: [Builder,
  392. $: jQuery
  393. delegate:
  394. 'click div': ->
  395. ++click_count
  396. click:
  397. div: ->
  398. ++click_count
  399. render: ->
  400. @key = 'test'
  401. @table(
  402. @tr(
  403. @td(),
  404. @td(
  405. @div().click =>
  406. ++click_count
  407. assert.equal @key, 'test'
  408. )
  409. )
  410. )
  411. ]
  412. $BuilderView.initialize -> before_exit ->
  413. $BuilderView.$('div').trigger('click')
  414. assert.equal click_count, 3
  415. assert.equal $BuilderView.$('td').length, 2
  416. module.exports.canReverseLookup = ->
  417. {ReverseLookupView} = View.create ReverseLookupView:
  418. $: jQuery
  419. ReverseLookupView.initialize ->
  420. assert.equal jQuery(@).view().name, 'ReverseLookupView'
  421. assert.equal @$.view().name, 'ReverseLookupView'
  422. module.exports.anonViewHasElement = ->
  423. anon = View.create()
  424. assert.ok anon[0]
  425. assert.equal anon[0].tagName, 'DIV'