joosy 0.1.0.RC1
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.
- data/.gitignore +5 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +159 -0
- data/Guardfile +30 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +3 -0
- data/Rakefile +14 -0
- data/app/assets/javascripts/joosy.js.coffee +7 -0
- data/app/assets/javascripts/joosy/core/application.js.coffee +28 -0
- data/app/assets/javascripts/joosy/core/form.js.coffee +87 -0
- data/app/assets/javascripts/joosy/core/helpers.js.coffee +6 -0
- data/app/assets/javascripts/joosy/core/joosy.js.coffee +65 -0
- data/app/assets/javascripts/joosy/core/layout.js.coffee +47 -0
- data/app/assets/javascripts/joosy/core/modules/container.js.coffee +59 -0
- data/app/assets/javascripts/joosy/core/modules/events.js.coffee +35 -0
- data/app/assets/javascripts/joosy/core/modules/filters.js.coffee +39 -0
- data/app/assets/javascripts/joosy/core/modules/log.js.coffee +15 -0
- data/app/assets/javascripts/joosy/core/modules/module.js.coffee +43 -0
- data/app/assets/javascripts/joosy/core/modules/renderer.js.coffee +116 -0
- data/app/assets/javascripts/joosy/core/modules/time_manager.js.coffee +25 -0
- data/app/assets/javascripts/joosy/core/modules/widgets_manager.js.coffee +58 -0
- data/app/assets/javascripts/joosy/core/page.js.coffee +156 -0
- data/app/assets/javascripts/joosy/core/preloader.js.coffee +5 -0
- data/app/assets/javascripts/joosy/core/resource/generic.js.coffee +61 -0
- data/app/assets/javascripts/joosy/core/resource/rest.js.coffee +76 -0
- data/app/assets/javascripts/joosy/core/resource/rest_collection.js.coffee +48 -0
- data/app/assets/javascripts/joosy/core/router.js.coffee +89 -0
- data/app/assets/javascripts/joosy/core/templaters/rails_jst.js.coffee +20 -0
- data/app/assets/javascripts/joosy/core/widget.js.coffee +41 -0
- data/app/assets/javascripts/joosy/preloaders/caching.js.coffee +94 -0
- data/app/assets/javascripts/joosy/preloaders/inline.js.coffee +55 -0
- data/app/helpers/joosy/sprockets_helper.rb +23 -0
- data/app/views/layouts/json_wrapper.json.erb +1 -0
- data/joosy.gemspec +25 -0
- data/lib/joosy.rb +9 -0
- data/lib/joosy/forms.rb +47 -0
- data/lib/joosy/rails/engine.rb +17 -0
- data/lib/joosy/rails/version.rb +5 -0
- data/lib/rails/generators/joosy/application_generator.rb +41 -0
- data/lib/rails/generators/joosy/joosy_base.rb +30 -0
- data/lib/rails/generators/joosy/layout_generator.rb +32 -0
- data/lib/rails/generators/joosy/page_generator.rb +44 -0
- data/lib/rails/generators/joosy/preloader_generator.rb +32 -0
- data/lib/rails/generators/joosy/resource_generator.rb +29 -0
- data/lib/rails/generators/joosy/templates/app.js.coffee +10 -0
- data/lib/rails/generators/joosy/templates/app/helpers/application.js.coffee +4 -0
- data/lib/rails/generators/joosy/templates/app/layouts/application.js.coffee +2 -0
- data/lib/rails/generators/joosy/templates/app/layouts/template.js.coffee +2 -0
- data/lib/rails/generators/joosy/templates/app/pages/application.js.coffee +1 -0
- data/lib/rails/generators/joosy/templates/app/pages/template.js.coffee +5 -0
- data/lib/rails/generators/joosy/templates/app/pages/welcome/index.js.coffee +22 -0
- data/lib/rails/generators/joosy/templates/app/resources/template.js.coffee +2 -0
- data/lib/rails/generators/joosy/templates/app/routes.js.coffee +8 -0
- data/lib/rails/generators/joosy/templates/app/templates/layouts/application.jst.hamlc +2 -0
- data/lib/rails/generators/joosy/templates/app/templates/pages/welcome/index.jst.hamlc +7 -0
- data/lib/rails/generators/joosy/templates/app/widgets/template.js.coffee +2 -0
- data/lib/rails/generators/joosy/templates/app_controller.rb +9 -0
- data/lib/rails/generators/joosy/templates/app_preloader.js.coffee.erb +13 -0
- data/lib/rails/generators/joosy/templates/preload.html.erb +26 -0
- data/lib/rails/generators/joosy/templates/preload.html.haml +19 -0
- data/lib/rails/generators/joosy/widget_generator.rb +32 -0
- data/spec/javascripts/helpers/spec_helper.js.coffee +44 -0
- data/spec/javascripts/joosy/core/application_spec.js.coffee +40 -0
- data/spec/javascripts/joosy/core/form_spec.js.coffee +141 -0
- data/spec/javascripts/joosy/core/joosy_spec.js.coffee +72 -0
- data/spec/javascripts/joosy/core/layout_spec.js.coffee +50 -0
- data/spec/javascripts/joosy/core/modules/container_spec.js.coffee +92 -0
- data/spec/javascripts/joosy/core/modules/events_spec.js.coffee +53 -0
- data/spec/javascripts/joosy/core/modules/filters_spec.js.coffee +71 -0
- data/spec/javascripts/joosy/core/modules/log_spec.js.coffee +15 -0
- data/spec/javascripts/joosy/core/modules/module_spec.js.coffee +47 -0
- data/spec/javascripts/joosy/core/modules/renderer_spec.js.coffee +149 -0
- data/spec/javascripts/joosy/core/modules/time_manager_spec.js.coffee +25 -0
- data/spec/javascripts/joosy/core/modules/widget_manager_spec.js.coffee +75 -0
- data/spec/javascripts/joosy/core/page_spec.js.coffee +175 -0
- data/spec/javascripts/joosy/core/resource/generic_spec.js.coffee +35 -0
- data/spec/javascripts/joosy/core/resource/rest_collection_spec.js.coffee +65 -0
- data/spec/javascripts/joosy/core/resource/rest_spec.js.coffee +108 -0
- data/spec/javascripts/joosy/core/router_spec.js.coffee +123 -0
- data/spec/javascripts/joosy/core/templaters/rails_jst_spec.js.coffee +25 -0
- data/spec/javascripts/joosy/core/widget_spec.js.coffee +51 -0
- data/spec/javascripts/joosy/preloaders/caching_spec.js.coffee +36 -0
- data/spec/javascripts/joosy/preloaders/inline_spec.js.coffee +16 -0
- data/spec/javascripts/support/assets/coolface.jpg +0 -0
- data/spec/javascripts/support/assets/okay.jpg +0 -0
- data/spec/javascripts/support/assets/test.js +1 -0
- data/spec/javascripts/support/jasmine.yml +74 -0
- data/spec/javascripts/support/jasmine_config.rb +23 -0
- data/spec/javascripts/support/jasmine_runner.rb +32 -0
- data/spec/javascripts/support/sinon-1.3.1.js +3469 -0
- data/spec/javascripts/support/sinon-ie-1.3.1.js +82 -0
- data/vendor/assets/javascripts/base64.js +135 -0
- data/vendor/assets/javascripts/inflection.js +656 -0
- data/vendor/assets/javascripts/jquery.form.js +980 -0
- data/vendor/assets/javascripts/jquery.hashchange.js +390 -0
- data/vendor/assets/javascripts/metamorph.js +409 -0
- data/vendor/assets/javascripts/sugar.js +6040 -0
- 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()
|