6205d410 by Michael Richards

Merge branch 'specs'

2 parents 9e589b36 491c56db
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
2 "http://www.w3.org/TR/html4/loose.dtd"> 2 "http://www.w3.org/TR/html4/loose.dtd">
3 <html> 3 <html>
4 <head> 4 <head>
5 <title>Rivets test suite</title> 5 <title>Rivets.js test suite</title>
6 6
7 <link rel="stylesheet" type="text/css" href="lib/jasmine.css"> 7 <link rel="stylesheet" type="text/css" href="lib/jasmine.css">
8 8
...@@ -13,7 +13,9 @@ ...@@ -13,7 +13,9 @@
13 13
14 <script type="text/javascript" src="matchers.js"></script> 14 <script type="text/javascript" src="matchers.js"></script>
15 <script type="text/javascript" src="mock.data.js"></script> 15 <script type="text/javascript" src="mock.data.js"></script>
16 <script type="text/javascript" src="rivets.js"></script> 16 <script type="text/javascript" src="rivets/binding.js"></script>
17 <script type="text/javascript" src="rivets/routines.js"></script>
18 <script type="text/javascript" src="rivets/functional.js"></script>
17 19
18 <script type="text/javascript"> 20 <script type="text/javascript">
19 (function() { 21 (function() {
......
1 describe('Rivets.Binding', function() {
2 var model, el, view, binding;
3
4 beforeEach(function() {
5 rivets.configure({
6 adapter: {
7 subscribe: function() {},
8 unsubscribe: function() {},
9 read: function() {},
10 publish: function() {}
11 }
12 });
13
14 el = document.createElement('div');
15 el.setAttribute('data-text', 'obj.name');
16 view = rivets.bind(el, {obj: {}});
17 binding = view.bindings[0];
18 });
19
20 it('gets assigned the routine function matching the identifier', function() {
21 expect(binding.routine).toBe(rivets.routines.text);
22 });
23
24 describe('set()', function() {
25 it('performs the binding routine with the supplied value', function() {
26 spyOn(binding, 'routine');
27 binding.set('sweater');
28 expect(binding.routine).toHaveBeenCalledWith(el, 'sweater');
29 });
30
31 it('applies any formatters to the value before performing the routine', function() {
32 rivets.config.formatters = {
33 awesome: function(value) { return 'awesome ' + value }
34 };
35 binding.formatters.push('awesome');
36 spyOn(binding, 'routine');
37 binding.set('sweater');
38 expect(binding.routine).toHaveBeenCalledWith(el, 'awesome sweater');
39 });
40
41 describe('on an event binding', function() {
42 beforeEach(function() {
43 binding.bindType = 'event';
44 });
45
46 it('performs the binding routine with the supplied function and current listener', function() {
47 spyOn(binding, 'routine');
48 func = function() { return 1 + 2; }
49 binding.set(func);
50 expect(binding.routine).toHaveBeenCalledWith(el, func, undefined);
51 });
52
53 it('passes the previously set funcation as the current listener on subsequent calls', function() {
54 spyOn(binding, 'routine');
55 funca = function() { return 1 + 2; };
56 funcb = function() { return 2 + 5; };
57
58 binding.set(funca);
59 expect(binding.routine).toHaveBeenCalledWith(el, funca, undefined);
60
61 binding.set(funcb);
62 expect(binding.routine).toHaveBeenCalledWith(el, funcb, funca);
63 });
64 });
65 });
66 });
1 describe('Functional', function() {
2 var data, bindData, el, input;
3
4 beforeEach(function() {
5 data = new Data({foo: 'bar'});
6 bindData = {data: data};
7 el = document.createElement('div');
8 input = document.createElement('input');
9 input.setAttribute('type', 'text');
10
11 rivets.configure({
12 preloadData: true,
13 adapter: {
14 subscribe: function(obj, keypath, callback) {
15 obj.on(keypath, callback);
16 },
17 read: function(obj, keypath) {
18 return obj.get(keypath);
19 },
20 publish: function(obj, keypath, value) {
21 attributes = {};
22 attributes[keypath] = value;
23 obj.set(attributes);
24 }
25 }
26 });
27 });
28
29 describe('Adapter', function() {
30 it('should read the initial value', function() {
31 spyOn(data, 'get');
32 el.setAttribute('data-text', 'data.foo');
33 rivets.bind(el, bindData);
34 expect(data.get).toHaveBeenCalledWith('foo');
35 });
36
37 it('should read the initial value unless preloadData is false', function() {
38 rivets.configure({preloadData: false});
39 spyOn(data, 'get');
40 el.setAttribute('data-value', 'data.foo');
41 rivets.bind(el, bindData);
42 expect(data.get).not.toHaveBeenCalled();
43 });
44
45 it('should subscribe to updates', function() {
46 spyOn(data, 'on');
47 el.setAttribute('data-value', 'data.foo');
48 rivets.bind(el, bindData);
49 expect(data.on).toHaveBeenCalled();
50 });
51 });
52
53 describe('Binds', function() {
54 describe('Text', function() {
55 it('should set the text content of the element', function() {
56 el.setAttribute('data-text', 'data.foo');
57 rivets.bind(el, bindData);
58 expect(el.textContent || el.innerText).toBe(data.get('foo'));
59 });
60
61 it('should correctly handle HTML in the content', function() {
62 el.setAttribute('data-text', 'data.foo');
63 value = '<b>Fail</b>';
64 data.set({foo: value});
65 rivets.bind(el, bindData);
66 expect(el.textContent || el.innerText).toBe(value);
67 });
68 });
69
70 describe('HTML', function() {
71 it('should set the html content of the element', function() {
72 el.setAttribute('data-html', 'data.foo');
73 rivets.bind(el, bindData);
74 expect(el).toHaveTheTextContent(data.get('foo'));
75 });
76
77 it('should correctly handle HTML in the content', function() {
78 el.setAttribute('data-html', 'data.foo');
79 value = '<b>Fail</b>';
80 data.set({foo: value});
81 rivets.bind(el, bindData);
82 expect(el.innerHTML).toBe(value);
83 });
84 });
85
86 describe('Value', function() {
87 it('should set the value of the element', function() {
88 input.setAttribute('data-value', 'data.foo');
89 rivets.bind(input, bindData);
90 expect(input.value).toBe(data.get('foo'));
91 });
92 });
93 });
94
95 describe('Updates', function() {
96 it('should change the value', function() {
97 el.setAttribute('data-text', 'data.foo');
98 rivets.bind(el, bindData);
99 data.set({foo: 'some new value'});
100 expect(el).toHaveTheTextContent(data.get('foo'));
101 });
102 });
103
104 describe('Input', function() {
105 it('should update the model value', function() {
106 input.setAttribute('data-value', 'data.foo');
107 rivets.bind(input, bindData);
108 input.value = 'some new value';
109 var event = document.createEvent('HTMLEvents')
110 event.initEvent('change', true, true);
111 input.dispatchEvent(event);
112 expect(input.value).toBe(data.get('foo'));
113 });
114 });
115 });
1 describe('Rivets', function() { 1 describe('Routines', function() {
2 var data, bindData, el, input; 2 var el, input;
3 3
4 beforeEach(function() { 4 beforeEach(function() {
5 data = new Data({foo: 'bar'});
6 bindData = {data: data};
7 el = document.createElement('div');
8 input = document.createElement('input');
9 input.setAttribute('type', 'text');
10
11 rivets.configure({ 5 rivets.configure({
12 preloadData: true,
13 adapter: { 6 adapter: {
14 subscribe: function(obj, keypath, callback) { 7 subscribe: function() {},
15 obj.on(keypath, callback); 8 unsubscribe: function() {},
16 }, 9 read: function() {},
17 read: function(obj, keypath) { 10 publish: function() {}
18 return obj.get(keypath);
19 },
20 publish: function(obj, keypath, value) {
21 attributes = {};
22 attributes[keypath] = value;
23 obj.set(attributes);
24 }
25 } 11 }
26 }); 12 });
13
14 el = document.createElement('div');
15 input = document.createElement('input');
16 input.setAttribute('type', 'text');
27 }); 17 });
28 18
29 describe('Adapter', function() { 19 describe('text', function() {
30 it('should read the initial value', function() { 20 it("sets the element's text content", function() {
31 spyOn(data, 'get'); 21 rivets.routines.text(el, '<em>gluten-free</em>');
32 el.setAttribute('data-text', 'data.foo'); 22 expect(el.textContent || el.innerText).toBe('<em>gluten-free</em>');
33 rivets.bind(el, bindData); 23 expect(el.innerHTML).toBe('&lt;em&gt;gluten-free&lt;/em&gt;');
34 expect(data.get).toHaveBeenCalledWith('foo');
35 }); 24 });
25 });
36 26
37 it('should read the initial value unless preloadData is false', function() { 27 describe('html', function() {
38 rivets.configure({preloadData: false}); 28 it("sets the element's HTML content", function() {
39 spyOn(data, 'get'); 29 rivets.routines.html(el, '<strong>fixie</strong>');
40 el.setAttribute('data-value', 'data.foo'); 30 expect(el.textContent || el.innerText).toBe('fixie');
41 rivets.bind(el, bindData); 31 expect(el.innerHTML).toBe('<strong>fixie</strong>');
42 expect(data.get).not.toHaveBeenCalled();
43 }); 32 });
33 });
44 34
45 it('should subscribe to updates', function() { 35 describe('value', function() {
46 spyOn(data, 'on'); 36 it("sets the element's value", function() {
47 el.setAttribute('data-value', 'data.foo'); 37 rivets.routines.value(input, 'pitchfork');
48 rivets.bind(el, bindData); 38 expect(input.value).toBe('pitchfork');
49 expect(data.on).toHaveBeenCalled();
50 }); 39 });
51 }); 40 });
52 41
53 describe('Routines', function() { 42 describe('show', function() {
54 describe('text', function() { 43 describe('with a truthy value', function() {
55 it("sets the element's text content", function() { 44 it('shows the element', function() {
56 rivets.routines.text(el, '<em>gluten-free</em>'); 45 rivets.routines.show(el, true);
57 expect(el.textContent || el.innerText).toBe('<em>gluten-free</em>'); 46 expect(el.style.display).toBe('');
58 expect(el.innerHTML).toBe('&lt;em&gt;gluten-free&lt;/em&gt;');
59 }); 47 });
60 }); 48 });
61 49
62 describe('html', function() { 50 describe('with a falsey value', function() {
63 it("sets the element's HTML content", function() { 51 it('hides the element', function() {
64 rivets.routines.html(el, '<strong>fixie</strong>'); 52 rivets.routines.show(el, false);
65 expect(el.textContent || el.innerText).toBe('fixie'); 53 expect(el.style.display).toBe('none');
66 expect(el.innerHTML).toBe('<strong>fixie</strong>');
67 }); 54 });
68 }); 55 });
56 });
69 57
70 describe('value', function() { 58 describe('hide', function() {
71 it("sets the element's value", function() { 59 describe('with a truthy value', function() {
72 rivets.routines.value(input, 'pitchfork'); 60 it('hides the element', function() {
73 expect(input.value).toBe('pitchfork'); 61 rivets.routines.hide(el, true);
62 expect(el.style.display).toBe('none');
74 }); 63 });
75 }); 64 });
76 65
77 describe('show', function() { 66 describe('with a falsey value', function() {
78 describe('with a truthy value', function() { 67 it('shows the element', function() {
79 it('shows the element', function() { 68 rivets.routines.hide(el, false);
80 rivets.routines.show(el, true); 69 expect(el.style.display).toBe('');
81 expect(el.style.display).toBe('');
82 });
83 });
84
85 describe('with a falsey value', function() {
86 it('hides the element', function() {
87 rivets.routines.show(el, false);
88 expect(el.style.display).toBe('none');
89 });
90 }); 70 });
91 }); 71 });
72 });
92 73
93 describe('hide', function() { 74 describe('enabled', function() {
94 describe('with a truthy value', function() { 75 describe('with a truthy value', function() {
95 it('hides the element', function() { 76 it('enables the element', function() {
96 rivets.routines.hide(el, true); 77 rivets.routines.enabled(el, true);
97 expect(el.style.display).toBe('none'); 78 expect(el.disabled).toBe(false);
98 });
99 });
100
101 describe('with a falsey value', function() {
102 it('shows the element', function() {
103 rivets.routines.hide(el, false);
104 expect(el.style.display).toBe('');
105 });
106 }); 79 });
107 }); 80 });
108
109 describe('enabled', function() {
110 describe('with a truthy value', function() {
111 it('enables the element', function() {
112 rivets.routines.enabled(el, true);
113 expect(el.disabled).toBe(false);
114 });
115 });
116 81
117 describe('with a falsey value', function() { 82 describe('with a falsey value', function() {
118 it('disables the element', function() { 83 it('disables the element', function() {
119 rivets.routines.enabled(el, false); 84 rivets.routines.enabled(el, false);
120 expect(el.disabled).toBe(true); 85 expect(el.disabled).toBe(true);
121 });
122 }); 86 });
123 }); 87 });
88 });
124 89
125 describe('disabled', function() { 90 describe('disabled', function() {
126 describe('with a truthy value', function() { 91 describe('with a truthy value', function() {
127 it('disables the element', function() { 92 it('disables the element', function() {
128 rivets.routines.disabled(el, true); 93 rivets.routines.disabled(el, true);
129 expect(el.disabled).toBe(true); 94 expect(el.disabled).toBe(true);
130 });
131 });
132
133 describe('with a falsey value', function() {
134 it('enables the element', function() {
135 rivets.routines.disabled(el, false);
136 expect(el.disabled).toBe(false);
137 });
138 });
139 });
140
141 describe('checked', function() {
142 describe('with a truthy value', function() {
143 it('checks the element', function() {
144 rivets.routines.checked(el, true);
145 expect(el.checked).toBe(true);
146 });
147 });
148
149 describe('with a falsey value', function() {
150 it('unchecks the element', function() {
151 rivets.routines.checked(el, false);
152 expect(el.checked).toBe(false);
153 });
154 }); 95 });
155 }); 96 });
156 97
157 describe('unchecked', function() { 98 describe('with a falsey value', function() {
158 describe('with a truthy value', function() { 99 it('enables the element', function() {
159 it('unchecks the element', function() { 100 rivets.routines.disabled(el, false);
160 rivets.routines.unchecked(el, true); 101 expect(el.disabled).toBe(false);
161 expect(el.checked).toBe(false);
162 });
163 });
164
165 describe('with a falsey value', function() {
166 it('checks the element', function() {
167 rivets.routines.unchecked(el, false);
168 expect(el.checked).toBe(true);
169 });
170 }); 102 });
171 }); 103 });
104 });
172 105
173 describe('selected', function() { 106 describe('checked', function() {
174 describe('with a truthy value', function() { 107 describe('with a truthy value', function() {
175 it('selects the element', function() { 108 it('checks the element', function() {
176 rivets.routines.selected(el, true); 109 rivets.routines.checked(el, true);
177 expect(el.selected).toBe(true); 110 expect(el.checked).toBe(true);
178 });
179 });
180
181 describe('with a falsey value', function() {
182 it('unselects the element', function() {
183 rivets.routines.selected(el, false);
184 expect(el.selected).toBe(false);
185 });
186 }); 111 });
187 }); 112 });
188 113
189 describe('unselected', function() { 114 describe('with a falsey value', function() {
190 describe('with a truthy value', function() { 115 it('unchecks the element', function() {
191 it('unselects the element', function() { 116 rivets.routines.checked(el, false);
192 rivets.routines.unselected(el, true); 117 expect(el.checked).toBe(false);
193 expect(el.selected).toBe(false);
194 });
195 });
196
197 describe('with a falsey value', function() {
198 it('selects the element', function() {
199 rivets.routines.unselected(el, false);
200 expect(el.selected).toBe(true);
201 });
202 }); 118 });
203 }); 119 });
204 }); 120 });
205 121
206 describe('Binds', function() { 122 describe('unchecked', function() {
207 describe('Text', function() { 123 describe('with a truthy value', function() {
208 it('should set the text content of the element', function() { 124 it('unchecks the element', function() {
209 el.setAttribute('data-text', 'data.foo'); 125 rivets.routines.unchecked(el, true);
210 rivets.bind(el, bindData); 126 expect(el.checked).toBe(false);
211 expect(el.textContent || el.innerText).toBe(data.get('foo'));
212 });
213
214 it('should correctly handle HTML in the content', function() {
215 el.setAttribute('data-text', 'data.foo');
216 value = '<b>Fail</b>';
217 data.set({foo: value});
218 rivets.bind(el, bindData);
219 expect(el.textContent || el.innerText).toBe(value);
220 }); 127 });
221 }); 128 });
222 129
223 describe('HTML', function() { 130 describe('with a falsey value', function() {
224 it('should set the html content of the element', function() { 131 it('checks the element', function() {
225 el.setAttribute('data-html', 'data.foo'); 132 rivets.routines.unchecked(el, false);
226 rivets.bind(el, bindData); 133 expect(el.checked).toBe(true);
227 expect(el).toHaveTheTextContent(data.get('foo'));
228 }); 134 });
135 });
136 });
229 137
230 it('should correctly handle HTML in the content', function() { 138 describe('selected', function() {
231 el.setAttribute('data-html', 'data.foo'); 139 describe('with a truthy value', function() {
232 value = '<b>Fail</b>'; 140 it('selects the element', function() {
233 data.set({foo: value}); 141 rivets.routines.selected(el, true);
234 rivets.bind(el, bindData); 142 expect(el.selected).toBe(true);
235 expect(el.innerHTML).toBe(value);
236 }); 143 });
237 }); 144 });
238 145
239 describe('Value', function() { 146 describe('with a falsey value', function() {
240 it('should set the value of the element', function() { 147 it('unselects the element', function() {
241 input.setAttribute('data-value', 'data.foo'); 148 rivets.routines.selected(el, false);
242 rivets.bind(input, bindData); 149 expect(el.selected).toBe(false);
243 expect(input.value).toBe(data.get('foo'));
244 }); 150 });
245 }); 151 });
246 }); 152 });
247 153
248 describe('Updates', function() { 154 describe('unselected', function() {
249 it('should change the value', function() { 155 describe('with a truthy value', function() {
250 el.setAttribute('data-text', 'data.foo'); 156 it('unselects the element', function() {
251 rivets.bind(el, bindData); 157 rivets.routines.unselected(el, true);
252 data.set({foo: 'some new value'}); 158 expect(el.selected).toBe(false);
253 expect(el).toHaveTheTextContent(data.get('foo')); 159 });
254 }); 160 });
255 });
256 161
257 describe('Input', function() { 162 describe('with a falsey value', function() {
258 it('should update the model value', function() { 163 it('selects the element', function() {
259 input.setAttribute('data-value', 'data.foo'); 164 rivets.routines.unselected(el, false);
260 rivets.bind(input, bindData); 165 expect(el.selected).toBe(true);
261 input.value = 'some new value'; 166 });
262 var event = document.createEvent('HTMLEvents')
263 event.initEvent('change', true, true);
264 input.dispatchEvent(event);
265 expect(input.value).toBe(data.get('foo'));
266 }); 167 });
267 }); 168 });
268 }); 169 });
......