joosy 0.1.0.RC1 → 0.1.0.RC2

Sign up to get free protection for your applications and to get access to all the features.
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()