joosy 0.1.0.RC1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +14 -0
  3. data/Gemfile.lock +159 -0
  4. data/Guardfile +30 -0
  5. data/MIT-LICENSE +21 -0
  6. data/README.rdoc +3 -0
  7. data/Rakefile +14 -0
  8. data/app/assets/javascripts/joosy.js.coffee +7 -0
  9. data/app/assets/javascripts/joosy/core/application.js.coffee +28 -0
  10. data/app/assets/javascripts/joosy/core/form.js.coffee +87 -0
  11. data/app/assets/javascripts/joosy/core/helpers.js.coffee +6 -0
  12. data/app/assets/javascripts/joosy/core/joosy.js.coffee +65 -0
  13. data/app/assets/javascripts/joosy/core/layout.js.coffee +47 -0
  14. data/app/assets/javascripts/joosy/core/modules/container.js.coffee +59 -0
  15. data/app/assets/javascripts/joosy/core/modules/events.js.coffee +35 -0
  16. data/app/assets/javascripts/joosy/core/modules/filters.js.coffee +39 -0
  17. data/app/assets/javascripts/joosy/core/modules/log.js.coffee +15 -0
  18. data/app/assets/javascripts/joosy/core/modules/module.js.coffee +43 -0
  19. data/app/assets/javascripts/joosy/core/modules/renderer.js.coffee +116 -0
  20. data/app/assets/javascripts/joosy/core/modules/time_manager.js.coffee +25 -0
  21. data/app/assets/javascripts/joosy/core/modules/widgets_manager.js.coffee +58 -0
  22. data/app/assets/javascripts/joosy/core/page.js.coffee +156 -0
  23. data/app/assets/javascripts/joosy/core/preloader.js.coffee +5 -0
  24. data/app/assets/javascripts/joosy/core/resource/generic.js.coffee +61 -0
  25. data/app/assets/javascripts/joosy/core/resource/rest.js.coffee +76 -0
  26. data/app/assets/javascripts/joosy/core/resource/rest_collection.js.coffee +48 -0
  27. data/app/assets/javascripts/joosy/core/router.js.coffee +89 -0
  28. data/app/assets/javascripts/joosy/core/templaters/rails_jst.js.coffee +20 -0
  29. data/app/assets/javascripts/joosy/core/widget.js.coffee +41 -0
  30. data/app/assets/javascripts/joosy/preloaders/caching.js.coffee +94 -0
  31. data/app/assets/javascripts/joosy/preloaders/inline.js.coffee +55 -0
  32. data/app/helpers/joosy/sprockets_helper.rb +23 -0
  33. data/app/views/layouts/json_wrapper.json.erb +1 -0
  34. data/joosy.gemspec +25 -0
  35. data/lib/joosy.rb +9 -0
  36. data/lib/joosy/forms.rb +47 -0
  37. data/lib/joosy/rails/engine.rb +17 -0
  38. data/lib/joosy/rails/version.rb +5 -0
  39. data/lib/rails/generators/joosy/application_generator.rb +41 -0
  40. data/lib/rails/generators/joosy/joosy_base.rb +30 -0
  41. data/lib/rails/generators/joosy/layout_generator.rb +32 -0
  42. data/lib/rails/generators/joosy/page_generator.rb +44 -0
  43. data/lib/rails/generators/joosy/preloader_generator.rb +32 -0
  44. data/lib/rails/generators/joosy/resource_generator.rb +29 -0
  45. data/lib/rails/generators/joosy/templates/app.js.coffee +10 -0
  46. data/lib/rails/generators/joosy/templates/app/helpers/application.js.coffee +4 -0
  47. data/lib/rails/generators/joosy/templates/app/layouts/application.js.coffee +2 -0
  48. data/lib/rails/generators/joosy/templates/app/layouts/template.js.coffee +2 -0
  49. data/lib/rails/generators/joosy/templates/app/pages/application.js.coffee +1 -0
  50. data/lib/rails/generators/joosy/templates/app/pages/template.js.coffee +5 -0
  51. data/lib/rails/generators/joosy/templates/app/pages/welcome/index.js.coffee +22 -0
  52. data/lib/rails/generators/joosy/templates/app/resources/template.js.coffee +2 -0
  53. data/lib/rails/generators/joosy/templates/app/routes.js.coffee +8 -0
  54. data/lib/rails/generators/joosy/templates/app/templates/layouts/application.jst.hamlc +2 -0
  55. data/lib/rails/generators/joosy/templates/app/templates/pages/welcome/index.jst.hamlc +7 -0
  56. data/lib/rails/generators/joosy/templates/app/widgets/template.js.coffee +2 -0
  57. data/lib/rails/generators/joosy/templates/app_controller.rb +9 -0
  58. data/lib/rails/generators/joosy/templates/app_preloader.js.coffee.erb +13 -0
  59. data/lib/rails/generators/joosy/templates/preload.html.erb +26 -0
  60. data/lib/rails/generators/joosy/templates/preload.html.haml +19 -0
  61. data/lib/rails/generators/joosy/widget_generator.rb +32 -0
  62. data/spec/javascripts/helpers/spec_helper.js.coffee +44 -0
  63. data/spec/javascripts/joosy/core/application_spec.js.coffee +40 -0
  64. data/spec/javascripts/joosy/core/form_spec.js.coffee +141 -0
  65. data/spec/javascripts/joosy/core/joosy_spec.js.coffee +72 -0
  66. data/spec/javascripts/joosy/core/layout_spec.js.coffee +50 -0
  67. data/spec/javascripts/joosy/core/modules/container_spec.js.coffee +92 -0
  68. data/spec/javascripts/joosy/core/modules/events_spec.js.coffee +53 -0
  69. data/spec/javascripts/joosy/core/modules/filters_spec.js.coffee +71 -0
  70. data/spec/javascripts/joosy/core/modules/log_spec.js.coffee +15 -0
  71. data/spec/javascripts/joosy/core/modules/module_spec.js.coffee +47 -0
  72. data/spec/javascripts/joosy/core/modules/renderer_spec.js.coffee +149 -0
  73. data/spec/javascripts/joosy/core/modules/time_manager_spec.js.coffee +25 -0
  74. data/spec/javascripts/joosy/core/modules/widget_manager_spec.js.coffee +75 -0
  75. data/spec/javascripts/joosy/core/page_spec.js.coffee +175 -0
  76. data/spec/javascripts/joosy/core/resource/generic_spec.js.coffee +35 -0
  77. data/spec/javascripts/joosy/core/resource/rest_collection_spec.js.coffee +65 -0
  78. data/spec/javascripts/joosy/core/resource/rest_spec.js.coffee +108 -0
  79. data/spec/javascripts/joosy/core/router_spec.js.coffee +123 -0
  80. data/spec/javascripts/joosy/core/templaters/rails_jst_spec.js.coffee +25 -0
  81. data/spec/javascripts/joosy/core/widget_spec.js.coffee +51 -0
  82. data/spec/javascripts/joosy/preloaders/caching_spec.js.coffee +36 -0
  83. data/spec/javascripts/joosy/preloaders/inline_spec.js.coffee +16 -0
  84. data/spec/javascripts/support/assets/coolface.jpg +0 -0
  85. data/spec/javascripts/support/assets/okay.jpg +0 -0
  86. data/spec/javascripts/support/assets/test.js +1 -0
  87. data/spec/javascripts/support/jasmine.yml +74 -0
  88. data/spec/javascripts/support/jasmine_config.rb +23 -0
  89. data/spec/javascripts/support/jasmine_runner.rb +32 -0
  90. data/spec/javascripts/support/sinon-1.3.1.js +3469 -0
  91. data/spec/javascripts/support/sinon-ie-1.3.1.js +82 -0
  92. data/vendor/assets/javascripts/base64.js +135 -0
  93. data/vendor/assets/javascripts/inflection.js +656 -0
  94. data/vendor/assets/javascripts/jquery.form.js +980 -0
  95. data/vendor/assets/javascripts/jquery.hashchange.js +390 -0
  96. data/vendor/assets/javascripts/metamorph.js +409 -0
  97. data/vendor/assets/javascripts/sugar.js +6040 -0
  98. metadata +232 -0
@@ -0,0 +1,25 @@
1
+ describe "Joosy.Modules.TimeManager", ->
2
+
3
+ beforeEach ->
4
+ class @TestTimeManager extends Joosy.Module
5
+ @include Joosy.Modules.TimeManager
6
+ @box = new @TestTimeManager()
7
+
8
+
9
+ it "should keep timeouts list", ->
10
+ timer = @box.setTimeout 10000, ->
11
+ expect(@box.__timeouts).toEqual [timer]
12
+ window.clearTimeout timer
13
+
14
+ it "should keep intervals list", ->
15
+ timer = @box.setInterval 10000, ->
16
+ expect(@box.__intervals).toEqual [timer]
17
+ window.clearInterval timer
18
+
19
+ it "should stop intervals and timeouts", ->
20
+ callback = sinon.spy()
21
+ runs ->
22
+ @box.setTimeout 10, callback
23
+ @box.clearTime()
24
+ waits(10)
25
+ runs -> expect(callback.callCount).toEqual(0)
@@ -0,0 +1,75 @@
1
+ describe "Joosy.Modules.WidgetsManager", ->
2
+
3
+ beforeEach ->
4
+ class @TestWidgetManager extends Joosy.Module
5
+ @include Joosy.Modules.WidgetsManager
6
+ @box = new @TestWidgetManager()
7
+ @widgetMock = Object.extended(
8
+ __load: sinon.stub()
9
+ __unload: sinon.spy()
10
+ )
11
+ @widgetMock.__load.returns @widgetMock
12
+
13
+
14
+ it "should register and unregister widget", ->
15
+ expect(@box.registerWidget @ground, @widgetMock).toBe @widgetMock
16
+ expect(@box.__activeWidgets).toEqual [@widgetMock]
17
+ expect(@widgetMock.__load.callCount).toEqual 1
18
+
19
+ expect(@box.unregisterWidget @widgetMock).toBeTruthy()
20
+ expect(@box.__activeWidgets).toEqual []
21
+ expect(@widgetMock.__unload.callCount).toEqual 1
22
+
23
+ it "should unload all widgets", ->
24
+ 0.upto(2).each => @box.registerWidget(@ground, @widgetMock)
25
+ @box.__unloadWidgets()
26
+ expect(@widgetMock.__unload.callCount).toEqual 3
27
+
28
+ it "should inherit widget declarations", ->
29
+ @box.container = @ground
30
+ @TestWidgetManager::widgets =
31
+ 'test': 'widget'
32
+ class SubWidgetManagerA extends @TestWidgetManager
33
+ widgets:
34
+ 'selector': 'widget'
35
+ class SubWidgetManagerB extends SubWidgetManagerA
36
+ widgets:
37
+ 'widgets': 'widget'
38
+ 'selector': 'overriden'
39
+ subBox = new SubWidgetManagerB()
40
+ target = subBox.__collectWidgets()
41
+ expect(target).toEqual Object.extended
42
+ 'test': 'widget'
43
+ 'widgets': 'widget'
44
+ 'selector': 'overriden'
45
+
46
+ it "should register widgets per declaration", ->
47
+ @seedGround()
48
+ @box.container = $('#application')
49
+ @box.elements = {footer: '.footer'}
50
+ @box.widgets =
51
+ '$container': Joosy.Widget
52
+ '$footer': Joosy.Widget
53
+ '.post': sinon.stub()
54
+ @box.widgets['.post'].returns @widgetMock
55
+ @box.__setupWidgets()
56
+ expect(@box.__activeWidgets.length).toEqual 5
57
+ expect(@box.widgets['.post'].callCount).toEqual 3
58
+ expect(@box.widgets['.post'].getCall(0).calledOn @box).toBeTruthy()
59
+
60
+ it "should bootstrap widget properly", ->
61
+ class TextWidget extends Joosy.Widget
62
+ @view -> 'fluffy'
63
+ constructor: (@tester) ->
64
+
65
+ @seedGround()
66
+ @box.container = $('#application')
67
+ @box.widgets =
68
+ '.post:first': TextWidget
69
+ '.widget:first': (i) -> new TextWidget i
70
+ @box.__setupWidgets()
71
+
72
+ expect(@ground.find('.post').html()).toEqual 'fluffy'
73
+ expect(@ground.find('.widget').html()).toEqual 'fluffy'
74
+ expect(@box.__activeWidgets[0].tester).toBeUndefined()
75
+ expect(@box.__activeWidgets[1].tester).toEqual 0
@@ -0,0 +1,175 @@
1
+ describe "Joosy.Page", ->
2
+
3
+ beforeEach ->
4
+ window.JST = 'app/templates/layouts/default': (->)
5
+ class window.ApplicationLayout extends Joosy.Layout
6
+ class @TestPage extends Joosy.Page
7
+
8
+
9
+ describe "not rendered page", ->
10
+
11
+ beforeEach ->
12
+ sinon.stub @TestPage.prototype, '__bootstrap'
13
+ sinon.stub @TestPage.prototype, '__bootstrapLayout'
14
+ @box = new @TestPage()
15
+ expect(@TestPage::__bootstrap.callCount).toEqual 0
16
+ expect(@TestPage::__bootstrapLayout.callCount).toEqual 1
17
+
18
+
19
+ it "should have appropriate accessors", ->
20
+ callback_names = ['fetch', 'beforePaint', 'paint', 'afterPaint', 'erase']
21
+ callback_names.each (func) =>
22
+ @TestPage[func] 'callback'
23
+ expect(@TestPage::['__' + func]).toEqual 'callback'
24
+
25
+ @TestPage.scroll '#here'
26
+ expect(@TestPage::__scrollElement).toEqual '#here'
27
+ expect(@TestPage::__scrollSpeed).toEqual 500
28
+ expect(@TestPage::__scrollMargin).toEqual 0
29
+
30
+ @TestPage.scroll '#there', speed: 1000, margin: -5
31
+ expect(@TestPage::__scrollElement).toEqual '#there'
32
+ expect(@TestPage::__scrollSpeed).toEqual 1000
33
+ expect(@TestPage::__scrollMargin).toEqual -5
34
+
35
+ @TestPage.layout 'test'
36
+ expect(@TestPage::__layoutClass).toEqual 'test'
37
+
38
+ it "should not render layout if it not changes", ->
39
+ @box.layout = new ApplicationLayout()
40
+ @box.layout.yield()
41
+ new @TestPage {}, @box
42
+ expect(@TestPage::__bootstrap.callCount).toEqual 1
43
+ expect(@TestPage::__bootstrapLayout.callCount).toEqual 1
44
+
45
+ it "should render layout if it changes", ->
46
+ class SubLayout extends Joosy.Layout
47
+ @box = new @TestPage()
48
+ new @TestPage {}, @box
49
+ expect(@TestPage::__bootstrap.callCount).toEqual 0
50
+ expect(@TestPage::__bootstrapLayout.callCount).toEqual 3
51
+
52
+ it "should stop render on beforeFilter result", ->
53
+ sinon.stub @TestPage.prototype, '__runBeforeLoads'
54
+ @TestPage::__runBeforeLoads.returns(false)
55
+ new @TestPage()
56
+ expect(@TestPage::__bootstrap.callCount).toEqual 0
57
+ expect(@TestPage::__bootstrapLayout.callCount).toEqual 1
58
+
59
+ it "should use Router", ->
60
+ target = sinon.stub Joosy.Router, 'navigate'
61
+ @box.navigate 'there'
62
+ expect(target.callCount).toEqual 1
63
+ expect(target.alwaysCalledWithExactly 'there').toBeTruthy()
64
+ Joosy.Router.navigate.restore()
65
+
66
+ it "should load itself", ->
67
+ spies = []
68
+ spies.push sinon.spy(@box, 'refreshElements')
69
+ spies.push sinon.spy(@box, '__delegateEvents')
70
+ spies.push sinon.spy(@box, '__setupWidgets')
71
+ spies.push sinon.spy(@box, '__runAfterLoads')
72
+ @box.__load()
73
+ expect(spies).toBeSequenced()
74
+
75
+ it "should unload itself", ->
76
+ spies = []
77
+ spies.push sinon.spy(@box, 'clearTime')
78
+ spies.push sinon.spy(@box, '__unloadWidgets')
79
+ spies.push sinon.spy(@box, '__removeMetamorphs')
80
+ spies.push sinon.spy(@box, '__runAfterUnloads')
81
+ @box.__unload()
82
+ expect(spies).toBeSequenced()
83
+
84
+ describe "rendered page", ->
85
+
86
+ beforeEach ->
87
+ @box.previous = new @TestPage()
88
+ @box.previous.layout = new @box.previous.__layoutClass
89
+ @box.__renderer = sinon.spy()
90
+ @box.__layoutClass.prototype.__renderer = sinon.spy()
91
+ @TestPage::__bootstrap.restore()
92
+ @TestPage::__bootstrapLayout.restore()
93
+
94
+
95
+ it "should wait stageClear and dataReceived event to start render", ->
96
+ spies = []
97
+
98
+ spies.push @box.previous.__erase = sinon.spy (stage, callback) ->
99
+ expect(stage.selector).toEqual @layout.content().selector
100
+ callback()
101
+
102
+ spies.push sinon.spy(@box.previous, '__unload')
103
+
104
+ spies.push @box.__beforePaint = sinon.spy (stage, callback) ->
105
+ expect(stage.selector).toEqual @layout.content().selector
106
+ expect(@__oneShotEvents[0][0]).toEqual ['stageClear', 'dataReceived']
107
+ callback()
108
+ expect(@__oneShotEvents[0][0]).toEqual ['dataReceived']
109
+
110
+ spies.push @box.__fetch = sinon.spy (callback) ->
111
+ expect(@__oneShotEvents[0][0]).toEqual ['dataReceived']
112
+ callback()
113
+ expect(@__oneShotEvents).toEqual []
114
+
115
+ spies.push @box.__paint = sinon.spy (stage, callback) ->
116
+ expect(stage.selector).toEqual @layout.content().selector
117
+ expect(typeof callback).toEqual 'function'
118
+ # callback() - start rendering
119
+
120
+ @box.__bootstrap()
121
+
122
+ expect(spies).toBeSequenced()
123
+
124
+ it "should render page", ->
125
+ spies = []
126
+
127
+ spies.push @box.__renderer
128
+ spies.push sinon.spy(@box, 'swapContainer')
129
+ spies.push sinon.spy(@box, '__load')
130
+
131
+ @box.__bootstrap()
132
+ expect(spies).toBeSequenced()
133
+
134
+ it "should wait stageClear and dataReceived event to start layout render", ->
135
+ spies = []
136
+
137
+ spies.push ApplicationLayout::__erase = sinon.spy (stage, page, callback) ->
138
+ expect(stage.selector).toEqual Joosy.Application.content().selector
139
+ callback()
140
+
141
+ spies.push sinon.spy(@box.previous.layout, '__unload')
142
+ spies.push sinon.spy(@box.previous, '__unload')
143
+
144
+ spies.push ApplicationLayout::__beforePaint = sinon.spy (stage, page, callback) =>
145
+ expect(stage.selector).toEqual Joosy.Application.content().selector
146
+ expect(@box.__oneShotEvents[0][0]).toEqual ['stageClear', 'dataReceived']
147
+ callback()
148
+ expect(@box.__oneShotEvents[0][0]).toEqual ['dataReceived']
149
+
150
+ spies.push @box.__fetch = sinon.spy (callback) ->
151
+ expect(@__oneShotEvents[0][0]).toEqual ['dataReceived']
152
+ callback()
153
+ expect(@__oneShotEvents).toEqual []
154
+
155
+ spies.push ApplicationLayout::__paint = sinon.spy (stage, page, callback) ->
156
+ expect(stage.selector).toEqual Joosy.Application.content().selector
157
+ expect(typeof callback).toEqual 'function'
158
+ # callback() - start rendering
159
+
160
+ @box.__bootstrapLayout()
161
+
162
+ expect(spies).toBeSequenced()
163
+
164
+ it "should render layout and page", ->
165
+ spies = []
166
+
167
+ spies.push @box.__layoutClass.prototype.__renderer
168
+ spies.push @box.__renderer
169
+ swapContainer = sinon.spy(@box, 'swapContainer')
170
+ spies.push @box.__layoutClass.prototype.__load = sinon.spy()
171
+ spies.push sinon.spy(@box, '__load')
172
+
173
+ @box.__bootstrapLayout()
174
+ expect(spies).toBeSequenced()
175
+ expect(swapContainer.callCount).toEqual 2
@@ -0,0 +1,35 @@
1
+ describe "Joosy.Resource.Generic", ->
2
+
3
+ beforeEach ->
4
+ @resource = Joosy.Resource.Generic.create @data =
5
+ foo: 'bar'
6
+ bar: 'baz'
7
+ very:
8
+ deep:
9
+ value: 'boo!'
10
+
11
+
12
+ it "should remember where it belongs", ->
13
+ resource = new Joosy.Resource.Generic foo: 'bar'
14
+ expect(resource.e).toEqual Object.extended(foo: 'bar')
15
+
16
+ it "should produce magic function", ->
17
+ expect(Object.isFunction @resource).toBeTruthy()
18
+ expect(@resource.e).toEqual Object.extended(@data)
19
+
20
+ it "should get values", ->
21
+ expect(@resource 'foo').toEqual 'bar'
22
+ expect(@resource 'very.deep').toEqual value: 'boo!'
23
+ expect(@resource 'very.deep.value').toEqual 'boo!'
24
+
25
+ it "should set values", ->
26
+ expect(@resource 'foo').toEqual 'bar'
27
+ @resource 'foo', 'baz'
28
+ expect(@resource 'foo').toEqual 'baz'
29
+
30
+ expect(@resource 'very.deep').toEqual value: 'boo!'
31
+ @resource 'very.deep', 'banana!'
32
+ expect(@resource 'very.deep').toEqual 'banana!'
33
+
34
+ @resource 'another.deep.value', 'banana strikes back'
35
+ expect(@resource 'another.deep').toEqual value: 'banana strikes back'
@@ -0,0 +1,65 @@
1
+ describe "Joosy.Resource.RESTCollection", ->
2
+
3
+ class Test extends Joosy.Resource.REST
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.pages[1]).toEqual collection.data
11
+ expect(collection.data[0].constructor == Test).toBeTruthy()
12
+ expect(collection.data[0].e.name).toEqual 'test1'
13
+
14
+ spoofData = (server) ->
15
+ target = server.requests.last()
16
+ expect(target.method).toEqual 'GET'
17
+ expect(target.url).toMatch /^\/tests\/\?(page=\d+&)?_=\d+/
18
+ target.respond 200, 'Content-Type': 'application/json', data
19
+
20
+ beforeEach ->
21
+ @server = sinon.fakeServer.create()
22
+ @collection = new Joosy.Resource.RESTCollection(Test)
23
+
24
+ afterEach ->
25
+ @server.restore()
26
+
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
+ it "should fetch", ->
43
+ @collection.fetch()
44
+ spoofData @server
45
+ checkData @collection
46
+
47
+ it "should paginate", ->
48
+ @collection.fetch()
49
+ spoofData @server
50
+ checkData @collection
51
+
52
+ @collection.page 2, callback=sinon.spy()
53
+ spoofData @server
54
+ 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'
58
+
59
+ # Again from cache
60
+ @collection.page 2, callback=sinon.spy()
61
+ spoofData @server
62
+ 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'
@@ -0,0 +1,108 @@
1
+ describe "Joosy.Resource.REST", ->
2
+
3
+ beforeEach ->
4
+ @server = sinon.fakeServer.create()
5
+ class @Test extends Joosy.Resource.REST
6
+ @entity 'test'
7
+
8
+ afterEach ->
9
+ @server.restore()
10
+
11
+ it "should have default primary key", ->
12
+ expect(@Test::__primaryKey).toEqual 'id'
13
+
14
+ it "should have appropriate accessors", ->
15
+ @Test.entity 'tada'
16
+ expect(@Test::__entityName).toEqual 'tada'
17
+ expect(@Test.entityName()).toEqual 'tada'
18
+ @Test.source 'uri'
19
+ expect(@Test::__source).toEqual 'uri'
20
+ expect(@Test.__buildSource()).toEqual 'uri/'
21
+ @Test.primary 'uid'
22
+ expect(@Test::__primaryKey).toEqual 'uid'
23
+ @Test.beforeLoad 'function'
24
+ expect(@Test::__beforeLoad).toEqual 'function'
25
+
26
+ it "should build source url based on entity name", ->
27
+ options =
28
+ extension: 'id'
29
+ params:
30
+ test: 1
31
+ expect(@Test.__buildSource(options)).toEqual '/tests/id?test=1'
32
+
33
+ it "should have overloaded constructor", ->
34
+ resource = @Test.create 'someId'
35
+ expect(resource.id).toEqual 'someId'
36
+
37
+ data = {id: 'someId', field: 'value'}
38
+
39
+ rooted = @Test.create {test: data}
40
+ unrooted = @Test.create data
41
+
42
+ expect(rooted.e).toEqual unrooted.e
43
+ expect(rooted.id).toEqual 'someId'
44
+ expect(rooted.e.id).toEqual 'someId'
45
+ expect(rooted.e.field).toEqual 'value'
46
+
47
+ it 'should find single object', ->
48
+ @Test.beforeLoad beforeLoadCallback = sinon.spy (data) ->
49
+ expect(data.id).toEqual 1
50
+ expect(data.name).toEqual 'test1'
51
+ Object.extended(test: data)
52
+ @Test.find 1, callback = sinon.spy (target) ->
53
+ expect(target.id).toEqual 1
54
+ expect(target.e?.name).toEqual 'test1'
55
+ target = @server.requests[0]
56
+ expect(target.method).toEqual 'GET'
57
+ expect(target.url).toMatch /^\/tests\/1\?_=\d+/
58
+ target.respond 200, 'Content-Type': 'application/json',
59
+ '{"id": 1, "name": "test1"}'
60
+ expect(callback.callCount).toEqual 1
61
+ expect(beforeLoadCallback.callCount).toEqual 1
62
+
63
+ it 'should find objects collection with params', ->
64
+ callback = sinon.spy (collection) ->
65
+ i = 1
66
+ collection.data.each (target) ->
67
+ expect(target.id).toEqual i
68
+ expect(target.e?.name).toEqual 'test' + i
69
+ i += 1
70
+ @Test.find null, callback
71
+ target = @server.requests[0]
72
+ expect(target.method).toEqual 'GET'
73
+ expect(target.url).toMatch /^\/tests\/\?_=\d+/
74
+ target.respond 200, 'Content-Type': 'application/json',
75
+ '[{"id": 1, "name": "test1"}, {"id": 2, "name": "test2"}]'
76
+ expect(callback.callCount).toEqual 1
77
+
78
+ it 'should find all objects collection', ->
79
+ callback = sinon.spy (collection) ->
80
+ i = 1
81
+ collection.data.each (target) ->
82
+ expect(target.id).toEqual i
83
+ expect(target.e?.name).toEqual 'test' + i
84
+ i += 1
85
+ @Test.find callback
86
+ target = @server.requests[0]
87
+ expect(target.method).toEqual 'GET'
88
+ expect(target.url).toMatch /^\/tests\/\?_=\d+/
89
+ target.respond 200, 'Content-Type': 'application/json',
90
+ '[{"id": 1, "name": "test1"}, {"id": 2, "name": "test2"}]'
91
+ expect(callback.callCount).toEqual 1
92
+
93
+ it 'should destroy single object', ->
94
+ obj = @Test.create 1
95
+ callback = sinon.spy (target) ->
96
+ expect(target).toBe obj
97
+ obj.destroy callback
98
+ target = @server.requests[0]
99
+ expect(target.method).toEqual 'DELETE'
100
+ expect(target.url).toEqual '/tests/1'
101
+ target.respond 200
102
+ expect(callback.callCount).toEqual 1
103
+
104
+ it "should identify identifiers", ->
105
+ [0, 123, -5, '123abd', 'whatever'].each (variant) =>
106
+ expect(@Test.__isId variant).toBeTruthy()
107
+ [(->) , [], {}, null, undefined, true, false].each (variant) =>
108
+ expect(@Test.__isId variant).toBeFalsy()