1 |
|
2 | var test = require('tape');
|
3 | var AmpCollection = require('ampersand-collection');
|
4 | var AmpModel = require('ampersand-model');
|
5 | var AmpView = require('ampersand-view');
|
6 | var CollectionView = require('../ampersand-collection-view');
|
7 |
|
8 |
|
9 |
|
10 | var data = [
|
11 | {id: 1, name: 'mary'},
|
12 | {id: 2, name: 'sue'},
|
13 | {id: 3, name: 'dave'}
|
14 | ];
|
15 |
|
16 |
|
17 | var Person = AmpModel.extend({
|
18 | props: {id: 'number', name: 'string'}
|
19 | });
|
20 |
|
21 |
|
22 | var Collection = AmpCollection.extend({
|
23 | model: Person,
|
24 | last: function () {
|
25 | return this.models[this.models.length - 1];
|
26 | },
|
27 | first: function () {
|
28 | return this.models[0];
|
29 | }
|
30 | });
|
31 |
|
32 | var ItemView = AmpView.extend({
|
33 | template: '<div></div>',
|
34 | bindings: {
|
35 | 'model.name': ''
|
36 | },
|
37 | render: function () {
|
38 | this.renderWithTemplate();
|
39 | this.el.id = '_' + this.model.id;
|
40 | return this;
|
41 | }
|
42 | });
|
43 |
|
44 | var MainView = AmpView.extend({
|
45 | initialize: function () {
|
46 | this.el = document.createElement('div');
|
47 | this.el.id = 'container';
|
48 | this.collection = new Collection(data);
|
49 | },
|
50 | render: function (opts) {
|
51 | this.el.innerHTML = '<ul></ul>';
|
52 | this.renderCollection(this.collection, ItemView, this.get('ul'), opts);
|
53 | return this;
|
54 | }
|
55 | });
|
56 |
|
57 | function getRendered(view) {
|
58 | return Array.prototype.slice.call(view.el.querySelectorAll('div'));
|
59 | }
|
60 |
|
61 | function numberRendered(view) {
|
62 | return getRendered(view).length;
|
63 | }
|
64 |
|
65 | test('should render all when calling `render`', function (t) {
|
66 | var coll = new Collection(data);
|
67 | var div = document.createElement('div');
|
68 | var cv = new CollectionView({
|
69 | el: div,
|
70 | collection: coll,
|
71 | view: ItemView
|
72 | });
|
73 | t.equal(cv.el.innerHTML, '');
|
74 | cv.render();
|
75 | t.equal(cv.el.innerHTML, '<div id="_1">mary</div><div id="_2">sue</div><div id="_3">dave</div>');
|
76 | t.end();
|
77 | });
|
78 |
|
79 | test('should call `remove` on view corresponding to removed model', function (t) {
|
80 | var coll = new Collection(data);
|
81 | var div = document.createElement('div');
|
82 | var cv = new CollectionView({
|
83 | el: div,
|
84 | collection: coll,
|
85 | view: ItemView
|
86 | });
|
87 | var count = 0;
|
88 | cv.render();
|
89 | t.equal(cv.views.length, 3);
|
90 | var firstView = cv.views[0];
|
91 | firstView.remove = function () {
|
92 | count++;
|
93 | };
|
94 | coll.remove(coll.at(0));
|
95 | t.equal(cv.views.length, 2);
|
96 | t.equal(count, 1, 'remove should have been called once');
|
97 | t.end();
|
98 | });
|
99 |
|
100 | test('adding to collection should work', function (t) {
|
101 | var coll = new Collection(data);
|
102 | var div = document.createElement('div');
|
103 | var cv = new CollectionView({
|
104 | el: div,
|
105 | collection: coll,
|
106 | view: ItemView
|
107 | });
|
108 | cv.render();
|
109 | var firstView = cv.views[0];
|
110 | var firstEl = firstView && firstView.el;
|
111 |
|
112 | coll.add({name: 'henrik', id: 4});
|
113 | t.equal(cv.views.length, 4);
|
114 | t.equal(cv.el.innerHTML, '<div id="_1">mary</div><div id="_2">sue</div><div id="_3">dave</div><div id="_4">henrik</div>');
|
115 | t.equal(cv.views[0], firstView);
|
116 | t.equal(cv.views[0].el, firstEl);
|
117 |
|
118 | t.end();
|
119 | });
|
120 |
|
121 | test('add', function (t) {
|
122 | var coll = new Collection(data);
|
123 | var div = document.createElement('div');
|
124 | var view = new CollectionView({
|
125 | el: div,
|
126 | collection: coll,
|
127 | view: ItemView
|
128 | });
|
129 | view.render();
|
130 | view.collection.add({id: 6});
|
131 | t.equal(numberRendered(view), view.collection.length);
|
132 | t.end();
|
133 | });
|
134 |
|
135 | test('remove', function (t) {
|
136 | var coll = new Collection(data);
|
137 | var div = document.createElement('div');
|
138 | var view = new CollectionView({
|
139 | el: div,
|
140 | collection: coll,
|
141 | view: ItemView
|
142 | });
|
143 | view.render();
|
144 | view.collection.remove(view.collection.models[view.collection.models.length - 1]);
|
145 | t.equal(numberRendered(view), view.collection.length);
|
146 | t.end();
|
147 | });
|
148 |
|
149 | test('reset', function (t) {
|
150 | var coll = new Collection(data);
|
151 | var div = document.createElement('div');
|
152 | var view = new CollectionView({
|
153 | el: div,
|
154 | collection: coll,
|
155 | view: ItemView
|
156 | });
|
157 | view.render();
|
158 | view.collection.reset();
|
159 | t.equal(numberRendered(view), view.collection.length);
|
160 | t.equal(numberRendered(view), 0);
|
161 | t.end();
|
162 | });
|
163 |
|
164 | test('sort', function (t) {
|
165 | var coll = new Collection(data);
|
166 | var div = document.createElement('div');
|
167 | var view = new CollectionView({
|
168 | el: div,
|
169 | collection: coll,
|
170 | view: ItemView
|
171 | });
|
172 | view.render();
|
173 | view.collection.comparator = function (model) {
|
174 | return model.get('name');
|
175 | };
|
176 | view.collection.sort();
|
177 | t.equal(numberRendered(view), view.collection.length);
|
178 | var domIds = [];
|
179 | getRendered(view).forEach(function (el) {
|
180 | domIds.push(Number(el.id.slice(1)));
|
181 | });
|
182 | t.deepEqual(domIds, [3, 1, 2]);
|
183 | t.end();
|
184 | });
|
185 |
|
186 | test('animateRemove', function (t) {
|
187 | var coll = new Collection(data);
|
188 | var div = document.createElement('div');
|
189 | var view = new CollectionView({
|
190 | el: div,
|
191 | collection: coll,
|
192 | view: ItemView
|
193 | });
|
194 | view.render();
|
195 | var prevAnimateRemove = ItemView.prototype.animateRemove;
|
196 | ItemView.prototype.animateRemove = function () {
|
197 | var self = this;
|
198 | this.el.className = 'fadeOut';
|
199 | setTimeout(function () {
|
200 | self.remove();
|
201 | }, 100);
|
202 | t.ok('animateRemove called');
|
203 | };
|
204 | view.collection.remove(view.collection.last());
|
205 | setTimeout(function () {
|
206 | t.equal(numberRendered(view), view.collection.length);
|
207 |
|
208 | ItemView.prototype.animateRemove = prevAnimateRemove;
|
209 | t.end();
|
210 | }, 150);
|
211 | });
|
212 |
|
213 | test('filtered', function (t) {
|
214 | var view = new MainView();
|
215 | view.render({
|
216 | filter: function (model) {
|
217 | return model.get('name').length > 3;
|
218 | }
|
219 | });
|
220 | t.equal(numberRendered(view), 2);
|
221 | t.end();
|
222 | });
|
223 |
|
224 | test('reversed', function (t) {
|
225 | var view = new MainView();
|
226 | view.render({
|
227 | reverse: true
|
228 | });
|
229 | var domIds = [];
|
230 | getRendered(view).forEach(function (el) {
|
231 | domIds.push(Number(el.id.slice(1)));
|
232 | });
|
233 | t.deepEqual(domIds, [3, 2, 1]);
|
234 | t.end();
|
235 | });
|
236 |
|
237 | test('cleanup', function (t) {
|
238 | var coll = new Collection(data);
|
239 | var div = document.createElement('div');
|
240 | var view = new CollectionView({
|
241 | el: div,
|
242 | collection: coll,
|
243 | view: ItemView
|
244 | });
|
245 | view.render();
|
246 | t.equal(numberRendered(view), view.collection.length);
|
247 | var firstModel = view.collection.first();
|
248 | var firstView = view.views[0];
|
249 | firstView.listenTo(firstModel, 'change:something', function () {});
|
250 | t.equal(view.collection.first()._events['change:something'].length, 1);
|
251 | view.remove();
|
252 |
|
253 |
|
254 | t.notOk(view.collection.first()._events['change:something']);
|
255 | t.end();
|
256 | });
|
257 |
|
258 | test('child view can choose to insert self', function (t) {
|
259 | var view = new MainView();
|
260 | ItemView.prototype.insertSelf = true;
|
261 | ItemView.prototype.render = function (extraInfo) {
|
262 | t.ok(extraInfo.containerEl);
|
263 | this.renderWithTemplate();
|
264 | };
|
265 |
|
266 | view.render();
|
267 | t.equal(numberRendered(view), 0, 'Parent should not have rendered anything');
|
268 | view.remove();
|
269 | t.end();
|
270 | });
|
271 |
|