@@ -298,6 +298,119 @@ test(`[Offline] form switches to readonly in offline mode`, async () => {
298298 expect ( `.o_field_x2many_list_row_add` ) . toHaveCount ( 1 ) ;
299299} ) ;
300300
301+ test ( `[Offline] save a form view offline (click save icon)` , async ( ) => {
302+ let offline = false ;
303+ onRpc (
304+ "/web/dataset/call_kw/partner/web_save" ,
305+ ( ) => {
306+ expect . step ( "web_save" ) ;
307+ if ( offline ) {
308+ return new Response ( "" , { status : 502 } ) ;
309+ }
310+ } ,
311+ { pure : true }
312+ ) ;
313+
314+ Partner . _views = {
315+ form : `<form><field name="foo"/></form>` ,
316+ list : `<list><field name="foo"/></list>` ,
317+ search : `<search/>` ,
318+ } ;
319+ defineActions ( [
320+ {
321+ id : 1 ,
322+ name : "Partner" ,
323+ res_model : "partner" ,
324+ views : [
325+ [ false , "list" ] ,
326+ [ false , "form" ] ,
327+ ] ,
328+ } ,
329+ ] ) ;
330+
331+ await mountWithCleanup ( WebClient ) ;
332+ await getService ( "action" ) . doAction ( 1 ) ;
333+
334+ await contains ( ".o_data_row .o_data_cell" ) . click ( ) ;
335+ expect ( ".o_form_renderer" ) . toHaveClass ( "o_form_editable" ) ;
336+ expect ( ".o_field_widget[name=foo] input" ) . toHaveValue ( "yop" ) ;
337+ await contains ( ".o_field_widget[name=foo] input" ) . edit ( "new foo" ) ;
338+
339+ offline = true ;
340+ await contains ( ".o_form_button_save" ) . click ( ) ;
341+ expect ( ".o_form_renderer" ) . toHaveClass ( "o_form_readonly" ) ;
342+ expect ( ".o_field_widget[name=foo]" ) . toHaveText ( "new foo" ) ;
343+ expect ( getService ( "offline" ) . status . offline ) . toBe ( true ) ;
344+ expect . verifySteps ( [ "web_save" ] ) ;
345+
346+ offline = false ;
347+ getService ( "offline" ) . status . offline = false ;
348+ await animationFrame ( ) ;
349+ expect ( ".o_form_renderer" ) . toHaveClass ( "o_form_editable" ) ;
350+ await contains ( ".o_form_button_save" ) . click ( ) ;
351+ expect . verifySteps ( [ "web_save" ] ) ;
352+
353+ await contains ( ".o_breadcrumb .o_back_button" ) . click ( ) ;
354+ expect ( ".o_data_cell:first" ) . toHaveText ( "new foo" ) ;
355+ } ) ;
356+
357+ test ( `[Offline] save a form view offline (autosave when leaving)` , async ( ) => {
358+ // this test is the same as above, but in this one we don't manually save
359+ // the record before leaving
360+ let offline = false ;
361+ onRpc (
362+ "/web/dataset/call_kw/partner/web_save" ,
363+ ( ) => {
364+ expect . step ( "web_save" ) ;
365+ if ( offline ) {
366+ return new Response ( "" , { status : 502 } ) ;
367+ }
368+ } ,
369+ { pure : true }
370+ ) ;
371+
372+ Partner . _views = {
373+ form : `<form><field name="foo"/></form>` ,
374+ list : `<list><field name="foo"/></list>` ,
375+ search : `<search/>` ,
376+ } ;
377+ defineActions ( [
378+ {
379+ id : 1 ,
380+ name : "Partner" ,
381+ res_model : "partner" ,
382+ views : [
383+ [ false , "list" ] ,
384+ [ false , "form" ] ,
385+ ] ,
386+ } ,
387+ ] ) ;
388+
389+ await mountWithCleanup ( WebClient ) ;
390+ await getService ( "action" ) . doAction ( 1 ) ;
391+
392+ await contains ( ".o_data_row .o_data_cell" ) . click ( ) ;
393+ expect ( ".o_form_renderer" ) . toHaveClass ( "o_form_editable" ) ;
394+ expect ( ".o_field_widget[name=foo] input" ) . toHaveValue ( "yop" ) ;
395+ await contains ( ".o_field_widget[name=foo] input" ) . edit ( "new foo" ) ;
396+
397+ offline = true ;
398+ await contains ( ".o_breadcrumb .o_back_button" ) . click ( ) ;
399+ expect ( ".o_form_renderer" ) . toHaveClass ( "o_form_readonly" ) ;
400+ expect ( ".o_field_widget[name=foo]" ) . toHaveText ( "new foo" ) ;
401+ expect ( getService ( "offline" ) . status . offline ) . toBe ( true ) ;
402+ expect . verifySteps ( [ "web_save" ] ) ;
403+
404+ offline = false ;
405+ getService ( "offline" ) . status . offline = false ;
406+ await animationFrame ( ) ;
407+ expect ( ".o_form_renderer" ) . toHaveClass ( "o_form_editable" ) ;
408+
409+ await contains ( ".o_breadcrumb .o_back_button" ) . click ( ) ;
410+ expect ( ".o_data_cell:first" ) . toHaveText ( "new foo" ) ;
411+ expect . verifySteps ( [ "web_save" ] ) ;
412+ } ) ;
413+
301414test ( `form rendering with class and style attributes` , async ( ) => {
302415 await mountView ( {
303416 resModel : "partner" ,
0 commit comments