honkster-jelly 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +1 -2
  3. data/Gemfile.lock +1 -1
  4. data/Rakefile +0 -16
  5. data/jelly.gemspec +13 -64
  6. data/lib/jelly/jelly_helper.rb +1 -1
  7. data/spec/fixtures/public/javascripts/components/component1.js +0 -0
  8. data/spec/fixtures/public/javascripts/foo/components/paw.js +0 -0
  9. data/spec/fixtures/public/javascripts/foo/components/teeth.js +0 -0
  10. data/spec/fixtures/public/javascripts/foo/pages/bears.js +0 -0
  11. data/spec/fixtures/public/javascripts/foo/pages/lions.js +0 -0
  12. data/spec/fixtures/public/javascripts/foo/pages/tigers.js +0 -0
  13. data/spec/fixtures/public/javascripts/pages/page1.js +0 -0
  14. data/spec/jasmine/TrivialReporter.js +129 -0
  15. data/spec/jasmine/jasmine-0.10.0.js +2149 -0
  16. data/spec/jasmine/jasmine.css +76 -0
  17. data/spec/jasmine/json2.js +478 -0
  18. data/spec/jasmine_runner.html +30 -0
  19. data/spec/javascript/ajax_with_jelly_spec.js +157 -0
  20. data/spec/javascript/jelly_spec.js +649 -0
  21. data/spec/javascript/spec_helper.js +7 -0
  22. data/spec/jelly/common_spec.rb +56 -0
  23. data/spec/jelly/jelly_controller_spec.rb +331 -0
  24. data/spec/jelly/jelly_helper_spec.rb +88 -0
  25. data/spec/rails_root/Gemfile +31 -0
  26. data/spec/rails_root/Gemfile.lock +73 -0
  27. data/spec/rails_root/README +256 -0
  28. data/spec/rails_root/Rakefile +7 -0
  29. data/spec/rails_root/app/controllers/application_controller.rb +3 -0
  30. data/spec/rails_root/app/helpers/application_helper.rb +2 -0
  31. data/spec/rails_root/app/views/layouts/application.html.erb +14 -0
  32. data/spec/rails_root/config.ru +4 -0
  33. data/spec/rails_root/config/application.rb +42 -0
  34. data/spec/rails_root/config/boot.rb +6 -0
  35. data/spec/rails_root/config/database.yml +22 -0
  36. data/spec/rails_root/config/environment.rb +5 -0
  37. data/spec/rails_root/config/environments/development.rb +26 -0
  38. data/spec/rails_root/config/environments/production.rb +49 -0
  39. data/spec/rails_root/config/environments/test.rb +35 -0
  40. data/spec/rails_root/config/initializers/backtrace_silencers.rb +7 -0
  41. data/spec/rails_root/config/initializers/inflections.rb +10 -0
  42. data/spec/rails_root/config/initializers/mime_types.rb +5 -0
  43. data/spec/rails_root/config/initializers/new_rails_defaults.rb +19 -0
  44. data/spec/rails_root/config/initializers/secret_token.rb +7 -0
  45. data/spec/rails_root/config/initializers/session_store.rb +8 -0
  46. data/spec/rails_root/config/locales/en.yml +5 -0
  47. data/spec/rails_root/config/routes.rb +58 -0
  48. data/spec/rails_root/db/seeds.rb +7 -0
  49. data/spec/rails_root/db/test.sqlite3 +1 -0
  50. data/spec/rails_root/doc/README_FOR_APP +2 -0
  51. data/spec/rails_root/log/development.log +0 -0
  52. data/spec/rails_root/log/production.log +0 -0
  53. data/spec/rails_root/log/server.log +0 -0
  54. data/spec/rails_root/log/test.log +6 -0
  55. data/spec/rails_root/public/404.html +26 -0
  56. data/spec/rails_root/public/422.html +26 -0
  57. data/spec/rails_root/public/500.html +26 -0
  58. data/spec/rails_root/public/favicon.ico +0 -0
  59. data/spec/rails_root/public/images/rails.png +0 -0
  60. data/spec/rails_root/public/index.html +239 -0
  61. data/spec/rails_root/public/javascripts/application.js +2 -0
  62. data/spec/rails_root/public/javascripts/controls.js +965 -0
  63. data/spec/rails_root/public/javascripts/dragdrop.js +974 -0
  64. data/spec/rails_root/public/javascripts/effects.js +1123 -0
  65. data/spec/rails_root/public/javascripts/prototype.js +6001 -0
  66. data/spec/rails_root/public/javascripts/rails.js +191 -0
  67. data/spec/rails_root/public/robots.txt +5 -0
  68. data/spec/rails_root/script/about +4 -0
  69. data/spec/rails_root/script/console +3 -0
  70. data/spec/rails_root/script/dbconsole +3 -0
  71. data/spec/rails_root/script/destroy +3 -0
  72. data/spec/rails_root/script/generate +3 -0
  73. data/spec/rails_root/script/performance/benchmarker +3 -0
  74. data/spec/rails_root/script/performance/profiler +3 -0
  75. data/spec/rails_root/script/plugin +3 -0
  76. data/spec/rails_root/script/rails +6 -0
  77. data/spec/rails_root/script/runner +3 -0
  78. data/spec/rails_root/script/server +3 -0
  79. data/spec/rails_root/test/performance/browsing_test.rb +9 -0
  80. data/spec/rails_root/test/test_helper.rb +13 -0
  81. data/spec/spec_helper.rb +37 -0
  82. data/spec/spec_suite.rb +3 -0
  83. metadata +271 -46
  84. data/VERSION.yml +0 -5
@@ -0,0 +1,30 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
2
+ "http://www.w3.org/TR/html4/loose.dtd">
3
+ <html>
4
+ <head>
5
+ <title>Jasmine Test Runner</title>
6
+ </head>
7
+ <script type="text/javascript" src="jasmine/jasmine-0.10.0.js"></script>
8
+ <script type="text/javascript" src="jasmine/TrivialReporter.js"></script>
9
+ <link href="jasmine/jasmine.css" rel="stylesheet" type="text/css"/>
10
+
11
+ <script type="text/javascript" src="../generators/jelly/templates/javascripts/jquery/jquery-1.3.2.js"></script>
12
+ <script type="text/javascript" src="../generators/jelly/templates/javascripts/ajax_with_jelly.js"></script>
13
+ <script type="text/javascript" src="../generators/jelly/templates/javascripts/jelly.js"></script>
14
+
15
+ <script type="text/javascript">
16
+ jasmine.include('javascript/jelly_spec.js', true);
17
+ jasmine.include('javascript/ajax_with_jelly_spec.js', true);
18
+ </script>
19
+
20
+ <script type="text/javascript">
21
+ $(document).ready(function() {
22
+ var jasmineEnv = jasmine.getEnv();
23
+ jasmineEnv.reporter = new jasmine.TrivialReporter();
24
+ jasmineEnv.execute();
25
+ });
26
+ </script>
27
+
28
+ <body>
29
+ </body>
30
+ </html>
@@ -0,0 +1,157 @@
1
+ describe("Jelly", function() {
2
+ var our_token;
3
+
4
+ beforeEach(function() {
5
+ Jelly.add("MyPage", {
6
+ on_my_method : function() {
7
+ }
8
+ });
9
+ page = Jelly.all["MyPage"];
10
+ spyOn($, 'ajax');
11
+ our_token = "authenticity token";
12
+ window._token = our_token;
13
+ });
14
+
15
+ afterEach(function() {
16
+ delete Jelly.all["MyPage"];
17
+ });
18
+
19
+ describe(".ajaxWithJelly", function() {
20
+ it("should set default params and call ajax", function() {
21
+ var params = {foo: "bar"};
22
+ var modifiedParams = "whatever";
23
+ spyOn($.ajaxWithJelly, 'params').andReturn(modifiedParams);
24
+ $.ajaxWithJelly(params);
25
+ expect($.ajaxWithJelly.params).wasCalled();
26
+ expect($.ajaxWithJelly.params).wasCalledWith(params);
27
+ expect($.ajax).wasCalled();
28
+ expect($.ajax).wasCalledWith(modifiedParams);
29
+ });
30
+ });
31
+
32
+ describe(".ajaxWithJelly.params", function() {
33
+ it("should set some base params", function() {
34
+ var ajaxParams = $.ajaxWithJelly.params();
35
+ expect(ajaxParams['dataType']).toEqual('json');
36
+ expect(ajaxParams['cache']).toBeFalsy();
37
+ expect(ajaxParams['success']).toBeTruthy();
38
+ });
39
+
40
+ it("should preserve passed data", function() {
41
+ var ajaxParams = $.ajaxWithJelly.params({foo : 'bar', data: {bar : 'baz'}});
42
+ expect(ajaxParams['foo']).toEqual('bar');
43
+ expect(ajaxParams['data']['bar']).toEqual('baz');
44
+ });
45
+
46
+ it("should allow override of type", function() {
47
+ var ajaxParams = $.ajaxWithJelly.params({type : 'DELETE'});
48
+ expect(ajaxParams['type']).toEqual('DELETE');
49
+ });
50
+
51
+ describe("whether to set authenticity token", function() {
52
+ it("should set an auth token when type is not a GET", function() {
53
+ var ajaxParams = $.ajaxWithJelly.params({type: "NON-GET"});
54
+ expect(ajaxParams['data']['authenticity_token']).toEqual(our_token);
55
+ });
56
+
57
+ it("should not set an auth token when type is not passed in", function() {
58
+ var ajaxParams = $.ajaxWithJelly.params();
59
+ expect(ajaxParams['data']).toEqual(undefined);
60
+ });
61
+
62
+ it("should not set an auth token when type is GET", function() {
63
+ var ajaxParams = $.ajaxWithJelly.params({type: "GET"});
64
+ expect(ajaxParams['data']).toEqual(undefined);
65
+ });
66
+ });
67
+
68
+ describe(".ajaxWithJelly.params.success", function() {
69
+ describe("when no observers are passed into params", function() {
70
+ it("calls Jelly.notifyObservers on Jelly.observers", function() {
71
+ var observerArgs;
72
+ var observer = {
73
+ on_my_method: function(arg1, arg2) {
74
+ observerArgs = [arg1, arg2];
75
+ }
76
+ };
77
+ Jelly.attach({component: observer, arguments: []});
78
+ expect(Jelly.observers).toContain(observer);
79
+
80
+ var notification = {
81
+ "arguments":["arg1", "arg2"],
82
+ "method":"on_my_method"
83
+ };
84
+ $.ajaxWithJelly.params().success(notification);
85
+
86
+ expect(observerArgs).toEqual(["arg1", "arg2"]);
87
+ });
88
+ });
89
+
90
+ describe("when observers are passed into params", function() {
91
+ it("calls Jelly.notifyObservers on passed-in observers", function() {
92
+ var observerArgs;
93
+ var observer = {
94
+ on_my_method: function(arg1, arg2) {
95
+ observerArgs = [arg1, arg2];
96
+ }
97
+ };
98
+ var observers = [observer];
99
+ expect(Jelly.observers).toNotContain(observer);
100
+
101
+ var notification = {
102
+ "arguments":["arg1", "arg2"],
103
+ "method":"on_my_method"
104
+ };
105
+ $.ajaxWithJelly.params({observers: observers}).success(notification);
106
+
107
+ expect(observerArgs).toEqual(["arg1", "arg2"]);
108
+ });
109
+ });
110
+ });
111
+ });
112
+
113
+
114
+ describe(".ajaxFormWithJelly", function() {
115
+
116
+ describe("without ajaxForm plugin", function() {
117
+ it("should not be defined", function() {
118
+ expect($.fn.ajaxForm).toEqual(undefined);
119
+ expect($.fn.ajaxFormWithJelly).toEqual(undefined);
120
+ });
121
+ });
122
+
123
+ describe("with ajaxForm plugin", function() {
124
+ var $form;
125
+ beforeEach(function() {
126
+ $form = $('body').append('<form id="myForm"></form>').find('#myForm');
127
+ $.fn.ajaxForm = {};
128
+ spyOn($.fn, 'ajaxForm');
129
+ Jelly.defineAjaxWithJellyFunctions($);
130
+ });
131
+
132
+ afterEach(function() {
133
+ $.fn.ajaxForm = undefined;
134
+ Jelly.defineAjaxWithJellyFunctions($);
135
+ });
136
+
137
+ it("should set default params and call ajax", function() {
138
+ var modifiedParams = "whatever";
139
+ spyOn($.ajaxWithJelly, 'params').andReturn(modifiedParams);
140
+ $form.ajaxFormWithJelly();
141
+ expect($.ajaxWithJelly.params).wasCalled();
142
+ expect($.ajaxWithJelly.params).wasCalledWith(undefined);
143
+ expect($.fn.ajaxForm).wasCalled();
144
+ expect($.fn.ajaxForm).wasCalledWith(modifiedParams);
145
+ expect($.fn.ajaxForm.mostRecentCall.object.get(0)).toEqual($form.get(0));
146
+ });
147
+
148
+ it("should merge in params", function() {
149
+ var params = {foo: "bar"};
150
+ spyOn($.ajaxWithJelly, 'params');
151
+ $form.ajaxFormWithJelly(params);
152
+ expect($.ajaxWithJelly.params).wasCalled();
153
+ expect($.ajaxWithJelly.params).wasCalledWith(params);
154
+ });
155
+ });
156
+ });
157
+ });
@@ -0,0 +1,649 @@
1
+ describe("Jelly", function() {
2
+ var our_token;
3
+
4
+ beforeEach(function() {
5
+ spyOn($, 'ajax');
6
+ our_token = "authenticity token";
7
+ window._token = our_token;
8
+ Jelly.init();
9
+ });
10
+
11
+ describe(".add", function() {
12
+ afterEach(function() {
13
+ delete Jelly.Pages.all["test-name"];
14
+ });
15
+
16
+ it("instantiates a Page with the passed-in name and attaches the set of passed-in functions to the Page object", function() {
17
+ expect(Jelly.Pages.all["test-name"]).toEqual(undefined);
18
+
19
+ var showFn = function() {
20
+ };
21
+ var newFn = function() {
22
+ };
23
+ var indexFn = function() {
24
+ };
25
+ var newPage = Jelly.Pages.add("test-name", {show: showFn}, {'new': newFn}, {index: indexFn});
26
+ expect(Jelly.Pages.all["test-name"]).toNotEqual(undefined);
27
+ expect(newPage).toEqual(Jelly.Pages.all["test-name"]);
28
+ expect(newPage.show).toEqual(showFn);
29
+ expect(newPage['new']).toEqual(newFn);
30
+ expect(newPage.index).toEqual(indexFn);
31
+ });
32
+ });
33
+
34
+ describe(".attach", function() {
35
+ describe("when the argument contains a 'component' key", function() {
36
+ describe("when the component does not respond to init", function() {
37
+ describe("when the component is referenced as a String", function() {
38
+ beforeEach(function() {
39
+ window.MyComponent = {
40
+ };
41
+ });
42
+
43
+ afterEach(function() {
44
+ delete window.MyComponent;
45
+ });
46
+
47
+ it("attaches the component to Jelly.observers", function() {
48
+ Jelly.attach({component: "MyComponent"});
49
+ expect(Jelly.observers).toContain(MyComponent);
50
+ });
51
+ });
52
+
53
+ describe("when the component is referenced as itself", function() {
54
+ it("attaches the component to Jelly.observers", function() {
55
+ var component = {};
56
+ Jelly.attach({component: component});
57
+ expect(Jelly.observers).toContain(component);
58
+ });
59
+ });
60
+ });
61
+
62
+ describe("when component responds to init", function() {
63
+ describe("when the component's init method returns undefined", function() {
64
+ describe("when the component is referenced as a String", function() {
65
+ beforeEach(function() {
66
+ window.MyComponent = {
67
+ init: function() {
68
+ }
69
+ };
70
+ });
71
+
72
+ afterEach(function() {
73
+ delete window.MyComponent;
74
+ });
75
+
76
+ it("calls the init method on the component and attaches the component to Jelly.observers", function() {
77
+ spyOn(MyComponent, 'init');
78
+ Jelly.attach({component: MyComponent, arguments: [1, 2]});
79
+ expect(MyComponent.init).wasCalledWith(1, 2);
80
+ expect(Jelly.observers).toContain(MyComponent);
81
+ });
82
+ });
83
+
84
+ describe("when the component is referenced as itself", function() {
85
+ var component;
86
+ beforeEach(function() {
87
+ component = {
88
+ init: function() {
89
+ }
90
+ };
91
+ });
92
+
93
+ it("calls the init method on the component and attaches the component to Jelly.observers", function() {
94
+ spyOn(component, 'init');
95
+ Jelly.attach({component: component, arguments: [1, 2]});
96
+ expect(component.init).wasCalledWith(1, 2);
97
+ expect(Jelly.observers).toContain(component);
98
+ });
99
+ });
100
+ });
101
+
102
+ describe("when the component's init method returns false", function() {
103
+ var component;
104
+ beforeEach(function() {
105
+ component = {
106
+ init: function() {
107
+ component.initCalled = true;
108
+ return false;
109
+ }
110
+ };
111
+ });
112
+
113
+ it("calls the init method on the component and does not attaches an observer to Jelly.observers", function() {
114
+ var originalObserversLength = Jelly.observers.length;
115
+ Jelly.attach({component: component, arguments: [1, 2]});
116
+ expect(component.initCalled).toBeTruthy();
117
+ expect(Jelly.observers.length).toEqual(originalObserversLength);
118
+ expect(Jelly.observers).toNotContain(component);
119
+ });
120
+ });
121
+
122
+ describe("when the component's init method returns null", function() {
123
+ var component;
124
+ beforeEach(function() {
125
+ component = {
126
+ init: function() {
127
+ component.initCalled = true;
128
+ return null;
129
+ }
130
+ };
131
+ });
132
+
133
+ it("calls the init method on the component and does not attaches an observer to Jelly.observers", function() {
134
+ var originalObserversLength = Jelly.observers.length;
135
+ Jelly.attach({component: component, arguments: [1, 2]});
136
+ expect(component.initCalled).toBeTruthy();
137
+ expect(Jelly.observers.length).toEqual(originalObserversLength);
138
+ expect(Jelly.observers).toNotContain(component);
139
+ });
140
+ });
141
+
142
+ describe("when the component's init method returns an object", function() {
143
+ it("attaches the returned object (instead of the component) to Jelly.observers", function() {
144
+ var observer = new Object();
145
+ var component = {
146
+ init: function() {
147
+ return observer;
148
+ }
149
+ };
150
+ Jelly.attach({component: component, arguments: [1, 2]});
151
+ expect(Jelly.observers).toContain(observer);
152
+ expect(Jelly.observers).toNotContain(component);
153
+ });
154
+ });
155
+ });
156
+ });
157
+
158
+ describe("when the argument does not contain a 'component' key", function() {
159
+ describe("when the component is referenced as a String", function() {
160
+ beforeEach(function() {
161
+ window.MyComponent = {
162
+ init: function() {
163
+ }
164
+ };
165
+ });
166
+
167
+ afterEach(function() {
168
+ delete window.MyComponent;
169
+ });
170
+
171
+ it("does not call init and attaches the component to Jelly.observers", function() {
172
+ spyOn(MyComponent, 'init');
173
+ Jelly.attach("MyComponent");
174
+ expect(MyComponent.init).wasNotCalled();
175
+ expect(Jelly.observers).toContain(MyComponent);
176
+ });
177
+ });
178
+
179
+ describe("when the component is referenced as itself", function() {
180
+ it("does not call init and attaches the component to Jelly.observers", function() {
181
+ var component = {
182
+ init: function() {
183
+ }
184
+ };
185
+ spyOn(component, 'init');
186
+ Jelly.attach(component);
187
+ expect(component.init).wasNotCalled();
188
+ expect(Jelly.observers).toContain(component);
189
+ });
190
+ });
191
+ });
192
+ });
193
+
194
+ describe(".Observers.notify", function() {
195
+ beforeEach(function() {
196
+ Jelly.Pages.add("MyPage", {
197
+ on_my_method : function() {
198
+ }
199
+ });
200
+ Jelly.attach({component: "Jelly.Page", arguments: ["MyPage", "index"]});
201
+ });
202
+
203
+ describe(".notifying", function() {
204
+ it("should be set to true only while observers are being notified", function() {
205
+ expect(Jelly.Observers.notifying).toBe(false);
206
+ var notifyingWasSet = false;
207
+ page.on_my_method = function() {
208
+ notifyingWasSet = Jelly.Observers.notifying;
209
+ }
210
+ Jelly.notifyObservers({
211
+ "method":"on_my_method"
212
+ });
213
+ expect(notifyingWasSet).toBe(true);
214
+ });
215
+
216
+ it("should be reset to its prior value when notification is complete", function() {
217
+ Jelly.Observers.notifying = true;
218
+ spyOn(page, 'on_my_method');
219
+ Jelly.notifyObservers({
220
+ "method":"on_my_method"
221
+ });
222
+ expect(page.on_my_method).wasCalled();
223
+ expect(Jelly.Observers.notifying).toBe(true);
224
+ });
225
+ });
226
+
227
+ describe("when bound to the default Jelly.observers collection", function() {
228
+ describe("the active page object", function() {
229
+ describe("when the notify method is defined on the page", function() {
230
+ it("should call the notify method on the page", function() {
231
+ spyOn(page, 'on_my_method');
232
+ Jelly.notifyObservers({
233
+ "arguments":["arg1", "arg2"],
234
+ "method":"on_my_method"
235
+ });
236
+ expect(page.on_my_method).wasCalled();
237
+ expect(page.on_my_method).wasCalledWith('arg1', 'arg2');
238
+ });
239
+
240
+ describe("when there are attached components", function() {
241
+ it("calls the notify methods in the order of the attached components", function() {
242
+ var component = {
243
+ on_my_method: function() {
244
+ }
245
+ };
246
+ Jelly.attach({component: component, arguments: []});
247
+
248
+ var functionsCalledInOrder = [];
249
+ spyOn(page, 'on_my_method').andCallFake(function() {
250
+ functionsCalledInOrder.push("page");
251
+ });
252
+ spyOn(component, 'on_my_method').andCallFake(function() {
253
+ functionsCalledInOrder.push("component");
254
+ });
255
+ Jelly.notifyObservers({
256
+ "arguments":["arg1", "arg2"],
257
+ "method":"on_my_method"
258
+ });
259
+ expect(page.on_my_method).wasCalled();
260
+ expect(page.on_my_method).wasCalledWith('arg1', 'arg2');
261
+ expect(component.on_my_method).wasCalled();
262
+ expect(component.on_my_method).wasCalledWith('arg1', 'arg2');
263
+ expect(functionsCalledInOrder).toEqual(["page", "component"]);
264
+ });
265
+ });
266
+ });
267
+
268
+ describe("when the page object does not define the notify method", function() {
269
+ it("does not blow up", function() {
270
+ expect(page.on_my_undefined_method).toBe(undefined);
271
+ Jelly.notifyObservers({
272
+ "arguments":["arg1", "arg2"],
273
+ "method":"on_my_undefined_method"
274
+ });
275
+ });
276
+ });
277
+ });
278
+
279
+ describe("when the 'on' parameter is present", function() {
280
+ beforeEach(function() {
281
+ GlobalObject = {on_my_method: function() {
282
+ }};
283
+ GlobalObject.secondObject = {on_my_method: function() {
284
+ }};
285
+ });
286
+
287
+ afterEach(function() {
288
+ delete GlobalObject;
289
+ });
290
+
291
+ describe("when the 'on' parameter is a string", function() {
292
+ describe("when the 'on' object defines the notify method", function() {
293
+ it("should call on_my_method on that object and not on the rest of the observers", function() {
294
+ spyOn(GlobalObject, 'on_my_method');
295
+ spyOn(GlobalObject.secondObject, 'on_my_method');
296
+ Jelly.attach(GlobalObject);
297
+ Jelly.notifyObservers({
298
+ "arguments":["arg1", "arg2"],
299
+ "method":"on_my_method",
300
+ "on":"GlobalObject.secondObject"
301
+ });
302
+ expect(GlobalObject.on_my_method).wasNotCalled();
303
+ expect(GlobalObject.secondObject.on_my_method).wasCalledWith('arg1', 'arg2');
304
+ });
305
+ });
306
+
307
+ describe("when the 'on' object does not define the notify method", function() {
308
+ it("does not blow up", function() {
309
+ expect(GlobalObject.secondObject.on_my_undefined_method).toBe(undefined);
310
+ Jelly.notifyObservers({
311
+ "arguments":["arg1", "arg2"],
312
+ "method":"on_my_undefined_method",
313
+ "on":"GlobalObject.secondObject"
314
+ });
315
+ });
316
+ })
317
+ });
318
+
319
+ describe("when the 'on' parameter is an object", function() {
320
+ describe("when the 'on' object defines the notify method", function() {
321
+ it("should call on_my_method on that object and not on the rest of the observers", function() {
322
+ spyOn(GlobalObject, 'on_my_method');
323
+ spyOn(GlobalObject.secondObject, 'on_my_method');
324
+ Jelly.attach(GlobalObject);
325
+ Jelly.notifyObservers({
326
+ "arguments":["arg1", "arg2"],
327
+ "method":"on_my_method",
328
+ "on": GlobalObject.secondObject
329
+ });
330
+ expect(GlobalObject.on_my_method).wasNotCalled();
331
+ expect(GlobalObject.secondObject.on_my_method).wasCalledWith('arg1', 'arg2');
332
+ });
333
+ });
334
+
335
+ describe("when the 'on' object does not define the notify method", function() {
336
+ it("does not blow up", function() {
337
+ expect(GlobalObject.secondObject.on_my_undefined_method).toBe(undefined);
338
+ Jelly.notifyObservers({
339
+ "arguments":["arg1", "arg2"],
340
+ "method":"on_my_undefined_method",
341
+ "on": GlobalObject.secondObject
342
+ });
343
+ });
344
+ })
345
+ });
346
+ });
347
+ });
348
+
349
+ describe("when bound to an array of custom observers", function() {
350
+ it("notifies the given observers and not the existing Jelly.observers, unless in the list of observers", function() {
351
+ var component = {
352
+ on_my_method: function() {
353
+ }
354
+ };
355
+ Jelly.attach({component: "Jelly.Page", arguments: ["MyPage", "index"]});
356
+ Jelly.attach({component: component, arguments: []});
357
+
358
+ spyOn(page, 'on_my_method');
359
+ spyOn(component, 'on_my_method');
360
+
361
+ var customObserver1 = {on_my_method: function() {
362
+ }};
363
+ spyOn(customObserver1, 'on_my_method');
364
+ var customObserver2 = {on_my_method: function() {
365
+ }};
366
+ spyOn(customObserver2, 'on_my_method');
367
+
368
+ Jelly.notifyObservers.call([customObserver1, customObserver2], {
369
+ "arguments":["arg1", "arg2"],
370
+ "method":"on_my_method"
371
+ });
372
+
373
+ expect(page.on_my_method).wasNotCalled();
374
+ expect(component.on_my_method).wasNotCalled();
375
+
376
+ expect(customObserver1.on_my_method).wasCalled();
377
+ expect(customObserver1.on_my_method).wasCalledWith('arg1', 'arg2');
378
+ expect(customObserver2.on_my_method).wasCalled();
379
+ expect(customObserver2.on_my_method).wasCalledWith('arg1', 'arg2');
380
+ });
381
+ });
382
+
383
+ describe("an observer listening to on_notify", function() {
384
+ it("receives a notify event with the notify hash", function() {
385
+ var observer = {
386
+ on_notify: function() {
387
+ }
388
+ };
389
+ spyOn(observer, 'on_notify');
390
+
391
+ Jelly.notifyObservers.call([observer], {
392
+ "arguments":["arg1", "arg2"],
393
+ "method":"on_my_method"
394
+ });
395
+
396
+ expect(observer.on_notify).wasCalledWith({method: "on_my_method", arguments: ["arg1", "arg2"]});
397
+ });
398
+ });
399
+
400
+ describe("an observer listening to the notify method", function() {
401
+ var observer;
402
+ beforeEach(function() {
403
+ observer = {
404
+ on_my_method: function() {
405
+ }
406
+ };
407
+ Jelly.attach({component: observer, arguments: []});
408
+ expect(Jelly.observers).toContain(observer);
409
+ });
410
+
411
+ describe("when the observer does not have a detach method defined", function() {
412
+ beforeEach(function() {
413
+ expect(observer.detach).toBe(undefined);
414
+ });
415
+
416
+ it("leaves the observer in Jelly.observers and calls the notify method on the observer", function() {
417
+ spyOn(observer, "on_my_method");
418
+
419
+ Jelly.notifyObservers({method: "on_my_method", arguments: []});
420
+ expect(Jelly.observers).toContain(observer);
421
+ expect(observer.on_my_method).wasCalled();
422
+ });
423
+ });
424
+
425
+ describe("when the observer a detach method defined", function() {
426
+ describe("when the detach method is truthy", function() {
427
+ var anotherObserver;
428
+ beforeEach(function() {
429
+ observer.detach = function() {
430
+ return true;
431
+ };
432
+ anotherObserver = {
433
+ on_my_method: function() {
434
+ }
435
+ };
436
+ Jelly.attach({component: anotherObserver, arguments: []});
437
+ });
438
+
439
+ it("removes observer in Jelly.observers, does not call the notify method on the observer, and calls the other observers", function() {
440
+ spyOn(observer, "on_my_method");
441
+ spyOn(anotherObserver, "on_my_method");
442
+
443
+ Jelly.notifyObservers({method: "on_my_method", arguments: []});
444
+ expect(Jelly.observers).toNotContain(observer);
445
+ expect(observer.on_my_method).wasNotCalled();
446
+ expect(anotherObserver.on_my_method).wasCalled();
447
+ });
448
+ });
449
+
450
+ describe("when the detach method is falsy", function() {
451
+ beforeEach(function() {
452
+ observer.detach = function() {
453
+ return undefined;
454
+ }
455
+ });
456
+
457
+ it("leaves the observer in Jelly.observers and calls the notify method on the observer", function() {
458
+ spyOn(observer, "on_my_method");
459
+
460
+ Jelly.notifyObservers({method: "on_my_method", arguments: []});
461
+ expect(Jelly.observers).toContain(observer);
462
+ expect(observer.on_my_method).wasCalled();
463
+ });
464
+ });
465
+ });
466
+ });
467
+
468
+ describe("when the 'attach' parameter is present", function() {
469
+ var observers;
470
+ beforeEach(function() {
471
+ MyComponent = {
472
+ init: function() {
473
+ }
474
+ };
475
+ spyOn(MyComponent, 'init');
476
+ observers = [];
477
+ });
478
+
479
+ describe("when the method is present", function() {
480
+ it("attaches the given attachments to the observers and calls the notify on the recently attached observer", function() {
481
+ Jelly.notifyObservers.call(observers, {
482
+ "arguments":["arg1", "arg2"],
483
+ "method":"on_my_method",
484
+ "attach":[
485
+ {
486
+ component: "MyComponent",
487
+ arguments: [1,2]
488
+ }
489
+ ]
490
+ });
491
+ expect(MyComponent.init).wasCalledWith(1, 2);
492
+ expect(Jelly.observers).toNotContain(MyComponent);
493
+ expect(observers).toContain(MyComponent);
494
+ });
495
+ });
496
+
497
+ describe("when there are no other paramaters present", function() {
498
+ it("attaches the given attachments to the observers", function() {
499
+ Jelly.notifyObservers.call(observers, {
500
+ "attach":[
501
+ {
502
+ component: "MyComponent",
503
+ arguments: [1,2]
504
+ }
505
+ ]
506
+ });
507
+ expect(Jelly.observers).toNotContain(MyComponent);
508
+ expect(observers).toContain(MyComponent);
509
+ });
510
+ });
511
+ });
512
+
513
+ describe("when given an array of notify instructions", function() {
514
+ it("notifies the observers of all of the notify hashes", function() {
515
+ page.on_my_method2 = function() {
516
+ };
517
+ spyOn(page, 'on_my_method');
518
+ spyOn(page, 'on_my_method2');
519
+ Jelly.notifyObservers([
520
+ {
521
+ "arguments":["arg1", "arg2"],
522
+ "method":"on_my_method"
523
+ },
524
+ {
525
+ "arguments": ["arg3"],
526
+ "method":"on_my_method2"
527
+ }
528
+ ]);
529
+
530
+ expect(page.on_my_method).wasCalledWith('arg1', 'arg2');
531
+ expect(page.on_my_method2).wasCalledWith('arg3');
532
+ });
533
+ });
534
+ });
535
+ });
536
+
537
+ describe("Jelly.Page", function() {
538
+ var our_token;
539
+
540
+ beforeEach(function() {
541
+ spyOn($, 'ajax');
542
+ our_token = "authenticity token";
543
+ window._token = our_token;
544
+ Jelly.init();
545
+ });
546
+
547
+ describe(".init", function() {
548
+ beforeEach(function() {
549
+ Jelly.Pages.add("DefinedComponent", {
550
+ baz : function() {
551
+ },
552
+ all : function() {
553
+ },
554
+ show: function() {
555
+ }
556
+ });
557
+ spyOn(Jelly.Pages.all["DefinedComponent"], "show");
558
+ });
559
+
560
+ afterEach(function() {
561
+ delete Jelly.Pages.all["DefinedComponent"];
562
+ });
563
+
564
+ describe("when the passed-in controllerName is defined", function() {
565
+ describe("when the actionName is defined", function() {
566
+ it("invokes the page-specific method", function() {
567
+ var foobar = Jelly.Pages.all["DefinedComponent"];
568
+ expect(foobar.show).wasNotCalled();
569
+ Jelly.Page.init("DefinedComponent", "show");
570
+ expect(foobar.show).wasCalled();
571
+ });
572
+
573
+ describe("when the 'all' method is defined", function() {
574
+ var invokedMethods;
575
+ beforeEach(function() {
576
+ invokedMethods = [];
577
+ spyOn(Jelly.Pages.all["DefinedComponent"], "all").andCallFake(function() {
578
+ invokedMethods.push("all");
579
+ });
580
+ spyOn(Jelly.Pages.all["DefinedComponent"], "baz").andCallFake(function() {
581
+ invokedMethods.push("baz");
582
+ });
583
+ });
584
+
585
+ it("invokes the all method before invoking the page-specific method", function() {
586
+ expect(invokedMethods).toEqual([]);
587
+ Jelly.Page.init("DefinedComponent", "baz");
588
+ expect(invokedMethods).toEqual(['all', 'baz']);
589
+ });
590
+ });
591
+ });
592
+
593
+ describe("when the actionName is not defined", function() {
594
+ it("does not blow up", function() {
595
+ expect(Jelly.Pages.all["DefinedComponent"].easterBunny).toEqual(undefined);
596
+ Jelly.Page.init("DefinedComponent", "easterBunny");
597
+ });
598
+
599
+ describe("when the 'all' method is defined", function() {
600
+ var invokedMethods;
601
+ beforeEach(function() {
602
+ invokedMethods = [];
603
+ Jelly.Pages.all["DefinedComponent"].all = function() {
604
+ invokedMethods.push("all");
605
+ };
606
+ });
607
+
608
+ it("invokes the all method", function() {
609
+ expect(Jelly.Pages.all["DefinedComponent"].easterBunny).toEqual(undefined);
610
+ expect(invokedMethods).toEqual([]);
611
+ Jelly.Page.init("DefinedComponent", "easterBunny");
612
+ expect(invokedMethods).toEqual(['all']);
613
+ });
614
+ });
615
+ });
616
+ });
617
+
618
+ describe("when the passed-in controllerName is not defined", function() {
619
+ it("does nothing and does not cause an error", function() {
620
+ expect(Jelly.Pages.all["UndefinedComponent"]).toEqual(undefined);
621
+ Jelly.Page.init("UndefinedComponent", "easterBunny");
622
+ });
623
+ });
624
+ });
625
+ });
626
+
627
+ describe("Jelly.Location", function() {
628
+ var our_token, originalTop;
629
+
630
+ beforeEach(function() {
631
+ spyOn($, 'ajax');
632
+ our_token = "authenticity token";
633
+ window._token = our_token;
634
+ Jelly.init();
635
+ originalTop = window.top;
636
+ });
637
+
638
+ afterEach(function() {
639
+ window.top = originalTop;
640
+ });
641
+
642
+ describe(".on_redirect", function() {
643
+ it("sets top.location.href to the given location", function() {
644
+ window.top = {location: {}};
645
+ Jelly.Location.on_redirect("http://mars.com");
646
+ expect(window.top.location.href).toEqual("http://mars.com");
647
+ });
648
+ });
649
+ });