From 8d99f2f41556522e18e4b330ced0aff09a08e6b8 Mon Sep 17 00:00:00 2001 From: Renaud Thiry Date: Wed, 13 Mar 2024 10:00:48 +0100 Subject: [PATCH] [MOV] test_website, web_editor: move test to right module Some web_editor test was in "test_website" when it could have simply been in web_editor. It is moved there and modified to reuse existing imports and pass standard web linting rules. task-3741858 closes odoo/odoo#155704 Signed-off-by: David Monjoie (dmo) --- addons/test_website/__manifest__.py | 3 - .../static/tests/field_html_file_upload.js | 168 --------------- .../static/tests/html_field_tests.js | 199 +++++++++++++++++- addons/web_editor/static/tests/test_utils.js | 2 +- addons/web_unsplash/__manifest__.py | 3 + .../static/tests/html_field_tests.js | 7 + 6 files changed, 208 insertions(+), 174 deletions(-) delete mode 100644 addons/test_website/static/tests/field_html_file_upload.js create mode 100644 addons/web_unsplash/static/tests/html_field_tests.js diff --git a/addons/test_website/__manifest__.py b/addons/test_website/__manifest__.py index 0bddc6f870d..2ad2c239bc1 100644 --- a/addons/test_website/__manifest__.py +++ b/addons/test_website/__manifest__.py @@ -43,9 +43,6 @@ models which only purpose is to run tests.""", 'web.assets_tests': [ 'test_website/static/tests/tours/*', ], - 'web.qunit_suite_tests': [ - 'test_website/static/tests/*.js', - ], }, 'license': 'LGPL-3', } diff --git a/addons/test_website/static/tests/field_html_file_upload.js b/addons/test_website/static/tests/field_html_file_upload.js deleted file mode 100644 index 99814dcdd57..00000000000 --- a/addons/test_website/static/tests/field_html_file_upload.js +++ /dev/null @@ -1,168 +0,0 @@ -/** @odoo-module **/ - -import { FileSelectorControlPanel } from '@web_editor/components/media_dialog/file_selector'; -import { getFixture, patchWithCleanup } from "@web/../tests/helpers/utils"; -import { HtmlField } from '@web_editor/js/backend/html_field'; -import {registry} from '@web/core/registry'; -import testUtils from '@web/../tests/legacy/helpers/test_utils'; -import { uploadService } from '@web_editor/components/upload_progress_toast/upload_service'; -import { unsplashService } from '@web_unsplash/services/unsplash_service'; -import { createWebClient, doAction } from "@web/../tests/webclient/helpers"; -import { click } from "@web/../tests/utils"; -import weTestUtils from '@web_editor/../tests/test_utils'; -import {Wysiwyg} from '@web_editor/js/wysiwyg/wysiwyg'; -import { useEffect } from "@odoo/owl"; - -QUnit.module('field html file upload', { - beforeEach: function () { - this.data = weTestUtils.wysiwygData({ - 'mail.compose.message': { - fields: { - display_name: { - string: "Displayed name", - type: "char" - }, - body: { - string: "Message Body inline (to send)", - type: "html" - }, - attachment_ids: { - string: "Attachments", - type: "many2many", - relation: "ir.attachment", - } - }, - records: [{ - id: 1, - display_name: "Some Composer", - body: "Hello", - attachment_ids: [], - }], - }, - }); - }, -}, function () { - QUnit.test('media dialog: upload', async function (assert) { - assert.expect(8); - const onAttachmentChangeTriggered = testUtils.makeTestPromise(); - patchWithCleanup(HtmlField.prototype, { - _onAttachmentChange(event) { - super._onAttachmentChange(event); - onAttachmentChangeTriggered.resolve(true); - } - }); - const defFileSelector = testUtils.makeTestPromise(); - const onChangeTriggered = testUtils.makeTestPromise(); - const webSaveTriggered = testUtils.makeTestPromise(); - patchWithCleanup(FileSelectorControlPanel.prototype, { - setup() { - super.setup(); - useEffect(() => { - defFileSelector.resolve(true); - }, () => []); - }, - async onChangeFileInput() { - super.onChangeFileInput(); - onChangeTriggered.resolve(true); - } - }); - patchWithCleanup(Wysiwyg.prototype, { - async _getColorpickerTemplate() { - return weTestUtils.COLOR_PICKER_TEMPLATE; - } - }); - - // create and load form view - const serviceRegistry = registry.category("services"); - serviceRegistry.add("upload", uploadService); - serviceRegistry.add("unsplash", unsplashService); - const serverData = { - models: this.data, - }; - serverData.actions = { - 1: { - id: 1, - name: "test", - res_model: "mail.compose.message", - type: "ir.actions.act_window", - views: [[false, "form"]], - }, - }; - serverData.views = { - "mail.compose.message,false,search": "", - "mail.compose.message,false,form": ` -
- - - `, - }; - const mockRPC = (route, args) => { - if (args.method === "web_save") { - const createVals = args.args[1]; - assert.ok(createVals && createVals.attachment_ids); - assert.equal(createVals.attachment_ids[0][0], 4); // link command - assert.equal(createVals.attachment_ids[0][1], 5); // on attachment id "5" - webSaveTriggered.resolve(); - } - if (route === "/web_editor/attachment/add_data") { - const attachment = { - id: 5, - name: "test.jpg", - description: false, - mimetype: "image/jpeg", - checksum: "7951a43bbfb08fd742224ada280913d1897b89ab", - url: false, - type: "binary", - res_id: 0, - res_model: "mail.compose.message", - public: false, - access_token: false, - image_src: "/web/image/1-a0e63e61/test.jpg", - image_width: 1, - image_height: 1, - original_id: false, - }; - serverData.models['ir.attachment'].records.push({...attachment}); - return Promise.resolve(attachment); - } else if (route === "/web/dataset/call_kw/ir.attachment/generate_access_token") { - return Promise.resolve(["129a52e1-6bf2-470a-830e-8e368b022e13"]); - } - }; - const webClient = await createWebClient({ serverData, mockRPC }); - await doAction(webClient, 1); - //trigger wysiwyg mediadialog - const fixture = getFixture(); - const formField = fixture.querySelector('.o_field_html[name="body"]'); - const textInput = formField.querySelector('.note-editable p'); - textInput.innerText = "test"; - const pText = $(textInput).contents()[0]; - Wysiwyg.setRange(pText, 1, pText, 2); - await new Promise((resolve) => setTimeout(resolve)); //ensure fully set up - const wysiwyg = $(textInput.parentElement).data('wysiwyg'); - wysiwyg.openMediaDialog(); - assert.ok(await Promise.race([defFileSelector, new Promise((res, _) => setTimeout(() => res(false), 400))]), "File Selector did not mount"); - // upload test - const fileInputs = document.querySelectorAll(".o_select_media_dialog input.d-none.o_file_input"); - const fileB64 = '/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiigD//2Q=='; - const fileBytes = new Uint8Array(atob(fileB64).split('').map(char => char.charCodeAt(0))); - // redefine 'files' so we can put mock data in through js - fileInputs.forEach((input) => Object.defineProperty(input, 'files', { - value: [new File(fileBytes, "test.jpg", { type: 'image/jpeg' })], - })); - fileInputs.forEach(input => { - input.dispatchEvent(new Event('change', {})); - }); - - assert.ok(await Promise.race([onChangeTriggered, new Promise((res, _) => setTimeout(() => res(false), 400))]), - "File change event was not triggered"); - assert.ok(await Promise.race([onAttachmentChangeTriggered, new Promise((res, _) => setTimeout(() => res(false), 400))]), - "_onAttachmentChange was not called with the new attachment, necessary for unsused upload cleanup on backend"); - - // wait to check that dom is properly updated - await new Promise((res, _) => setTimeout(() => res(false), 400)); - assert.ok(fixture.querySelector('.o_attachment[title="test.jpg"]')); - - await click(".o_form_button_save"); - await webSaveTriggered; - }); -}); diff --git a/addons/web_editor/static/tests/html_field_tests.js b/addons/web_editor/static/tests/html_field_tests.js index c4538e069ae..94b3a9e19ed 100644 --- a/addons/web_editor/static/tests/html_field_tests.js +++ b/addons/web_editor/static/tests/html_field_tests.js @@ -1,14 +1,18 @@ /** @odoo-module **/ import { click, editInput, getFixture, makeDeferred, mockSendBeacon, nextTick, patchWithCleanup } from "@web/../tests/helpers/utils"; +import { createWebClient, doAction } from "@web/../tests/webclient/helpers"; import { makeView, setupViewRegistries } from "@web/../tests/views/helpers"; +import { FileSelectorControlPanel } from "@web_editor/components/media_dialog/file_selector"; import { FormController } from '@web/views/form/form_controller'; import { HtmlField } from "@web_editor/js/backend/html_field"; import { MediaDialog } from "@web_editor/components/media_dialog/media_dialog"; import { parseHTML, setSelection } from "@web_editor/js/editor/odoo-editor/src/utils/utils"; -import { onRendered } from "@odoo/owl"; -import { wysiwygData } from "@web_editor/../tests/test_utils"; +import { onRendered, useEffect } from "@odoo/owl"; +import { registry } from "@web/core/registry"; +import { COLOR_PICKER_TEMPLATE, wysiwygData } from "@web_editor/../tests/test_utils"; import { OdooEditor } from '@web_editor/js/editor/odoo-editor/src/OdooEditor'; +import { uploadService } from "@web_editor/components/upload_progress_toast/upload_service"; import { Wysiwyg } from "@web_editor/js/wysiwyg/wysiwyg"; import { insertText } from '@web_editor/js/editor/odoo-editor/test/utils'; @@ -1056,3 +1060,194 @@ QUnit.module("WebEditor.HtmlField", ({ beforeEach }) => { }); }); + +export const mediaDialogServices = { + upload: uploadService, +}; + +export const uploadTestModule = QUnit.module( + "WebEditor.HtmlField.upload", + { + beforeEach: function () { + this.data = wysiwygData({ + "mail.compose.message": { + fields: { + display_name: { + string: "Displayed name", + type: "char", + }, + body: { + string: "Message Body inline (to send)", + type: "html", + }, + attachment_ids: { + string: "Attachments", + type: "many2many", + relation: "ir.attachment", + }, + }, + records: [ + { + id: 1, + display_name: "Some Composer", + body: "Hello", + attachment_ids: [], + }, + ], + }, + }); + }, + }, + function () { + QUnit.test("media dialog: upload", async function (assert) { + assert.expect(7); + const onAttachmentChangeTriggered = makeDeferred(); + patchWithCleanup(HtmlField.prototype, { + _onAttachmentChange(event) { + super._onAttachmentChange(event); + onAttachmentChangeTriggered.resolve(true); + }, + }); + const defFileSelector = makeDeferred(); + const onChangeTriggered = makeDeferred(); + const webSaveTriggered = makeDeferred(); + patchWithCleanup(FileSelectorControlPanel.prototype, { + setup() { + super.setup(); + useEffect( + () => { + defFileSelector.resolve(true); + }, + () => [], + ); + }, + async onChangeFileInput() { + super.onChangeFileInput(); + onChangeTriggered.resolve(true); + }, + }); + patchWithCleanup(Wysiwyg.prototype, { + async _getColorpickerTemplate() { + return COLOR_PICKER_TEMPLATE; + }, + }); + // create and load form view + const serviceRegistry = registry.category("services"); + for (const [serviceName, serviceDefinition] of Object.entries(mediaDialogServices)) { + serviceRegistry.add(serviceName, serviceDefinition); + } + const serverData = { + models: this.data, + }; + serverData.actions = { + 1: { + id: 1, + name: "test", + res_model: "mail.compose.message", + type: "ir.actions.act_window", + views: [[false, "form"]], + }, + }; + serverData.views = { + "mail.compose.message,false,search": "", + "mail.compose.message,false,form": ` +
+ + + `, + }; + const mockRPC = (route, args) => { + if (args.method === "web_save") { + const createVals = args.args[1]; + assert.ok(createVals && createVals.attachment_ids); + assert.equal(createVals.attachment_ids[0][0], 4); // link command + assert.equal(createVals.attachment_ids[0][1], 5); // on attachment id "5" + webSaveTriggered.resolve(); + } + if (route === "/web_editor/attachment/add_data") { + const attachment = { + id: 5, + name: "test.jpg", + description: false, + mimetype: "image/jpeg", + checksum: "7951a43bbfb08fd742224ada280913d1897b89ab", + url: false, + type: "binary", + res_id: 0, + res_model: "mail.compose.message", + public: false, + access_token: false, + image_src: "/web/image/1-a0e63e61/test.jpg", + image_width: 1, + image_height: 1, + original_id: false, + }; + serverData.models["ir.attachment"].records.push({ ...attachment }); + return Promise.resolve(attachment); + } else if (route === "/web/dataset/call_kw/ir.attachment/generate_access_token") { + return Promise.resolve(["129a52e1-6bf2-470a-830e-8e368b022e13"]); + } + }; + const webClient = await createWebClient({ serverData, mockRPC }); + await doAction(webClient, 1); + //trigger wysiwyg mediadialog + const fixture = getFixture(); + const formField = fixture.querySelector('.o_field_html[name="body"]'); + const textInput = formField.querySelector(".note-editable p"); + textInput.innerText = "test"; + const pText = $(textInput).contents()[0]; + Wysiwyg.setRange(pText, 1, pText, 2); + await new Promise((resolve) => setTimeout(resolve)); //ensure fully set up + const wysiwyg = $(textInput.parentElement).data("wysiwyg"); + wysiwyg.openMediaDialog(); + assert.ok( + await Promise.race([ + defFileSelector, + new Promise((res, _) => setTimeout(() => res(false), 400)), + ]), + "File Selector did not mount", + ); + // upload test + const fileInputs = document.querySelectorAll( + ".o_select_media_dialog input.d-none.o_file_input", + ); + const fileB64 = + "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiigD//2Q=="; + const fileBytes = new Uint8Array( + atob(fileB64) + .split("") + .map((char) => char.charCodeAt(0)), + ); + // redefine 'files' so we can put mock data in through js + fileInputs.forEach((input) => + Object.defineProperty(input, "files", { + value: [new File(fileBytes, "test.jpg", { type: "image/jpeg" })], + }), + ); + fileInputs.forEach((input) => { + input.dispatchEvent(new Event("change", {})); + }); + + assert.ok( + await Promise.race([ + onChangeTriggered, + new Promise((res, _) => setTimeout(() => res(false), 400)), + ]), + "File change event was not triggered", + ); + assert.ok( + await Promise.race([ + onAttachmentChangeTriggered, + new Promise((res, _) => setTimeout(() => res(false), 400)), + ]), + "_onAttachmentChange was not called with the new attachment, necessary for unsused upload cleanup on backend" + ); + // wait to check that dom is properly updated + await new Promise((res, _) => setTimeout(() => res(false), 400)); + assert.ok(fixture.querySelector('.o_attachment[title="test.jpg"]')); + + await click(fixture.querySelector(".o_form_button_save")); + await webSaveTriggered; + }); + }, +); diff --git a/addons/web_editor/static/tests/test_utils.js b/addons/web_editor/static/tests/test_utils.js index 0646778a4f0..05557477afc 100644 --- a/addons/web_editor/static/tests/test_utils.js +++ b/addons/web_editor/static/tests/test_utils.js @@ -8,7 +8,7 @@ import { Wysiwyg } from '@web_editor/js/wysiwyg/wysiwyg'; import options from "@web_editor/js/editor/snippets.options"; import { TABLE_ATTRIBUTES, TABLE_STYLES } from '@web_editor/js/backend/convert_inline'; -const COLOR_PICKER_TEMPLATE = ` +export const COLOR_PICKER_TEMPLATE = `