joosy 0.1.0.RC1 → 0.1.0.RC2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. data/Gemfile +1 -0
  2. data/Gemfile.lock +8 -1
  3. data/MIT-LICENSE +2 -2
  4. data/README.md +89 -0
  5. data/app/assets/javascripts/joosy/core/application.js.coffee +25 -5
  6. data/app/assets/javascripts/joosy/core/form.js.coffee +212 -22
  7. data/app/assets/javascripts/joosy/core/helpers.js.coffee +11 -1
  8. data/app/assets/javascripts/joosy/core/joosy.js.coffee +22 -17
  9. data/app/assets/javascripts/joosy/core/layout.js.coffee +17 -7
  10. data/app/assets/javascripts/joosy/core/modules/container.js.coffee +19 -15
  11. data/app/assets/javascripts/joosy/core/modules/events.js.coffee +10 -9
  12. data/app/assets/javascripts/joosy/core/modules/filters.js.coffee +16 -12
  13. data/app/assets/javascripts/joosy/core/modules/log.js.coffee +8 -5
  14. data/app/assets/javascripts/joosy/core/modules/module.js.coffee +31 -21
  15. data/app/assets/javascripts/joosy/core/modules/renderer.js.coffee +114 -51
  16. data/app/assets/javascripts/joosy/core/modules/time_manager.js.coffee +2 -2
  17. data/app/assets/javascripts/joosy/core/modules/widgets_manager.js.coffee +10 -10
  18. data/app/assets/javascripts/joosy/core/page.js.coffee +31 -21
  19. data/app/assets/javascripts/joosy/core/preloader.js.coffee +3 -3
  20. data/app/assets/javascripts/joosy/core/resource/collection.js.coffee +137 -0
  21. data/app/assets/javascripts/joosy/core/resource/generic.js.coffee +178 -13
  22. data/app/assets/javascripts/joosy/core/resource/rest.js.coffee +167 -44
  23. data/app/assets/javascripts/joosy/core/resource/rest_collection.js.coffee +100 -32
  24. data/app/assets/javascripts/joosy/core/router.js.coffee +23 -25
  25. data/app/assets/javascripts/joosy/core/templaters/rails_jst.js.coffee +19 -3
  26. data/app/assets/javascripts/joosy/core/widget.js.coffee +7 -9
  27. data/app/assets/javascripts/joosy/preloaders/caching.js.coffee +117 -57
  28. data/app/assets/javascripts/joosy/preloaders/inline.js.coffee +23 -24
  29. data/app/helpers/joosy/sprockets_helper.rb +1 -1
  30. data/lib/joosy/forms.rb +2 -12
  31. data/lib/joosy/rails/version.rb +1 -1
  32. data/lib/rails/generators/joosy/templates/app/pages/template.js.coffee +1 -1
  33. data/lib/rails/generators/joosy/templates/app/resources/template.js.coffee +1 -1
  34. data/spec/javascripts/joosy/core/form_spec.js.coffee +55 -12
  35. data/spec/javascripts/joosy/core/layout_spec.js.coffee +1 -1
  36. data/spec/javascripts/joosy/core/modules/container_spec.js.coffee +0 -1
  37. data/spec/javascripts/joosy/core/modules/module_spec.js.coffee +1 -1
  38. data/spec/javascripts/joosy/core/modules/renderer_spec.js.coffee +39 -3
  39. data/spec/javascripts/joosy/core/modules/time_manager_spec.js.coffee +1 -1
  40. data/spec/javascripts/joosy/core/page_spec.js.coffee +4 -1
  41. data/spec/javascripts/joosy/core/resource/collection_spec.js.coffee +84 -0
  42. data/spec/javascripts/joosy/core/resource/generic_spec.js.coffee +86 -3
  43. data/spec/javascripts/joosy/core/resource/rest_collection_spec.js.coffee +15 -22
  44. data/spec/javascripts/joosy/core/resource/rest_spec.js.coffee +27 -4
  45. data/spec/javascripts/joosy/core/widget_spec.js.coffee +3 -14
  46. metadata +21 -19
  47. data/README.rdoc +0 -3
@@ -3,7 +3,7 @@ describe "Joosy.Form", ->
3
3
  beforeEach ->
4
4
  @server = sinon.fakeServer.create()
5
5
  @seedGround()
6
- @nudeForm = "<form id='nude'><input name='test[foo]'/><input name='test[bar]'/></form>"
6
+ @nudeForm = "<form id='nude'><input name='test[foo]'/><input name='test[bar]'/><input name='test[bool]' type='checkbox' value='1'/></form>"
7
7
  @putForm = "<form id='put' method='put'><input name='test[camel_baz]'/></form>"
8
8
  @moreForm = "<form id='more' method='put'><input name='test[ololo]'/></form>"
9
9
 
@@ -20,6 +20,7 @@ describe "Joosy.Form", ->
20
20
  foo: 'foo',
21
21
  bar: 'bar'
22
22
  camelBaz: 'baz'
23
+ bool: true
23
24
 
24
25
  afterEach ->
25
26
  @server.restore()
@@ -36,7 +37,7 @@ describe "Joosy.Form", ->
36
37
  formWithProperties = new Joosy.Form @nudeForm, invalidationClass: 'fluffy'
37
38
  expect(formWithProperties.container).toEqual @nudeForm
38
39
  expect(formWithProperties.invalidationClass).toEqual 'fluffy'
39
- expect(formWithProperties.fields.length).toEqual 2
40
+ expect(formWithProperties.fields.length).toEqual 3
40
41
 
41
42
  expect(@spy.callCount).toEqual 1
42
43
 
@@ -63,12 +64,15 @@ describe "Joosy.Form", ->
63
64
  @putForm = new Joosy.Form @putForm
64
65
  @moreForm = new Joosy.Form @moreForm
65
66
 
66
- it "should fill form and set propert action and method", ->
67
+ it "should fill form, set propert action and method and store resource", ->
67
68
  @nudeForm.fill @resource
68
69
  expect(@nudeForm.fields[0].value).toEqual 'foo'
69
70
  expect(@nudeForm.fields[1].value).toEqual 'bar'
71
+ expect(@nudeForm.fields[2].checked).toEqual true
72
+ expect(@nudeForm.fields[2].value).toEqual '1'
70
73
  expect(@nudeForm.container.attr('method').toLowerCase()).toEqual 'post'
71
74
  expect(@nudeForm.container.attr 'action').toEqual '/tests/'
75
+ expect(@nudeForm.__resource).toEqual @resource
72
76
 
73
77
  it "should fill form with camelized properties", ->
74
78
  @putForm.fill @resource
@@ -83,6 +87,7 @@ describe "Joosy.Form", ->
83
87
  expect(@moreForm.fields[0].value).toEqual 'baz'
84
88
 
85
89
  describe "Callbacks", ->
90
+
86
91
  beforeEach ->
87
92
  @nudeForm = new Joosy.Form @nudeForm, @spy=sinon.spy()
88
93
  @nudeForm.fill @resource
@@ -97,33 +102,33 @@ describe "Joosy.Form", ->
97
102
  expect(@spy.args[0][0]).toEqual {form: 'works'}
98
103
 
99
104
  it "should fill class for invalidated fields by default", ->
100
- @target.respond 422, 'Content-Type': 'application/json', '{"test[foo]": "error!"}'
105
+ @target.respond 422, 'Content-Type': 'application/json', '{"foo": "error!"}'
101
106
  expect($(@nudeForm.fields[0]).attr 'class').toEqual 'field_with_errors'
102
107
 
103
108
  it "should trigger 'error' and complete default action if it returned true", ->
104
109
  @nudeForm.error = sinon.spy ->
105
110
  true
106
- @target.respond 422, 'Content-Type': 'application/json', '{"test[foo]": "error!"}'
111
+ @target.respond 422, 'Content-Type': 'application/json', '{"foo": "error!"}'
107
112
  expect($(@nudeForm.fields[0]).attr 'class').toEqual 'field_with_errors'
108
113
  expect(@nudeForm.error.callCount).toEqual 1
109
- expect(@nudeForm.error.args[0][0]).toEqual Object.extended
110
- "test[foo]": "error!"
114
+ expect(@nudeForm.error.args[0][0]).toEqual
115
+ "foo": "error!"
111
116
 
112
117
  it "should trigger 'error' and skip default action if it returned false", ->
113
118
  @nudeForm.error = sinon.spy ->
114
119
  false
115
- @target.respond 422, 'Content-Type': 'application/json', '{"test[foo]": "error!"}'
120
+ @target.respond 422, 'Content-Type': 'application/json', '{"foo": "error!"}'
116
121
  expect($(@nudeForm.fields[0]).attr 'class').toNotEqual 'field_with_errors'
117
122
  expect(@nudeForm.error.callCount).toEqual 1
118
123
 
119
124
  it "should clear fields before another submit", ->
120
- @target.respond 422, 'Content-Type': 'application/json', '{"test[foo]": "error!"}'
125
+ @target.respond 422, 'Content-Type': 'application/json', '{"foo": "error!"}'
121
126
  expect($(@nudeForm.fields[0]).attr 'class').toEqual 'field_with_errors'
122
127
  @nudeForm.container.submit()
123
128
  expect($(@nudeForm.fields[0]).attr 'class').toNotEqual 'field_with_errors'
124
129
 
125
130
  it "should trigger 'before' and do default action if it returns true", ->
126
- @target.respond 422, 'Content-Type': 'application/json', '{"test[foo]": "error!"}'
131
+ @target.respond 422, 'Content-Type': 'application/json', '{"foo": "error!"}'
127
132
  expect($(@nudeForm.fields[0]).attr 'class').toEqual 'field_with_errors'
128
133
  @nudeForm.before = sinon.spy ->
129
134
  true
@@ -132,10 +137,48 @@ describe "Joosy.Form", ->
132
137
  expect(@nudeForm.before.callCount).toEqual 1
133
138
 
134
139
  it "should trigger 'before' and skip default action if it returns false", ->
135
- @target.respond 422, 'Content-Type': 'application/json', '{"test[foo]": "error!"}'
140
+ @target.respond 422, 'Content-Type': 'application/json', '{"foo": "error!"}'
136
141
  expect($(@nudeForm.fields[0]).attr 'class').toEqual 'field_with_errors'
137
142
  @nudeForm.before = sinon.spy ->
138
143
  false
139
144
  @nudeForm.container.submit()
140
145
  expect($(@nudeForm.fields[0]).attr 'class').toEqual 'field_with_errors'
141
- expect(@nudeForm.before.callCount).toEqual 1
146
+ expect(@nudeForm.before.callCount).toEqual 1
147
+
148
+ describe "Error response handling", ->
149
+
150
+ beforeEach ->
151
+ @nudeForm = new Joosy.Form @nudeForm, @spy=sinon.spy()
152
+
153
+ it "should prepare simple response", ->
154
+ errors = {zombie: ['suck'], puppies: ['rock']}
155
+ result = @nudeForm.__stringifyErrors(errors)
156
+
157
+ expect(result).toEqual zombie: ['suck'], puppies: ['rock']
158
+
159
+ it "should prepare inline response", ->
160
+ errors = {"zombie.in1.subin1": ['suck'], "zombie.in2": ['rock']}
161
+ result = @nudeForm.__stringifyErrors(errors)
162
+
163
+ expect(result).toEqual {"zombie[in1][subin1]": ['suck'], "zombie[in2]": ['rock']}
164
+
165
+ it "should prepare inline response with resource attached", ->
166
+ @nudeForm.fill @resource
167
+ errors = {"zombie.in1.subin1": ['suck'], "zombie.in2": ['rock']}
168
+ result = @nudeForm.__stringifyErrors(errors)
169
+
170
+ expect(result).toEqual {"test[zombie][in1][subin1]": ['suck'], "test[zombie][in2]": ['rock']}
171
+
172
+ it "should prepare simple response with resource attached", ->
173
+ @nudeForm.fill @resource
174
+ errors = {zombie: ['suck'], puppies: ['rock']}
175
+ result = @nudeForm.__stringifyErrors(errors)
176
+
177
+ expect(result).toEqual { "test[zombie]": ['suck'], "test[puppies]": ['rock'] }
178
+
179
+ it "should prepare complexe response", ->
180
+ @nudeForm.fill @resource
181
+ errors = {fluffies: {zombie: {mumbas: ['ololo']}}}
182
+ result = @nudeForm.__stringifyErrors(errors)
183
+
184
+ expect(result).toEqual { "fluffies[zombie][mumbas]": ['ololo'] }
@@ -32,7 +32,7 @@ describe "Joosy.Layout", ->
32
32
 
33
33
  it "should unload itself", ->
34
34
  spies = []
35
- spies.push sinon.spy(@box, 'clearTime')
35
+ spies.push sinon.spy(@box, '__clearTime')
36
36
  spies.push sinon.spy(@box, '__unloadWidgets')
37
37
  spies.push sinon.spy(@box, '__runAfterUnloads')
38
38
  @box.__unload()
@@ -30,7 +30,6 @@ describe "Joosy.Modules.Container", ->
30
30
  new_container.trigger 'test'
31
31
  expect(new_container.html()).toEqual 'new content'
32
32
  expect(new_container.parent().get(0)).toBe parent.get 0
33
- expect(old_container.parent().get(0)).toBeUndefined()
34
33
  expect(callback.callCount).toEqual 1
35
34
 
36
35
  it "should inherit element declarations", ->
@@ -43,5 +43,5 @@ describe "Joosy.Module", ->
43
43
  expect(TestModule[callback].getCall(0).calledOn(Klass)).toBeTruthy()
44
44
 
45
45
  it "should have minimal set of properties", ->
46
- expect(Object.extended(Joosy.Module).keys()).toEqual ['__namespace__', '__className__', 'hasAncestor', 'include', 'extend']
46
+ expect(Object.extended(Joosy.Module).keys()).toEqual ['__namespace__', '__className', 'hasAncestor', 'merge', 'include', 'extend']
47
47
  expect(Object.extended(Joosy.Module.prototype).keys()).toEqual []
@@ -27,7 +27,7 @@ describe "Joosy.Modules.Renderer", ->
27
27
  template = (locals) ->
28
28
  "#{locals.object.value}"
29
29
 
30
- @render(template, locals)
30
+ @renderDynamic(template, locals)
31
31
 
32
32
  elem = $("<div></div>")
33
33
  @ground.append elem
@@ -60,7 +60,7 @@ describe "Joosy.Modules.Renderer", ->
60
60
  template = (locals) ->
61
61
  "#{locals.zombie}"
62
62
 
63
- @render(template, locals)
63
+ @renderDynamic(template, locals)
64
64
 
65
65
  elem = $("<div></div>")
66
66
  @ground.append elem
@@ -80,12 +80,48 @@ describe "Joosy.Modules.Renderer", ->
80
80
  runs ->
81
81
  expect(elem.text()).toBe "suck"
82
82
 
83
+ it "should render collections and keep html up2date", ->
84
+ class Foo extends Joosy.Resource.Generic
85
+ @entity 'foo'
86
+
87
+ data = new Joosy.Resource.Collection(Foo)
88
+
89
+ data.reset [
90
+ { zombie: 'rock' },
91
+ { zombie: 'never sleep' }
92
+ ]
93
+
94
+ @TestContainer.view (locals) ->
95
+ template = (locals) ->
96
+ "#{locals.data[1] 'zombie'}"
97
+
98
+ @renderDynamic(template, locals)
99
+
100
+ elem = $("<div></div>")
101
+ @ground.append elem
102
+
103
+ elem.html @dummyContainer.__renderer(data)
104
+
105
+ waits 0
106
+
107
+ runs ->
108
+ expect(elem.text()).toBe "never sleep"
109
+
110
+ runs ->
111
+ data.data[1] 'zombie', 'suck'
112
+
113
+ waits 0
114
+
115
+ runs ->
116
+ expect(elem.text()).toBe "suck"
117
+
118
+
83
119
  it "should debounce morpher updates", ->
84
120
  @TestContainer.view (locals) ->
85
121
  template = (locals) ->
86
122
  "#{locals.object.value}"
87
123
 
88
- @render(template, locals)
124
+ @renderDynamic(template, locals)
89
125
 
90
126
  elem = $("<div></div>")
91
127
  @ground.append elem
@@ -20,6 +20,6 @@ describe "Joosy.Modules.TimeManager", ->
20
20
  callback = sinon.spy()
21
21
  runs ->
22
22
  @box.setTimeout 10, callback
23
- @box.clearTime()
23
+ @box.__clearTime()
24
24
  waits(10)
25
25
  runs -> expect(callback.callCount).toEqual(0)
@@ -74,7 +74,7 @@ describe "Joosy.Page", ->
74
74
 
75
75
  it "should unload itself", ->
76
76
  spies = []
77
- spies.push sinon.spy(@box, 'clearTime')
77
+ spies.push sinon.spy(@box, '__clearTime')
78
78
  spies.push sinon.spy(@box, '__unloadWidgets')
79
79
  spies.push sinon.spy(@box, '__removeMetamorphs')
80
80
  spies.push sinon.spy(@box, '__runAfterUnloads')
@@ -163,6 +163,8 @@ describe "Joosy.Page", ->
163
163
 
164
164
  it "should render layout and page", ->
165
165
  spies = []
166
+
167
+ @box.params = {tested: true}
166
168
 
167
169
  spies.push @box.__layoutClass.prototype.__renderer
168
170
  spies.push @box.__renderer
@@ -173,3 +175,4 @@ describe "Joosy.Page", ->
173
175
  @box.__bootstrapLayout()
174
176
  expect(spies).toBeSequenced()
175
177
  expect(swapContainer.callCount).toEqual 2
178
+ expect(@box.layout.params).toEqual {tested: true}
@@ -0,0 +1,84 @@
1
+ describe "Joosy.Resource.Collection", ->
2
+
3
+ class Test extends Joosy.Resource.Generic
4
+ @entity 'test'
5
+
6
+ data = '[{"id": 1, "name": "test1"}, {"id": 2, "name": "test2"}]'
7
+
8
+ checkData = (collection) ->
9
+ expect(collection.data.length).toEqual 2
10
+ expect(collection.data[0].constructor == Test).toBeTruthy()
11
+ expect(collection.data[0].e.name).toEqual 'test1'
12
+
13
+ beforeEach ->
14
+ @collection = new Joosy.Resource.Collection(Test)
15
+
16
+ it "should initialize", ->
17
+ expect(@collection.model).toEqual Test
18
+ expect(@collection.data).toEqual []
19
+
20
+ it "should modelize", ->
21
+ result = @collection.modelize $.parseJSON(data)
22
+ expect(result[0].constructor == Test).toBeTruthy()
23
+ expect(result[0].e.name).toEqual 'test1'
24
+
25
+ it "should reset", ->
26
+ @collection.reset $.parseJSON(data)
27
+ checkData @collection
28
+
29
+ it "should trigger changes", ->
30
+ @collection.bind 'changed', callback = sinon.spy()
31
+ @collection.reset $.parseJSON(data)
32
+ expect(callback.callCount).toEqual 1
33
+
34
+ it "should not trigger changes", ->
35
+ @collection.bind 'changed', callback = sinon.spy()
36
+ @collection.reset $.parseJSON(data), false
37
+ expect(callback.callCount).toEqual 0
38
+
39
+ it "should properly handle the before filter", ->
40
+ class RC extends Joosy.Resource.Collection
41
+ @beforeLoad (data) ->
42
+ data.each (entry, i) ->
43
+ data[i].tested = true
44
+ data
45
+
46
+ collection = new RC(Test)
47
+ collection.reset $.parseJSON(data)
48
+
49
+ expect(collection.at(0)('tested')).toBeTruthy()
50
+
51
+ it "should remove item from collection", ->
52
+ @collection.reset $.parseJSON(data)
53
+ @collection.bind 'changed', callback = sinon.spy()
54
+ @collection.remove @collection.data[1]
55
+ expect(@collection.data.length).toEqual 1
56
+ @collection.remove 0
57
+ expect(@collection.data.length).toEqual 0
58
+ expect(callback.callCount).toEqual 2
59
+
60
+ it "should silently remove item from collection", ->
61
+ @collection.reset $.parseJSON(data)
62
+ @collection.bind 'changed', callback = sinon.spy()
63
+ @collection.remove @collection.data[1], false
64
+ expect(@collection.data.length).toEqual 1
65
+ @collection.remove 0, false
66
+ expect(@collection.data.length).toEqual 0
67
+ expect(callback.callCount).toEqual 0
68
+
69
+ it "should add item from collection", ->
70
+ @collection.reset $.parseJSON(data)
71
+ @collection.bind 'changed', callback = sinon.spy()
72
+ @collection.add new Test {'rocking': 'mocking'}
73
+ expect(@collection.data.length).toEqual 3
74
+ expect(@collection.at(2).e).toEqual {'rocking': 'mocking'}
75
+ @collection.add new Test({'rocking': 'mocking'}), 1
76
+ expect(@collection.data.length).toEqual 4
77
+ expect(@collection.at(1).e).toEqual {'rocking': 'mocking'}
78
+ expect(@collection.at(3).e).toEqual {'rocking': 'mocking'}
79
+
80
+ it "should find items by id", ->
81
+ @collection.reset $.parseJSON(data)
82
+
83
+ expect(@collection.findById 1).toEqual @collection.data[0]
84
+ expect(@collection.findById 2).toEqual @collection.data[1]
@@ -11,11 +11,11 @@ describe "Joosy.Resource.Generic", ->
11
11
 
12
12
  it "should remember where it belongs", ->
13
13
  resource = new Joosy.Resource.Generic foo: 'bar'
14
- expect(resource.e).toEqual Object.extended(foo: 'bar')
14
+ expect(resource.e).toEqual foo: 'bar'
15
15
 
16
16
  it "should produce magic function", ->
17
17
  expect(Object.isFunction @resource).toBeTruthy()
18
- expect(@resource.e).toEqual Object.extended(@data)
18
+ expect(@resource.e).toEqual @data
19
19
 
20
20
  it "should get values", ->
21
21
  expect(@resource 'foo').toEqual 'bar'
@@ -32,4 +32,87 @@ describe "Joosy.Resource.Generic", ->
32
32
  expect(@resource 'very.deep').toEqual 'banana!'
33
33
 
34
34
  @resource 'another.deep.value', 'banana strikes back'
35
- expect(@resource 'another.deep').toEqual value: 'banana strikes back'
35
+ expect(@resource 'another.deep').toEqual value: 'banana strikes back'
36
+
37
+ it "should handle lambdas in @source properly", ->
38
+ class Fluffy extends Joosy.Resource.Generic
39
+ @source (rumbas) -> "#{rumbas}!"
40
+
41
+ clone = Fluffy.at('rumbas')
42
+
43
+ expect(-> clone.at 'kutuzka').toThrow(new Error 'clone> should be created directly (without `at\')')
44
+ expect(clone.__source).toEqual 'rumbas!'
45
+
46
+ expect(Joosy.Module.hasAncestor clone, Fluffy).toBeTruthy()
47
+ # clone won't be instanceof Fluffy in IE
48
+ #expect(clone.create({}) instanceof Fluffy).toBeTruthy()
49
+
50
+ it "should trigger 'changed' right", ->
51
+ callback = sinon.spy()
52
+ @resource.bind 'changed', callback
53
+ @resource 'foo', 'baz'
54
+ @resource 'foo', 'baz2'
55
+
56
+ expect(callback.callCount).toEqual(2)
57
+
58
+ it "should properly handle the before filter", ->
59
+ class R extends Joosy.Resource.Generic
60
+ @beforeLoad (data) ->
61
+ data ||= {}
62
+ data.tested = true
63
+ data
64
+
65
+ resource = R.create()
66
+
67
+ expect(resource 'tested').toBeTruthy()
68
+
69
+ it "should map inlines", ->
70
+ class RumbaMumba extends Joosy.Resource.Generic
71
+ @entity 'rumba_mumba'
72
+
73
+ class R extends Joosy.Resource.Generic
74
+ @map 'rumbaMumbas', RumbaMumba
75
+
76
+ resource = R.create
77
+ rumbaMumbas: [
78
+ {foo: 'bar'},
79
+ {bar: 'baz'}
80
+ ]
81
+ expect(resource.rumbaMumbas instanceof Joosy.Resource.Collection).toBeTruthy()
82
+ expect(resource.rumbaMumbas.at(0)('foo')).toEqual 'bar'
83
+
84
+
85
+ it "should use magic collections", ->
86
+ class window.RumbaMumbasCollection extends Joosy.Resource.Collection
87
+
88
+ class RumbaMumba extends Joosy.Resource.Generic
89
+ @entity 'rumba_mumba'
90
+ class R extends Joosy.Resource.Generic
91
+ @map 'rumbaMumbas', RumbaMumba
92
+
93
+ resource = R.create
94
+ rumbaMumbas: [
95
+ {foo: 'bar'},
96
+ {bar: 'baz'}
97
+ ]
98
+ expect(resource.rumbaMumbas instanceof RumbaMumbasCollection).toBeTruthy()
99
+ expect(resource.rumbaMumbas.at(0)('foo')).toEqual 'bar'
100
+
101
+ window.RumbaMumbasCollection = undefined
102
+
103
+ it "should use manually set collections", ->
104
+ class OloCollection extends Joosy.Resource.Collection
105
+
106
+ class RumbaMumba extends Joosy.Resource.Generic
107
+ @entity 'rumba_mumba'
108
+ @collection OloCollection
109
+ class R extends Joosy.Resource.Generic
110
+ @map 'rumbaMumbas', RumbaMumba
111
+
112
+ resource = R.create
113
+ rumbaMumbas: [
114
+ {foo: 'bar'},
115
+ {bar: 'baz'}
116
+ ]
117
+ expect(resource.rumbaMumbas instanceof OloCollection).toBeTruthy()
118
+ expect(resource.rumbaMumbas.at(0)('foo')).toEqual 'bar'
@@ -7,7 +7,6 @@ describe "Joosy.Resource.RESTCollection", ->
7
7
 
8
8
  checkData = (collection) ->
9
9
  expect(collection.data.length).toEqual 2
10
- expect(collection.pages[1]).toEqual collection.data
11
10
  expect(collection.data[0].constructor == Test).toBeTruthy()
12
11
  expect(collection.data[0].e.name).toEqual 'test1'
13
12
 
@@ -24,21 +23,6 @@ describe "Joosy.Resource.RESTCollection", ->
24
23
  afterEach ->
25
24
  @server.restore()
26
25
 
27
- it "should initialize", ->
28
- expect(@collection.model).toEqual Test
29
- expect(@collection.params).toEqual Object.extended()
30
- expect(@collection.data).toEqual []
31
- expect(@collection.pages).toEqual Object.extended()
32
-
33
- it "should modelize", ->
34
- result = @collection.modelize $.parseJSON(data)
35
- expect(result[0].constructor == Test).toBeTruthy()
36
- expect(result[0].e.name).toEqual 'test1'
37
-
38
- it "should reset", ->
39
- @collection.reset $.parseJSON(data)
40
- checkData @collection
41
-
42
26
  it "should fetch", ->
43
27
  @collection.fetch()
44
28
  spoofData @server
@@ -52,14 +36,23 @@ describe "Joosy.Resource.RESTCollection", ->
52
36
  @collection.page 2, callback=sinon.spy()
53
37
  spoofData @server
54
38
  expect(callback.callCount).toEqual 1
55
- expect(@collection.data.length).toEqual 4
56
- expect(@collection.data[2].constructor == Test).toBeTruthy()
57
- expect(@collection.data[2].e.name).toEqual 'test1'
39
+ expect(@collection.data.length).toEqual 2
40
+ expect(@collection.data[0].constructor == Test).toBeTruthy()
41
+ expect(@collection.data[0].e.name).toEqual 'test1'
58
42
 
59
43
  # Again from cache
60
44
  @collection.page 2, callback=sinon.spy()
61
45
  spoofData @server
62
46
  expect(callback.callCount).toEqual 1
63
- expect(@collection.data.length).toEqual 4
64
- expect(@collection.data[2].constructor == Test).toBeTruthy()
65
- expect(@collection.data[2].e.name).toEqual 'test1'
47
+ expect(@collection.data.length).toEqual 2
48
+ expect(@collection.data[0].constructor == Test).toBeTruthy()
49
+ expect(@collection.data[0].e.name).toEqual 'test1'
50
+
51
+ it "should trigger changes", ->
52
+ @collection.bind 'changed', callback = sinon.spy()
53
+ @collection.fetch()
54
+ spoofData @server
55
+ expect(callback.callCount).toEqual 1
56
+ @collection.page 2
57
+ spoofData @server
58
+ expect(callback.callCount).toEqual 2
@@ -14,9 +14,8 @@ describe "Joosy.Resource.REST", ->
14
14
  it "should have appropriate accessors", ->
15
15
  @Test.entity 'tada'
16
16
  expect(@Test::__entityName).toEqual 'tada'
17
- expect(@Test.entityName()).toEqual 'tada'
18
17
  @Test.source 'uri'
19
- expect(@Test::__source).toEqual 'uri'
18
+ expect(@Test.__source).toEqual 'uri'
20
19
  expect(@Test.__buildSource()).toEqual 'uri/'
21
20
  @Test.primary 'uid'
22
21
  expect(@Test::__primaryKey).toEqual 'uid'
@@ -48,7 +47,7 @@ describe "Joosy.Resource.REST", ->
48
47
  @Test.beforeLoad beforeLoadCallback = sinon.spy (data) ->
49
48
  expect(data.id).toEqual 1
50
49
  expect(data.name).toEqual 'test1'
51
- Object.extended(test: data)
50
+ Object.extended(data)
52
51
  @Test.find 1, callback = sinon.spy (target) ->
53
52
  expect(target.id).toEqual 1
54
53
  expect(target.e?.name).toEqual 'test1'
@@ -56,13 +55,14 @@ describe "Joosy.Resource.REST", ->
56
55
  expect(target.method).toEqual 'GET'
57
56
  expect(target.url).toMatch /^\/tests\/1\?_=\d+/
58
57
  target.respond 200, 'Content-Type': 'application/json',
59
- '{"id": 1, "name": "test1"}'
58
+ '{"test": {"id": 1, "name": "test1"}}'
60
59
  expect(callback.callCount).toEqual 1
61
60
  expect(beforeLoadCallback.callCount).toEqual 1
62
61
 
63
62
  it 'should find objects collection with params', ->
64
63
  callback = sinon.spy (collection) ->
65
64
  i = 1
65
+ expect(collection instanceof Joosy.Resource.RESTCollection).toBeTruthy()
66
66
  collection.data.each (target) ->
67
67
  expect(target.id).toEqual i
68
68
  expect(target.e?.name).toEqual 'test' + i
@@ -78,6 +78,7 @@ describe "Joosy.Resource.REST", ->
78
78
  it 'should find all objects collection', ->
79
79
  callback = sinon.spy (collection) ->
80
80
  i = 1
81
+ expect(collection instanceof Joosy.Resource.RESTCollection).toBeTruthy()
81
82
  collection.data.each (target) ->
82
83
  expect(target.id).toEqual i
83
84
  expect(target.e?.name).toEqual 'test' + i
@@ -106,3 +107,25 @@ describe "Joosy.Resource.REST", ->
106
107
  expect(@Test.__isId variant).toBeTruthy()
107
108
  [(->) , [], {}, null, undefined, true, false].each (variant) =>
108
109
  expect(@Test.__isId variant).toBeFalsy()
110
+
111
+ it "should trigger 'changed' on fetch", ->
112
+ resource = @Test.find 1, callback = sinon.spy (target) ->
113
+ expect(target.id).toEqual 1
114
+ expect(target.e?.name).toEqual 'test1'
115
+ target = @server.requests[0]
116
+ expect(target.method).toEqual 'GET'
117
+ expect(target.url).toMatch /^\/tests\/1\?_=\d+/
118
+ target.respond 200, 'Content-Type': 'application/json',
119
+ '{"test": {"id": 1, "name": "test1"}}'
120
+ expect(callback.callCount).toEqual 1
121
+
122
+ resource.bind 'changed', callback = sinon.spy()
123
+ resource.fetch()
124
+
125
+ target = @server.requests[1]
126
+ expect(target.method).toEqual 'GET'
127
+ expect(target.url).toMatch /^\/tests\/1\?_=\d+/
128
+ target.respond 200, 'Content-Type': 'application/json',
129
+ '{"test": {"id": 1, "name": "test1"}}'
130
+
131
+ expect(callback.callCount).toEqual 1
@@ -11,19 +11,6 @@ describe "Joosy.Widget", ->
11
11
  @TestWidget.view 'test'
12
12
  expect(@TestWidget::__renderer instanceof Function).toBeTruthy()
13
13
 
14
- it "should use parent's TimeManager", ->
15
- @box.parent =
16
- setInterval: sinon.spy()
17
- setTimeout: sinon.spy()
18
- @box.setInterval 1, 2, 3
19
- @box.setTimeout 1, 2, 3
20
- target = @box.parent.setInterval
21
- expect(target.callCount).toEqual 1
22
- expect(target.alwaysCalledWithExactly 1, 2, 3).toBeTruthy()
23
- target = @box.parent.setTimeout
24
- expect(target.callCount).toEqual 1
25
- expect(target.alwaysCalledWithExactly 1, 2, 3).toBeTruthy()
26
-
27
14
  it "should use Router", ->
28
15
  target = sinon.stub Joosy.Router, 'navigate'
29
16
  @box.navigate 'there'
@@ -32,6 +19,7 @@ describe "Joosy.Widget", ->
32
19
  Joosy.Router.navigate.restore()
33
20
 
34
21
  it "should load itself", ->
22
+ @box.data = {tested: true}
35
23
  spies = [sinon.spy()]
36
24
  @TestWidget.view spies[0]
37
25
  @parent = new Joosy.Layout()
@@ -41,6 +29,7 @@ describe "Joosy.Widget", ->
41
29
  target = @box.__load @parent, @ground
42
30
  expect(target).toBe @box
43
31
  expect(@box.__renderer.getCall(0).calledOn()).toBeFalsy()
32
+ expect(@box.__renderer.getCall(0).args[0]).toEqual {tested: true}
44
33
  expect(spies).toBeSequenced()
45
34
 
46
35
  it "should unload itself", ->
@@ -48,4 +37,4 @@ describe "Joosy.Widget", ->
48
37
  @box.__unload()
49
38
  target = @box.__runAfterUnloads
50
39
  expect(target.callCount).toEqual 1
51
- expect(target.getCall(0).calledOn()).toBeFalsy()
40
+ expect(target.getCall(0).calledOn()).toBeFalsy()