[FIX] adjust view top when header height changes
[odoo/odoo.git] / addons / web / static / test / list-editable.js
1 openerp.testing.section('editor', {
2     dependencies: ['web.list_editable'],
3     rpc: 'mock',
4     templates: true,
5     setup: function (instance, $s, mock) {
6         mock('test.model:create', function () {
7             return 42;
8         });
9     }
10 }, function (test) {
11     /**
12      *
13      * @param {String} name
14      * @param {Object} [attrs]
15      * @param {String} [attrs.type="char"]
16      * @param {Boolean} [attrs.required]
17      * @param {Boolean} [attrs.invisible]
18      * @param {Boolean} [attrs.readonly]
19      * @return {Object}
20      */
21     function field(name, attrs) {
22         attrs = attrs || {};
23         attrs.name = name;
24         return _.defaults(attrs, {
25             type: 'char'
26         });
27     }
28
29     /**
30      * @param {Array} [fields]
31      * @return {Object}
32      */
33     function makeFormView(fields) {
34         var fobj = {};
35         _(fields).each(function (field) {
36             fobj[field.name] = {
37                 type: field.type,
38                 string: field.string
39             };
40         });
41         var children = _(fields).map(function (field) {
42             return {
43                 tag: 'field',
44                 attrs: {
45                     name: field.name,
46                     modifiers: JSON.stringify({
47                         required: field.required,
48                         invisible: field.invisible,
49                         readonly: field.readonly
50                     })
51                 }
52             };
53         });
54         return {
55             arch: {
56                 tag: 'form',
57                 attrs: {
58                     version: '7.0',
59                     'class': 'oe_form_container'
60                 },
61                 children: children
62             },
63             fields: fobj
64         };
65     }
66
67     test('base-state', {asserts: 2}, function (instance, $fix) {
68         var e = new instance.web.list.Editor({
69             dataset: {ids: []},
70             edition_view: function () {
71                 return makeFormView();
72             }
73         });
74         return e.appendTo($fix)
75             .done(function () {
76                 ok(!e.is_editing(), "should not be editing");
77                 ok(e.form instanceof instance.web.FormView,
78                    "should use default form type");
79             });
80     });
81     test('toggle-edition-save', {
82         asserts: 4,
83         setup: function (instance, $s, mock) {
84             mock('test.model:search_read', function () {
85                 return [{id: 42, a: false, b: false, c: false}];
86             });
87         }
88     }, function (instance, $fix) {
89         var e = new instance.web.list.Editor({
90             dataset: new instance.web.DataSetSearch(null, 'test.model'),
91             prepends_on_create: function () { return false; },
92             edition_view: function () {
93                 return makeFormView([ field('a'), field('b'), field('c') ]);
94             }
95         });
96         var counter = 0;
97         return e.appendTo($fix)
98             .then(function () {
99                 return e.edit({}, function () {
100                     ++counter;
101                 });
102             })
103             .then(function (form) {
104                 ok(e.is_editing(), "should be editing");
105                 equal(counter, 3, "should have configured all fields");
106                 return e.save();
107             })
108             .done(function (record) {
109                 ok(!e.is_editing(), "should have stopped editing");
110                 equal(record.id, 42, "should have newly created id");
111             });
112     });
113     test('toggle-edition-cancel', { asserts: 2 }, function (instance, $fix) {
114         var e = new instance.web.list.Editor({
115             dataset: new instance.web.DataSetSearch(null, 'test.model'),
116             prepends_on_create: function () { return false; },
117             edition_view: function () {
118                 return makeFormView([ field('a'), field('b'), field('c') ]);
119             }
120         });
121         var counter = 0;
122         return e.appendTo($fix)
123             .then(function () {
124                 return e.edit({}, function () {
125                     ++counter;
126                 });
127             })
128             .then(function (form) {
129                 return e.cancel();
130             })
131             .done(function (record) {
132                 ok(!e.is_editing(), "should have stopped editing");
133                 ok(!record.id, "should have no id");
134             });
135     });
136     test('toggle-save-required', {
137         asserts: 2,
138         fail_on_rejection: false
139     }, function (instance, $fix) {
140         var e = new instance.web.list.Editor({
141             do_warn: function () {
142                 warnings++;
143             },
144             dataset: new instance.web.DataSetSearch(null, 'test.model'),
145             prepends_on_create: function () { return false; },
146             edition_view: function () {
147                 return makeFormView([
148                     field('a', {required: true}), field('b'), field('c') ]);
149             }
150         });
151         var counter = 0;
152         var warnings = 0;
153         return e.appendTo($fix)
154             .then(function () {
155                 return e.edit({}, function () {
156                     ++counter;
157                 });
158             })
159             .then(function (form) {
160                 return e.save();
161             })
162             .done(function () { ok(false, "cancel should not succeed"); })
163             .fail(function () {
164                 equal(warnings, 1, "should have been warned");
165                 ok(e.is_editing(), "should have kept editing");
166             });
167     });
168 });
169 openerp.testing.section('list.edition', {
170     dependencies: ['web.list_editable'],
171     rpc: 'mock',
172     templates: true,
173     setup: function (instance, $s, mock) {
174         var records = {};
175         mock('demo:create', function (args) {
176             records[42] = _.extend({}, args[0]);
177             return 42;
178         });
179         mock('demo:read', function (args) {
180             var id = args[0][0];
181             if (id in records) {
182                 return [records[id]];
183             }
184             return [];
185         });
186         mock('demo:search_read', function (args) {
187             // args[0][0] = ["id", "=", 42] 
188             // args[0][0] = 42
189             var id = args[0][0][2];
190             if (id in records) {
191                 return [records[id]];
192             }
193             return [];
194         });
195         mock('demo:fields_view_get', function () {
196             return {
197                 type: 'tree',
198                 fields: {
199                     a: {type: 'char', string: "A"},
200                     b: {type: 'char', string: "B"},
201                     c: {type: 'char', string: "C"}
202                 },
203                 arch: '<tree><field name="a"/><field name="b"/><field name="c"/></tree>',
204             };
205         });
206     }
207 }, function (test) {
208     test('newrecord', {asserts: 6}, function (instance, $fix, mock) {
209         var got_defaults = false;
210         mock('demo:default_get', function (args) {
211             var fields = args[0];
212             deepEqual(
213                 fields, ['a', 'b', 'c'],
214                 "should ask defaults for all fields");
215             got_defaults = true;
216             return { a: "qux", b: "quux" };
217         });
218
219         var ds = new instance.web.DataSetStatic(null, 'demo', null, [1]);
220         var l = new instance.web.ListView({}, ds, false, {editable: 'top'});
221
222         return l.appendTo($fix)
223             .then(l.proxy('reload_content'))
224             .then(function () {
225                 return l.start_edition();
226             })
227             .then(function () {
228                 ok(got_defaults, "should have fetched default values for form");
229
230                 return l.save_edition();
231             })
232             .then(function (result) {
233                 ok(result.created, "should yield newly created record");
234                 equal(result.record.get('a'), "qux",
235                       "should have used default values");
236                 equal(result.record.get('b'), "quux",
237                       "should have used default values");
238                 ok(!result.record.get('c'),
239                     "should have no value if there was no default");
240             });
241     });
242 });
243 openerp.testing.section('list.edition.events', {
244     dependencies: ['web.list_editable'],
245     rpc: 'mock',
246     templates: true,
247     setup: function (instance, $s, mock) {
248         mock('demo:read', function () {
249             return [{ id: 1, a: 'foo', b: 'bar', c: 'baz' }];
250         });
251         mock('demo:fields_view_get', function () {
252             return {
253                 type: 'tree',
254                 fields: {
255                     a: {type: 'char', string: "A"},
256                     b: {type: 'char', string: "B"},
257                     c: {type: 'char', string: "C"}
258                 },
259                 arch: '<tree><field name="a"/><field name="b"/><field name="c"/></tree>',
260             };
261         });
262     }
263 }, function (test) {
264     test('edition events', {asserts: 4}, function (instance, $fix) {
265         var ds = new instance.web.DataSetStatic(null, 'demo', null, [1]);
266         var o = {
267             counter: 0,
268             onEvent: function (e) { this.counter++; }
269         };
270         var l = new instance.web.ListView({}, ds, false, {editable: 'top'});
271         l.on('edit:before edit:after', o, o.onEvent);
272         return l.appendTo($fix)
273             .then(l.proxy('reload_content'))
274             .then(function () {
275                 ok(l.options.editable, "should be editable");
276                 equal(o.counter, 0, "should have seen no event yet");
277                 return l.start_edition(l.records.get(1));
278             })
279             .then(function () {
280                 ok(l.editor.is_editing(), "should be editing");
281                 equal(o.counter, 2, "should have seen two edition events");
282             });
283     });
284
285     test('edition events: cancelling', {asserts: 3}, function (instance, $fix) {
286         var edit_after = false;
287         var ds = new instance.web.DataSetStatic(null, 'demo', null, [1]);
288         var l = new instance.web.ListView({}, ds, false, {editable: 'top'});
289         l.on('edit:before', {}, function (e) {
290             e.cancel = true;
291         });
292         l.on('edit:after', {}, function () {
293             edit_after = true;
294         });
295         return l.appendTo($fix)
296             .then(l.proxy('reload_content'))
297             .then(function () {
298                 ok(l.options.editable, "should be editable");
299                 return l.start_edition();
300             })
301             // cancelling an event rejects the deferred
302             .then($.Deferred().reject(), function () {
303                 ok(!l.editor.is_editing(), "should not be editing");
304                 ok(!edit_after, "should not have fired the edit:after event");
305                 return $.when();
306             });
307     });
308 });
309
310 openerp.testing.section('list.edition.onwrite', {
311     dependencies: ['web.list_editable'],
312     rpc: 'mock',
313     templates: true,
314 }, function (test) {
315     test('record-to-read', {asserts: 4}, function (instance, $fix, mock) {
316         mock('demo:fields_view_get', function () {
317             return {
318                 type: 'tree',
319                 fields: {
320                     a: {type: 'char', string: "A"}
321                 },
322                 arch: '<tree on_write="on_write" colors="red:a == \'foo\'"><field name="a"/></tree>',
323             };
324         });
325         mock('demo:read', function (args, kwargs) {
326             if (_.isEmpty(args[0])) {
327                 return [];
328             }
329             throw new Error(JSON.stringify(_.toArray(arguments)));
330         });
331         mock('demo:search_read', function (args, kwargs) {
332             if (_.isEqual(args[0], [['id', 'in', [1]]])) {
333                 return [{id: 1, a: 'some value'}];
334             } else if (_.isEqual(args[0], [['id', 'in', [42]]])) {
335                 return [ {id: 42, a: 'foo'} ];
336             }
337             throw new Error(JSON.stringify(_.toArray(arguments)));
338         });
339         mock('demo:default_get', function () { return {}; });
340         mock('demo:create', function () { return 1; });
341         mock('demo:on_write', function () { return [42]; });
342
343         var ds = new instance.web.DataSetStatic(null, 'demo', null, []);
344         var l = new instance.web.ListView({}, ds, false, {editable: 'top'});
345         return l.appendTo($fix)
346         .then(l.proxy('reload_content'))
347         .then(function () {
348             return l.start_edition();
349         })
350         .then(function () {
351             $fix.find('.oe_form_field input').val("some value").change();
352         })
353         .then(function () {
354             return l.save_edition();
355         })
356         .then(function () {
357             strictEqual(ds.ids.length, 2,
358                 'should have id of created + on_write');
359             strictEqual(l.records.length, 2,
360                 'should have record of created + on_write');
361             strictEqual(
362                 $fix.find('tbody tr:eq(1)').css('color'), 'rgb(255, 0, 0)',
363                 'shoud have color applied');
364             notStrictEqual(
365                 $fix.find('tbody tr:eq(2)').css('color'), 'rgb(255, 0, 0)',
366                 'should have default color applied');
367         });
368     });
369 });