mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-19 23:32:01 +02:00
Initial commit: Core packages
This commit is contained in:
commit
12c29a983b
9512 changed files with 8379910 additions and 0 deletions
|
|
@ -0,0 +1,242 @@
|
|||
odoo.define('web.data_manager_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
const config = require('web.config');
|
||||
const DataManager = require('web.DataManager');
|
||||
const MockServer = require('web.MockServer');
|
||||
const rpc = require('web.rpc');
|
||||
const testUtils = require('web.test_utils');
|
||||
|
||||
/**
|
||||
* Create a simple data manager with mocked functions:
|
||||
* - mockRPC -> rpc.query
|
||||
* - isDebug -> config.isDebug
|
||||
* @param {Object} params
|
||||
* @param {Object} params.archs
|
||||
* @param {Object} params.data
|
||||
* @param {Function} params.isDebug
|
||||
* @param {Function} params.mockRPC
|
||||
* @returns {DataManager}
|
||||
*/
|
||||
function createDataManager({ archs, data, isDebug, mockRPC }) {
|
||||
const dataManager = new DataManager();
|
||||
const server = new MockServer(data, { archs });
|
||||
|
||||
const serverMethods = {
|
||||
async get_views({ kwargs, model }) {
|
||||
const models = {};
|
||||
models[model] = server.fieldsGet(model);
|
||||
const views = {};
|
||||
for (const [viewId, viewType] of kwargs.views) {
|
||||
const arch = archs[[model, viewId || false, viewType].join()];
|
||||
views[viewType] = server.getView({ arch, model, viewId });
|
||||
for (const modelName of views[viewType].models) {
|
||||
models[modelName] = server.fieldsGet(modelName);
|
||||
}
|
||||
}
|
||||
const result = { models, views };
|
||||
if (kwargs.options.load_filters && views.search) {
|
||||
views.search.filters = data['ir.filters'].records.filter(r => r.model_id === model);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
async get_filters({ args, model }) {
|
||||
return data[model].records.filter(r => r.model_id === args[0]);
|
||||
},
|
||||
async create_or_replace({ args }) {
|
||||
const id = data['ir.filters'].records.reduce((i, r) => Math.max(i, r.id), 0) + 1;
|
||||
const filter = Object.assign(args[0], { id });
|
||||
data['ir.filters'].records.push(filter);
|
||||
return id;
|
||||
},
|
||||
async unlink({ args }) {
|
||||
data['ir.filters'].records = data['ir.filters'].records.filter(
|
||||
r => r.id !== args[0]
|
||||
);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
testUtils.mock.patch(rpc, {
|
||||
async query({ method }) {
|
||||
this._super = serverMethods[method].bind(this, ...arguments);
|
||||
return mockRPC.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
testUtils.mock.patch(config, { isDebug });
|
||||
|
||||
return dataManager;
|
||||
}
|
||||
|
||||
QUnit.module("Services", {
|
||||
beforeEach() {
|
||||
this.archs = {
|
||||
'oui,10,kanban': '<kanban/>',
|
||||
'oui,20,search': '<search/>',
|
||||
};
|
||||
this.data = {
|
||||
oui: { fields: {}, records: [] },
|
||||
'ir.filters': {
|
||||
fields: {
|
||||
context: { type: "Text", string: "Context" },
|
||||
domain: { type: "Text", string: "Domain" },
|
||||
model_id: { type: "Selection", string: "Model" },
|
||||
name: { type: "Char", string: "Name" },
|
||||
},
|
||||
records: [{
|
||||
id: 2,
|
||||
context: '{}',
|
||||
domain: '[]',
|
||||
model_id: 'oui',
|
||||
name: "Favorite",
|
||||
}]
|
||||
}
|
||||
};
|
||||
this.loadViewsParams = {
|
||||
model: "oui",
|
||||
context: {},
|
||||
views_descr: [
|
||||
[10, 'kanban'],
|
||||
[20, 'search'],
|
||||
],
|
||||
};
|
||||
},
|
||||
afterEach() {
|
||||
testUtils.mock.unpatch(rpc);
|
||||
testUtils.mock.unpatch(config);
|
||||
},
|
||||
}, function () {
|
||||
|
||||
QUnit.module("Data manager");
|
||||
|
||||
QUnit.test("Load views with filters (non-debug mode)", async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
const dataManager = createDataManager({
|
||||
archs: this.archs,
|
||||
data: this.data,
|
||||
isDebug() {
|
||||
return false;
|
||||
},
|
||||
async mockRPC({ method, model }) {
|
||||
assert.step([model, method].join('.'));
|
||||
return this._super(...arguments);
|
||||
},
|
||||
});
|
||||
|
||||
const firstLoad = await dataManager.load_views(this.loadViewsParams, {
|
||||
load_filters: true,
|
||||
});
|
||||
const secondLoad = await dataManager.load_views(this.loadViewsParams, {
|
||||
load_filters: true,
|
||||
});
|
||||
const filters = await dataManager.load_filters({ modelName: 'oui' });
|
||||
|
||||
assert.deepEqual(firstLoad, secondLoad,
|
||||
"query with same params and options should yield the same results");
|
||||
assert.deepEqual(firstLoad.search.favoriteFilters, filters,
|
||||
"load filters should yield the same result as the first load_views' filters");
|
||||
assert.verifySteps(['oui.get_views'],
|
||||
"only load once when not in assets debugging");
|
||||
});
|
||||
|
||||
QUnit.test("Load views with filters (debug mode)", async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const dataManager = createDataManager({
|
||||
archs: this.archs,
|
||||
data: this.data,
|
||||
isDebug() {
|
||||
return true; // assets
|
||||
},
|
||||
async mockRPC({ method, model }) {
|
||||
assert.step([model, method].join('.'));
|
||||
return this._super(...arguments);
|
||||
},
|
||||
});
|
||||
|
||||
const firstLoad = await dataManager.load_views(this.loadViewsParams, {
|
||||
load_filters: true,
|
||||
});
|
||||
const secondLoad = await dataManager.load_views(this.loadViewsParams, {
|
||||
load_filters: true,
|
||||
});
|
||||
const filters = await dataManager.load_filters({ modelName: 'oui' });
|
||||
|
||||
assert.deepEqual(firstLoad, secondLoad,
|
||||
"query with same params and options should yield the same results");
|
||||
assert.deepEqual(firstLoad.search.favoriteFilters, filters,
|
||||
"load filters should yield the same result as the first load_views' filters");
|
||||
assert.verifySteps([
|
||||
'oui.get_views',
|
||||
'oui.get_views',
|
||||
'ir.filters.get_filters',
|
||||
], "reload each time when in assets debugging");
|
||||
});
|
||||
|
||||
QUnit.test("Cache invalidation and filters addition/deletion", async function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
const dataManager = createDataManager({
|
||||
archs: this.archs,
|
||||
data: this.data,
|
||||
isDebug() {
|
||||
return false; // Cache only works if 'debug !== assets'
|
||||
},
|
||||
async mockRPC({ method, model }) {
|
||||
assert.step([model, method].join('.'));
|
||||
return this._super(...arguments);
|
||||
},
|
||||
});
|
||||
|
||||
// A few unnecessary 'load_filters' are done in this test to assert
|
||||
// that the cache invalidation mechanics are working.
|
||||
let filters;
|
||||
|
||||
const firstLoad = await dataManager.load_views(this.loadViewsParams, {
|
||||
load_filters: true,
|
||||
});
|
||||
// Cache is valid -> should not trigger an RPC
|
||||
filters = await dataManager.load_filters({ modelName: 'oui' });
|
||||
assert.deepEqual(firstLoad.search.favoriteFilters, filters,
|
||||
"load_filters and load_views.search should return the same filters");
|
||||
|
||||
const filterId = await dataManager.create_filter({
|
||||
context: "{}",
|
||||
domain: "[]",
|
||||
model_id: 'oui',
|
||||
name: "Temp",
|
||||
});
|
||||
// Cache is not valid anymore -> triggers a 'get_filters'
|
||||
filters = await dataManager.load_filters({ modelName: 'oui' });
|
||||
// Cache is valid -> should not trigger an RPC
|
||||
filters = await dataManager.load_filters({ modelName: 'oui' });
|
||||
|
||||
assert.strictEqual(filters.length, 2,
|
||||
"A new filter should have been added");
|
||||
assert.ok(filters.find(f => f.id === filterId) === filters[filters.length - 1],
|
||||
"Create filter should return the id of the last created filter");
|
||||
|
||||
await dataManager.delete_filter(filterId);
|
||||
|
||||
// Views cache is valid but filters cache is not -> triggers a 'get_filters'
|
||||
const secondLoad = await dataManager.load_views(this.loadViewsParams, {
|
||||
load_filters: true,
|
||||
});
|
||||
filters = secondLoad.search.favoriteFilters;
|
||||
// Filters cache is once again valid -> no RPC
|
||||
const expectedFilters = await dataManager.load_filters({ modelName: 'oui' });
|
||||
|
||||
assert.deepEqual(filters, expectedFilters,
|
||||
"Filters loaded by the load_views should be equal to the result of a load_filters");
|
||||
|
||||
assert.verifySteps([
|
||||
'oui.get_views',
|
||||
'ir.filters.create_or_replace',
|
||||
'ir.filters.get_filters',
|
||||
'ir.filters.unlink',
|
||||
'ir.filters.get_filters',
|
||||
], "server should have been called only when needed");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { browser } from "@web/core/browser/browser";
|
||||
import AbstractAction from "web.AbstractAction";
|
||||
import core from "web.core";
|
||||
import * as LegacyRegistry from "web.Registry";
|
||||
import { registerCleanup } from "../../helpers/cleanup";
|
||||
import { nextTick, patchWithCleanup } from "../../helpers/utils";
|
||||
import { createWebClient, doAction } from "../../webclient/helpers";
|
||||
|
||||
let legacyParams;
|
||||
|
||||
QUnit.module("Service Provider Adapter Notification", (hooks) => {
|
||||
hooks.beforeEach(() => {
|
||||
legacyParams = {
|
||||
serviceRegistry: new LegacyRegistry(),
|
||||
};
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"can display and close a sticky danger notification with a title (legacy)",
|
||||
async function (assert) {
|
||||
assert.expect(8);
|
||||
let notifId;
|
||||
let timeoutCB;
|
||||
patchWithCleanup(browser, {
|
||||
setTimeout: (cb, delay) => {
|
||||
if (!delay) {
|
||||
return; // Timeouts from router service
|
||||
}
|
||||
timeoutCB = cb;
|
||||
assert.step("time: " + delay);
|
||||
return 1;
|
||||
},
|
||||
});
|
||||
const NotifyAction = AbstractAction.extend({
|
||||
on_attach_callback() {
|
||||
notifId = this.call("notification", "notify", {
|
||||
title: "Some title",
|
||||
message: "I'm a danger notification",
|
||||
type: "danger",
|
||||
sticky: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
const CloseAction = AbstractAction.extend({
|
||||
on_attach_callback() {
|
||||
this.call("notification", "close", notifId, false, 3000);
|
||||
},
|
||||
});
|
||||
core.action_registry.add("NotifyTestLeg", NotifyAction);
|
||||
core.action_registry.add("CloseTestLeg", CloseAction);
|
||||
registerCleanup(() => {
|
||||
delete core.action_registry.map.NotifyTestLeg;
|
||||
delete core.action_registry.map.CloseTestLeg;
|
||||
});
|
||||
const webClient = await createWebClient({ legacyParams });
|
||||
await doAction(webClient, "NotifyTestLeg");
|
||||
await nextTick();
|
||||
assert.containsOnce(document.body, ".o_notification");
|
||||
const notif = document.body.querySelector(".o_notification");
|
||||
assert.strictEqual(notif.querySelector(".o_notification_title").textContent, "Some title");
|
||||
assert.strictEqual(
|
||||
notif.querySelector(".o_notification_content").textContent,
|
||||
"I'm a danger notification"
|
||||
);
|
||||
assert.hasClass(notif, "border-danger");
|
||||
|
||||
//Close the notification
|
||||
await doAction(webClient, "CloseTestLeg");
|
||||
await nextTick();
|
||||
assert.containsOnce(document.body, ".o_notification");
|
||||
// simulate end of timeout
|
||||
timeoutCB();
|
||||
await nextTick();
|
||||
assert.containsNone(document.body, ".o_notification");
|
||||
assert.verifySteps(["time: 3000"]);
|
||||
}
|
||||
);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue