[FIX] adjust view top when header height changes
[odoo/odoo.git] / addons / web / static / test / list-utils.js
1 openerp.testing.section('list.events', {
2     dependencies: ['web.list']
3 }, function (test) {
4     var create = function (o) {
5         if (typeof Object.create === 'function') {
6             return Object.create(o);
7         }
8         function Cls() {}
9         Cls.prototype = o;
10         return new Cls();
11     };
12     test('Simple event triggering', function (instance) {
13         var e = create(instance.web.list.Events), passed = false;
14         e.bind('foo', function () { passed = true; });
15         e.trigger('foo');
16         ok(passed);
17     });
18     test('Bind all', function (instance) {
19         var e = create(instance.web.list.Events), event = null;
20         e.bind(null, function (ev) { event = ev; });
21         e.trigger('foo');
22         strictEqual(event, 'foo');
23     });
24     test('Propagate trigger params', function (instance) {
25        var e = create(instance.web.list.Events), p = false;
26         e.bind(null, function (_, param) { p = param; });
27         e.trigger('foo', true);
28         strictEqual(p, true);
29     });
30     test('Bind multiple callbacks', function (instance) {
31         var e = create(instance.web.list.Events), count;
32         e.bind('foo', function () { count++; })
33          .bind('bar', function () { count++; })
34          .bind(null, function () { count++; })
35          .bind('foo', function () { count++; })
36          .bind(null, function () { count++; })
37          .bind(null, function () { count++; });
38
39         count = 0;
40         e.trigger('foo');
41         strictEqual(count, 5);
42
43         count = 0;
44         e.trigger('bar');
45         strictEqual(count, 4);
46
47         count = 0;
48         e.trigger('baz');
49         strictEqual(count, 3);
50     });
51     test('Mixin events', function (instance) {
52         var cls = instance.web.Class.extend({
53             method: function () { this.trigger('e'); }
54         });
55         cls.include(instance.web.list.Events);
56         var i = new cls(), triggered = false;
57
58         i.bind('e', function () { triggered = true; });
59         i.method();
60
61         ok(triggered);
62     });
63     test('Unbind all handlers', function (instance) {
64         var e = create(instance.web.list.Events), passed = 0;
65         e.bind('foo', function () { passed++; });
66         e.trigger('foo');
67         strictEqual(passed, 1);
68         e.unbind('foo');
69         e.trigger('foo');
70         strictEqual(passed, 1);
71     });
72     test('Unbind one handler', function (instance) {
73         var e = create(instance.web.list.Events), p1 = 0, p2 = 0,
74             h1 = function () { p1++; }, h2 = function () { p2++; };
75         e.bind('foo', h1);
76         e.bind('foo', h2);
77         e.trigger('foo');
78         strictEqual(p1, 1);
79         strictEqual(p2, 1);
80         e.unbind('foo', h1);
81         e.trigger('foo');
82         strictEqual(p1, 1);
83         strictEqual(p2, 2);
84     });
85 });
86 openerp.testing.section('list.records', {
87     dependencies: ['web.list']
88 }, function (test) {
89     test('Basic record initialization', function (instance) {
90         var r = new instance.web.list.Record({qux: 3});
91         r.set('foo', 1);
92         r.set('bar', 2);
93         strictEqual(r.get('foo'), 1);
94         strictEqual(r.get('bar'), 2);
95         strictEqual(r.get('qux'), 3);
96     });
97     test('Change all the things', function (instance) {
98         var r = new instance.web.list.Record(), changed = false, field;
99         r.bind('change', function () { changed = true; });
100         r.bind(null, function (e) { field = field || e.split(':')[1]; });
101         r.set('foo', 1);
102         strictEqual(r.get('foo'), 1);
103         ok(changed);
104         strictEqual(field, 'foo');
105     });
106     test('Change single field', function (instance) {
107         var r = new instance.web.list.Record(), changed = 0;
108         r.bind('change:foo', function () { changed++; });
109         r.set('foo', 1);
110         r.set('bar', 1);
111         strictEqual(r.get('foo'), 1);
112         strictEqual(r.get('bar'), 1);
113         strictEqual(changed, 1);
114     });
115 });
116 openerp.testing.section('list.collections', {
117     dependencies: ['web.list']
118 }, function (test) {
119     test('degenerate-fetch', function (instance) {
120         var c = new instance.web.list.Collection();
121         strictEqual(c.length, 0);
122         c.add({id: 1, value: 2});
123         c.add({id: 2, value: 3});
124         c.add({id: 3, value: 5});
125         c.add({id: 4, value: 7});
126         strictEqual(c.length, 4);
127         var r = c.at(2), r2 = c.get(1);
128
129         ok(r instanceof instance.web.list.Record);
130         strictEqual(r.get('id'), 3);
131         strictEqual(r.get('value'), 5);
132
133         ok(r2 instanceof instance.web.list.Record);
134         strictEqual(r2.get('id'), 1);
135         strictEqual(r2.get('value'), 2);
136     });
137     test('degenerate-indexed-add', function (instance) {
138         var c = new instance.web.list.Collection([
139             {id: 1, value: 5},
140             {id: 2, value: 10},
141             {id: 3, value: 20}
142         ]);
143         strictEqual(c.at(1).get('value'), 10);
144         equal(c.at(3), undefined);
145         c.add({id:4, value: 55}, {at: 1});
146         strictEqual(c.at(1).get('value'), 55);
147         strictEqual(c.at(3).get('value'), 20);
148     });
149     test('degenerate-remove', function (instance) {
150         var c = new instance.web.list.Collection([
151             {id: 1, value: 5},
152             {id: 2, value: 10},
153             {id: 3, value: 20}
154         ]);
155         var record = c.get(2);
156         strictEqual(c.length, 3);
157         c.remove(record);
158         strictEqual(c.length, 2);
159         equal(c.get(2), undefined);
160         strictEqual(c.at(1).get('value'), 20);
161     });
162     test('degenerate-remove-bound', function (instance) {
163         var changed = false,
164             c = new instance.web.list.Collection([ {id: 1, value: 5} ]);
165         c.bind('change', function () { changed = true; });
166         var record = c.get(1);
167         c.remove(record);
168         record.set('value', 42);
169         ok(!changed, 'removed records should not trigger events in their ' +
170                      'parent collection');
171     });
172     test('degenerate-reset', function (instance) {
173         var event, obj, c = new instance.web.list.Collection([
174             {id: 1, value: 5},
175             {id: 2, value: 10},
176             {id: 3, value: 20}
177         ]);
178         c.bind(null, function (e, instance) { event = e; obj = instance; });
179         c.reset();
180         strictEqual(c.length, 0);
181         strictEqual(event, 'reset');
182         strictEqual(obj, c);
183         c.add([
184             {id: 1, value: 5},
185             {id: 2, value: 10},
186             {id: 3, value: 20}
187         ]);
188         c.reset([{id: 42, value: 55}]);
189         strictEqual(c.length, 1);
190         strictEqual(c.get(42).get('value'), 55);
191     });
192     test('degenerate-reset-bound', function (instance) {
193         var changed = false,
194             c = new instance.web.list.Collection([ {id: 1, value: 5} ]);
195         c.bind('change', function () { changed = true; });
196         var record = c.get(1);
197         c.reset();
198         record.set('value', 42);
199         ok(!changed, 'removed records should not trigger events in their ' +
200                      'parent collection');
201     });
202
203     test('degenerate-propagations', function (instance) {
204         var values = [];
205         var c = new instance.web.list.Collection([
206             {id: 1, value: 5},
207             {id: 2, value: 10},
208             {id: 3, value: 20}
209         ]);
210         c.bind('change:value', function (e, record, value) {
211             values.push(value);
212         });
213         c.get(1).set('value', 6);
214         c.get(2).set('value', 11);
215         c.get(3).set('value', 21);
216         deepEqual(values, [6, 11, 21]);
217     });
218     test('BTree', function (instance) {
219         var root = new instance.web.list.Collection(),
220             c = root.proxy('admin'),
221             total = 0;
222         c.add({id: 1, name: "Administrator", login: 'admin'});
223         c.add({id: 3, name: "Demo", login: 'demo'});
224         root.bind('change:wealth', function () {
225             total = (root.get(1).get('wealth') || 0) + (root.get(3).get('wealth') || 0);
226         });
227
228         strictEqual(total, 0);
229         c.at(0).set('wealth', 42);
230         strictEqual(total, 42);
231         c.at(1).set('wealth', 5);
232         strictEqual(total, 47);
233     });
234     test('degenerate-successor', function (instance) {
235         var root = new instance.web.list.Collection([
236             {id: 1, value: 1},
237             {id: 2, value: 2},
238             {id: 3, value: 3},
239             {id: 4, value: 5},
240             {id: 5, value: 8}
241         ]);
242
243         deepEqual(root.succ(root.at(2)).attributes,
244                   root.at(3).attributes,
245                   "should return the record at (index + 1) from the pivot");
246         equal(root.succ(root.at(4)), null,
247               "should return null as successor to last record");
248         deepEqual(root.succ(root.at(4), {wraparound: true}).attributes,
249                   root.at(0).attributes,
250                   "should return index 0 as successor to last record if" +
251                   " wraparound is set");
252         deepEqual(root.succ(root.at(2), {wraparound: true}).attributes,
253                   root.at(3).attributes,
254                   "wraparound should have no effect if not succ(last_record)");
255     });
256     test('successor', function (instance) {
257         var root = new instance.web.list.Collection();
258         root.proxy('first').add([{id: 1, value: 1}, {id: 2, value: 2}]);
259         root.proxy('second').add([{id: 3, value: 3}, {id: 4, value: 5}]);
260         root.proxy('third').add([{id: 5, value: 8}, {id: 6, value: 13}]);
261
262         deepEqual(root.succ(root.get(3)).attributes,
263                   root.get(4).attributes,
264                   "should get successor");
265         equal(root.succ(root.get(4)),
266               null,
267               "successors do not cross collections");
268         deepEqual(root.succ(root.get(4), {wraparound: true}).attributes,
269                   root.get(3).attributes,
270                   "should wraparound within a collection");
271     });
272     test('degenerate-predecessor', function (instance) {
273         var root = new instance.web.list.Collection([
274             {id: 1, value: 1},
275             {id: 2, value: 2},
276             {id: 3, value: 3},
277             {id: 4, value: 5},
278             {id: 5, value: 8}
279         ]);
280
281         deepEqual(root.pred(root.at(2)).attributes,
282                   root.at(1).attributes,
283                   "should return the record at (index - 1) from the pivot");
284         equal(root.pred(root.at(0)), null,
285               "should return null as predecessor to first record");
286         deepEqual(root.pred(root.at(0), {wraparound: true}).attributes,
287                   root.at(4).attributes,
288                   "should return last record as predecessor to first record" +
289                   " if wraparound is set");
290         deepEqual(root.pred(root.at(1), {wraparound: true}).attributes,
291                   root.at(0).attributes,
292                   "wraparound should have no effect if not pred(first_record)");
293     });
294     test('predecessor', function (instance) {
295         var root = new instance.web.list.Collection();
296         root.proxy('first').add([{id: 1, value: 1}, {id: 2, value: 2}]);
297         root.proxy('second').add([{id: 3, value: 3}, {id: 4, value: 5}]);
298         root.proxy('third').add([{id: 5, value: 8}, {id: 6, value: 13}]);
299
300         deepEqual(root.pred(root.get(4)).attributes,
301                   root.get(3).attributes,
302                   "should get predecessor");
303         equal(root.pred(root.get(3)),
304               null,
305               "predecessor do not cross collections");
306         deepEqual(root.pred(root.get(3), {wraparound: true}).attributes,
307                   root.get(4).attributes,
308                   "should wraparound within a collection");
309     });
310 });
311 openerp.testing.section('list.collections.hom', {
312     dependencies: ['web.list']
313 }, function (test) {
314     test('each, degenerate', function (instance) {
315         var c = new instance.web.list.Collection([
316             {id: 1, value: 5},
317             {id: 2, value: 10},
318             {id: 3, value: 20}
319         ]), ids = [];
320         c.each(function (record) {
321             ids.push(record.get('id'));
322         });
323         deepEqual(
324             ids, [1, 2, 3],
325             'degenerate collections should be iterated in record order');
326     });
327     test('each, deep', function (instance) {
328         var root = new instance.web.list.Collection(),
329             ids = [];
330         root.proxy('foo').add([
331             {id: 1, value: 5},
332             {id: 2, value: 10},
333             {id: 3, value: 20}]);
334         root.proxy('bar').add([
335             {id: 10, value: 5},
336             {id: 20, value: 10},
337             {id: 30, value: 20}]);
338         root.each(function (record) {
339             ids.push(record.get('id'));
340         });
341         // No contract on sub-collection iteration order (for now anyway)
342         ids.sort(function (a, b) { return a - b; });
343         deepEqual(
344             ids, [1, 2, 3, 10, 20, 30],
345             'tree collections should be deeply iterated');
346     });
347     test('map, degenerate', function (instance) {
348         var c = new instance.web.list.Collection([
349             {id: 1, value: 5},
350             {id: 2, value: 10},
351             {id: 3, value: 20}
352         ]);
353         var ids = c.map(function (record) {
354             return record.get('id');
355         });
356         deepEqual(
357             ids, [1, 2, 3],
358             'degenerate collections should be iterated in record order');
359     });
360     test('map, deep', function (instance) {
361         var root = new instance.web.list.Collection();
362         root.proxy('foo').add([
363             {id: 1, value: 5},
364             {id: 2, value: 10},
365             {id: 3, value: 20}]);
366         root.proxy('bar').add([
367             {id: 10, value: 5},
368             {id: 20, value: 10},
369             {id: 30, value: 20}]);
370         var ids = root.map(function (record) {
371             return record.get('id');
372         });
373         // No contract on sub-collection iteration order (for now anyway)
374         ids.sort(function (a, b) { return a - b; });
375         deepEqual(
376             ids, [1, 2, 3, 10, 20, 30],
377             'tree collections should be deeply iterated');
378     });
379 });
380 openerp.testing.section('list.collection.weirdoes', {
381     dependencies: ['web.list']
382 }, function (test) {
383     test('set-from-noid', function (instance) {
384         var root = new instance.web.list.Collection();
385         root.add({v: 3});
386         root.at(0).set('id', 42);
387         var record = root.get(42);
388         equal(root.length, 1);
389         equal(record.get('v'), 3, "should have fetched the original record");
390     });
391     test('set-from-previd', function (instance) {
392         var root = new instance.web.list.Collection();
393         root.add({id: 1, v: 2});
394         root.get(1).set('id', 42);
395         var record = root.get(42);
396         equal(root.length, 1);
397         equal(record.get('v'), 2, "should have fetched the original record");
398     });
399 });