19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:32:39 +01:00
parent 38c6088dcc
commit d9452d2060
243 changed files with 30797 additions and 10815 deletions

View file

@ -0,0 +1,15 @@
import { Interaction } from "@web/public/interaction";
import { registry } from "@web/core/registry";
import { rpc } from "@web/core/network/rpc";
export class TestError extends Interaction {
static selector = ".rpc_error a";
dynamicContent = {
_root: { "t-on-click.prevent": () => rpc(this.el.getAttribute("href")) },
}
}
registry
.category("public.interactions")
.add("test_website.test_error", TestError);

View file

@ -1,30 +0,0 @@
odoo.define('website_forum.test_error', function (require) {
'use strict';
var publicWidget = require('web.public.widget');
publicWidget.registry.testError = publicWidget.Widget.extend({
selector: '.rpc_error',
events: {
'click a': '_onRpcErrorClick',
},
//----------------------------------------------------------------------
// Handlers
//----------------------------------------------------------------------
/**
* make a rpc call with the href of the DOM element clicked
* @private
* @param {Event} ev
* @returns {Promise}
*/
_onRpcErrorClick: function (ev) {
ev.preventDefault();
var $link = $(ev.currentTarget);
return this._rpc({
route: $link.attr('href'),
});
}
});
});

View file

@ -1,137 +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.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 weTestUtils from 'web_editor.test_utils';
import Wysiwyg from 'web_editor.wysiwyg';
const { useEffect } = 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(4);
const onAttachmentChangeTriggered = testUtils.makeTestPromise();
patchWithCleanup(HtmlField.prototype, {
'_onAttachmentChange': function (event) {
this._super(event);
onAttachmentChangeTriggered.resolve(true);
}
});
const defFileSelector = testUtils.makeTestPromise();
const onChangeTriggered = testUtils.makeTestPromise();
patchWithCleanup(FileSelectorControlPanel.prototype, {
setup() {
this._super();
useEffect(() => {
defFileSelector.resolve(true);
}, () => []);
},
async onChangeFileInput() {
this._super();
onChangeTriggered.resolve(true);
}
});
// 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": "<search></search>",
"mail.compose.message,false,form": `
<form>
<field name="body" type="html"/>
<field name="attachment_ids" widget="many2many_binary"/>
</form>`,
};
const mockRPC = (route, args) => {
if (route === "/web_editor/attachment/add_data") {
return Promise.resolve({"id": 5, "name": "test.jpg", "description": false, "mimetype": "image/jpeg", "checksum": "7951a43bbfb08fd742224ada280913d1897b89ab",
"url": false, "type": "binary", "res_id": 1, "res_model": "note.note", "public": false, "access_token": false,
"image_src": "/web/image/1-a0e63e61/test.jpg", "image_width": 1, "image_height": 1, "original_id": false
});
}
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"]'));
});
});

View file

@ -1,7 +1,4 @@
odoo.define('test_website.custom_snippets', function (require) {
'use strict';
const wTourUtils = require('website.tour_utils');
import { insertSnippet, registerWebsitePreviewTour } from "@website/js/tours/tour_utils";
/**
* The purpose of this tour is to check the custom snippets flow:
@ -11,8 +8,8 @@ const wTourUtils = require('website.tour_utils');
* -> customize banner (set text)
* -> save banner as custom snippet
* -> confirm save
* -> ensure custom snippet is available
* -> drag custom snippet
* -> ensure custom snippet is available in the "add snippet" dialog
* -> add custom snippet into the page
* -> ensure block appears as banner
* -> ensure block appears as custom banner
* -> rename custom banner
@ -22,87 +19,89 @@ const wTourUtils = require('website.tour_utils');
* -> ensure it was deleted
*/
wTourUtils.registerWebsitePreviewTour('test_custom_snippet', {
registerWebsitePreviewTour('test_custom_snippet', {
url: '/',
edition: true,
test: true,
}, [
}, () => [
...insertSnippet({
id: 's_banner',
name: 'Banner',
groupName: "Intro",
}),
{
content: "drop a snippet",
trigger: ".oe_snippet[name='Banner'] .oe_snippet_thumbnail:not(.o_we_already_dragging)",
moveTrigger: ".oe_drop_zone",
run: "drag_and_drop iframe #wrap",
content: "Customize snippet",
trigger: ":iframe #wrapwrap .s_banner h1",
run: "editor Test",
},
{
content: "customize snippet",
trigger: "iframe #wrapwrap .s_banner h1",
run: "text",
consumeEvent: "input",
content: "Save custom snippet",
trigger: "div[data-container-title='Banner'] .oe_snippet_save",
run: "click",
},
{
content: "save custom snippet",
trigger: ".snippet-option-SnippetSave we-button",
content: "Confirm reload",
trigger: ".modal-dialog button:contains('Save')",
run: "click",
},
{
content: "confirm reload",
trigger: ".modal-dialog button span:contains('Save and Reload')",
content: "Click on the block tab",
trigger: ".o-snippets-tabs button[data-name='blocks']",
run: "click",
},
{
content: "ensure custom snippet appeared",
trigger: "#oe_snippets.o_loaded .oe_snippet[name='Custom Banner']",
run: function () {
$("#oe_snippets .oe_snippet[name='Custom Banner'] .o_rename_btn").attr("style", "display: block;");
// hover is needed for rename button to appear
},
content: "Click on the Custom category block",
trigger: ".o_block_tab:not(.o_we_ongoing_insertion) #snippet_groups .o_snippet[name='Custom'].o_draggable .o_snippet_thumbnail .o_snippet_thumbnail_area",
run: "click",
},
{
content: "rename custom snippet",
trigger: ".oe_snippet[name='Custom Banner'] we-button.o_rename_btn",
extra_trigger: ".oe_snippet[name='Custom Banner'] .oe_snippet_thumbnail:not(.o_we_already_dragging)",
content: "Ensure custom snippet preview appeared in the dialog",
trigger: ":iframe .o_snippet_preview_wrap[data-snippet-id^='s_banner_'] section[data-name='Custom Banner']",
},
{
content: "set name",
trigger: ".oe_snippet[name='Custom Banner'] input",
run: "text Bruce Banner",
content: "Rename custom snippet",
trigger: ":iframe .o_custom_snippet_edit > button",
run: "click",
},
{
content: "confirm rename",
trigger: ".oe_snippet[name='Custom Banner'] we-button.o_we_confirm_btn",
content: "Set name",
trigger: ".modal-dialog:not(.o_inactive_modal body) input[id='inputConfirmation']",
run: "edit Bruce Banner",
},
{
content: "drop custom snippet",
trigger: ".oe_snippet[name='Bruce Banner'] .oe_snippet_thumbnail:not(.o_we_already_dragging)",
extra_trigger: "iframe body.editor_enable",
moveTrigger: ".oe_drop_zone",
run: "drag_and_drop iframe #wrap",
content: "Confirm rename",
trigger: ".modal-dialog:not(.o_inactive_modal body) footer .btn-primary",
run: "click",
},
{
content: "ensure banner section exists",
trigger: "iframe #wrap section[data-name='Banner']",
run: function () {}, // check
content: "Click on the 'Bruce Banner' snippet",
trigger: ":iframe .o_snippet_preview_wrap[data-snippet-id^='s_banner_']:has(section[data-name='Bruce Banner'])",
run: "click",
},
{
content: "ensure custom banner section exists",
trigger: "iframe #wrap section[data-name='Bruce Banner']",
run: function () {
$("#oe_snippets .oe_snippet[name='Bruce Banner'] .o_delete_btn").attr("style", "display: block;");
// hover is needed for delete button to appear
},
content: "Ensure banner section exists",
trigger: ":iframe #wrap section[data-name='Banner']",
},
{
content: "delete custom snippet",
trigger: ".oe_snippet[name='Bruce Banner'] we-button.o_delete_btn",
extra_trigger: ".oe_snippet[name='Bruce Banner'] .oe_snippet_thumbnail:not(.o_we_already_dragging)",
content: "Ensure custom banner section exists",
trigger: ":iframe #wrap section[data-name='Bruce Banner']",
},
{
content: "confirm delete",
trigger: ".modal-dialog button:has(span:contains('Yes'))",
content: "Click on the Custom category block",
trigger: ".o_block_tab:not(.o_we_ongoing_insertion) #snippet_groups .o_snippet[name='Custom'].o_draggable .o_snippet_thumbnail .o_snippet_thumbnail_area",
run: "click",
},
{
content: "ensure custom snippet disappeared",
trigger: "#oe_snippets:not(:has(.oe_snippet[name='Bruce Banner']))",
run: function () {}, // check
content: "Delete custom snippet",
trigger: ":iframe .o_custom_snippet_edit > button + button",
run: "click",
},
{
content: "Confirm delete",
trigger: ".modal-dialog button:contains('Yes')",
run: "click",
},
{
content: "Ensure custom snippet disappeared",
trigger: ":iframe .o_add_snippets_preview:not(:has(section[data-name='Bruce Banner']))",
},
]);
});

View file

@ -1,56 +1,81 @@
odoo.define('test_website.error_views', function (require) {
'use strict';
import { registry } from "@web/core/registry";
var tour = require('web_tour.tour');
tour.register('test_error_website', {
test: true,
registry.category("web_tour.tours").add('test_error_website', {
url: '/test_error_view',
},
[
steps: () => [
// RPC ERROR
{
content: "trigger rpc user error",
trigger: 'a[href="/test_user_error_json"]',
}, {
run: "click",
},
{
trigger: '.o_notification:contains("This is a user rpc test")',
},
{
content: "rpc user error modal has message",
extra_trigger: 'div.o_notification_content:contains("This is a user rpc test")',
trigger: 'button.o_notification_close',
run: "click",
}, {
content: "trigger rpc access error",
trigger: 'a[href="/test_access_error_json"]',
}, {
run: "click",
},
{
trigger: '.o_notification:contains("This is an access rpc test")',
},
{
content: "rpc access error modal has message",
extra_trigger: 'div.o_notification_content:contains("This is an access rpc test")',
trigger: 'button.o_notification_close',
run: "click",
}, {
content: "trigger validation rpc error",
trigger: 'a[href="/test_validation_error_json"]',
}, {
run: "click",
},
{
trigger: '.o_notification:contains("This is a validation rpc test")',
},
{
content: "rpc validation error modal has message",
extra_trigger: 'div.o_notification_content:contains("This is a validation rpc test")',
trigger: 'button.o_notification_close',
run: "click",
}, {
content: "trigger rpc missing error",
trigger: 'a[href="/test_missing_error_json"]',
}, {
run: "click",
},
{
trigger: '.o_notification:contains("This is a missing rpc test")',
},
{
content: "rpc missing error modal has message",
extra_trigger: 'div.o_notification_content:contains("This is a missing rpc test")',
trigger: 'button.o_notification_close',
run: "click",
}, {
content: "trigger rpc error 403",
trigger: 'a[href="/test_access_denied_json"]',
}, {
run: "click",
},
{
trigger: '.o_notification:contains("This is an access denied rpc test")',
},
{
content: "rpc error 403 modal has message",
extra_trigger: 'div.o_notification_content:contains("This is an access denied rpc test")',
trigger: 'button.o_notification_close',
run: "click",
}, {
content: "trigger rpc error 500",
trigger: 'a[href="/test_internal_error_json"]',
}, {
run: "click",
},
{
trigger: "div.o_error_dialog.modal-content",
},
{
content: "rpc error 500 modal is an ErrorDialog",
extra_trigger: 'div.o_dialog_error.modal-content div.alert.alert-warning',
trigger: '.modal-footer button.btn.btn-primary',
run: "click",
},
// HTTP ERROR
{
@ -59,94 +84,139 @@ tour.register('test_error_website', {
run: function () {
window.location.href = window.location.origin + '/test_user_error_http?debug=0';
},
}, {
expectUnloadPage: true,
},
{
trigger: 'h1:contains("Something went wrong.")',
},
{
content: "http user error page has title and message",
extra_trigger: 'h1:contains("Something went wrong.")',
trigger: 'div.container pre:contains("This is a user http test")',
run: function () {
window.location.href = window.location.origin + '/test_user_error_http?debug=1';
},
}, {
expectUnloadPage: true,
},
{
trigger: 'h1:contains("Something went wrong.")',
},
{
content: "http user error page debug has title and message open",
extra_trigger: 'h1:contains("Something went wrong.")',
trigger: 'div#error_main.collapse.show pre:contains("This is a user http test")',
run: function () {},
}, {
content: "http user error page debug has traceback closed",
trigger: 'body:has(div#error_traceback.collapse:not(.show) pre#exception_traceback)',
run: function () {
window.location.href = window.location.origin + '/test_validation_error_http?debug=0';
},
}, {
expectUnloadPage: true,
},
{
trigger: 'h1:contains("Something went wrong.")',
},
{
content: "http validation error page has title and message",
extra_trigger: 'h1:contains("Something went wrong.")',
trigger: 'div.container pre:contains("This is a validation http test")',
run: function () {
window.location.href = window.location.origin + '/test_validation_error_http?debug=1';
},
}, {
expectUnloadPage: true,
},
{
trigger: 'h1:contains("Something went wrong.")',
},
{
content: "http validation error page debug has title and message open",
extra_trigger: 'h1:contains("Something went wrong.")',
trigger: 'div#error_main.collapse.show pre:contains("This is a validation http test")',
run: function () {},
}, {
content: "http validation error page debug has traceback closed",
trigger: 'body:has(div#error_traceback.collapse:not(.show) pre#exception_traceback)',
run: function () {
window.location.href = window.location.origin + '/test_access_error_http?debug=0';
},
}, {
expectUnloadPage: true,
},
{
trigger: 'h1:contains("403: Forbidden")',
},
{
content: "http access error page has title and message",
extra_trigger: 'h1:contains("403: Forbidden")',
trigger: 'div.container pre:contains("This is an access http test")',
run: function () {
window.location.href = window.location.origin + '/test_access_error_http?debug=1';
},
}, {
expectUnloadPage: true,
},
{
trigger: 'h1:contains("403: Forbidden")',
},
{
content: "http access error page debug has title and message open",
extra_trigger: 'h1:contains("403: Forbidden")',
trigger: 'div#error_main.collapse.show pre:contains("This is an access http test")',
run: function () {},
}, {
content: "http access error page debug has traceback closed",
trigger: 'body:has(div#error_traceback.collapse:not(.show) pre#exception_traceback)',
run: function () {
window.location.href = window.location.origin + '/test_view_access_error?debug=0';
},
expectUnloadPage: true,
},
{
trigger: 'h1:contains("403: Forbidden")',
},
{
content: "http access error page has title and message",
trigger: 'div.container pre:contains("Uh-oh! Looks like you have stumbled upon some top-secret records.")',
run: function () {
window.location.href = window.location.origin + '/test_view_access_error?debug=1';
},
expectUnloadPage: true,
},
{
trigger: 'h1:contains("403: Forbidden")',
},
{
content: "http access error page debug has title and message open",
trigger: 'div#error_main.collapse.show pre:contains("Uh-oh! Looks like you have stumbled upon some top-secret records.")',
}, {
content: "http access error page debug has traceback closed",
trigger: 'body:has(div#error_traceback.collapse:not(.show) pre#exception_traceback)',
run: function () {
window.location.href = window.location.origin + '/test_missing_error_http?debug=0';
},
}, {
content: "http missing error page has title and message",
extra_trigger: 'h1:contains("Something went wrong.")',
trigger: 'div.container pre:contains("This is a missing http test")',
expectUnloadPage: true,
},
{
trigger: 'h1:contains("Error 404")',
run: function () {
window.location.href = window.location.origin + '/test_missing_error_http?debug=1';
},
}, {
content: "http missing error page debug has title and message open",
extra_trigger: 'h1:contains("Something went wrong.")',
trigger: 'div#error_main.collapse.show pre:contains("This is a missing http test")',
run: function () {},
}, {
content: "http missing error page debug has traceback closed",
trigger: 'body:has(div#error_traceback.collapse:not(.show) pre#exception_traceback)',
run: function () {
window.location.href = window.location.origin + '/test_access_denied_http?debug=0';
},
}, {
content: "http error 403 page has title but no message",
extra_trigger: 'h1:contains("403: Forbidden")',
trigger: 'div#wrap:not(:has(pre:contains("This is an access denied http test"))', //See ir_http.py handle_exception, the exception is replaced so there is no message !
expectUnloadPage: true,
},
{
trigger: 'h1:contains("Error 404")',
run: function () {
window.location.href = window.location.origin + '/test_access_denied_http?debug=1';
},
}, {
content: "http 403 error page debug has title but no message",
extra_trigger: 'h1:contains("403: Forbidden")',
trigger: 'div#debug_infos:not(:has(#error_main))',
run: function () {},
}, {
content: "http 403 error page debug has traceback open",
trigger: 'body:has(div#error_traceback.collapse.show pre#exception_traceback)',
run: function () {},
expectUnloadPage: true,
},
]);
});
{
trigger: 'h1:contains("403: Forbidden")',
},
{
content: "http error 403 page has title but no message",
// See http.py _transactionning, the exception is replaced so there is no message !
trigger: 'div#wrap:not(:has(pre:contains("Traceback"))',
run: function () {
window.location.href = window.location.origin + '/test_access_denied_http?debug=1';
},
expectUnloadPage: true,
},
{
trigger: 'h1:contains("403: Forbidden")',
},
{
content: "http 403 error page debug has title but no message",
trigger: 'div#wrap:not(:has(pre:contains("Traceback"))',
},
]});

View file

@ -0,0 +1,59 @@
import {
clickOnEditAndWaitEditMode,
clickOnSave,
registerWebsitePreviewTour,
changeOptionInPopover,
} from "@website/js/tours/tour_utils";
registerWebsitePreviewTour(
"test_form_conditional_visibility_record_field",
{
url: "/test_website/model_item/1",
edition: true,
},
() => [
{
content: "Select name field",
trigger: ":iframe .s_website_form .s_website_form_input[name=name]",
run: "click",
},
...changeOptionInPopover("Field", "Visibility", "Visible only if"),
{
content: "Open model selector",
trigger: "button[id='hidden_condition_record_opt']:contains('Test Tag')",
run: "click",
},
{
content: "Set model to tag #2",
trigger: ".o_popover div.o-dropdown-item:contains('Test Tag #2')",
run: "click",
},
...clickOnSave(),
{
content: "Name field is hidden",
trigger: ":iframe .s_website_form:has(.s_website_form_field_hidden_if.d-none)",
},
...clickOnEditAndWaitEditMode(),
{
content: "Select name field",
trigger: ":iframe .s_website_form .s_website_form_input[name=name]",
run: "click",
},
{
content: "Open comparator dropdown",
trigger: "button[id='hidden_condition_record_opt']:contains('Is equal to')",
run: "click",
},
{
content: "Set comparator to Is not equal",
trigger: ".o_popover div.o-dropdown-item:contains('Is not equal to')",
run: "click",
},
...clickOnSave(),
{
content: "Name field is shown",
trigger: ":iframe .s_website_form:has(.s_website_form_field_hidden_if:not(.d-none))",
},
],
);

View file

@ -1,6 +1,4 @@
/** @odoo-module **/
import wTourUtils from 'website.tour_utils';
import { insertSnippet, registerWebsitePreviewTour } from '@website/js/tours/tour_utils';
/**
* The purpose of this tour is to check the link on image flow.
@ -8,78 +6,81 @@ import wTourUtils from 'website.tour_utils';
const selectImageSteps = [{
content: "select block",
trigger: "iframe #wrapwrap .s_text_image",
trigger: ":iframe #wrapwrap .s_text_image",
async run(helpers) {
await helpers.click();
const el = this.anchor;
const sel = el.ownerDocument.getSelection();
sel.collapse(el, 0);
el.focus();
},
}, {
content: "check link popover disappeared",
trigger: "iframe body:not(:has(.o_edit_menu_popover))",
run: () => {}, // check
trigger: ":iframe body:not(:has(.o_edit_menu_popover))",
}, {
content: "select image",
trigger: "iframe #wrapwrap .s_text_image img",
trigger: ":iframe #wrapwrap .s_text_image img",
run: "click",
}];
wTourUtils.registerWebsitePreviewTour('test_image_link', {
test: true,
registerWebsitePreviewTour('test_image_link', {
url: '/',
edition: true,
}, [
wTourUtils.dragNDrop({
}, () => [
...insertSnippet({
id: 's_text_image',
name: 'Text - Image',
groupName: "Content",
}),
...selectImageSteps,
{
content: "enable link",
trigger: "#oe_snippets we-customizeblock-options:has(we-title:contains('Image')) we-customizeblock-option:has(we-title:contains(Media)) we-button.fa-link",
trigger: ".o_customize_tab [data-container-title='Image'] button[data-action-id='setLink']",
run: "click",
}, {
content: "enter site URL",
trigger: "#oe_snippets we-customizeblock-options:has(we-title:contains('Image')) we-input:contains(Your URL) input",
run: "text odoo.com",
trigger: ".o_customize_tab [data-container-title='Image'] div[data-action-id='setUrl'] input",
run: "edit odoo.com && click body",
},
...selectImageSteps,
{
content: "check popover content has site URL",
trigger: "iframe .o_edit_menu_popover a.o_we_url_link[href='http://odoo.com/']:contains(http://odoo.com/)",
run: () => {}, // check
trigger: ".o-we-linkpopover a.o_we_url_link[href='http://odoo.com']:contains(http://odoo.com)",
}, {
content: "remove URL",
trigger: "#oe_snippets we-customizeblock-options:has(we-title:contains('Image')) we-input:contains(Your URL) input",
run: "remove_text",
trigger: ".o_customize_tab [data-container-title='Image'] div[data-action-id='setUrl'] input",
run: "clear && click body",
},
...selectImageSteps,
{
content: "check popover content has no URL",
trigger: "iframe .o_edit_menu_popover a.o_we_url_link:not([href]):contains(No URL specified)",
run: () => {}, // check
trigger: ".o-we-linkpopover .o_we_href_input_link:value()",
}, {
content: "enter email URL",
trigger: "#oe_snippets we-customizeblock-options:has(we-title:contains('Image')) we-input:contains(Your URL) input",
run: "text mailto:test@test.com",
trigger: ".o_customize_tab [data-container-title='Image'] div[data-action-id='setUrl'] input",
run: "edit mailto:test@test.com && click body",
},
...selectImageSteps,
{
content: "check popover content has mail URL",
trigger: "iframe .o_edit_menu_popover:has(.fa-envelope-o) a.o_we_url_link[href='mailto:test@test.com']:contains(mailto:test@test.com)",
run: () => {}, // check
trigger: ".o-we-linkpopover:has(.fa-envelope-o) a.o_we_url_link[href='mailto:test@test.com']:contains(mailto:test@test.com)",
}, {
content: "enter phone URL",
trigger: "#oe_snippets we-customizeblock-options:has(we-title:contains('Image')) we-input:contains(Your URL) input",
run: "text tel:555-2368",
trigger: ".o_customize_tab [data-container-title='Image'] div[data-action-id='setUrl'] input",
run: "edit tel:555-2368 && click body",
},
...selectImageSteps,
{
content: "check popover content has phone URL",
trigger: "iframe .o_edit_menu_popover:has(.fa-phone) a.o_we_url_link[href='tel:555-2368']:contains(tel:555-2368)",
run: () => {}, // check
trigger: ".o-we-linkpopover:has(.fa-phone) a.o_we_url_link[href='tel:555-2368']:contains(tel:555-2368)",
}, {
content: "remove URL",
trigger: "#oe_snippets we-customizeblock-options:has(we-title:contains('Image')) we-input:contains(Your URL) input",
run: "remove_text",
trigger: ".o_customize_tab [data-container-title='Image'] div[data-action-id='setUrl'] input",
run: "clear && click body",
},
...selectImageSteps,
{
content: "check popover content has no URL",
trigger: "iframe .o_edit_menu_popover a.o_we_url_link:not([href]):contains(No URL specified)",
run: () => {}, // check
trigger: ".o-we-linkpopover .o_we_href_input_link:value()",
},
]);

View file

@ -1,13 +1,10 @@
odoo.define('test_website.image_upload_progress', function (require) {
'use strict';
import { insertSnippet, registerWebsitePreviewTour } from "@website/js/tours/tour_utils";
const wTourUtils = require('website.tour_utils');
const { FileSelectorControlPanel } = require('@web_editor/components/media_dialog/file_selector');
const { patch, unpatch } = require('web.utils');
import { FileSelectorControlPanel } from "@html_editor/main/media/media_dialog/file_selector";
import { patch } from "@web/core/utils/patch";
let patchWithError = false;
const patchMediaDialog = () => patch(FileSelectorControlPanel.prototype, 'test_website.mock_image_widgets', {
const patchMediaDialog = () => patch(FileSelectorControlPanel.prototype, {
async onChangeFileInput() {
const getFileFromB64 = (fileData) => {
const binary = atob(fileData[2]);
@ -37,46 +34,50 @@ const patchMediaDialog = () => patch(FileSelectorControlPanel.prototype, 'test_w
}
});
const unpatchMediaDialog = () => unpatch(FileSelectorControlPanel.prototype, 'test_website.mock_image_widgets');
let unpatchMediaDialog = null;
const setupSteps = [{
content: "reload to load patch",
trigger: ".o_website_preview",
run: () => {
patchMediaDialog();
},
}, {
content: "drop a snippet",
trigger: "#oe_snippets .oe_snippet[name='Text - Image'] .oe_snippet_thumbnail:not(.o_we_already_dragging)",
moveTrigger: "iframe .oe_drop_zone",
run: "drag_and_drop iframe #wrap",
}, {
content: "drop a snippet",
trigger: "#oe_snippets .oe_snippet[name='Image Gallery'] .oe_snippet_thumbnail:not(.o_we_already_dragging)",
extra_trigger: "body.editor_has_snippets",
moveTrigger: ".oe_drop_zone",
run: "drag_and_drop iframe #wrap",
}];
const setupSteps = function () {
return [
{
content: "reload to load patch",
trigger: ".o_website_preview",
run() {
unpatchMediaDialog = patchMediaDialog();
},
},
...insertSnippet({
id: "s_text_image",
name: "Text - Image",
groupName: "Content",
}),
...insertSnippet({
id: "s_image_gallery",
name: "Image Gallery",
groupName: "Images",
})
];
};
const formatErrorMsg = "format is not supported. Try with: .gif, .jpe, .jpeg, .jpg, .png, .svg";
const formatErrorMsg = "format is not supported. Try with: .gif, .jpe, .jpeg, .jpg, .png, .svg, .webp";
wTourUtils.registerWebsitePreviewTour('test_image_upload_progress', {
registerWebsitePreviewTour('test_image_upload_progress', {
url: '/test_image_progress',
test: true,
edition: true,
}, [
...setupSteps,
}, () => [
...setupSteps(),
// 1. Check multi image upload
{
content: "click on dropped snippet",
trigger: "iframe #wrap .s_image_gallery .img",
trigger: ":iframe #wrap .s_image_gallery .img",
run: "click",
}, {
content: "click on add images to open image dialog (in multi mode)",
trigger: 'we-customizeblock-option [data-add-images]',
trigger: "button[data-action-id='addImage']",
run: "click",
}, {
content: "manually trigger input change",
trigger: ".o_select_media_dialog .o_upload_media_button",
run: () => {
run() {
// This will trigger upload of dummy files for test purpose, as a
// test can't select local files to upload into the input.
document.body.querySelector('.o_select_media_dialog .o_file_input').dispatchEvent(new Event('change'));
@ -84,52 +85,50 @@ wTourUtils.registerWebsitePreviewTour('test_image_upload_progress', {
}, {
content: "check upload progress bar is correctly shown (1)",
trigger: `.o_we_progressbar:contains('icon.ico'):contains('${formatErrorMsg}')`,
in_modal: false,
run: function () {}, // it's a check
}, {
content: "check upload progress bar is correctly shown (2)",
trigger: `.o_we_progressbar:contains('image.webp'):contains('${formatErrorMsg}')`,
in_modal: false,
run: function () {}, // it's a check
trigger: ".o_we_progressbar:contains('image.webp'):contains('File has been uploaded')",
}, {
content: "check upload progress bar is correctly shown (3)",
trigger: ".o_we_progressbar:contains('image.png'):contains('File has been uploaded')",
in_modal: false,
run: function () {}, // it's a check
}, {
content: "check upload progress bar is correctly shown (4)",
trigger: ".o_we_progressbar:contains('image.jpeg'):contains('File has been uploaded')",
in_modal: false,
run: function () {}, // it's a check
}, {
content: "there should only have one notification toaster",
},
{
trigger: ".o_notification",
in_modal: false,
run: () => {
const notificationCount = $('.o_notification').length;
},
{
content: "there should only have one notification toaster",
trigger: "body",
run() {
const notificationCount = document.querySelectorAll(".o_notification").length;
if (notificationCount !== 1) {
console.error("There should be one noficiation toaster opened, and only one.");
throw new Error(`There should be one notification toaster opened, and only one, found ${notificationCount}.`);
}
}
}, {
content: "close notification",
trigger: '.o_notification_close',
in_modal: false,
run: "click",
}, {
content: "close media dialog",
trigger: '.modal-footer .btn-secondary',
run: "click",
},
// 2. Check success single image upload
{
content: "click on dropped snippet",
trigger: "iframe #wrap .s_text_image .img",
trigger: ":iframe #wrap .s_text_image .img",
run: "click",
}, {
content: "click on replace media to open image dialog",
trigger: 'we-customizeblock-option [data-replace-media]',
trigger: "button[data-action-id='replaceMedia']",
run: "click",
}, {
content: "manually trigger input change",
trigger: ".o_select_media_dialog .o_upload_media_button",
run: () => {
run() {
// This will trigger upload of dummy files for test purpose, as a
// test can't select local files to upload into the input.
document.body.querySelector('.o_select_media_dialog .o_file_input').dispatchEvent(new Event('change'));
@ -137,43 +136,38 @@ wTourUtils.registerWebsitePreviewTour('test_image_upload_progress', {
}, {
content: "check upload progress bar is correctly shown",
trigger: ".o_we_progressbar:contains('image.png')",
in_modal: false,
run: function () {}, // it's a check
}, {
content: "there should only have one notification toaster",
trigger: ".o_notification",
in_modal: false,
run: () => {
const notificationCount = $('.o_notification').length;
run() {
const notificationCount = document.querySelectorAll(".o_notification").length;
if (notificationCount !== 1) {
console.error("There should be one noficiation toaster opened, and only one.");
throw new Error(`There should be one notification toaster opened, and only one, found ${notificationCount}.`);
}
}
}, {
content: "media dialog has closed after the upload",
trigger: 'body:not(:has(.o_select_media_dialog))',
run: () => {}, // It's a check.
}, {
content: "the upload progress toast was updated",
trigger: ".o_we_progressbar:contains('image.png'):contains('File has been uploaded')",
run: () => {}, // It's a check.
}, {
content: "toaster should disappear after a few seconds if the uploaded image is successful",
trigger: "body:not(:has(.o_we_progressbar))",
run: function () {}, // it's a check
},
// 3. Check error single image upload
{
content: "click on dropped snippet",
trigger: "iframe #wrap .s_text_image .img",
trigger: ":iframe #wrap .s_text_image .img",
run: "click",
}, {
content: "click on replace media to open image dialog",
trigger: 'we-customizeblock-option [data-replace-media]',
trigger: "button[data-action-id='replaceMedia']",
run: "click",
}, {
content: "manually trigger input change",
trigger: ".o_select_media_dialog .o_upload_media_button",
in_modal: false,
run: () => {
run() {
patchWithError = true;
// This will trigger upload of dummy files for test purpose, as a
// test can't select local files to upload into the input.
@ -183,18 +177,16 @@ wTourUtils.registerWebsitePreviewTour('test_image_upload_progress', {
}, {
content: "check upload progress bar is correctly shown",
trigger: `.o_we_progressbar:contains('icon.ico'):contains('${formatErrorMsg}')`,
in_modal: false,
run: function () {
run() {
patchWithError = false;
},
}, {
content: "there should only have one notification toaster",
trigger: ".o_notification",
in_modal: false,
run: () => {
const notificationCount = $('.o_notification').length;
run() {
const notificationCount = document.querySelectorAll(".o_notification").length;
if (notificationCount !== 1) {
console.error("There should be one noficiation toaster opened, and only one.");
throw new Error(`There should be one noficiation toaster opened, and only one, found ${notificationCount}.`);
}
unpatchMediaDialog();
}
@ -202,44 +194,45 @@ wTourUtils.registerWebsitePreviewTour('test_image_upload_progress', {
]);
wTourUtils.registerWebsitePreviewTour('test_image_upload_progress_unsplash', {
registerWebsitePreviewTour('test_image_upload_progress_unsplash', {
url: '/test_image_progress',
test: true,
edition: true,
}, [
...setupSteps,
}, () => [
...setupSteps(),
// 1. Check multi image upload
{
content: "click on dropped snippet",
trigger: "iframe #wrap .s_image_gallery .img",
trigger: ":iframe #wrap .s_image_gallery .img",
run: "click",
}, {
content: "click on replace media to open image dialog",
trigger: 'we-customizeblock-option [data-replace-media]',
trigger: "button[data-action-id='replaceMedia']",
run: "click",
}, {
content: "search 'fox' images",
trigger: ".o_we_search",
run: "text fox",
run: "edit fox",
}, {
content: "click on unsplash result", // note that unsplash is mocked
trigger: "img[alt~=fox]"
}, {
trigger: ".o_we_media_dialog_img_wrapper:has(img[alt~=fox]) + .o_button_area",
run: "click",
},
{
trigger: ".o_notification_close",
},
{
content: "check that the upload progress bar is correctly shown",
// ensure it is there so we are sure next step actually test something
extra_trigger: '.o_notification_close',
trigger: ".o_we_progressbar:contains('fox'):contains('File has been uploaded')",
in_modal: false,
run: function () {}, // it's a check
}, {
content: "notification should close after 3 seconds",
trigger: 'body:not(:has(.o_notification_close))',
in_modal: false,
run: "click",
}, {
content: "unsplash image (mocked to logo) should have been used",
trigger: "iframe #wrap .s_image_gallery .img[data-original-src^='/unsplash/HQqIOc8oYro/fox']",
run: () => {
trigger: ":iframe #wrap .s_image_gallery img[data-original-src^='/unsplash/HQqIOc8oYro/fox']",
run() {
unpatchMediaDialog();
},
},
]);
});

View file

@ -1,16 +1,12 @@
odoo.define('test_website.json_auth', function (require) {
'use strict';
import { registry } from "@web/core/registry";
import { rpc } from "@web/core/network/rpc";
var tour = require('web_tour.tour');
var session = require('web.session')
tour.register('test_json_auth', {
test: true,
}, [{
registry.category("web_tour.tours").add('test_json_auth', {
steps: () => [{
trigger: 'body',
run: async function () {
await session.rpc('/test_get_dbname').then( function (result){
return session.rpc("/web/session/authenticate", {
await rpc('/test_get_dbname').then( function (result){
return rpc("/web/session/authenticate", {
db: result,
login: 'admin',
password: 'admin'
@ -18,9 +14,8 @@ tour.register('test_json_auth', {
});
window.location.href = window.location.origin;
},
expectUnloadPage: true,
}, {
trigger: 'span:contains(Mitchell Admin), span:contains(Administrator)',
run: function () {},
}
]);
});
]});

View file

@ -1,77 +1,87 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import tour from 'web_tour.tour';
tour.register('test_website_page_manager', {
test: true,
url: '/web#action=test_website.action_test_model_multi_website',
}, [
registry.category("web_tour.tours").add('test_website_page_manager', {
url: '/odoo/action-test_website.action_test_model_multi_website',
steps: () => [
// Part 1: check that the website filter is working
{
content: "Check that we see records from My Website",
trigger: ".o_list_table .o_data_row .o_data_cell[name=name]:contains('Test Multi Model Website 1') " +
"~ .o_data_cell[name=website_id]:contains('My Website')",
run: () => null, // it's a check
}, {
content: "Check that there is only 2 records in the pager",
trigger: ".o_pager .o_pager_value:contains('1-2')",
run: () => null, // it's a check
}, {
content: "Click on the 'Select all records' checkbox",
trigger: "thead .o_list_record_selector",
run: "click",
}, {
content: "Check that there is only 2 records selected",
trigger: ".o_list_selection_box:contains('2 selected')",
run: () => null, // it's a check
trigger: ".o_selection_box:contains(2):contains(selected)",
}, {
content: "Click on My Website search filter",
trigger: "button.dropdown-toggle:contains('My Website')",
content: "Click on the 'Select all records' checkbox again to unselect all records and see the search bar",
trigger: "thead .o_list_record_selector",
run: "click",
}, {
content: "Select My Website 2",
trigger: ".dropdown-menu.show > .dropdown-item:contains('My Website 2')",
content: "Click on the search options",
trigger: ".o_searchview_dropdown_toggler",
run: "click",
}, {
content: "Remove 'My Website' filter",
trigger: ".o_filter_menu .o-dropdown-item:contains('My Website')",
run: "click",
}, {
content: "Select 'My Website 2' filter",
trigger: ".o_filter_menu .o-dropdown-item:contains('My Website 2')",
run: "click",
}, {
// This step is just here to ensure there is more records than the 2
// available on website 1, to ensure the test is actually testing something.
content: "Check that we see records from My Website 2",
trigger: ".o_list_table .o_data_row .o_data_cell[name=name]:contains('Test Model Multi Website 2') " +
"~ .o_data_cell[name=website_id]:contains('My Website 2')",
run: () => null, // it's a check
},
// Part 2: ensure Kanban View is working / not crashing
{
content: "Click on Kanban View",
trigger: '.o_cp_switch_buttons .o_kanban',
}, {
run: "click",
},
{
trigger: ".o_kanban_renderer",
},
{
content: "Click on List View",
extra_trigger: '.o_kanban_renderer',
trigger: '.o_cp_switch_buttons .o_list',
run: "click",
}, {
content: "Wait for List View to be loaded",
trigger: '.o_list_renderer',
run: () => null, // it's a check
}]);
}]
});
tour.register('test_website_page_manager_js_class_bug', {
test: true,
url: '/web#action=test_website.action_test_model_multi_website_js_class_bug',
}, [{
registry.category("web_tour.tours").add('test_website_page_manager_js_class_bug', {
url: '/odoo/action-test_website.action_test_model_multi_website_js_class_bug',
steps: () => [
{
content: "Click on Kanban View",
trigger: '.o_cp_switch_buttons .o_kanban',
run: "click",
}, {
content: "Wait for Kanban View to be loaded",
trigger: '.o_kanban_renderer',
run: () => null, // it's a check
}]);
}]
});
tour.register('test_website_page_manager_no_website_id', {
test: true,
url: '/web#action=test_website.action_test_model',
}, [{
registry.category("web_tour.tours").add('test_website_page_manager_no_website_id', {
url: '/odoo/action-test_website.action_test_model',
steps: () => [
{
content: "Click on Kanban View",
trigger: '.o_cp_switch_buttons .o_kanban',
run: "click",
}, {
content: "Wait for Kanban View to be loaded",
trigger: '.o_kanban_renderer',
run: () => null, // it's a check
}]);
}]
});

View file

@ -1,19 +1,20 @@
/** @odoo-module **/
import { patch } from '@web/core/utils/patch';
import { VideoSelector } from '@web_editor/components/media_dialog/video_selector';
import wTourUtils from 'website.tour_utils';
import { patch } from "@web/core/utils/patch";
import { VideoSelector } from "@html_editor/main/media/media_dialog/video_selector";
import {
changeOption,
insertSnippet,
registerWebsitePreviewTour,
} from '@website/js/tours/tour_utils';
const VIDEO_URL = 'https://www.youtube.com/watch?v=Dpq87YCHmJc';
/**
* The purpose of this tour is to check the media replacement flow.
*/
wTourUtils.registerWebsitePreviewTour('test_replace_media', {
registerWebsitePreviewTour('test_replace_media', {
url: '/',
test: true,
edition: true,
}, [
}, () => [
{
trigger: "body",
run: function () {
@ -23,138 +24,148 @@ wTourUtils.registerWebsitePreviewTour('test_replace_media', {
// specific to an URL only, it is acceptable).
// TODO if we ever give the possibility to upload its own videos,
// this won't be necessary anymore.
patch(VideoSelector.prototype, "Video selector patch", {
patch(VideoSelector.prototype, {
async _getVideoURLData(src, options) {
if (src === VIDEO_URL || src === 'about:blank') {
return {platform: 'youtube', embed_url: 'about:blank'};
}
return this._super(...arguments);
return super._getVideoURLData(...arguments);
},
});
},
},
{
content: "drop picture snippet",
trigger: "#oe_snippets .oe_snippet[name='Picture'] .oe_snippet_thumbnail:not(.o_we_already_dragging)",
moveTrigger: "iframe .oe_drop_zone",
run: "drag_and_drop iframe #wrap",
},
...insertSnippet({
name: 'Title - Image',
id: 's_picture',
groupName: "Images",
}),
{
content: "select image",
trigger: "iframe .s_picture figure img",
trigger: ":iframe .s_picture figure img",
run: "click",
},
{
content: "ensure image size is displayed",
trigger: "#oe_snippets we-title:contains('Image') .o_we_image_weight:contains('kb')",
run: function () {}, // check
trigger: ".o_customize_tab [data-container-title='Image'] .options-container-header:contains('kb')",
},
wTourUtils.changeOption("ImageTools", 'we-select[data-name="shape_img_opt"] we-toggler'),
wTourUtils.changeOption("ImageTools", "we-button[data-set-img-shape]"),
changeOption("Image", "[data-label='Shape'] .dropdown-toggle"),
{
content: "replace image",
trigger: "#oe_snippets we-button[data-replace-media]",
content: "Click on the first image shape",
trigger: "button[data-action-id='setImageShape']",
run: "click",
},
{
content: "Open MediaDialog from an image",
trigger: "button[data-action-id='replaceMedia']",
run: "click",
},
{
content: "select svg",
trigger: ".o_select_media_dialog img[title='sample.svg']",
trigger: ".o_select_media_dialog .o_button_area[aria-label='sample.svg']",
run: "click",
},
{
content: "ensure the svg doesn't have a shape",
trigger: "iframe .s_picture figure img:not([data-shape])",
run: function () {}, // check
content: "ensure the svg does have a shape",
trigger: ":iframe .s_picture figure img[data-shape]",
},
{
content: "ensure image size is not displayed",
trigger: "#oe_snippets we-title:contains('Image'):not(:has(.o_we_image_weight:visible))",
run: function () {}, // check
content: "ensure image size is displayed",
trigger: ".o_customize_tab [data-container-title='Image'] span[title='Size']",
},
{
content: "replace image",
trigger: "#oe_snippets we-button[data-replace-media]",
trigger: "button[data-action-id='replaceMedia']",
run: "click",
},
{
content: "go to pictogram tab",
trigger: ".o_select_media_dialog .nav-link:contains('Icons')",
run: "click",
},
{
content: "select an icon",
trigger: ".o_select_media_dialog:has(.nav-link.active:contains('Icons')) .tab-content span.fa-lemon-o",
trigger: ".o_select_media_dialog:has(.nav-link.active:contains('Icons')) .tab-content span.fa-heart",
run: "click",
},
{
content: "ensure icon block is displayed",
trigger: "#oe_snippets we-customizeblock-options we-title:contains('Icon')",
run: function () {}, // check
trigger: ".o_customize_tab [data-container-title='Icon']",
},
{
content: "select footer",
trigger: "iframe footer",
trigger: ":iframe footer",
run: "click",
},
{
content: "select icon",
trigger: "iframe .s_picture figure span.fa-lemon-o",
trigger: ":iframe .s_picture figure span.fa-heart",
run: "click",
},
{
content: "ensure icon block is still displayed",
trigger: "#oe_snippets we-customizeblock-options we-title:contains('Icon')",
run: function () {}, // check
trigger: ".o_customize_tab [data-container-title='Icon']",
},
{
content: "replace icon",
trigger: "#oe_snippets we-button[data-replace-media]",
trigger: "button[data-action-id='replaceMedia']",
run: "click",
},
{
content: "go to video tab",
trigger: ".o_select_media_dialog .nav-link:contains('Video')",
run: "click",
},
{
content: "enter a video URL",
trigger: ".o_select_media_dialog #o_video_text",
// Design your first web page.
run: `text ${VIDEO_URL}`,
run: `edit ${VIDEO_URL}`,
},
{
content: "wait for preview to appear",
// "about:blank" because the VideoWidget was patched at the start of this tour
trigger: ".o_select_media_dialog div.media_iframe_video iframe[src='about:blank']",
run: function () {}, // check
trigger: ".o_select_media_dialog div.media_iframe_video [src='about:blank']:iframe body",
},
{
content: "confirm selection",
trigger: ".o_select_media_dialog .modal-footer .btn-primary",
run: "click",
},
{
content: "ensure video option block is displayed",
trigger: "#oe_snippets we-customizeblock-options we-title:contains('Video')",
run: function () {}, // check
trigger: ".o_customize_tab [data-container-title='Video']",
},
{
content: "replace image",
trigger: "#oe_snippets we-button[data-replace-media]",
trigger: ".btn-success[data-action-id='replaceMedia']",
run: "click",
},
{
content: "go to pictogram tab",
trigger: ".o_select_media_dialog .nav-link:contains('Icons')",
run: "click",
},
{
content: "select an icon",
trigger: ".o_select_media_dialog:has(.nav-link.active:contains('Icons')) .tab-content span.fa-lemon-o",
trigger: ".o_select_media_dialog:has(.nav-link.active:contains('Icons')) .tab-content span.fa-heart",
run: "click",
},
{
content: "ensure icon block is displayed",
trigger: "#oe_snippets we-customizeblock-options we-title:contains('Icon')",
run: function () {}, // check
trigger: ".o_customize_tab [data-container-title='Icon']",
},
{
content: "select footer",
trigger: "iframe footer",
trigger: ":iframe footer",
run: "click",
},
{
content: "select icon",
trigger: "iframe .s_picture figure span.fa-lemon-o",
trigger: ":iframe .s_picture figure span.fa-heart",
run: "click",
},
{
content: "ensure icon block is still displayed",
trigger: "#oe_snippets we-customizeblock-options we-title:contains('Icon')",
run: function () {}, // check
trigger: ".o_customize_tab [data-container-title='Icon']",
},
]);

View file

@ -1,8 +1,6 @@
/* global ace */
odoo.define('test_website.reset_views', function (require) {
'use strict';
const wTourUtils = require('website.tour_utils');
import { clickOnSave, registerWebsitePreviewTour } from "@website/js/tours/tour_utils";
var BROKEN_STEP = {
// because saving a broken template opens a recovery page with no assets
@ -10,98 +8,110 @@ var BROKEN_STEP = {
// to properly wait for the page to be saved & reloaded in order to fix the
// race condition of a tour ending on a side-effect (with the possible
// exception of somehow telling the harness / browser to do it)
trigger: 'body',
run: function () {}
trigger: "body",
};
wTourUtils.registerWebsitePreviewTour('test_reset_page_view_complete_flow_part1', {
test: true,
url: '/test_page_view',
// 1. Edit the page through Edit Mode, it will COW the view
edition: true,
},
[
registerWebsitePreviewTour(
"test_reset_page_view_complete_flow_part1",
{
url: "/test_page_view",
// 1. Edit the page through Edit Mode, it will COW the view
edition: true,
},
() => [
{
content: "drop a snippet",
trigger: ".oe_snippet:has(.s_cover) .oe_snippet_thumbnail",
content: "Drag the Intro snippet group and drop it in #oe_structure_test_website_page.",
trigger:
".o_block_tab:not(.o_we_ongoing_insertion) #snippet_groups .o_snippet[name='Intro'] .o_snippet_thumbnail .o_snippet_thumbnail_area",
// id starting by 'oe_structure..' will actually create an inherited view
run: "drag_and_drop iframe #oe_structure_test_website_page",
run: "drag_and_drop :iframe #oe_structure_test_website_page",
},
{
content: "save the page",
extra_trigger: 'iframe #oe_structure_test_website_page.o_dirty',
trigger: "button[data-action=save]",
content: "Click on the s_cover snippet.",
trigger: ':iframe .o_snippet_preview_wrap[data-snippet-id="s_cover"]',
run: "click",
},
...clickOnSave(),
// 2. Edit that COW'd view in the HTML editor to break it.
{
content: "open site menu",
extra_trigger: "iframe body:not(.editor_enable)",
trigger: 'button[data-menu-xmlid="website.menu_site"]',
run: "click",
},
{
content: "open html editor",
trigger: 'a[data-menu-xmlid="website.menu_ace_editor"]',
run: "click",
},
{
content: "add a broken t-field in page DOM",
trigger: 'div.ace_line .ace_xml:contains("placeholder")',
run: function () {
ace.edit('ace-view-editor').getSession().insert({row: 4, column: 1}, '<t t-field="not.exist"/>\n');
run() {
ace.edit(document.querySelector("#resource-editor div"))
.getSession()
.insert({row: 4, column: 1}, '<t t-field="not.exist"/>\n');
},
},
{
content: "save the html editor",
extra_trigger: '.ace_content:contains("not.exist")',
trigger: ".o_ace_view_editor button[data-action=save]",
trigger: '.ace_content:contains("not.exist")',
},
BROKEN_STEP
{
content: "save the html editor",
trigger: ".o_resource_editor button:contains(Save)",
run: "click",
},
BROKEN_STEP,
]
);
wTourUtils.registerWebsitePreviewTour('test_reset_page_view_complete_flow_part2', {
test: true,
url: '/test_page_view',
},
[
registerWebsitePreviewTour(
"test_reset_page_view_complete_flow_part2",
{
url: "/test_page_view",
},
() => [
{
content: "check that the view got fixed",
trigger: 'iframe p:containsExact("Test Page View")',
run: function () {}, // it's a check
trigger: ":iframe p:text(Test Page View)",
},
{
content: "check that the inherited COW view is still there (created during edit mode)",
trigger: 'iframe #oe_structure_test_website_page .s_cover',
run: function () {}, // it's a check
trigger: ":iframe #oe_structure_test_website_page .s_cover",
},
//4. Now break the inherited view created when dropping a snippet
{
content: "open site menu",
trigger: 'button[data-menu-xmlid="website.menu_site"]',
run: "click",
},
{
content: "open html editor",
trigger: 'a[data-menu-xmlid="website.menu_ace_editor"]',
run: "click",
},
{
content: "select oe_structure view",
trigger: '#s2id_ace-view-list', // use select2 version
run: function () {
var viewId = $('#ace-view-list option:contains("oe_structure_test_website_page")').val();
$('#ace-view-list').val(viewId).trigger('change');
},
trigger: ".o_resource_editor_title .o_select_menu_toggler",
run: "click",
},
{
content: "select oe_structure view",
trigger: ".o_select_menu_menu .o_select_menu_item:contains(Test Page View)",
run: "click",
},
{
content: "add a broken t-field in page DOM",
trigger: 'div.ace_line .ace_xml:contains("oe_structure_test_website_page")',
run: function () {
ace.edit('ace-view-editor').getSession().insert({row: 4, column: 1}, '<t t-field="not.exist"/>\n');
run() {
ace.edit(document.querySelector("#resource-editor div"))
.getSession()
.insert({row: 4, column: 1}, '<t t-field="not.exist"/>\n');
},
},
{
content: "save the html editor",
trigger: ".o_ace_view_editor button[data-action=save]",
trigger: ".o_resource_editor button:contains(Save)",
run: "click",
},
BROKEN_STEP
BROKEN_STEP,
]
);
});

View file

@ -0,0 +1,174 @@
import {
clickOnSave,
clickOnEditAndWaitEditMode,
clickOnExtraMenuItem,
registerWebsitePreviewTour,
insertSnippet
} from '@website/js/tours/tour_utils';
import { stepUtils } from "@web_tour/tour_utils";
const EDIT_BUTTON_SELECTOR = "body .o_menu_systray button.o-website-btn-custo-primary:contains(edit)";
const checkNoTranslate = {
content: "Check there is no translate button",
trigger: `${EDIT_BUTTON_SELECTOR}:not(.o-dropdown-toggle-custo)`,
};
const translate = [{
content: "Open Edit menu",
trigger: `${EDIT_BUTTON_SELECTOR}.o-dropdown-toggle-custo`,
run: "click",
}, {
content: "Click on translate button",
trigger: ".o_popover .o_translate_website_dropdown_item:contains(translate)",
run: "click",
}];
const closeErrorDialog = [{
content: "Check has error dialog",
trigger: ".modal:contains(error) .o_error_dialog.modal-content",
}, {
content: "Close error dialog",
trigger: ".modal .modal-footer button.btn.btn-primary",
run: "click",
}, {
trigger: "body:not(:has(.modal))",
}];
const switchTo = (lang) => [
{
content: `Switch to ${lang}`,
trigger: `:iframe .js_change_lang[data-url_code='${lang}']`,
run: "click",
},
{
content: `Wait until ${lang} is applied`,
trigger: `:iframe html[lang*="${lang}"]`,
},
stepUtils.waitIframeIsReady(),
];
const goToMenuItem = [
clickOnExtraMenuItem({}, true),
{
content: "Navigate to model item page",
trigger: ":iframe a[href='/test_website/model_item/1']",
run: "click",
},
{
content: "Wait to land on model item page",
trigger: ':iframe a[href="/test_website/model_item/1"].nav-link.active:not(:visible)',
},
stepUtils.waitIframeIsReady(),
];
registerWebsitePreviewTour('test_restricted_editor_only', {
url: '/',
}, () => [
// Home
checkNoTranslate,
...clickOnEditAndWaitEditMode(),
{
content: "Check icons cannot be dragged",
trigger: "#snippet_groups .o_snippet[name='Intro'].o_disabled",
run: function () {
if (document.querySelector("button.o_snippet_thumbnail_area")) {
console.error(
"The button to open the add snippet dialog should not be display for restricted editor."
);
}
},
},
...clickOnSave(),
...switchTo('fr'),
...translate,
...closeErrorDialog,
...switchTo('en'),
// Model item
{
trigger: ":iframe body:contains(welcome to your)"
},
...goToMenuItem,
checkNoTranslate,
...clickOnEditAndWaitEditMode(),
{
content: "Check icons cannot be dragged",
trigger: "#snippet_groups .o_snippet[name='Intro'].o_disabled",
run: function () {
if (document.querySelector("button.o_snippet_thumbnail_area")) {
console.error(
"The button to open the add snippet dialog should not be display for restricted editor."
);
}
},
},
...clickOnSave(),
...switchTo('fr'),
...translate,
...closeErrorDialog,
]);
registerWebsitePreviewTour('test_restricted_editor_test_admin', {
url: '/',
}, () => [
// Home
checkNoTranslate,
...clickOnEditAndWaitEditMode(),
{
content: "Check icons cannot be dragged",
trigger: "#snippet_groups .o_snippet[name='Intro'].o_disabled",
},
...clickOnSave(),
...switchTo('fr'),
...translate,
...closeErrorDialog,
...switchTo('en'),
// Model item
...goToMenuItem,
checkNoTranslate,
...clickOnEditAndWaitEditMode(),
{
content: "Check icons can be dragged",
trigger: "#snippet_groups .o_snippet[name='Intro']:not(.o_disabled)",
},
...insertSnippet({ id: "s_banner", name: "Banner", groupName: "Intro" }),
{
content: "Change name",
trigger: ":iframe [data-oe-expression='record.name']",
run: "editor New value",
},
...clickOnSave(),
...switchTo('fr'),
...translate,
{
content: "Close the dialog",
trigger: ".modal .modal-footer .btn-primary",
run: "click",
},
{
content: "Assure the modal is well closed",
trigger: "body:not(:has(.modal))",
},
{
content: "Check that html fields are not content editable when translating",
trigger: ":iframe [data-oe-expression='record.website_description']:not([contenteditable='true'])",
},
{
content: "Translate name",
trigger: ":iframe [data-oe-expression='record.name']",
run: "editor Nouvelle valeur",
},
{
content: "Translate some banner text",
trigger: ":iframe [data-oe-expression='record.website_description'] strong",
run: "editor potentiel.",
},
...clickOnSave(),
]);
registerWebsitePreviewTour('test_restricted_editor_tester', {
url: '/test_model/1',
}, () => [
...clickOnEditAndWaitEditMode(),
{
content: "Footer should not be be editable for restricted user",
trigger: ":iframe :has(.o_editable) footer:not(.o_editable):not(:has(.o_editable))",
},
...clickOnSave(),
]);

View file

@ -0,0 +1,83 @@
/** @odoo-module **/
import { patch } from "@web/core/utils/patch";
import { VideoSelector } from "@html_editor/main/media/media_dialog/video_selector";
import { insertSnippet, registerWebsitePreviewTour } from "@website/js/tours/tour_utils";
registerWebsitePreviewTour(
"snippet_background_video",
{
url: "/",
edition: true,
}, () => [
{
trigger: "body",
run: function () {
// Patch the VideoDialog so that it does not do external calls
// during the test (note that we don't unpatch but as the patch
// is only done after the execution of a test_website test, it
// is acceptable).
// TODO we should investigate to rather mock the external calls,
// maybe not using a tour. Probably easier to discuss when the
// new OWL editor will have been implemented.
patch(VideoSelector.prototype, {
async prepareVimeoPreviews() {
// Ignore the super call and directly push a fake video
this.state.vimeoPreviews.push({
id: 1,
// Those lead to 404 but it's fine for the test
thumbnailSrc: "/hello/world.jpg",
src: "/hello/world.mp4",
});
},
async _getVideoURLData(src, options) {
if (src === '/hello/world.mp4') {
return {
'platform': 'vimeo',
'embed_url': 'about:blank',
};
}
return super._getVideoURLData(...arguments);
},
});
},
},
...insertSnippet({
id: "s_text_block",
name: "Text",
groupName: "Text",
}),
{
content: "Click on the text block.",
trigger: ":iframe #wrap section.s_text_block",
run: "click",
},
{
content: "Click on the 'Background Video' button option.",
trigger: "button[data-action-id='toggleBgVideo']",
run: "click",
},
{
content: "Click on the first sample video in the modal.",
trigger: "#video-suggestion .o_sample_video",
run: "click",
},
{
content: "Check the video is select.",
trigger: "textarea.is-valid",
},
{
content: "Click on the 'Add' button to apply the selected video as the background.",
trigger: ".modal-footer button.btn-primary",
run: "click",
},
{
content: "Verify that the video is set as the background of the snippet.",
trigger: ":iframe #wrap section.o_background_video",
},
{
content: "Check that the video container is not editable.",
trigger: ":iframe #wrap section.o_background_video > .o_bg_video_container[contenteditable=false]",
},
]
);

View file

@ -1,6 +1,10 @@
/** @odoo-module **/
import wTourUtils from 'website.tour_utils';
import {
clickOnEditAndWaitEditMode,
clickOnSave,
registerWebsitePreviewTour,
} from '@website/js/tours/tour_utils';
import { stepUtils } from "@web_tour/tour_utils";
/**
* The purpose of these tours is to check the systray visibility:
@ -12,189 +16,209 @@ import wTourUtils from 'website.tour_utils';
* - as an unrelated user (neither "tester" nor restricted editor)
*/
const canPublish = [{
content: 'Publish',
const canPublish = () => [{
content: "Publish",
trigger: '.o_menu_systray .o_menu_systray_item:contains("Unpublished")',
run: "click",
}, {
content: 'Wait for Publish',
content: "Wait for Publish",
trigger: '.o_menu_systray .o_menu_systray_item:contains("Published"):not([data-processing])',
run: () => {}, // This is a check.
}, {
content: 'Unpublish',
content: "Unpublish",
trigger: '.o_menu_systray .o_menu_systray_item:contains("Published")',
run: "click",
}, {
content: 'Wait for Unpublish',
content: "Wait for Unpublish",
trigger: '.o_menu_systray .o_menu_systray_item:contains("Unpublished"):not([data-processing])',
run: () => {}, // This is a check.
}];
const cannotPublish = [{
content: 'Check has no Publish/Unpublish',
const cannotPublish = () => [{
content: "Check has no Publish/Unpublish",
trigger: '.o_menu_systray:not(:has(.o_menu_systray_item:contains("ublished")))',
run: () => {}, // This is a check.
}];
const canToggleMobilePreview = [{
content: 'Enable mobile preview',
trigger: '.o_menu_systray .o_menu_systray_item.o_mobile_preview:not(.o_mobile_preview_active)',
const canToggleMobilePreview = () => [{
content: "Enable mobile preview",
trigger: '.o_menu_systray .o_menu_systray_item.o_mobile_preview:not(.o_mobile_preview_active) span',
run: "click",
}, {
content: 'Disable mobile preview',
trigger: '.o_menu_systray .o_menu_systray_item.o_mobile_preview.o_mobile_preview_active',
content: "Disable mobile preview",
trigger: '.o_menu_systray .o_menu_systray_item.o_mobile_preview.o_mobile_preview_active span',
run: "click",
}];
const cannotToggleMobilePreview = [{
const cannotToggleMobilePreview = () => [{
content: 'Enable mobile preview',
trigger: '.o_menu_systray:not(:has(.o_menu_systray_item.o_mobile_preview))',
run: () => {}, // This is a check.
}];
// For non-website users, switching across website only works if the domains are
// specified. Within the scope of test tours, this cannot be achieved.
const canSwitchWebsiteNoCheck = [{
const canSwitchWebsiteNoCheck = () => [{
content: 'Open website switcher',
trigger: '.o_menu_systray .o_menu_systray_item.o_website_switcher_container .dropdown-toggle:contains("My Website"):not(:contains("My Website 2"))',
run: "click",
}, {
content: 'Switch to other website',
trigger: '.o_menu_systray .o_menu_systray_item.o_website_switcher_container .dropdown-item:contains("Other")',
run: () => {}, // This is a check.
content: 'Can switch to other website',
trigger: '.o-dropdown--menu .dropdown-item:contains("Other")',
}];
const canSwitchWebsite = [{
content: 'Open website switcher',
const canSwitchWebsite = () => [{
content: "Open website switcher",
trigger: '.o_menu_systray .o_menu_systray_item.o_website_switcher_container .dropdown-toggle:contains("My Website"):not(:contains("My Website 2"))',
run: "click",
}, {
content: 'Switch to other website',
trigger: '.o_menu_systray .o_menu_systray_item.o_website_switcher_container .dropdown-item:contains("Other")',
content: "Switch to other website",
trigger: '.o-dropdown--menu .dropdown-item:contains("Other")',
run: "click",
}, {
content: 'Wait for other website',
trigger: 'iframe body:contains("Test Model") div:contains("Other")',
run: () => {}, // This is a check.
content: "Wait for other website",
trigger: ':iframe body:contains("Test Model") div:contains("Other")',
}];
const canAddNewContent = [{
content: 'Open +New content',
trigger: '.o_menu_systray .o_menu_systray_item.o_new_content_container',
const canAddNewContent = () => [{
content: "Open +New content",
trigger: '.o_menu_systray .o_menu_systray_item.o_new_content_container button',
run: "click",
}, {
content: 'Close +New content',
trigger: '#o_new_content_menu_choices',
content: "Close +New content",
trigger: '.o_new_content_menu_choices',
run: "click",
}];
const cannotAddNewContent = [{
const cannotAddNewContent = () => [{
content: 'No +New content',
trigger: '.o_menu_systray:not(:has(.o_menu_systray_item.o_new_content_container))',
run: () => {}, // This is a check.
}];
const canEditInBackEnd = [{
content: 'Edit in backend',
const canEditInBackEnd = () => [{
content: "Edit in backend",
trigger: '.o_menu_systray .o_website_edit_in_backend a',
run: "click",
}, {
content: 'Check that the form is editable',
content: "Check that the form is editable",
trigger: '.o_form_view_container .o_form_editable',
run: () => {}, // This is a check.
}, {
content: 'Return to website',
trigger: '.oe_button_box .fa-globe',
content: "Return to website",
trigger: '.o-form-buttonbox .fa-globe',
run: "click",
}];
const canViewInBackEnd = [{
content: 'Go to backend',
const canViewInBackEnd = () => [{
content: "Go to backend",
trigger: '.o_menu_systray .o_website_edit_in_backend a',
run: "click",
}, {
content: 'Check that the form is read-only',
content: "Check that the form is read-only",
trigger: '.o_form_view_container .o_form_readonly',
run: () => {}, // This is a check.
}, {
content: 'Return to website',
trigger: '.oe_button_box .fa-globe',
content: "Return to website",
trigger: '.o-form-buttonbox .fa-globe',
run: "click",
}];
const canEdit = [
...wTourUtils.clickOnEditAndWaitEditMode(),
const canEdit = () => [
...clickOnEditAndWaitEditMode(),
{
content: 'Click on name',
trigger: 'iframe span[data-oe-expression="test_model.name"][contenteditable="true"]',
content: "Click on name",
trigger: ':iframe span[data-oe-expression="test_model.name"][contenteditable="true"]',
run: "click",
}, {
content: 'Change name',
trigger: 'iframe span[data-oe-expression="test_model.name"][contenteditable="true"]',
run: 'text Better name',
content: "Change name",
trigger: ':iframe span[data-oe-expression="test_model.name"][contenteditable="true"]',
run: "editor Better name",
}, {
content: 'Check that field becomes dirty',
trigger: 'iframe span[data-oe-expression="test_model.name"].o_dirty',
run: () => {}, // This is a check.
content: "Check that field becomes dirty",
trigger: ':iframe span[data-oe-expression="test_model.name"].o_dirty',
},
...wTourUtils.clickOnSave(),
...clickOnSave(),
{
content: 'Check whether name is saved',
trigger: 'iframe span[data-oe-expression="test_model.name"]:contains("Better name")',
run: () => {}, // This is a check.
content: "Check whether name is saved",
trigger: ':iframe span[data-oe-expression="test_model.name"]:contains("Better name")',
},
];
const cannotEdit = [{
content: 'Check Edit is not available',
const cannotEdit = () => [stepUtils.waitIframeIsReady(), {
content: "Check Edit is not available",
trigger: '.o_menu_systray:not(:has(.o_edit_website_container))',
run: () => {}, // This is a check.
}];
const canEditButCannotChange = [
...wTourUtils.clickOnEditAndWaitEditMode(),
const canEditButCannotChange = () => [
...clickOnEditAndWaitEditMode(),
{
content: 'Cannot change name',
trigger: 'iframe main:not(:has([data-oe-expression])):contains("Test Model")',
run: () => {}, // This is a check.
trigger: ':iframe main:not(:has([data-oe-expression])):contains("Test Model")',
},
];
const ensureWebsiteSwitcherIsNotVisible = [
{
content: "Ensure website switcher is hidden when only one website exists",
trigger: ".o_menu_systray:not(:has(.o_website_switcher_container))",
},
];
const ensureWebsiteSwitcherIsVisible = [
{
content: "Ensure website switcher is present when multiple website exists",
trigger: ".o_menu_systray:has(.o_website_switcher_container)",
},
];
const register = (title, steps) => {
wTourUtils.registerWebsitePreviewTour(title, {
url: '/test_model/1',
test: true,
registerWebsitePreviewTour(title, {
url: "/test_model/1",
}, steps);
};
register('test_systray_admin', [
...canPublish,
...canToggleMobilePreview,
...canSwitchWebsite,
...canAddNewContent,
...canEditInBackEnd,
...canEdit,
register("test_systray_admin", () => [
...canPublish(),
...canToggleMobilePreview(),
...canSwitchWebsite(),
...canAddNewContent(),
...canEditInBackEnd(),
...canEdit(),
]);
register('test_systray_reditor_tester', [
...canPublish,
...canToggleMobilePreview,
...canSwitchWebsite,
...canAddNewContent,
...canEditInBackEnd,
...canEdit,
register("test_systray_reditor_tester", () => [
...canPublish(),
...canToggleMobilePreview(),
...canSwitchWebsite(),
...canAddNewContent(),
...canEditInBackEnd(),
...canEdit(),
]);
register('test_systray_reditor_not_tester', [
...cannotPublish,
...canToggleMobilePreview,
...canSwitchWebsite,
...canAddNewContent,
...canViewInBackEnd,
...canEditButCannotChange,
register("test_systray_reditor_not_tester", () => [
...cannotPublish(),
...canToggleMobilePreview(),
...canSwitchWebsite(),
...canAddNewContent(),
...canViewInBackEnd(),
...canEditButCannotChange(),
]);
register('test_systray_not_reditor_tester', [
...canPublish,
...cannotToggleMobilePreview,
...canSwitchWebsiteNoCheck,
...cannotAddNewContent,
...canEditInBackEnd,
...cannotEdit,
register("test_systray_not_reditor_tester", () => [
...canPublish(),
...cannotToggleMobilePreview(),
...canSwitchWebsiteNoCheck(),
...cannotAddNewContent(),
...canEditInBackEnd(),
...cannotEdit(),
]);
register('test_systray_not_reditor_not_tester', [
...cannotPublish,
...cannotToggleMobilePreview,
...canSwitchWebsiteNoCheck,
...cannotAddNewContent,
...canViewInBackEnd,
...cannotEdit,
register("test_systray_not_reditor_not_tester", () => [
...cannotPublish(),
...cannotToggleMobilePreview(),
...canSwitchWebsiteNoCheck(),
...cannotAddNewContent(),
...canViewInBackEnd(),
...cannotEdit(),
{
trigger: ":iframe main:contains(test model)",
},
]);
register("test_systray_single_website", () => ensureWebsiteSwitcherIsNotVisible);
register("test_systray_multi_website", () => ensureWebsiteSwitcherIsVisible);

View file

@ -0,0 +1,499 @@
import {
clickOnEditAndWaitEditMode,
clickOnSave,
insertSnippet,
registerWebsitePreviewTour,
} from "@website/js/tours/tour_utils";
import { stepUtils } from "@web_tour/tour_utils";
import { translationIsReady } from "@web/core/l10n/translation";
function createNewPage() {
return [
{
content: "Open +New content",
trigger: ".o_menu_systray .o_menu_systray_item.o_new_content_container button",
run: "click",
},
{
content: "Create a New page",
trigger: `button.o_new_content_element img[src="/website/static/description/icon.png"]`,
run: "click",
},
{
content: "Select Blank page",
trigger: ".o_page_template:has(div.text-muted) .o_button_area:not(:visible)",
run: "click",
},
{
content: "Page name",
trigger: ".modal-dialog .o_website_dialog input",
run: "edit Test",
},
{
content: "Confirm creation",
trigger: ".modal-dialog .o_website_dialog .btn-primary",
run: "click",
},
{
trigger: ".o_builder_sidebar_open",
timeout: 20000,
},
...insertSnippet({
id: "s_banner",
name: "Banner",
groupName: "Intro",
}),
{
content: "Click on the link",
trigger: ":iframe main section.s_banner a",
async run(helpers) {
await helpers.click();
const el = this.anchor;
const sel = el.ownerDocument.getSelection();
sel.collapse(el, 0);
el.focus();
},
},
{
content: "Click on Edit link",
trigger: ".o_we_edit_link",
run: "click",
},
{
content: "Replace URL",
trigger: ".o-we-linkpopover .o_we_href_input_link",
run: "edit /test_view",
},
{
content: "Apply",
trigger: ".o-we-linkpopover .btn-primary",
run: "click",
},
...clickOnSave("bottom", 50000, false),
];
}
function openHtmlEditor() {
return [
{
content: "Open Site menu",
trigger: ".o_menu_sections [data-menu-xmlid='website.menu_site']",
run: "click",
},
{
content: "Open HTML editor",
trigger: ".o-overlay-item .dropdown-item[data-menu-xmlid='website.menu_ace_editor']",
run: "click",
},
{
content: "Edit anyway",
trigger: ".o_resource_editor_wrapper [role='alert'] button.btn-link",
run: "click",
},
];
}
function saveHtmlEditor() {
return [
{
content: "Save the html editor",
trigger: ".o_resource_editor button.btn-primary",
run: "click",
},
{
content: "Close the html editor",
trigger: ".o_resource_editor button.btn-secondary",
run: "click",
},
];
}
function singleLanguage() {
return [
{
content: "Ensure single language site",
trigger: ":iframe body:not(:has(.js_language_selector))",
},
// new page
...createNewPage(),
...openHtmlEditor(),
{
content: "Change text",
trigger: 'div.ace_line .ace_xml:contains("oe_structure")',
run() {
window.ace.edit(document.querySelector("#resource-editor div"))
.getSession()
.insert({row: 8, column: 1}, '<p>More text</p>\n');
},
},
...saveHtmlEditor(),
{
content: "Ensure page is updated",
trigger: ":iframe body:contains(More text)",
},
// xml record
{
content: "Go to test_view page",
trigger: ":iframe main section.s_banner a",
run: "click",
},
{
content: "Wait until page is reached",
trigger: ":iframe body:contains(Test View)",
},
...clickOnEditAndWaitEditMode(),
{
content: "Edit template text",
trigger: ":iframe main p.o_editable[data-oe-field='arch'][contenteditable='true']",
run: "editor Modified Text",
},
...clickOnSave("bottom", 50000, false),
...openHtmlEditor(),
{
content: "Change text",
trigger: 'div.ace_line .ace_xml:contains("test_website.test_view")',
run() {
window.ace.edit(document.querySelector("#resource-editor div"))
.getSession()
.insert({row: 2, column: 36}, 'Further ');
},
},
...saveHtmlEditor(),
{
content: "Ensure view is updated",
trigger: ":iframe body:contains(Further Modified Text)",
},
];
}
const ensureFrUser = {
content: "Ensure FR user",
trigger: ".o_website_systray:contains(Publié)",
};
const ensureEnUser = {
content: "Ensure EN user",
trigger: ".o_website_systray:contains(Published)",
};
const ensureFrSite = {
content: "Ensure FR site",
trigger: ":iframe .o_main_nav:contains(Accueil)",
};
const ensureEnSite = {
content: "Ensure EN site",
trigger: ":iframe .o_main_nav:contains(Home)",
};
registerWebsitePreviewTour(
"translation_single_language_fr_user_fr_site",
{
url: "/",
},
() => [
ensureFrUser,
ensureFrSite,
...singleLanguage(),
]
);
registerWebsitePreviewTour(
"translation_single_language_en_user_fr_site",
{
url: "/",
},
() => [
ensureEnUser,
ensureFrSite,
...singleLanguage(),
]
);
registerWebsitePreviewTour(
"translation_single_language_fr_user_en_site",
{
url: "/",
},
() => [
ensureFrUser,
ensureEnSite,
...singleLanguage(),
]
);
function switchLanguage(lang, timeout = 50000) {
return [
{
content: "Ensure was in other language",
trigger: `:iframe .o_header_language_selector:contains(${lang !== "fr" ? "Français" : "English"})`,
timeout,
}, {
content: "Open language dropdown",
trigger: ":iframe .o_header_language_selector .dropdown-toggle",
run: "click",
}, {
content: "Select language",
trigger: `:iframe .o_header_language_selector .js_change_lang[data-url_code=${lang}]`,
run: "click",
}, {
content: "Wait until target page is loaded",
trigger: `:iframe .o_header_language_selector:contains(${lang === "fr" ? "Français" : "English"})`,
timeout,
}
];
}
// TODO Such a step should not be needed, but test randomly fails without it.
const awaitTranslationIsReady = {
content: "Await translationIsReady",
trigger: "body",
run: async () => {
await translationIsReady;
},
};
function openTranslate(timeout = 50000) {
return [
stepUtils.waitIframeIsReady(),
awaitTranslationIsReady,
{
content: "Open edit dropdown",
trigger: ".o_edit_website_container button",
run: "click",
}, {
content: "Enter translate mode",
trigger: ".o_translate_website_dropdown_item",
run: "click",
}, {
content: "Effect's 200ms setTimeout passed",
trigger: ".o_builder_open .o_main_navbar.d-none:not(:visible)",
}, {
content: "Translatable text became highlighted",
trigger: ":iframe [data-oe-translation-state=to_translate]",
timeout,
}, {
content: "Confirm popup",
trigger: ".o_website_dialog .btn-secondary",
run: "click",
}
];
}
function saveTranslation(timeout = 50000) {
return [
{
content: "Save translation",
trigger: ".o-website-builder_sidebar button[data-action=save]",
run: "click",
}, {
content: "Back to preview mode",
trigger: ".o_edit_website_container button",
timeout,
}, {
trigger: "body:not(.o_builder_open)",
noPrepend: true,
timeout,
},
stepUtils.waitIframeIsReady(),
awaitTranslationIsReady,
];
}
function multiLanguage(mainLanguage, secondLanguage) {
return [
{
content: "Ensure multi language site",
trigger: ":iframe body:has(.js_language_selector)",
},
// new page
...createNewPage(),
...switchLanguage(secondLanguage),
...openTranslate(),
{
content: "Translate some text",
trigger: ":iframe h1 [data-oe-translation-state=to_translate]",
run: "editor Some translated text",
},
...saveTranslation(),
{
content: "Check translation is displayed",
trigger: ":iframe h1:contains(Some translated text)",
},
...openHtmlEditor(),
{
content: "Change text",
trigger: 'div.ace_line .ace_xml:contains("oe_structure")',
run() {
window.ace.edit(document.querySelector("#resource-editor div"))
.getSession()
.insert({row: 6, column: 50}, "more text ");
},
},
{
content: "Pollute old DOM to detect reload",
trigger: ":iframe body",
run() {
this.anchor.dataset.reloaded = false;
},
},
...saveHtmlEditor(),
{
content: "Ensure page is NOT updated",
trigger: ":iframe body:not([data-reloaded=false]) h1:not(:contains(more text))",
},
...switchLanguage(mainLanguage),
{
content: "Ensure French page IS updated",
trigger: ":iframe h1:contains(more text)",
},
...clickOnEditAndWaitEditMode(),
{
content: "Change text again",
trigger: ":iframe h1",
run: "editor Yet another version of the text.",
},
...clickOnSave("bottom", 50000, false),
...switchLanguage(secondLanguage),
{
content: "Ensure English page is NOT updated",
trigger: ":iframe h1:not(:contains(Yet another))",
},
...openTranslate(),
{
content: "Ensure English page is updated",
trigger: ":iframe h1:contains(Yet another)",
},
{
content: "Translate again",
trigger: ":iframe h1 [data-oe-translation-state=to_translate]",
run: "editor Yet another translated text",
},
...saveTranslation(),
{
content: "Check translation is displayed",
trigger: ":iframe h1:contains(Yet another translated text)",
},
// xml record
{
content: "Go to test_view page",
trigger: ":iframe main section.s_banner a",
run: "click",
},
{
content: "Wait until page is reached",
trigger: ":iframe body:contains(Test View)",
},
...switchLanguage(mainLanguage),
...clickOnEditAndWaitEditMode(),
{
content: "Edit template text",
trigger: ":iframe main p.o_editable[contenteditable='true']",
run: "editor Modified View",
},
...clickOnSave("bottom", 50000, false),
...switchLanguage(secondLanguage),
...openTranslate(),
{
content: "Translate test view",
trigger: ":iframe main > p > span[data-oe-translation-state=to_translate]",
run: "editor Some translated view",
},
...saveTranslation(),
{
content: "Check translation is displayed",
trigger: ":iframe p:contains(Some translated view)",
},
...switchLanguage(mainLanguage),
...openHtmlEditor(),
{
content: "Change text",
trigger: 'div.ace_line .ace_xml:contains("test_website.test_view")',
run() {
window.ace.edit(document.querySelector("#resource-editor div"))
.getSession()
.insert({row: 2, column: 36}, 'Further ');
},
},
...saveHtmlEditor(),
{
content: "Ensure view is updated",
trigger: ":iframe body:contains(Further Modified View)",
},
...clickOnEditAndWaitEditMode(),
{
content: "Edit template text",
trigger: ":iframe main p.o_editable[data-oe-field='arch'][contenteditable='true']",
run: "editor Even more modified Text",
},
...clickOnSave("bottom", 50000, false),
...switchLanguage(secondLanguage),
{
content: "Check old translation is displayed",
trigger: ":iframe p:contains(Some translated view)",
},
...openTranslate(),
{
content: "Check new original is displayed",
trigger: ":iframe p:contains(Even more modified text)",
},
{
content: "Translate test view",
trigger: ":iframe main > p > span[data-oe-translation-state=to_translate]",
run: "editor Even more translated text",
},
...saveTranslation(),
{
content: "Check new translation is displayed",
trigger: ":iframe p:contains(Even more translated text)",
},
];
}
registerWebsitePreviewTour(
"translation_multi_language_fr_user_fr_en_site",
{
url: "/fr",
},
() => [
ensureFrUser,
ensureFrSite,
...multiLanguage("fr", "en"),
]
);
registerWebsitePreviewTour(
"translation_multi_language_fr_user_en_fr_site",
{
url: "/en",
},
() => [
ensureFrUser,
ensureEnSite,
...multiLanguage("en", "fr"),
]
);
registerWebsitePreviewTour(
"translation_multi_language_en_user_fr_en_site",
{
url: "/fr",
},
() => [
ensureEnUser,
ensureFrSite,
...multiLanguage("fr", "en"),
]
);
registerWebsitePreviewTour(
"translation_multi_language_en_user_en_fr_site",
{
url: "/en",
},
() => [
ensureEnUser,
ensureEnSite,
...multiLanguage("en", "fr"),
]
);

View file

@ -0,0 +1,66 @@
import {
clickOnSave,
registerWebsitePreviewTour,
changeOptionInPopover,
} from "@website/js/tours/tour_utils";
function assertEqual(actual, expected) {
if (actual !== expected) {
throw new Error(`Assert failed: expected: ${expected} ; got: ${actual}`);
}
}
registerWebsitePreviewTour('website_controller_page_listing_layout', {
url: '/model/exposed-model',
edition: true,
}, () => [
{
content: "website is in preview mode",
trigger: '.o_website_preview',
run: "click",
},
{
content: "records are listed in grid mode by default",
trigger: ':iframe .o_website_grid',
run() {
const iframeDocument = document.querySelector(".o_website_preview iframe").contentDocument;
// grid option is selected by default in the switch
assertEqual(iframeDocument.querySelector(".listing_layout_switcher #o_wstudio_apply_grid").checked, true);
assertEqual([...iframeDocument.querySelectorAll(".test_record_listing")].length, 2);
},
},
{
content: "open customize tab",
trigger: ":iframe .listing_layout_switcher",
run: "click",
},
{
trigger: ".o-snippets-menu .o_customize_tab",
},
...changeOptionInPopover("Layout", "Default Layout", "list"),
{
content: "records are now displayed in list mode",
trigger: ':iframe .o_website_list',
run() {
const iframeDocument = document.querySelector(".o_website_preview iframe").contentDocument;
// list option is now selected in the switch
assertEqual(iframeDocument.querySelector(".listing_layout_switcher #o_wstudio_apply_list").checked, true);
},
},
...clickOnSave(),
]);
registerWebsitePreviewTour('website_controller_page_default_page_check', {
url: '/model/exposed-model',
}, () => [
{
content: "records are listed in list mode by default",
trigger: ':iframe [is-ready=true] .o_website_list',
run() {
const iframeDocument = document.querySelector(".o_website_preview iframe").contentDocument;
// list option is selected by default in the switch
assertEqual(iframeDocument.querySelector(".listing_layout_switcher #o_wstudio_apply_list").checked, true);
assertEqual([...iframeDocument.querySelectorAll(".test_record_listing")].length, 2);
},
},
]);

View file

@ -0,0 +1,60 @@
import { clickOnSave, registerWebsitePreviewTour } from "@website/js/tours/tour_utils";
// As admin, add a YouTube video iframe in a `sanitize_overridable` HTML field.
registerWebsitePreviewTour("website_designer_iframe_video",
{
url: "/test_website/model_item/1",
edition: true,
},
() => [
{
content: "As administrator, add a video block to the description field",
trigger: `.o_block_tab:not(.o_we_ongoing_insertion) #snippet_content .o_snippet[name="Video"].o_draggable .o_snippet_thumbnail`,
run: "drag_and_drop :iframe .o_test_website_description",
},
{
content: "Add a video URL",
trigger: ".o_select_media_dialog #o_video_text",
run: `edit https://www.youtube.com/watch?v=G8b4UZIcTfg`,
},
{
content: "Add the video",
trigger: ".o_select_media_dialog .modal-footer .btn-primary",
run: "click",
},
...clickOnSave(),
{
content: "Check that the video was correctly saved",
trigger: ":iframe .media_iframe_video[data-oe-expression*='G8b4UZIcTfg']",
run: () => {},
},
]
);
// Check that a restricted editor can edit the field content (even with
// a video iframe).
registerWebsitePreviewTour("website_restricted_editor_iframe_video", {
url: "/test_website/model_item/1",
edition: true,
},
() => [
{
content: "Check that the video iframe was correctly restored after saving the changes",
trigger:
":iframe [data-oe-field]:not([data-oe-sanitize-prevent-edition]) .media_iframe_video[data-oe-expression*='G8b4UZIcTfg']",
run: () => {},
},
{
content: "As a restricted editor, edit the HTML field content",
trigger: ":iframe .o_test_website_description",
run: "editor I can still edit the HTML field",
},
...clickOnSave(),
{
content: "Check that the HTML content (with a video iframe) was correctly updated",
trigger:
":iframe .o_test_website_description:contains('I can still edit the HTML field')",
run: () => {},
},
]
);

View file

@ -0,0 +1,382 @@
import {
assertPathName,
clickOnSave,
getClientActionUrl,
registerWebsitePreviewTour,
} from "@website/js/tours/tour_utils";
import { stepUtils } from "@web_tour/tour_utils";
const openPagePropertiesDialog = [
{
content: "Open Site backend menu",
trigger: '[data-menu-xmlid="website.menu_site"]',
run: "click",
},
{
content: "Open page properties dialog",
trigger: '[data-menu-xmlid="website.menu_page_properties"]',
run: "click",
},
];
const clickOnSaveButtonStep = [
{
content: "Click on Save & Close",
trigger: ".o_form_button_save:enabled",
run: "click",
},
{
content: "Wait",
trigger: "body:not(.modal-open)",
}
];
const openCreatePageDialog = [
{
content: "Open create content menu",
trigger: ".o_new_content_container button",
run: "click",
},
{
content: "Create a new page",
trigger: 'button[aria-label="New Page"]',
run: "click",
},
];
function assertPageCanonicalUrlIs(url) {
return [
{
content: `Verify page canonical url is ${url}`,
trigger: `:iframe head:hidden link[rel="canonical"][href$="${url}"]`,
},
];
}
function checkIsTemplate(isTemplate, pageTitle = undefined) {
return [
...openCreatePageDialog,
{
trigger: 'button[data-id="custom"]',
},
{
content: "Go to custom section",
trigger: 'button[data-id="custom"]',
run: "click",
},
...(isTemplate
? [
{
content: `Verify template ${pageTitle} exists`,
trigger: `.o_page_template .o_page_name:contains(${pageTitle}):hidden`,
},
]
: [
{
trigger: ".o_website_page_templates_pane .alert-info",
},
{
content: `Verify custom templates section is empty`,
trigger: `.o_website_page_templates_pane:not(:has(.o_page_template))`,
},
]
),
{
content: "Exit dialog",
trigger: ".modal-header .btn-close",
run: "click",
},
{
content: "Exit new content backdrop",
trigger: "body",
run: "press escape",
}
];
}
function testCommonProperties(url, canPublish, modifiedUrl = undefined) {
if (!modifiedUrl) {
modifiedUrl = url;
}
const steps = {
setup: [
{
content: "Open Edit Menu dialog",
trigger: '.o_field_widget[name="is_in_menu"] + .btn-link',
run: "click",
},
{
content: "Check that menu editor was opened",
trigger: ".oe_menu_editor",
},
{
content: "Close Edit Menu dialog",
trigger: ".modal:has(.oe_menu_editor) .btn-close",
run: "click",
},
{
content: "Add to menu",
trigger: "#is_in_menu_0",
run: "check",
},
{
content: "Set as homepage",
trigger: "#is_homepage_0",
run: "check",
},
],
check: [
{
content: "Verify is in menu",
trigger: `:visible :iframe #top_menu a[href="${modifiedUrl}"]`,
},
stepUtils.goToUrl(getClientActionUrl("/")),
...assertPageCanonicalUrlIs(modifiedUrl),
stepUtils.goToUrl(getClientActionUrl(modifiedUrl)),
],
teardown: [
{
content: "Remove from menu",
trigger: "#is_in_menu_0",
run: "uncheck",
},
{
content: "Unset as homepage",
trigger: "#is_homepage_0",
run: "uncheck",
},
],
checkTorndown: [
{
content: "Verify is not in menu",
trigger: `:visible :iframe #top_menu:not(:has(a[href="${url}"]))`,
},
stepUtils.goToUrl(getClientActionUrl("/")),
...assertPageCanonicalUrlIs("/"),
stepUtils.goToUrl(getClientActionUrl(url)),
],
finalize() {
return [
...openPagePropertiesDialog,
...this.setup,
...clickOnSaveButtonStep,
...this.check,
...openPagePropertiesDialog,
...this.teardown,
...clickOnSaveButtonStep,
...this.checkTorndown,
];
},
};
if (canPublish) {
steps.setup.push({
content: "Publish",
trigger: "#is_published_0",
run: "check",
});
steps.check.push({
content: "Verify is published",
trigger: '[data-hotkey="p"] .form-check input:checked',
});
steps.teardown.push({
content: "Unpublish",
trigger: "#is_published_0",
run: "uncheck",
});
steps.checkTorndown.push({
content: "Verify is not published",
trigger: '[data-hotkey="p"] .form-check input:not(:checked)',
});
}
return steps;
}
function testWebsitePageProperties() {
const steps = testCommonProperties("/new-page", true, "/cool-page");
steps.setup.unshift(
{
content: "Change page title",
trigger: "#name_0",
run: "edit Cool Page",
},
{
content: `Change url to /cool-page`,
trigger: "#url_0",
run: `edit cool-page && press Enter`,
},
{
content: "Enable old url redirect",
trigger: "#redirect_old_url_0",
run: "check",
},
{
content: "Open redirect type popup",
trigger: "#redirect_type_0",
run: "click"
},
{
content: "Set redirect type to temporary",
trigger: ".o-dropdown-item[data-choice-index='1']",
run: "click"
},
{
// TODO: this needs to be tested
content: "Change date published",
trigger: "#date_publish_0",
run: "edit 02/01/2005 01:00:00 && press enter",
},
{
content: "Don't index",
trigger: "#website_indexed_0",
run: "uncheck",
},
{
content: "Open visibility popup",
trigger: "#visibility_0",
run: "click",
},
{
// TODO: this needs to be tested
content: "Make visible with password only",
trigger: ".o-dropdown-item[data-choice-index='3']",
run: "click",
},
{
content: "Set password to 123",
trigger: "#visibility_password_display_0",
run: "edit 123",
},
{
content: "Make it a template",
trigger: "#is_new_page_template_0",
run: "check",
},
);
steps.check.push(
{
content: "Verify page title",
trigger: ":iframe head:hidden title:contains(/Cool Page/)",
},
...assertPageCanonicalUrlIs("/cool-page"),
stepUtils.goToUrl(getClientActionUrl("/new-page")),
assertPathName("/cool-page", "body"),
{
content: "Verify no index",
trigger: ':iframe head:hidden meta[name="robots"][content="noindex"]',
},
...checkIsTemplate(true, "Cool Page"),
);
steps.teardown.unshift(
{
content: "Reset page title",
trigger: "#name_0",
run: `edit New Page`,
},
{
content: `Change url back to /new-page`,
trigger: "#url_0",
run: `edit new-page && press Enter`,
},
{
content: "Open date published popup",
trigger: "#date_publish_0",
run: "click",
},
{
content: "Reset date published",
trigger: "button[title='Clear']",
run: "click",
},
{
content: "Do index",
trigger: "#website_indexed_0",
run: "check",
},
{
content: "Open visibility popup",
trigger: "#visibility_0",
run: "click",
},
{
content: "Make visible public",
trigger: ".o-dropdown-item[data-choice-index='0']",
run: "click",
},
{
content: "Remove from templates",
trigger: "#is_new_page_template_0",
run: "uncheck",
},
);
steps.checkTorndown.push(
{
content: "Verify page title",
trigger: ":iframe head:hidden title:contains(/New Page/)",
},
...assertPageCanonicalUrlIs("/new-page"),
stepUtils.goToUrl(getClientActionUrl("/new-page")),
assertPathName("/new-page", "body"),
{
content: "Verify is indexed",
trigger: ':iframe head:hidden:not(:has(meta[name="robots"][content="noindex"]))',
},
...checkIsTemplate(false),
);
return steps;
}
registerWebsitePreviewTour(
"website_page_properties_common",
{
url: "/test_view",
},
() => [...testCommonProperties("/test_view", false).finalize()],
);
registerWebsitePreviewTour(
"website_page_properties_can_publish",
{
url: "/test_website/model_item/1",
},
() => [...testCommonProperties("/test_website/model_item/1", true).finalize()],
);
registerWebsitePreviewTour(
"website_page_properties_website_page",
{
url: "/",
},
() => [
...openCreatePageDialog,
{
content: "Use blank template",
trigger: ".o_page_template .o_button_area:hidden",
run: "click",
},
{
content: "Name page",
trigger: ".modal-body input",
run: "edit New Page",
},
{
content: "Don't add to menu",
trigger: ".modal-body .o_switch",
run: "click",
},
{
content: "Click on Create button",
trigger: ".modal-footer .btn-primary",
run: "click",
},
{
content: "Wait for editor to open",
trigger: ":iframe body.editor_enable",
timeout: 30000,
},
...clickOnSave(),
...testWebsitePageProperties().finalize(),
],
);

View file

@ -1,49 +1,39 @@
/** @odoo-module */
import tour from "web_tour.tour";
import { registry } from "@web/core/registry";
import { stepUtils } from "@web_tour/tour_utils";
const websiteName = "Website Test Settings";
tour.register("website_settings_m2o_dirty", {
test: true,
url: "/web",
},
[
tour.stepUtils.showAppsMenuItem(),
{
content: "open settings",
trigger: ".o_app[data-menu-xmlid='base.menu_administration'",
}, {
content: "open website settings",
trigger: ".settings_tab .tab[data-key='website']",
}, {
content: "check that the 'Shared Customers Accounts' setting is checked",
trigger: "input#shared_user_account:checked",
run: function () {}, // it's a check
}, {
content: "open website switcher",
trigger: "input#website_id",
}, {
content: `select ${websiteName} in the website switcher`,
trigger: `li:has(.dropdown-item:contains('${websiteName}'))`,
}, {
content: `check that the settings of ${websiteName} are loaded (Shared Customers Accounts)`,
trigger: "input#shared_user_account:not(:checked)",
run: function () {}, // it's a check
}, {
content: "click on the fake website setting after checking the edited website",
trigger: "button[name='action_website_test_setting']",
}, {
content: "check that we are on '/'",
trigger: "iframe body div#wrap",
run: function () {
if (window.location.pathname !== "/") {
// If this fails, it's probably because the change of website
// in the settings dirty the record and so there is a dialog
// save/discard displayed. This test ensure that does not happen
// because it makes actions unreachable in multi website.
console.error("We should be on '/' the settings didn't work");
}
}
},
]);
registry.category("web_tour.tours").add("website_settings_m2o_dirty", {
url: "/odoo",
steps: () => [
stepUtils.showAppsMenuItem(),
{
content: "open settings",
trigger: ".o_app[data-menu-xmlid='base.menu_administration']",
run: "click",
},
{
content: "open website settings",
trigger: ".settings_tab .tab[data-key='website']",
run: "click",
},
{
content: "check that the 'Shared Customers Accounts' setting is checked",
trigger: "input[id^='shared_user_account']:checked",
},
{
content: "open website switcher",
trigger: "input[id^='website_id']",
run: `edit ${websiteName}`,
},
{
content: `select ${websiteName} in the website switcher`,
trigger: `li:has(.dropdown-item:contains('${websiteName}'))`,
run: "click",
},
{
content: `check that the settings of ${websiteName} are loaded (Shared Customers Accounts)`,
trigger: "input[id^='shared_user_account']:not(:checked)",
},
],
});