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