From 85b1ec969e508ed4e2cf3a414348d6798da52dd5 Mon Sep 17 00:00:00 2001 From: Younn Olivier Date: Thu, 19 May 2022 17:50:24 +0200 Subject: [PATCH] [FIX] web, web_editor, website: fix qunit tests This commit mocks the website service for all the QUnit tests. As the website module now defines a patch on the WebClient and NavBar components, adding the website service, this service needs to be mocked for all the tests. This is done by patching the QUnit.testStart hook. Also, after the addition of the new media dialog, this component is mocked at the field html unit test. See merge commit for more information. task-2687506 --- .../tests/core/debug/debug_manager_tests.js | 3 +- addons/web/static/tests/helpers/mock_env.js | 7 +- addons/web/static/tests/setup.js | 4 +- .../static/tests/field_html_tests.js | 68 ++++++++++--------- addons/website/__manifest__.py | 3 + .../static/src/components/navbar/navbar.js | 12 ++-- .../static/src/services/website_service.js | 10 ++- .../static/tests/website_service_mock.js | 31 +++++++++ 8 files changed, 95 insertions(+), 43 deletions(-) create mode 100644 addons/website/static/tests/website_service_mock.js diff --git a/addons/web/static/tests/core/debug/debug_manager_tests.js b/addons/web/static/tests/core/debug/debug_manager_tests.js index da9b649d94e..313bacf90ed 100644 --- a/addons/web/static/tests/core/debug/debug_manager_tests.js +++ b/addons/web/static/tests/core/debug/debug_manager_tests.js @@ -10,7 +10,7 @@ import { uiService } from "@web/core/ui/ui_service"; import { useSetupView } from "@web/views/helpers/view_hook"; import { ActionDialog } from "@web/webclient/actions/action_dialog"; import { hotkeyService } from "@web/core/hotkeys/hotkey_service"; -import { makeTestEnv, prepareRegistriesWithCleanup } from "../../helpers/mock_env"; +import { makeTestEnv, utils } from "../../helpers/mock_env"; import { fakeCommandService, makeFakeDialogService, @@ -31,6 +31,7 @@ import { editSearchView, editView } from "@web/views/debug_items"; import { setDefaults } from "@web/legacy/debug_manager"; const { Component, xml } = owl; +const { prepareRegistriesWithCleanup } = utils; export class DebugMenuParent extends Component { setup() { diff --git a/addons/web/static/tests/helpers/mock_env.js b/addons/web/static/tests/helpers/mock_env.js index 4233d1f4f39..47204fb7249 100644 --- a/addons/web/static/tests/helpers/mock_env.js +++ b/addons/web/static/tests/helpers/mock_env.js @@ -44,7 +44,7 @@ export function clearServicesMetadataWithCleanup() { registerCleanup(() => patch(SERVICES_METADATA, servicesMetadata)); } -export function prepareRegistriesWithCleanup() { +function prepareRegistriesWithCleanup() { // Clone registries cloneRegistryWithCleanup(registry.category("actions")); cloneRegistryWithCleanup(registry.category("views")); @@ -72,6 +72,11 @@ export function prepareRegistriesWithCleanup() { // better design for the way we clear these registries... } +// This is exported in a utils object to allow for patching +export const utils = { + prepareRegistriesWithCleanup, +}; + /** * @typedef {import("@web/env").OdooEnv} OdooEnv */ diff --git a/addons/web/static/tests/setup.js b/addons/web/static/tests/setup.js index a85f5168aee..5f5d584a0b2 100644 --- a/addons/web/static/tests/setup.js +++ b/addons/web/static/tests/setup.js @@ -6,7 +6,7 @@ import { browser, makeRAMLocalStorage } from "@web/core/browser/browser"; import { patchTimeZone, patchWithCleanup } from "@web/../tests/helpers/utils"; import { legacyProm } from "web.test_legacy"; import { registerCleanup } from "./helpers/cleanup"; -import { prepareRegistriesWithCleanup } from "./helpers/mock_env"; +import { utils } from "./helpers/mock_env"; import { session as sessionInfo } from "@web/session"; import { prepareLegacyRegistriesWithCleanup } from "./helpers/legacy_env_utils"; import { config as transitionConfig } from "@web/core/transition"; @@ -17,6 +17,8 @@ import { patch } from "@web/core/utils/patch"; import { processTemplates } from "@web/core/assets"; const { App, whenReady, loadFile } = owl; +const { prepareRegistriesWithCleanup } = utils; + patch(App.prototype, "TestOwlApp", { destroy() { if (!this.destroyed) { diff --git a/addons/web_editor/static/tests/field_html_tests.js b/addons/web_editor/static/tests/field_html_tests.js index 19c62309a46..1049adf6866 100644 --- a/addons/web_editor/static/tests/field_html_tests.js +++ b/addons/web_editor/static/tests/field_html_tests.js @@ -8,11 +8,13 @@ var testUtils = require('web.test_utils'); var weTestUtils = require('web_editor.test_utils'); var core = require('web.core'); var Wysiwyg = require('web_editor.wysiwyg'); -var MediaDialog = require('wysiwyg.widgets.MediaDialog'); +const { MediaDialogWrapper } = require('@web_editor/components/media_dialog/media_dialog'); var LinkDialog = require('wysiwyg.widgets.LinkDialog'); const { legacyExtraNextTick, patchWithCleanup } = require("@web/../tests/helpers/utils"); +const { useEffect } = owl; + var _t = core._t; let _formResolveTestPromise; @@ -347,34 +349,36 @@ QUnit.module('web_editor', {}, function () { await testUtils.form.clickEdit(form); var $field = form.$('.oe_form_field[name="body"]'); - // the dialog load some xml assets - var defMediaDialog = testUtils.makeTestPromise(); - testUtils.mock.patch(MediaDialog, { - init: function () { - this._super.apply(this, arguments); - this.opened(defMediaDialog.resolve.bind(defMediaDialog)); - } - }); - var pText = $field.find('.note-editable p').first().contents()[0]; Wysiwyg.setRange(pText, 1, pText, 2); await new Promise((resolve) => setTimeout(resolve)); const wysiwyg = $field.find('.note-editable').data('wysiwyg'); + + // Mock the MediaDialogWrapper + const defMediaDialog = testUtils.makeTestPromise(); + patchWithCleanup(MediaDialogWrapper.prototype, { + setup() { + useEffect(() => { + this.save(); + }, () => []); + }, + save() { + const imageEl = document.createElement('img'); + imageEl.src = '/web/image/123/transparent.png'; + this.props.save(imageEl); + defMediaDialog.resolve(); + }, + }); + wysiwyg.openMediaDialog(); - - // load static xml file (dialog, media dialog, unsplash image widget) await defMediaDialog; - await testUtils.dom.click($('.modal #editor-media-image .o_existing_attachment_cell:first').removeClass('d-none')); - var $editable = form.$('.oe_form_field[name="body"] .note-editable'); assert.ok($editable.find('img')[0].dataset.src.includes('/web/image/123/transparent.png'), "should have the image in the dom"); - testUtils.mock.unpatch(MediaDialog); - form.destroy(); }); @@ -402,26 +406,30 @@ QUnit.module('web_editor', {}, function () { await testUtils.form.clickEdit(form); var $field = form.$('.oe_form_field[name="body"]'); - // the dialog load some xml assets - var defMediaDialog = testUtils.makeTestPromise(); - testUtils.mock.patch(MediaDialog, { - init: function () { - this._super.apply(this, arguments); - this.opened(defMediaDialog.resolve.bind(defMediaDialog)); - } - }); var pText = $field.find('.note-editable p').first().contents()[0]; Wysiwyg.setRange(pText, 1, pText, 2); const wysiwyg = $field.find('.note-editable').data('wysiwyg'); - wysiwyg.openMediaDialog(); - // load static xml file (dialog, media dialog, unsplash image widget) + // Mock the MediaDialogWrapper + const defMediaDialog = testUtils.makeTestPromise(); + patchWithCleanup(MediaDialogWrapper.prototype, { + setup() { + useEffect(() => { + this.save(); + }, () => []); + }, + save() { + const iconEl = document.createElement('span'); + iconEl.classList.add('fa', 'fa-glass'); + this.props.save(iconEl); + defMediaDialog.resolve(); + }, + }); + + wysiwyg.openMediaDialog(); await defMediaDialog; - $('.modal .tab-content .tab-pane').removeClass('fade'); // to be sync in test - await testUtils.dom.click($('.modal a[aria-controls="editor-media-icon"]')); - await testUtils.dom.click($('.modal #editor-media-icon .font-icons-icon.fa-glass')); var $editable = form.$('.oe_form_field[name="body"] .note-editable'); @@ -429,8 +437,6 @@ QUnit.module('web_editor', {}, function () { '

tto toto toto

tata

', "should have the image in the dom"); - testUtils.mock.unpatch(MediaDialog); - form.destroy(); }); diff --git a/addons/website/__manifest__.py b/addons/website/__manifest__.py index b6a0cb53598..4e3a07ab426 100644 --- a/addons/website/__manifest__.py +++ b/addons/website/__manifest__.py @@ -183,6 +183,9 @@ 'website/static/tests/dashboard_tests.js', 'website/static/tests/website_tests.js', ], + 'web.tests_assets': [ + 'website/static/tests/website_service_mock.js', + ], 'web._assets_frontend_helpers': [ ('prepend', 'website/static/src/scss/bootstrap_overridden.scss'), ], diff --git a/addons/website/static/src/components/navbar/navbar.js b/addons/website/static/src/components/navbar/navbar.js index d89fe6516f4..3dbb292448a 100644 --- a/addons/website/static/src/components/navbar/navbar.js +++ b/addons/website/static/src/components/navbar/navbar.js @@ -16,8 +16,6 @@ patch(NavBar.prototype, 'website_navbar', { setup() { this._super(); this.websiteService = useService('website'); - this.dialogService = useService('dialog'); - this.user = useService('user'); this.websiteContext = useState(this.websiteService.context); this.aceEditor = WebsiteAceEditor; @@ -41,11 +39,11 @@ patch(NavBar.prototype, 'website_navbar', { this.websiteEditingMenus = { 'website.menu_edit_menu': { - component: EditMenuDialog, + Component: EditMenuDialog, isDisplayed: () => !!this.websiteService.currentWebsite, }, 'website.menu_optimize_seo': { - component: OptimizeSEODialog, + Component: OptimizeSEODialog, isDisplayed: () => this.websiteService.currentWebsite && !!this.websiteService.currentWebsite.metadata.mainObject, }, 'website.menu_ace_editor': { @@ -59,7 +57,7 @@ patch(NavBar.prototype, 'website_navbar', { }; onWillStart(async () => { - this.isWebsitePublisher = await this.user.hasGroup('website.group_website_publisher'); + this.isWebsitePublisher = await this.websiteService.isPublisher(); }); }, @@ -112,8 +110,8 @@ patch(NavBar.prototype, 'website_navbar', { if (websiteMenu) { return websiteMenu.openWidget ? websiteMenu.openWidget() : - this.dialogService.add( - websiteMenu.component, + this.websiteService.openMenuDialog( + websiteMenu.Component, websiteMenu.getProps && websiteMenu.getProps(), ); } diff --git a/addons/website/static/src/services/website_service.js b/addons/website/static/src/services/website_service.js index abad2e76e34..50cadc48a58 100644 --- a/addons/website/static/src/services/website_service.js +++ b/addons/website/static/src/services/website_service.js @@ -23,8 +23,8 @@ export const unslugHtmlDataObject = (repr) => { }; export const websiteService = { - dependencies: ['orm', 'action', 'hotkey'], - async start(env, { orm, action, hotkey }) { + dependencies: ['orm', 'action', 'user', 'dialog', 'hotkey'], + async start(env, { orm, action, user, dialog, hotkey }) { let websites = []; let currentWebsiteId; let currentMetadata = {}; @@ -120,6 +120,12 @@ export const websiteService = { get editedObjectPath() { return editedObjectPath; }, + isPublisher() { + return user.hasGroup('website.group_website_publisher'); + }, + openMenuDialog(Component, props) { + return dialog.add(Component, props); + }, goToWebsite({ websiteId, path, edition, translation } = {}) { action.doAction('website.website_preview', { clearBreadcrumbs: true, diff --git a/addons/website/static/tests/website_service_mock.js b/addons/website/static/tests/website_service_mock.js new file mode 100644 index 00000000000..c89e167f041 --- /dev/null +++ b/addons/website/static/tests/website_service_mock.js @@ -0,0 +1,31 @@ +/** @odoo-module */ + +import { patch } from '@web/core/utils/patch'; +import { registry } from '@web/core/registry'; +import { utils, clearRegistryWithCleanup } from '@web/../tests/helpers/mock_env'; + +const { prepareRegistriesWithCleanup } = utils; + +function makeFakeWebsiteService() { + return { + start() { + return { + get context() { + return {}; + }, + isPublisher() { + return true; + }, + }; + } + }; +} + +const serviceRegistry = registry.category('services'); +patch(utils, 'website_test_registries', { + prepareRegistriesWithCleanup() { + prepareRegistriesWithCleanup(...arguments); + serviceRegistry.add('website', makeFakeWebsiteService()); + clearRegistryWithCleanup(registry.category('website_systray')); + }, +});