summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/tests/field_html_tests.js
diff options
context:
space:
mode:
authorAntoine Guenet <age@odoo.com>2018-12-28 17:59:35 +0000
committerChristophe Matthieu <chm@odoo.com>2019-01-17 08:40:21 +0000
commiteb0ea8efbe932c140302e9f8da33a839bcd73146 (patch)
treee097625171b2b67ed5f5288ced67446608b9f633 /addons/web_editor/static/tests/field_html_tests.js
parentf296992317e96562c66bd7ad59a5080d6c551ed5 (diff)
[ADD] web_editor,*: Tests for new structure of web editor
The refactoring also had to be done in order to create a set of unit tests. Each behavior can be tested, including the behaviors performed as a consequence of keyboard interactions (for instance: Enter, Tab...). This commit also contains some changes to test_utils that were necessary given the new structure of the wysiwyg editor. Co-authored-by: Gorash <chm@odoo.com>
Diffstat (limited to 'addons/web_editor/static/tests/field_html_tests.js')
-rw-r--r--addons/web_editor/static/tests/field_html_tests.js954
1 files changed, 761 insertions, 193 deletions
diff --git a/addons/web_editor/static/tests/field_html_tests.js b/addons/web_editor/static/tests/field_html_tests.js
index 1995add777d..b01ab48586b 100644
--- a/addons/web_editor/static/tests/field_html_tests.js
+++ b/addons/web_editor/static/tests/field_html_tests.js
@@ -1,327 +1,895 @@
-odoo.define('web_editor.web_editor_tests', function (require) {
+odoo.define('web_editor.field_html_tests', function (require) {
"use strict";
+var ajax = require('web.ajax');
var FormView = require('web.FormView');
var testUtils = require('web.test_utils');
+var weTestUtils = require('web_editor.test_utils');
var core = require('web.core');
-var web_editor = require('web_editor.editor');
+var Wysiwyg = require('web_editor.wysiwyg');
+var MediaDialog = require('wysiwyg.widgets.MediaDialog');
var _t = core._t;
-QUnit.module('web_editor', {
- beforeEach: function() {
- this.data = {
+QUnit.module('web_editor', {}, function () {
+
+QUnit.module('field html', {
+ beforeEach: function () {
+ this.data = weTestUtils.wysiwygData({
+ 'note.note': {
+ fields: {
+ display_name: {
+ string: "Displayed name",
+ type: "char"
+ },
+ body: {
+ string: "Message",
+ type: "html"
+ },
+ },
+ records: [{
+ id: 1,
+ display_name: "first record",
+ body: "<p>toto toto toto</p><p>tata</p>",
+ }],
+ },
'mass.mailing': {
fields: {
- display_name: { string: "Displayed name", type: "char" },
- body: {string: "Message Body", type: "html"},
+ display_name: {
+ string: "Displayed name",
+ type: "char"
+ },
+ body_html: {
+ string: "Message Body inline (to send)",
+ type: "html"
+ },
+ body_arch: {
+ string: "Message Body for edition",
+ type: "html"
+ },
},
records: [{
id: 1,
display_name: "first record",
- body: "<div class='field_body'>yep</div>",
+ body_html: "<div class='field_body' style='background-color: red;'>yep</div>",
+ body_arch: "<div class='field_body'>yep</div>",
}],
- onchanges: {},
},
- };
- }
-});
+ });
+
+ testUtils.mock.patch(ajax, {
+ loadAsset: function (xmlId) {
+ if (xmlId === 'template.assets') {
+ return $.when({
+ cssLibs: [],
+ cssContents: ['body {background-color: red;}']
+ });
+ }
+ if (xmlId === 'template.assets_all_style') {
+ return $.when({
+ cssLibs: $('head link[href]:not([type="image/x-icon"])').map(function () {
+ return $(this).attr('href');
+ }).get(),
+ cssContents: ['body {background-color: red;}']
+ });
+ }
+ throw 'Wrong template';
+ },
+ });
+ },
+ afterEach: function () {
+ testUtils.mock.unpatch(ajax);
+ },
+}, function () {
+
+QUnit.module('basic');
-QUnit.test('field html widget', function (assert) {
+QUnit.test('simple rendering', function (assert) {
var done = assert.async();
assert.expect(3);
- var form = testUtils.createView({
+ testUtils.createAsyncView({
View: FormView,
- model: 'mass.mailing',
+ model: 'note.note',
data: this.data,
- arch: '<form string="Partners">' +
- '<field name="body" widget="html" style="height: 100px"/>' +
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px"/>' +
'</form>',
res_id: 1,
- });
-
- assert.strictEqual(form.$('.field_body').text(), 'yep',
- "should have rendered a div with correct content in readonly");
- assert.hasAttrValue(form.$('div[name=body]'), 'style', 'height: 100px',
- "should have applied the style correctly");
-
- testUtils.form.clickEdit(form);
-
- assert.strictEqual(form.$('.note-editable').html(), '<div class="field_body">yep</div>',
+ }).then(function (form) {
+ var $field = form.$('.oe_form_field[name="body"]');
+ assert.strictEqual($field.children('.o_readonly').html(),
+ '<p>toto toto toto</p><p>tata</p>',
+ "should have rendered a div with correct content in readonly");
+ assert.strictEqual($field.attr('style'), 'height: 100px',
+ "should have applied the style correctly");
+
+ form.$buttons.find('.o_form_button_edit').click();
+
+ $field = form.$('.oe_form_field[name="body"]');
+ assert.strictEqual($field.find('.note-editable').html(),
+ '<p>toto toto toto</p><p>tata</p>',
"should have rendered the field correctly in edit");
- // summernote invokes handlers after a setTimeout, so we must wait as well
- // before destroying the widget (otherwise we'll have a crash later on)
- setTimeout(function () {
form.destroy();
done();
- }, 0);
+ });
});
-QUnit.test('field html widget (with options inline-style)', function (assert) {
+QUnit.test('colorpicker', function (assert) {
var done = assert.async();
- assert.expect(3);
+ assert.expect(6);
- var form = testUtils.createView({
+ testUtils.createAsyncView({
View: FormView,
- model: 'mass.mailing',
+ model: 'note.note',
data: this.data,
- arch: '<form string="Partners">' +
- '<field name="body" widget="html" style="height: 100px" options="{\'style-inline\': true}"/>' +
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px"/>' +
'</form>',
res_id: 1,
- });
+ }).then(function (form) {
+ form.$buttons.find('.o_form_button_edit').click();
+ var $field = form.$('.oe_form_field[name="body"]');
+
+ // select the text
+ var pText = $field.find('.note-editable p').first().contents()[0];
+ Wysiwyg.setRange(pText, 1, pText, 10);
+ // text is selected
+
+ var range = Wysiwyg.getRange($field[0]);
+ assert.strictEqual(range.sc, pText,
+ "should select the text");
- assert.containsOnce(form, 'iframe',
- "should have rendered an iframe without crashing in readonly");
- assert.hasAttrValue(form.$('div[name=body]'), 'style', 'height: 100px',
- "should have applied the style correctly");
+ $field.find('.note-toolbar .note-bg-color button:first').mousedown().click();
- testUtils.form.clickEdit(form);
+ assert.ok($field.find('.note-bg-color').hasClass('show') && $field.find('.note-bg-color .dropdown-menu').hasClass('show'),
+ "should display the color picker");
- assert.strictEqual(form.$('.note-editable').html(), '<div class="field_body">yep</div>',
+ $field.find('.note-toolbar .note-bg-color button[data-value="#00FFFF"]').mousedown().click();
+
+ assert.ok(!$field.find('.note-bg-color').hasClass('show') && !$field.find('.note-bg-color .dropdown-menu').hasClass('show'),
+ "should close the color picker");
+
+ assert.strictEqual($field.find('.note-editable').html(),
+ '<p>t<font style="background-color: rgb(0, 255, 255);">oto toto&nbsp;</font>toto</p><p>tata</p>',
+ "should have rendered the field correctly in edit");
+
+ var fontContent = $field.find('.note-editable font').contents()[0];
+ var rangeControl = {
+ sc: fontContent,
+ so: 0,
+ ec: fontContent,
+ eo: fontContent.length,
+ };
+ range = Wysiwyg.getRange($field[0]);
+ assert.deepEqual(_.pick(range, 'sc', 'so', 'ec', 'eo'), rangeControl,
+ "should select the text after color change");
+
+ // select the text
+ pText = $field.find('.note-editable p').first().contents()[2];
+ Wysiwyg.setRange(fontContent, 5, pText, 2);
+ // text is selected
+
+ $field.find('.note-toolbar .note-bg-color button:first').mousedown().click();
+ $field.find('.note-toolbar .note-bg-color button[data-value="bg-gamma"]').mousedown().click();
+
+ assert.strictEqual($field.find('.note-editable').html(),
+ '<p>t<font style="background-color: rgb(0, 255, 255);">oto t</font><font class="bg-gamma">oto&nbsp;to</font>to</p><p>tata</p>',
"should have rendered the field correctly in edit");
- // summernote invokes handlers after a setTimeout, so we must wait as well
- // before destroying the widget (otherwise we'll have a crash later on)
- setTimeout(function () {
form.destroy();
done();
- }, 0);
+ });
});
-QUnit.test('field html translatable', function (assert) {
- assert.expect(3);
-
- var multiLang = _t.database.multi_lang;
- _t.database.multi_lang = true;
-
- this.data['mass.mailing'].fields.body.translate = true;
+QUnit.test('media dialog: image', function (assert) {
+ var done = assert.async();
+ assert.expect(1);
- var form = testUtils.createView({
+ testUtils.createAsyncView({
View: FormView,
- model: 'mass.mailing',
+ model: 'note.note',
data: this.data,
- arch: '<form string="Partners">' +
- '<field name="body" widget="html"/>' +
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px"/>' +
'</form>',
res_id: 1,
mockRPC: function (route, args) {
- if (route === '/web/dataset/call_button' && args.method === 'translate_fields') {
- assert.deepEqual(args.args, ['mass.mailing',1,'body',{}], "should call 'call_button' route");
- return $.when();
+ if (args.model === 'ir.attachment') {
+ if (args.method === "generate_access_token") {
+ return $.when();
+ }
+ if (args.kwargs.domain[7][2].join(',') === "image/gif,image/jpe,image/jpeg,image/jpg,image/gif,image/png") {
+ return $.when([{
+ "id": 1,
+ "public": true,
+ "name": "image",
+ "datas_fname": "image.png",
+ "mimetype": "image/png",
+ "checksum": false,
+ "url": "/web_editor/static/src/img/transparent.png",
+ "type": "url",
+ "res_id": 0,
+ "res_model": false,
+ "access_token": false
+ }]);
+ }
}
- return this._super.apply(this, arguments);
+ return this._super(route, args);
},
- });
+ }).then(function (form) {
+ form.$buttons.find('.o_form_button_edit').click();
+ var $field = form.$('.oe_form_field[name="body"]');
+
+ // the dialog load some xml assets
+ var defMediaDialog = $.Deferred();
+ testUtils.mock.patch(MediaDialog, {
+ init: function () {
+ this._super.apply(this, arguments);
+ this.opened(defMediaDialog.resolve.bind(defMediaDialog));
+ }
+ });
+
+ var pText = $field.find('.note-editable p').first().contents()[0];
+ Wysiwyg.setRange(pText, 1);
+
+ $field.find('.note-toolbar .note-insert button:has(.fa-file-image-o)').mousedown().click();
+
+ // load static xml file (dialog, media dialog, unsplash image widget)
+ defMediaDialog.then(function () {
+ $('.modal #editor-media-image .o_image:first').click();
+ $('.modal .modal-footer button.btn-primary').click();
- assert.containsNone(form, '.oe_form_field_html_text .o_field_translate',
- "should not have a translate button in readonly mode");
+ var $editable = form.$('.oe_form_field[name="body"] .note-editable');
- testUtils.form.clickEdit(form);
- var $button = form.$('.oe_form_field_html_text .o_field_translate');
- assert.strictEqual($button.length, 1, "should have a translate button");
- testUtils.dom.click($button);
+ assert.strictEqual($editable.data('wysiwyg').getValue(),
+ '<p>t<img class="img-fluid o_we_custom_image" data-src="/web_editor/static/src/img/transparent.png">oto toto toto</p><p>tata</p>',
+ "should have the image in the dom");
- form.destroy();
- _t.database.multi_lang = multiLang;
+ testUtils.mock.unpatch(MediaDialog);
+
+ form.destroy();
+ done();
+ });
+ });
});
-QUnit.test('field html_frame widget', function (assert) {
- assert.expect(6);
+QUnit.test('media dialog: icon', function (assert) {
+ var done = assert.async();
+ assert.expect(1);
- var form = testUtils.createView({
+ testUtils.createAsyncView({
View: FormView,
- model: 'mass.mailing',
+ model: 'note.note',
data: this.data,
- arch: '<form string="Partners">' +
- '<field name="body" widget="html_frame" options="{\'editor_url\': \'/logo\'}"/>' +
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px"/>' +
'</form>',
res_id: 1,
- session: {user_context: {lang: "en_us"}},
- mockRPC: function (route) {
- if (_.str.startsWith(route, '/logo')) {
- // those tests will be executed twice, once in readonly and once in edit
- assert.ok(route.search('model=mass.mailing') > 0,
- "the route should specify the correct model");
- assert.ok(route.search('res_id=1') > 0,
- "the route should specify the correct id");
- return $.when();
+ mockRPC: function (route, args) {
+ if (args.model === 'ir.attachment') {
+ return $.when([]);
}
- return this._super.apply(this, arguments);
+ return this._super(route, args);
},
- });
+ }).then(function (form) {
+ form.$buttons.find('.o_form_button_edit').click();
+ var $field = form.$('.oe_form_field[name="body"]');
+
+ // the dialog load some xml assets
+ var defMediaDialog = $.Deferred();
+ testUtils.mock.patch(MediaDialog, {
+ init: function () {
+ this._super.apply(this, arguments);
+ this.opened(defMediaDialog.resolve.bind(defMediaDialog));
+ }
+ });
+
+ var pText = $field.find('.note-editable p').first().contents()[0];
+ Wysiwyg.setRange(pText, 1);
+
+ $field.find('.note-toolbar .note-insert button:has(.fa-file-image-o)').mousedown().click();
+
+ // load static xml file (dialog, media dialog, unsplash image widget)
+ defMediaDialog.then(function () {
+ $('.modal .tab-content .tab-pane').removeClass('fade'); // to be sync in test
+ $('.modal a[aria-controls="editor-media-icon"]').click();
+ $('.modal #editor-media-icon .font-icons-icon.fa-glass').click();
+ $('.modal .modal-footer button.btn-primary').click();
- assert.containsOnce(form, 'iframe', "should have rendered an iframe without crashing");
+ var $editable = form.$('.oe_form_field[name="body"] .note-editable');
- testUtils.form.clickEdit(form);
+ assert.strictEqual($editable.data('wysiwyg').getValue(),
+ '<p>t<span class="fa fa-glass"></span>oto toto toto</p><p>tata</p>',
+ "should have the image in the dom");
- assert.containsOnce(form, 'iframe', "should have rendered an iframe without crashing");
+ testUtils.mock.unpatch(MediaDialog);
- form.destroy();
+ form.destroy();
+ done();
+ }, 200);
+ });
});
-QUnit.test('field htmlsimple does not crash when commitChanges is called in mode=readonly', function (assert) {
+QUnit.test('save', function (assert) {
+ var done = assert.async();
assert.expect(1);
- var form = testUtils.createView({
+ testUtils.createAsyncView({
View: FormView,
- model: 'mass.mailing',
+ model: 'note.note',
data: this.data,
- arch: '<form string="Partners">' +
- '<header>' +
- '<button name="some_method" class="s" string="Do it" type="object"/>' +
- '</header>' +
- '<sheet>' +
- '<field name="body"/>' +
- '</sheet>' +
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px"/>' +
'</form>',
res_id: 1,
- intercepts: {
- execute_action: function () {
- assert.step('execute_action');
+ mockRPC: function (route, args) {
+ if (args.method === "write") {
+ assert.strictEqual(args.args[1].body,
+ '<p>t<font class="bg-gamma">oto toto&nbsp;</font>toto</p><p>tata</p>',
+ "should save the content");
+
}
+ return this._super.apply(this, arguments);
},
- });
+ }).then(function (form) {
+ form.$buttons.find('.o_form_button_edit').click();
+ var $field = form.$('.oe_form_field[name="body"]');
+
+ // select the text
+ var pText = $field.find('.note-editable p').first().contents()[0];
+ Wysiwyg.setRange(pText, 1, pText, 10);
+ // text is selected
+
+ $field.find('.note-toolbar .note-bg-color button:first').mousedown().click();
+ $field.find('.note-toolbar .note-bg-color button[data-value="bg-gamma"]').mousedown().click();
+
+ form.$buttons.find('.o_form_button_save').click();
- testUtils.dom.click(form.$('button:contains(Do it)'));
- form.destroy();
+ form.destroy();
+ done();
+ });
});
-QUnit.test('html_frame does not crash when saving in readonly', function (assert) {
- // The 'Save' action may be triggered even in readonly (e.g. when clicking
- // on a button in the form view)
- assert.expect(2);
+QUnit.module('inline-style');
+
+QUnit.test('convert style to class on edit', function (assert) {
+ var done = assert.async();
+ assert.expect(5);
+
+ this.data['note.note'].records[0].body = '<p class="pull-right" style="float: right;">toto ' +
+ '<img data-class="fa fa-star" data-style="color: red;" src="/web_editor/font_to_img/61445/rgb(255,0,0)/13" style="border-style:none;vertical-align:middle;height: auto; width: auto;">' +
+ 'toto toto</p><p>tata</p>';
- var form = testUtils.createView({
+ testUtils.createAsyncView({
View: FormView,
- model: 'mass.mailing',
+ model: 'note.note',
data: this.data,
- arch: '<form string="Partners">' +
- '<sheet>' +
- '<field name="body" widget="html_frame" options="{\'editor_url\': \'/logo\'}"/>' +
- '</sheet>' +
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px" options="{\'style-inline\': true}"/>' +
'</form>',
res_id: 1,
mockRPC: function (route, args) {
- if (args.method) {
- assert.step(args.method);
+ if (args.method === "write") {
+ assert.strictEqual(args.args[1].body,
+ '<p class="pull-right" style="margin:0px;font-size:13px;font-family:&quot;Lucida Grande&quot;, Helvetica, Verdana, Arial, sans-serif;float:right;">' +
+ 'toto ' +
+ '<img ' +
+ 'data-class="fa fa-star" ' +
+ 'data-style="color: red;" ' +
+ 'style="border-style:none;vertical-align:middle;color: red; height: auto; width: auto;" ' +
+ 'data-src="/web_editor/font_to_img/61445/rgb(255,0,0)/13"' +
+ '>' +
+ 'toto toto' +
+ '</p>' +
+ '<p style="margin:0px;font-size:13px;font-family:&quot;Lucida Grande&quot;, Helvetica, Verdana, Arial, sans-serif;">' +
+ 'tata' +
+ '</p>',
+ "should save the content");
}
- if (_.str.startsWith(route, '/logo')) {
- // manually call the callback to simulate that the iframe has
- // been loaded (note: just the content, not the editor)
- window.odoo[$.deparam(route).callback + '_content'].call();
- return $.when();
+ if (route.indexOf("/web_editor/font_to_img/61445/rgb(") !== -1) {
+ assert.strictEqual(route,
+ '/web_editor/font_to_img/61445/rgb(255,0,0)/13',
+ "should use the image in function of the font and the color");
+ return $.when('#');
}
return this._super.apply(this, arguments);
},
+ }).then(function (form) {
+ var $field = form.$('.oe_form_field[name="body"]');
+
+ assert.strictEqual($field.children('.o_readonly').html(),
+ '<p class="pull-right" style="float: right;">' +
+ 'toto ' +
+ '<img data-class="fa fa-star" data-style="color: red;" ' +
+ 'style="border-style:none;vertical-align:middle;height: auto; width: auto;" ' +
+ 'data-src="/web_editor/font_to_img/61445/rgb(255,0,0)/13">' +
+ 'toto toto' +
+ '</p>' +
+ '<p>tata</p>',
+ "should have rendered a div with correct content in readonly");
+
+ form.$buttons.find('.o_form_button_edit').click();
+
+ $field = form.$('.oe_form_field[name="body"]');
+ assert.strictEqual($field.find('.note-editable').html(),
+ '<p class="pull-right">' +
+ 'toto ' +
+ '<span class="fa fa-star o_fake_not_editable" style="color: red;" contenteditable="false"></span>' +
+ 'toto toto' +
+ '</p>' +
+ '<p>tata</p>',
+ "should have rendered the field correctly in edit (remove inline style that used class)");
+
+ form.$buttons.find('.o_form_button_save').click();
+
+ form.destroy();
+ done();
});
+});
- form.saveRecord(); // before the fix done in this commit, it crashed here
+QUnit.module('cssReadonly');
- assert.verifySteps(['read']);
+QUnit.test('rendering with iframe for readonly mode', function (assert) {
+ var done = assert.async();
+ assert.expect(3);
- form.destroy();
+ testUtils.createAsyncView({
+ View: FormView,
+ model: 'note.note',
+ data: this.data,
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px" options="{\'cssReadonly\': \'template.assets\'}"/>' +
+ '</form>',
+ res_id: 1,
+ }).then(function (form) {
+ var $field = form.$('.oe_form_field[name="body"]');
+ var $iframe = $field.find('iframe.o_readonly');
+ $iframe.data('load-def').then(function () {
+ var doc = $iframe.contents()[0];
+ assert.strictEqual($(doc).find('#iframe_target').html(),
+ '<p>toto toto toto</p><p>tata</p>',
+ "should have rendered a div with correct content in readonly");
+
+ assert.strictEqual(doc.defaultView.getComputedStyle(doc.body).backgroundColor,
+ 'rgb(255, 0, 0)',
+ "should load the asset css");
+
+ form.$buttons.find('.o_form_button_edit').click();
+
+ $field = form.$('.oe_form_field[name="body"]');
+ assert.strictEqual($field.find('.note-editable').html(),
+ '<p>toto toto toto</p><p>tata</p>',
+ "should have rendered the field correctly in edit");
+
+ form.destroy();
+ done();
+ });
+ });
});
-QUnit.test('html_frame does not crash when saving in edit mode (editor not loaded)', function (assert) {
- // The 'Save' action may be triggered when saving in edit mode very fast
- // so that the editor may be not loaded, even though the content is!
- assert.expect(2);
+QUnit.module('cssEdit');
- var form = testUtils.createView({
+QUnit.test('rendering with iframe for edit mode', function (assert) {
+ var done = assert.async();
+ assert.expect(4);
+
+ testUtils.createAsyncView({
View: FormView,
- model: 'mass.mailing',
+ model: 'note.note',
data: this.data,
- arch: '<form string="Partners">' +
- '<sheet>' +
- '<field name="display_name"/>' +
- '<field name="body" widget="html_frame" options="{\'editor_url\': \'/logo\'}"/>' +
- '</sheet>' +
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px" options="{\'cssEdit\': \'template.assets\'}"/>' +
+ '</form>',
+ res_id: 1,
+ }).then(function (form) {
+ var $field = form.$('.oe_form_field[name="body"]');
+ assert.strictEqual($field.children('.o_readonly').html(),
+ '<p>toto toto toto</p><p>tata</p>',
+ "should have rendered a div with correct content in readonly");
+
+ form.$buttons.find('.o_form_button_edit').click();
+
+ $field = form.$('.oe_form_field[name="body"]');
+ var $iframe = $field.find('iframe');
+
+ $iframe.data('load-def').then(function () {
+ var doc = $iframe.contents()[0];
+ var $content = $('#iframe_target', doc);
+
+ assert.strictEqual($content.find('.note-editable').html(),
+ '<p>toto toto toto</p><p>tata</p>',
+ "should have rendered a div with correct content in edit mode");
+
+ assert.strictEqual(doc.defaultView.getComputedStyle(doc.body).backgroundColor,
+ 'rgb(255, 0, 0)',
+ "should load the asset css");
+
+ $content.find('.note-toolbar .note-bg-color button:first').mousedown().click();
+
+ assert.ok($content.find('.note-bg-color').hasClass('show') && $content.find('.note-bg-color .dropdown-menu').hasClass('show'),
+ "should display toolbar dropdown menu in iframe");
+
+ form.destroy();
+ done();
+ });
+ });
+});
+
+QUnit.test('use colorpicker and save', function (assert) {
+ var done = assert.async();
+ assert.expect(1);
+
+ testUtils.createAsyncView({
+ View: FormView,
+ model: 'note.note',
+ data: this.data,
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px" options="{\'cssEdit\': \'template.assets\'}"/>' +
'</form>',
res_id: 1,
mockRPC: function (route, args) {
- if (args.method) {
- assert.step(args.method);
- }
- if (_.str.startsWith(route, '/logo')) {
- // manually call the callback to simulate that the iframe has
- // been partially loaded (just the content, not the editor)
- window.odoo[$.deparam(route).callback + '_content']();
- return $.when();
+ if (args.method === "write") {
+ assert.strictEqual(args.args[1].body,
+ '<p>t<font class="bg-gamma">oto toto&nbsp;</font>toto</p><p>tata</p>',
+ "should save the content");
}
return this._super.apply(this, arguments);
},
+ }).then(function (form) {
+ form.$buttons.find('.o_form_button_edit').click();
+ var $field = form.$('.oe_form_field[name="body"]');
+ var $iframe = $field.find('iframe');
+
+ $iframe.data('load-def').then(function () {
+ var doc = $iframe.contents()[0];
+ var $content = $('#iframe_target', doc);
+ var $editable = $content.find('.note-editable');
+
+ // select the text
+ var pText = $editable.find('p').first().contents()[0];
+ Wysiwyg.setRange(pText, 1, pText, 10);
+ // text is selected
+
+ $content.find('.note-toolbar .note-bg-color button:first').mousedown().click();
+ $content.find('.note-toolbar .note-bg-color button[data-value="bg-gamma"]').mousedown().click();
+
+
+ form.$buttons.find('.o_form_button_save').click();
+
+ form.destroy();
+ done();
+ });
});
+});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input.o_input.o_field_char'), 'trululu');
- testUtils.form.clickSave(form); // crash without editor fully loaded
+QUnit.module('wrapper');
- assert.verifySteps(['read']);
+// todo add test wrapper
- form.destroy();
+QUnit.module('snippet (without iframe)');
+
+QUnit.test('rendering with snippet panel', function (assert) {
+ var done = assert.async();
+ assert.expect(1);
+
+ testUtils.createAsyncView({
+ View: FormView,
+ model: 'note.note',
+ data: this.data,
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px" options="{\'snippets\': \'web_editor.snippets\'}"/>' +
+ '</form>',
+ res_id: 1,
+ }).then(function (form) {
+ testUtils.mock.intercept(form, "snippets_loaded", function () {
+ assert.strictEqual(form.$('.oe_form_field #oe_snippets').length, 1,
+ "should display the snippet panel");
+ form.destroy();
+ done();
+ });
+ form.$buttons.find('.o_form_button_edit').click();
+ });
});
-QUnit.test('html_frame saving in edit mode (editor and content fully loaded)', function (assert) {
+QUnit.test('drag&drop snippet', function (assert) {
var done = assert.async();
- assert.expect(4);
+ assert.expect(1);
- var editorBar = new web_editor.Class();
- var loadDeferred = $.Deferred();
- var writeDeferred = $.Deferred();
+ testUtils.createAsyncView({
+ View: FormView,
+ model: 'note.note',
+ data: this.data,
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px" options="{\'snippets\': \'web_editor.snippets\'}"/>' +
+ '</form>',
+ res_id: 1,
+ }).then(function (form) {
+ var defSnippets = $.Deferred();
+ testUtils.mock.intercept(form, "snippets_loaded", function () {
+ defSnippets.resolve();
+ });
+
+ form.$buttons.find('.o_form_button_edit').click();
+ var $field = form.$('.oe_form_field[name="body"]');
+ var $editable = $field.find('.note-editable');
+
+ defSnippets.then(function () {
+ var $hr = $field.find('.oe_snippet_thumbnail:first');
+ testUtils.dom.dragAndDrop($hr, $editable.find('p'));
+
+ assert.strictEqual($editable.data('wysiwyg').getValue().replace(/\s+/g, ' '),
+ '<div class=\"s_hr pt32 pb32\"> <hr class=\"s_hr_1px s_hr_solid w-100 mx-auto\"> </div><p>toto toto toto</p><p>tata</p>',
+ "should drop the snippet");
+
+ form.destroy();
+ done();
+ });
+ });
+});
+
+// todo add test snippet + customize snippet
+
+QUnit.module('snippet & cssEdit');
- var form = testUtils.createView({
+QUnit.test('rendering with snippet panel', function (assert) {
+ var done = assert.async();
+ assert.expect(1);
+
+ testUtils.createAsyncView({
View: FormView,
- model: 'mass.mailing',
+ model: 'note.note',
data: this.data,
- arch: '<form string="Partners">' +
- '<sheet>' +
- '<field name="display_name"/>' +
- '<field name="body" widget="html_frame" options="{\'editor_url\': \'/logo\'}"/>' +
- '</sheet>' +
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px" options="{\'snippets\': \'web_editor.snippets\', \'cssEdit\': \'template.assets\'}"/>' +
'</form>',
res_id: 1,
- mockRPC: function (route, args) {
- if (args.method) {
- assert.step(args.method);
- if (args.method === 'write') {
- writeDeferred.resolve();
- }
+ }).then(function (form) {
+ testUtils.mock.intercept(form, "snippets_loaded", function () {
+ var doc = form.$('iframe').contents()[0];
+ var $content = $('#iframe_target', doc);
+ assert.strictEqual($content.find('#oe_snippets').length, 1,
+ "should display the snippet panel");
+ form.destroy();
+ done();
+ });
+ form.$buttons.find('.o_form_button_edit').click();
+ });
+});
+
+QUnit.test('drag&drop snippet', function (assert) {
+ var done = assert.async();
+ assert.expect(1);
+
+ testUtils.createAsyncView({
+ View: FormView,
+ model: 'note.note',
+ data: this.data,
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px" options="{\'snippets\': \'web_editor.snippets\', \'cssEdit\': \'template.assets_all_style\'}"/>' +
+ '</form>',
+ res_id: 1,
+ }).then(function (form) {
+ var defSnippets = $.Deferred();
+ testUtils.mock.intercept(form, "snippets_loaded", function () {
+ defSnippets.resolve();
+ });
+ form.$buttons.find('.o_form_button_edit').click();
+
+ defSnippets.then(function () {
+ var doc = form.$('iframe').contents()[0];
+ var $content = $('#iframe_target', doc);
+ var $editable = $content.find('.note-editable');
+
+ var $hr = $content.find('.oe_snippet_thumbnail:first');
+ var from = $hr.offset();
+ var to = $editable.find('p').offset();
+
+ $hr.trigger($.Event("mousedown", {
+ which: 1,
+ pageX: from.left + 1,
+ pageY: from.top + 1
+ }));
+ $hr.trigger($.Event("mousemove", {
+ which: 1,
+ pageX: to.left,
+ pageY: to.top
+ }));
+ $hr.trigger($.Event("mouseup", {
+ which: 1,
+ pageX: to.left,
+ pageY: to.top
+ }));
+
+ assert.strictEqual($editable.data('wysiwyg').getValue().replace(/\s+/g, ' '),
+ '<div class=\"s_hr pt32 pb32\"> <hr class=\"s_hr_1px s_hr_solid w-100 mx-auto\"> </div><p>toto toto toto</p><p>tata</p>',
+ "should drop the snippet");
+
+ form.destroy();
+ done();
+ });
+ });
+});
+
+QUnit.test('drag&drop snippet options', function (assert) {
+ var done = assert.async();
+ assert.expect(6);
+
+ testUtils.createAsyncView({
+ View: FormView,
+ model: 'note.note',
+ data: this.data,
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px" options="{\'snippets\': \'web_editor.snippets\', \'cssEdit\': \'template.assets_all_style\'}"/>' +
+ '</form>',
+ res_id: 1,
+ }).then(function (form) {
+ var defSnippets = $.Deferred();
+ testUtils.mock.intercept(form, "snippets_loaded", function () {
+ defSnippets.resolve();
+ });
+
+ var defActivateSnippet;
+ testUtils.mock.intercept(form, "snippet_focused", function (e) {
+ defActivateSnippet.resolve(e.target);
+ });
+
+ form.$buttons.find('.o_form_button_edit').click();
+
+ defSnippets.then(function () {
+ var doc = form.$('iframe').contents()[0];
+ var $content = $('#iframe_target', doc);
+ var $editable = $content.find('.note-editable');
+
+ function dropSnippet() {
+ defActivateSnippet = $.Deferred();
+
+ var $hr = $content.find('.oe_snippet_thumbnail:first');
+ var from = $hr.offset();
+ var to = $editable.find('p').offset();
+
+ $hr.trigger($.Event("mousedown", {
+ which: 1,
+ pageX: from.left + 1,
+ pageY: from.top + 1
+ }));
+ $hr.trigger($.Event("mousemove", {
+ which: 1,
+ pageX: to.left,
+ pageY: to.top
+ }));
+ $hr.trigger($.Event("mouseup", {
+ which: 1,
+ pageX: to.left,
+ pageY: to.top
+ }));
}
- if (_.str.startsWith(route, '/logo')) {
- // manually call the callback to simulate that the iframe has
- // been fully loaded (content + editor)
- var callback = $.deparam(route).callback;
- return loadDeferred.then(function () {
- var contentCallback = window.odoo[callback + '_content'];
- var editorCallback = window.odoo[callback + '_editor'];
- if (editorCallback && contentCallback) {
- contentCallback();
- editorCallback(editorBar);
- }
+
+ dropSnippet();
+ defActivateSnippet.then(function (snippet) {
+ assert.strictEqual($editable.data('wysiwyg').getValue().replace(/\s+/g, ' '),
+ '<div class=\"s_hr pt32 pb32 built focus\"> <hr class=\"s_hr_1px s_hr_solid w-100 mx-auto\"> </div><p>toto toto toto</p><p>tata</p>',
+ "should drop the snippet");
+
+ assert.strictEqual(snippet.$target.index(), 0,
+ 'should show the snippet editor for the first dropped block');
+
+ dropSnippet();
+ defActivateSnippet.then(function (snippet) {
+ assert.strictEqual($editable.data('wysiwyg').getValue().replace(/\s+/g, ' '),
+ '<div class=\"s_hr pt32 pb32 built\"> <hr class=\"s_hr_1px s_hr_solid w-100 mx-auto\"> ' +
+ '</div><div class=\"s_hr pt32 pb32 built focus\"> <hr class=\"s_hr_1px s_hr_solid w-100 mx-auto\"> ' +
+ '</div><p>toto toto toto</p><p>tata</p>',
+ "should drop the snippet");
+
+ assert.strictEqual(snippet.$target.index(), 1,
+ 'should show the snippet editor for the second dropped block');
+
+ assert.strictEqual($('.oe_active .oe_overlay_options .btn:visible', doc).length, 4,
+ 'should show the snippet editor buttons');
+
+ defActivateSnippet = $.Deferred();
+ $editable.find('hr:first').trigger('click');
+ defActivateSnippet.then(function (snippet) {
+
+ assert.strictEqual(snippet.$target.index(), 0,
+ 'should show the snippet editor for the first dropped block');
+
+ form.destroy();
+ done();
+ });
});
+ });
+ });
+ });
+});
+
+QUnit.module('translation');
+
+QUnit.test('field html translatable', function (assert) {
+ assert.expect(3);
+
+ var multiLang = _t.database.multi_lang;
+ _t.database.multi_lang = true;
+
+ this.data['note.note'].fields.body.translate = true;
+
+ testUtils.createAsyncView({
+ View: FormView,
+ model: 'note.note',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<field name="body" widget="html"/>' +
+ '</form>',
+ res_id: 1,
+ mockRPC: function (route, args) {
+ if (route === '/web/dataset/call_button' && args.method === 'translate_fields') {
+ assert.deepEqual(args.args, ['note.note', 1, 'body', {}], "should call 'call_button' route");
+ return $.when();
}
return this._super.apply(this, arguments);
},
+ }).then(function (form) {
+ assert.strictEqual(form.$('.oe_form_field_html .o_field_translate').length, 0,
+ "should not have a translate button in readonly mode");
+
+ form.$buttons.find('.o_form_button_edit').click();
+ var $button = form.$('.oe_form_field_html .note-toolbar .o_field_translate');
+ assert.strictEqual($button.length, 1, "should have a translate button");
+ $button.click();
+
+ form.destroy();
+ _t.database.multi_lang = multiLang;
+
});
+});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input.o_input.o_field_char'), 'trululu');
- testUtils.form.clickSave(form);
+QUnit.test('field html translatable in iframe', function (assert) {
+ var done = assert.async();
+ assert.expect(2);
- loadDeferred.resolve(); // simulate late loading of html frame
+ var multiLang = _t.database.multi_lang;
+ _t.database.multi_lang = true;
- assert.strictEqual(form.$('.o_field_char').val(), 'trululu',
- "should have saved the char field text");
+ this.data['note.note'].fields.body.translate = true;
- writeDeferred.then( function () { // html_frame is async with write
- assert.verifySteps(['read', 'write']);
- form.destroy();
- done();
+ testUtils.createAsyncView({
+ View: FormView,
+ model: 'note.note',
+ data: this.data,
+ arch: '<form>' +
+ '<field name="body" widget="html" style="height: 100px" options="{\'cssEdit\': \'template.assets\'}"/>' +
+ '</form>',
+ res_id: 1,
+ mockRPC: function (route, args) {
+ if (route === '/web/dataset/call_button' && args.method === 'translate_fields') {
+ assert.deepEqual(args.args, ['note.note', 1, 'body', {}], "should call 'call_button' route");
+ return $.when();
+ }
+ return this._super.apply(this, arguments);
+ },
+ }).then(function (form) {
+ var $field = form.$('.oe_form_field[name="body"]');
+ form.$buttons.find('.o_form_button_edit').click();
+ $field = form.$('.oe_form_field[name="body"]');
+ var $iframe = $field.find('iframe');
+
+ $iframe.data('load-def').then(function () {
+ var doc = $iframe.contents()[0];
+ var $content = $('#iframe_target', doc);
+
+ var $button = $content.find('.note-toolbar .o_field_translate');
+ assert.strictEqual($button.length, 1, "should have a translate button");
+ $button.click();
+
+ form.destroy();
+ _t.database.multi_lang = multiLang;
+ done();
+ });
});
-
});
});
+});
+});