diff --git a/addons/web/static/src/core/domain_selector_dialog/domain_selector_dialog.js b/addons/web/static/src/core/domain_selector_dialog/domain_selector_dialog.js index af4777cb503..bfef855dab1 100644 --- a/addons/web/static/src/core/domain_selector_dialog/domain_selector_dialog.js +++ b/addons/web/static/src/core/domain_selector_dialog/domain_selector_dialog.js @@ -11,6 +11,7 @@ export class DomainSelectorDialog extends Component { setup() { this.notification = useService("notification"); this.orm = useService("orm"); + this.user = useService("user"); this.state = useState({ domain: this.props.domain }); } @@ -51,7 +52,8 @@ export class DomainSelectorDialog extends Component { async onConfirm() { try { let domain = new Domain(this.state.domain); - domain = domain.toList(this.props.context); + const evalContext = { ...this.user.context, ...this.props.context }; + domain = domain.toList(evalContext); await this.orm.silent.searchCount(this.props.resModel, domain, { limit: 1 }); } catch { this.notification.add(this.env._t("Domain is invalid. Please correct it"), { diff --git a/addons/web/static/tests/core/domain_selector_dialog_tests.js b/addons/web/static/tests/core/domain_selector_dialog_tests.js new file mode 100644 index 00000000000..3b84dd74738 --- /dev/null +++ b/addons/web/static/tests/core/domain_selector_dialog_tests.js @@ -0,0 +1,139 @@ +/** @odoo-module **/ + +import { Component, xml } from "@odoo/owl"; +import { DomainSelectorDialog } from "@web/core/domain_selector_dialog/domain_selector_dialog"; +import { click, getFixture, mount } from "../helpers/utils"; +import { makeDialogTestEnv } from "../helpers/mock_env"; +import { registry } from "@web/core/registry"; +import { notificationService } from "@web/core/notifications/notification_service"; +import { ormService } from "@web/core/orm_service"; +import { uiService } from "@web/core/ui/ui_service"; +import { MainComponentsContainer } from "@web/core/main_components_container"; +import { makeFakeLocalizationService } from "../helpers/mock_services"; +import { hotkeyService } from "@web/core/hotkeys/hotkey_service"; +import { fieldService } from "@web/core/field_service"; +import { popoverService } from "@web/core/popover/popover_service"; + +/** + * @typedef {Record} Props + */ + +/** + * @param {Partial & { mockRPC: Function }} [params] + */ +async function makeDomainSelectorDialog(params = {}) { + const props = { ...params }; + const mockRPC = props.mockRPC; + delete props.mockRPC; + + class Parent extends Component { + static components = { DomainSelectorDialog }; + static template = xml``; + setup() { + this.domainSelectorProps = { + resModel: "partner", + readonly: false, + domain: "[]", + close: () => {}, + onConfirm: () => {}, + ...props, + }; + } + } + + const env = await makeDialogTestEnv({ serverData, mockRPC }); + await mount(MainComponentsContainer, fixture, { env }); + return mount(Parent, fixture, { env, props }); +} + +/** @type {Element} */ +let fixture; +let serverData; + +QUnit.module("Components", (hooks) => { + hooks.beforeEach(async () => { + serverData = { + models: { + partner: { + fields: { + foo: { string: "Foo", type: "char", searchable: true }, + bar: { string: "Bar", type: "boolean", searchable: true }, + product_id: { + string: "Product", + type: "many2one", + relation: "product", + searchable: true, + }, + datetime: { string: "Date Time", type: "datetime", searchable: true }, + int: { string: "Integer", type: "integer", searchable: true }, + json_field: { string: "Json Field", type: "json", searchable: true }, + }, + records: [ + { id: 1, foo: "yop", bar: true, product_id: 37 }, + { id: 2, foo: "blip", bar: true, product_id: false }, + { id: 4, foo: "abc", bar: false, product_id: 41 }, + ], + onchanges: {}, + }, + product: { + fields: { + name: { string: "Product Name", type: "char", searchable: true }, + }, + records: [ + { id: 37, display_name: "xphone" }, + { id: 41, display_name: "xpad" }, + ], + }, + }, + }; + + registry.category("services").add("notification", notificationService); + registry.category("services").add("orm", ormService); + registry.category("services").add("ui", uiService); + registry.category("services").add("hotkey", hotkeyService); + registry.category("services").add("localization", makeFakeLocalizationService()); + registry.category("services").add("popover", popoverService); + registry.category("services").add("field", fieldService); + + fixture = getFixture(); + }); + + QUnit.module("DomainSelector"); + + QUnit.test("a domain with a user context dynamic part is valid", async (assert) => { + await makeDomainSelectorDialog({ + domain: "[('foo', '=', uid)]", + onConfirm(domain) { + assert.strictEqual(domain, "[('foo', '=', uid)]"); + assert.step("confirmed"); + }, + mockRPC(route, args) { + if (args.method === "search_count") { + const domain = args.args[0]; + assert.deepEqual(domain, [["foo", "=", 7]]); + assert.step("rpc validation"); + } + }, + }); + const confirmButton = fixture.querySelector(".o_dialog footer button"); + await click(confirmButton); + assert.verifySteps(["rpc validation", "confirmed"]); + }); + + QUnit.test("can override user context", async (assert) => { + await makeDomainSelectorDialog({ + domain: "[('foo', '=', uid)]", + context: { uid: 99 }, + mockRPC(route, args) { + if (args.method === "search_count") { + const domain = args.args[0]; + assert.deepEqual(domain, [["foo", "=", 99]]); + assert.step("rpc validation"); + } + }, + }); + const confirmButton = fixture.querySelector(".o_dialog footer button"); + await click(confirmButton); + assert.verifySteps(["rpc validation"]); + }); +});