odoo-13.0/addons/web/static/tests/helpers/test_utils_create.js
/**
 * create a view from various parameters.  Here, a view means a javascript
 * instance of an AbstractView class, such as a form view, a list view or a
 * kanban view.
 *
 * It returns the instance of the view, properly created, with all rpcs going
 * through a mock method using the data object as source, and already loaded/
 * started.
 *
 * @param {Object} params
 * @param {string} params.arch the xml (arch) of the view to be instantiated
 * @param {any[]} [params.domain] the initial domain for the view
 * @param {Object} [params.context] the initial context for the view
 * @param {Object} [params.debug=false] if true, the widget will be appended in
 *   the DOM. Also, RPCs and uncaught OdooEvent will be logged
 * @param {string[]} [params.groupBy] the initial groupBy for the view
 * @param {integer} [params.fieldDebounce=0] the debounce value to use for the
 *   duration of the test.
 * @param {AbstractView} params.View the class that will be instantiated
 * @param {string} params.model a model name, will be given to the view
 * @param {Object} params.intercepts an object with event names as key, and
 *   callback as value.  Each key,value will be used to intercept the event.
 *   Note that this is particularly useful if you want to intercept events going
 *   up in the init process of the view, because there are no other way to do it
 *   after this method returns
 * @returns {Promise<AbstractController>} resolves with the instance of the view
 */
create a view from various parameters.  Here, a view means a javascript
instance of an AbstractView class, such as a form view, a list view or a
kanban view.

It returns the instance of the view, properly created, with all rpcs going
through a mock method using the data object as source, and already loaded
started.


create a view from various parameters . Here a view means a javascript instance of an AbstractView class such as a form view a list view or a kanban view . It returns the instance of the view properly created with all rpcs going through a mock method using the data object as source and already loaded started .
async function createView(params) {
    var $target = $('#qunit-fixture');
    var widget = new Widget();
    if (params.debug) {
        $target = $('body');
        $target.addClass('debug');
    }
    var $webClient = $('<div>').addClass('o_web_client').prependTo($target);
    var $actionManager = $('<div>').addClass('o_action_manager').appendTo($webClient);
    var mockServer = testUtilsMock.addMockEnvironment(widget, params);
    var viewInfo = testUtilsMock.fieldsViewGet(mockServer, params);
    var View = params.View;
    var viewOptions = _.defaults({}, params.viewOptions, {
        modelName: params.model || 'foo',
        ids: 'res_id' in params ? [params.res_id] : undefined,
        currentId: 'res_id' in params ? params.res_id : undefined,
        domain: params.domain || [],
        context: params.context || {},
        hasSidebar: false,
    });
    testUtilsMock.patch(View, {
        _updateMVCParams: function () {
            this._super.apply(this, arguments);
            this.loadParams.groupedBy = params.groupBy || viewOptions.groupBy || [];
            testUtilsMock.unpatch(View);
        },
    });
    if ('hasSelectors' in params) {
        viewOptions.hasSelectors = params.hasSelectors;
    }
    var view;
    if (viewInfo.type === 'controlpanel' || viewInfo.type === 'search') {
        view = new params.View({
            viewInfo: viewInfo,
            modelName: params.model || 'foo',
        });
    } else {
        viewOptions.controlPanelFieldsView = testUtilsMock.fieldsViewGet(mockServer, {
            arch: params.archs && params.archs[params.model + ',false,search'] || '<search/>',
            fields: viewInfo.fields,
            model: params.model,
        });
        view = new params.View(viewInfo, viewOptions);
    }
    if (params.interceptsPropagate) {
        _.each(params.interceptsPropagate, function (cb, name) {
            testUtilsMock.intercept(widget, name, cb, true);
        });
    }
    return view.getController(widget).then(function (view) {
        view.__destroy = view.destroy;
        view.destroy = function () {
            delete view.destroy;
            widget.destroy();
            $webClient.remove();
        };
        var fragment = document.createDocumentFragment();
        return view.appendTo(fragment).then(function () {
            dom.prepend($actionManager, fragment, {
                callbacks: [{ widget: view }],
                in_DOM: true,
            });
            view.$el.on('click', 'a', function (ev) {
                ev.preventDefault();
            });
            return view;
        });
    });
}
async function createView ( params ) { var $target = $ ( '#qunit-fixture' ) ; var widget = new Widget ( ) ; if ( params . debug ) { $target = $ ( 'body' ) ; $target . addClass ( 'debug' ) ; } var $webClient = $ ( '<div>' ) . addClass ( 'o_web_client' ) . prependTo ( $target ) ; var $actionManager = $ ( '<div>' ) . addClass ( 'o_action_manager' ) . appendTo ( $webClient ) ; var mockServer = testUtilsMock . addMockEnvironment ( widget , params ) ; var viewInfo = testUtilsMock . fieldsViewGet ( mockServer , params ) ; var View = params . View ; var viewOptions = _ . defaults ( { } , params . viewOptions , { modelName : params . model || 'foo' , ids : 'res_id' in params ? [ params . res_id ] : undefined , currentId : 'res_id' in params ? params . res_id : undefined , domain : params . domain || [ ] , context : params . context || { } , hasSidebar : false , } ) ; testUtilsMock . patch ( View , { _updateMVCParams : function ( ) { this . _super . apply ( this , arguments ) ; this . loadParams . groupedBy = params . groupBy || viewOptions . groupBy || [ ] ; testUtilsMock . unpatch ( View ) ; } , } ) ; if ( 'hasSelectors' in params ) { viewOptions . hasSelectors = params . hasSelectors ; } var view ; if ( viewInfo . type === 'controlpanel' || viewInfo . type === 'search' ) { view = new params . View ( { viewInfo : viewInfo , modelName : params . model || 'foo' , } ) ; } else { viewOptions . controlPanelFieldsView = testUtilsMock . fieldsViewGet ( mockServer , { arch : params . archs && params . archs [ params . model + ',false,search' ] || '<search/>' , fields : viewInfo . fields , model : params . model , } ) ; view = new params . View ( viewInfo , viewOptions ) ; } if ( params . interceptsPropagate ) { _ . each ( params . interceptsPropagate , function ( cb , name ) { testUtilsMock . intercept ( widget , name , cb , true ) ; } ) ; } return view . getController ( widget ) . then ( function ( view ) { view . __destroy = view . destroy ; view . destroy = function ( ) { delete view . destroy ; widget . destroy ( ) ; $webClient . remove ( ) ; } ; var fragment = document . createDocumentFragment ( ) ; return view . appendTo ( fragment ) . then ( function ( ) { dom . prepend ( $actionManager , fragment , { callbacks : [ { widget : view } ] , in_DOM : true , } ) ; view . $el . on ( 'click' , 'a' , function ( ev ) { ev . preventDefault ( ) ; } ) ; return view ; } ) ; } ) ; }
create a view from various parameters.
create a view from various parameters .
// reproduce the DOM environment of views // add mock environment: mock server, session, fieldviewget, ... // create the view // patch the View to handle the groupBy given in params, as we can't give it // in init (unlike the domain and context which can be set in the action) // TODO: probably needs to create an helper just for that // override the view's 'destroy' so that it calls 'destroy' on the widget // instead, as the widget is the parent of the view and the mockServer. // remove the override to properly destroy the view and its children // when it will be called the second time (by its parent) // render the view in a fragment as they must be able to render correctly // without being in the DOM