diff --git a/addons/mail/static/src/components/discuss_sidebar_category_item/tests/discuss_sidebar_category_item_tests.js b/addons/mail/static/src/components/discuss_sidebar_category_item/tests/discuss_sidebar_category_item_tests.js
index 3bad19c38ec..350a3a15f39 100644
--- a/addons/mail/static/src/components/discuss_sidebar_category_item/tests/discuss_sidebar_category_item_tests.js
+++ b/addons/mail/static/src/components/discuss_sidebar_category_item/tests/discuss_sidebar_category_item_tests.js
@@ -101,9 +101,8 @@ QUnit.test('channel - avatar: should update avatar url from bus', async function
});
const newCacheKey = result[0]['avatarCacheKey'];
- // FIXME: current test framework does not replace `src` with `data-src` during the re-rendering.
assert.strictEqual(
- channelItemAvatar.getAttribute('src'),
+ channelItemAvatar.dataset.src,
`/web/image/mail.channel/20/avatar_128?unique=${newCacheKey}`,
);
});
diff --git a/addons/mail/static/tests/activity_tests.js b/addons/mail/static/tests/activity_tests.js
index d57062e7a9d..ee59cd8475c 100644
--- a/addons/mail/static/tests/activity_tests.js
+++ b/addons/mail/static/tests/activity_tests.js
@@ -580,7 +580,7 @@ QUnit.test('Activity view: many2one_avatar_user widget in activity view', async
await legacyExtraNextTick();
assert.containsN(target, '.o_m2o_avatar', 2);
- assert.containsOnce(target, 'tr[data-res-id=13] .o_m2o_avatar > img[src="/web/image/res.users/1/avatar_128"]',
+ assert.containsOnce(target, 'tr[data-res-id=13] .o_m2o_avatar > img[data-src="/web/image/res.users/1/avatar_128"]',
"should have m2o avatar image");
assert.containsNone(target, '.o_m2o_avatar > span',
"should not have text on many2one_avatar_user if onlyImage node option is passed");
diff --git a/addons/mail/static/tests/document_viewer_tests.js b/addons/mail/static/tests/document_viewer_tests.js
index c0fcb84970d..cde111a4b37 100644
--- a/addons/mail/static/tests/document_viewer_tests.js
+++ b/addons/mail/static/tests/document_viewer_tests.js
@@ -102,23 +102,16 @@ QUnit.module('document_viewer_tests.js', {
});
QUnit.test('Document Viewer Youtube', async function (assert) {
- assert.expect(3);
+ assert.expect(2);
- var youtubeURL = 'https://www.youtube.com/embed/FYqW0Gdwbzk';
var viewer = await createViewer({
attachmentID: 2,
attachments: this.attachments,
- mockRPC: function (route) {
- if (route === youtubeURL) {
- assert.ok(true, "should have called youtube URL");
- }
- return this._super.apply(this, arguments);
- },
});
assert.strictEqual(viewer.$(".o_image_caption:contains('urlYoutube')").length, 1,
"the viewer should be on the right attachment");
- assert.containsOnce(viewer, '.o_viewer_text[data-src="' + youtubeURL + '"]',
+ assert.containsOnce(viewer, '.o_viewer_text[data-src="https://www.youtube.com/embed/FYqW0Gdwbzk"]',
"there should be a video player");
viewer.destroy();
diff --git a/addons/mrp/static/tests/mrp_tests.js b/addons/mrp/static/tests/mrp_tests.js
index 951197cdc12..c7912f38fd9 100644
--- a/addons/mrp/static/tests/mrp_tests.js
+++ b/addons/mrp/static/tests/mrp_tests.js
@@ -92,7 +92,7 @@ QUnit.module('mrp', {
await testUtils.form.clickEdit(form);
assert.isNotVisible(form.$('iframe.o_embed_iframe'), "there should be an invisible iframe in edit mode");
await testUtils.fields.editAndTrigger(form.$('.o_field_char'), 'http://example.com', ['input', 'change', 'focusout']);
- assert.strictEqual(form.$('iframe.o_embed_iframe').attr('src'), 'http://example.com',
+ assert.strictEqual(form.$('iframe.o_embed_iframe').attr('data-src'), 'http://example.com',
"src should updated on the iframe");
assert.isVisible(form.$('iframe.o_embed_iframe'), "there should be a visible iframe in edit mode");
await testUtils.form.clickSave(form);
diff --git a/addons/web/static/tests/legacy/fields/basic_fields_tests.js b/addons/web/static/tests/legacy/fields/basic_fields_tests.js
index 83d4c80148e..35157a20735 100644
--- a/addons/web/static/tests/legacy/fields/basic_fields_tests.js
+++ b/addons/web/static/tests/legacy/fields/basic_fields_tests.js
@@ -2958,10 +2958,6 @@ QUnit.module('basic_fields', {
if (route === '/web/dataset/call_kw/partner/read') {
assert.deepEqual(args.args[1], ['document', '__last_update', 'display_name'], "The fields document, display_name and __last_update should be present when reading an image");
}
- if (route === `data:image/png;base64,${MY_IMAGE}`) {
- assert.ok(true, "should called the correct route");
- return 'wow';
- }
return this._super.apply(this, arguments);
},
});
@@ -2970,6 +2966,8 @@ QUnit.module('basic_fields', {
"the widget should have the correct class");
assert.containsOnce(form, 'div[name="document"] > img',
"the widget should contain an image");
+ assert.strictEqual(form.$('div[name="document"] > img')[0].dataset.src,
+ `data:image/png;base64,${MY_IMAGE}`, "the image should have the correct src");
assert.hasClass(form.$('div[name="document"] > img'),'img-fluid',
"the image should have the correct class");
assert.hasAttrValue(form.$('div[name="document"] > img'), 'width', "90",
@@ -2980,7 +2978,7 @@ QUnit.module('basic_fields', {
});
QUnit.test('image fields are correctly replaced when given an incorrect value', async function (assert) {
- assert.expect(7);
+ assert.expect(6);
this.data.partner.records[0].__last_update = '2017-02-08 10:00:00';
this.data.partner.records[0].document = 'incorrect_base64_value';
@@ -3006,19 +3004,14 @@ QUnit.module('basic_fields', {
`,
res_id: 1,
- async mockRPC(route, args) {
- const _super = this._super;
- if (route === '/web/static/img/placeholder.png') {
- assert.step('call placeholder route');
- }
- return _super.apply(this, arguments);
- },
});
assert.hasClass(form.$('div[name="document"]'),'o_field_image',
"the widget should have the correct class");
assert.containsOnce(form, 'div[name="document"] > img',
"the widget should contain an image");
+ assert.strictEqual(form.$('div[name="document"] > img')[0].dataset.src,
+ `/web/static/img/placeholder.png`, "the image should have the correct src");
assert.hasClass(form.$('div[name="document"] > img'), 'img-fluid',
"the image should have the correct class");
assert.hasAttrValue(form.$('div[name="document"] > img'), 'width', "90",
@@ -3026,7 +3019,6 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('div[name="document"] > img').css('max-width'), "90px",
"the image should correctly set its attributes");
- assert.verifySteps(['call placeholder route']);
form.destroy();
testUtils.mock.unpatch(basicFields.FieldBinaryImage);
@@ -3061,7 +3053,7 @@ QUnit.module('basic_fields', {
});
QUnit.test('image fields in subviews are loaded correctly', async function (assert) {
- assert.expect(6);
+ assert.expect(4);
this.data.partner.records[0].__last_update = '2017-02-08 10:00:00';
this.data.partner.records[0].document = MY_IMAGE;
@@ -3094,19 +3086,11 @@ QUnit.module('basic_fields', {
'' +
'',
res_id: 1,
- async mockRPC(route) {
- if (route === `data:image/png;base64,${MY_IMAGE}`) {
- assert.step("The view's image should have been fetched");
- return 'wow';
- }
- if (route === `data:image/gif;base64,${PRODUCT_IMAGE}`) {
- assert.step("The dialog's image should have been fetched");
- return;
- }
- return this._super.apply(this, arguments);
- },
});
- assert.verifySteps(["The view's image should have been fetched"]);
+ assert.ok(
+ document.querySelector(`img[data-src="data:image/png;base64,${MY_IMAGE}"]`),
+ "The view's image is in the DOM"
+ );
assert.containsOnce(form, '.o_kanban_record.oe_kanban_global_click',
'There should be one record in the many2many');
@@ -3115,7 +3099,10 @@ QUnit.module('basic_fields', {
await testUtils.dom.click(form.$('.oe_kanban_global_click'));
assert.strictEqual($('.modal').length, 1,
'The modal should have opened');
- assert.verifySteps(["The dialog's image should have been fetched"]);
+ assert.ok(
+ document.querySelector(`img[data-src="data:image/gif;base64,${PRODUCT_IMAGE}"]`),
+ "The dialog's image is in the DOM"
+ );
form.destroy();
});
@@ -3139,17 +3126,14 @@ QUnit.module('basic_fields', {
'' +
'',
res_id: 1,
- async mockRPC(route) {
- if (route === `data:image/gif;base64,${PRODUCT_IMAGE}`) {
- assert.ok(true, "The list's image should have been fetched");
- return;
- }
- return this._super.apply(this, arguments);
- },
});
assert.containsOnce(form, 'tr.o_data_row',
'There should be one record in the many2many');
+ assert.ok(
+ document.querySelector(`img[data-src="data:image/gif;base64,${PRODUCT_IMAGE}"]`),
+ "The list's image is in the DOM"
+ );
form.destroy();
});
@@ -3203,18 +3187,14 @@ QUnit.module('basic_fields', {
' ' +
'',
res_id: 6,
- async mockRPC(route, args) {
- if (route === FR_FLAG_URL) {
- assert.ok(true, "the correct route should have been called.");
- }
- return this._super.apply(this, arguments);
- },
});
assert.hasClass(form.$('div[name="foo"]'), 'o_field_image',
"the widget should have the correct class");
assert.containsOnce(form, 'div[name="foo"] > img',
"the widget should contain an image");
+ assert.strictEqual(form.$('div[name="foo"] > img')[0].dataset.src,
+ FR_FLAG_URL, "the image should have the correct src");
assert.hasClass(form.$('div[name="foo"] > img'), 'img-fluid',
"the image should have the correct class");
assert.hasAttrValue(form.$('div[name="foo"] > img'), 'width', "90",
@@ -3225,7 +3205,7 @@ QUnit.module('basic_fields', {
});
QUnit.test('image_url widget in subviews are loaded correctly', async function (assert) {
- assert.expect(6);
+ assert.expect(4);
this.data.partner_type.fields.image = {name: 'image', type: 'char'};
this.data.partner_type.records[0].image = EN_FLAG_URL;
@@ -3256,19 +3236,11 @@ QUnit.module('basic_fields', {
'' +
'',
res_id: 6,
- async mockRPC(route) {
- if (route === FR_FLAG_URL) {
- assert.step("The view's image should have been fetched");
- return 'wow';
- }
- if (route === EN_FLAG_URL) {
- assert.step("The dialog's image should have been fetched");
- return;
- }
- return this._super.apply(this, arguments);
- },
});
- assert.verifySteps(["The view's image should have been fetched"]);
+ assert.ok(
+ document.querySelector(`img[data-src="${FR_FLAG_URL}"]`),
+ "The view's image is in the DOM"
+ );
assert.containsOnce(form, '.o_kanban_record.oe_kanban_global_click',
'There should be one record in the many2many');
@@ -3277,7 +3249,10 @@ QUnit.module('basic_fields', {
await testUtils.dom.click(form.$('.oe_kanban_global_click'));
assert.strictEqual($('.modal').length, 1,
'The modal should have opened');
- assert.verifySteps(["The dialog's image should have been fetched"]);
+ assert.ok(
+ document.querySelector(`img[data-src="${EN_FLAG_URL}"]`),
+ "The dialog's image is in the DOM"
+ );
form.destroy();
});
@@ -3301,17 +3276,14 @@ QUnit.module('basic_fields', {
'' +
'',
res_id: 6,
- async mockRPC(route) {
- if (route === EN_FLAG_URL) {
- assert.ok(true, "The list's image should have been fetched");
- return;
- }
- return this._super.apply(this, arguments);
- },
});
assert.containsOnce(form, 'tr.o_data_row',
'There should be one record in the many2many');
+ assert.ok(
+ document.querySelector(`img[data-src="${EN_FLAG_URL}"]`),
+ "The list's image is in the DOM"
+ );
form.destroy();
});
diff --git a/addons/web/static/tests/legacy/helpers/test_utils_mock.js b/addons/web/static/tests/legacy/helpers/test_utils_mock.js
index f363fdeaced..9e7b941ffc3 100644
--- a/addons/web/static/tests/legacy/helpers/test_utils_mock.js
+++ b/addons/web/static/tests/legacy/helpers/test_utils_mock.js
@@ -287,44 +287,6 @@ function intercept(widget, eventName, fn, propagate) {
};
}
-/**
- * Removes the src attribute on images and iframes to prevent not found errors,
- * and optionally triggers an rpc with the src url as route on a widget.
- * This method is critical and must be fastest (=> no jQuery, no underscore)
- *
- * @param {HTMLElement} el
- * @param {[function]} rpc
- */
-function removeSrcAttribute(el, rpc) {
- var nodes;
- if (el.nodeName === "#comment") {
- return;
- }
- el = el.nodeType === 8 ? el.nextSibling : el;
- if (el.nodeName === 'IMG' || el.nodeName === 'IFRAME') {
- nodes = [el];
- } else {
- nodes = Array.prototype.slice.call(el.getElementsByTagName('img'))
- .concat(Array.prototype.slice.call(el.getElementsByTagName('iframe')));
- }
- var node;
- while (node = nodes.pop()) {
- var src = node.attributes.src && node.attributes.src.value;
- if (src && src !== 'about:blank') {
- node.setAttribute('data-src', src);
- if (node.nodeName === 'IMG') {
- node.attributes.removeNamedItem('src');
- } else {
- node.setAttribute('src', 'about:blank');
- }
- if (rpc) {
- rpc(src, []);
- }
- $(node).trigger('load');
- }
- }
-}
-
/**
* Add a mock environment to test Owl Components. This function generates a test
* env and sets it on the given Component. It also has several side effects,
@@ -396,15 +358,6 @@ async function addMockEnvironmentOwl(Component, params, mockServer) {
};
}
- // make sure images do not trigger a GET on the server
- $('body').on('DOMNodeInserted.removeSRC', function (ev) {
- let rpc;
- if (params.mockSRC) {
- rpc = mockServer.performRpc.bind(mockServer);
- }
- removeSrcAttribute(ev.target, rpc);
- });
-
// mock global objects for legacy widgets (session, config...)
const restoreMockedGlobalObjects = _mockGlobalObjects(params);
diff --git a/addons/web/static/tests/legacy/views/kanban_tests.js b/addons/web/static/tests/legacy/views/kanban_tests.js
index 91f6a9c1b28..c2a868f6b42 100644
--- a/addons/web/static/tests/legacy/views/kanban_tests.js
+++ b/addons/web/static/tests/legacy/views/kanban_tests.js
@@ -7124,13 +7124,6 @@ QUnit.module('Views', {
'
' +
'' +
'',
- mockRPC: function (route, args) {
- if (route === 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACAA==') {
- assert.ok("The view's image should have been fetched.");
- return Promise.resolve();
- }
- return this._super.apply(this, arguments);
- },
});
var images = kanban.el.querySelectorAll('img');
var placeholders = [];
@@ -7143,6 +7136,8 @@ QUnit.module('Views', {
assert.strictEqual(placeholders.length, this.data.partner.records.length - 1,
"partner with no image should display the placeholder");
+ assert.strictEqual(images[0].dataset.src, "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACAA==",
+ "The first partners non-placeholder image should be set");
kanban.destroy();
});
@@ -7161,13 +7156,6 @@ QUnit.module('Views', {
'
' +
'' +
'',
- mockRPC: function (route, args) {
- if (route === 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACAA==') {
- assert.ok("The view's image should have been fetched.");
- return Promise.resolve();
- }
- return this._super.apply(this, arguments);
- },
});
// the field image is set, but we request the image for a specific id
@@ -7176,6 +7164,9 @@ QUnit.module('Views', {
var imageOnRecord = kanban.$('img[data-src*="/web/image"][data-src*="&id=1"]');
assert.strictEqual(imageOnRecord.length, this.data.partner.records.length - 1,
"display image by url when requested for another record");
+ assert.strictEqual(kanban.el.querySelector("img").dataset.src,
+ "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACAA==",
+ "display image as value when requested for the record itself");
kanban.destroy();
});
diff --git a/addons/web/static/tests/setup.js b/addons/web/static/tests/setup.js
index 6952aab6610..5a5dfb65f67 100644
--- a/addons/web/static/tests/setup.js
+++ b/addons/web/static/tests/setup.js
@@ -222,4 +222,33 @@ export async function setupTests() {
const templates = await loadFile(templatesUrl);
window.__OWL_TEMPLATES__ = processTemplates(templates);
await Promise.all([whenReady(), legacyProm]);
+
+ // make sure images do not trigger a GET on the server
+ new MutationObserver((mutations) => {
+ const nodes = mutations.flatMap(({ target }) => {
+ if (target.nodeName === "IMG" || target.nodeName === "IFRAME") {
+ return target;
+ }
+ return [
+ ...target.getElementsByTagName("img"),
+ ...target.getElementsByTagName("iframe"),
+ ];
+ });
+ for (const node of nodes) {
+ const src = node.getAttribute("src");
+ if (src && src !== "about:blank") {
+ node.dataset.src = src;
+ if (node.nodeName === "IMG") {
+ node.removeAttribute("src");
+ } else {
+ node.setAttribute("src", "about:blank");
+ }
+ node.dispatchEvent(new Event("load"));
+ }
+ }
+ }).observe(document.body, {
+ subtree: true,
+ childList: true,
+ attributeFilter: ["src"],
+ });
}
diff --git a/addons/web/static/tests/webclient/user_menu_tests.js b/addons/web/static/tests/webclient/user_menu_tests.js
index 953620376db..829c71625d3 100644
--- a/addons/web/static/tests/webclient/user_menu_tests.js
+++ b/addons/web/static/tests/webclient/user_menu_tests.js
@@ -88,7 +88,7 @@ QUnit.test("can be rendered", async (assert) => {
let userMenuEl = userMenu.el;
assert.containsOnce(userMenuEl, "img.o_user_avatar");
assert.strictEqual(
- userMenuEl.querySelector("img.o_user_avatar").src,
+ userMenuEl.querySelector("img.o_user_avatar").dataset.src,
"http://lordofthering/web/image?model=res.users&field=avatar_128&id=7"
);
assert.containsOnce(userMenuEl, "span.oe_topbar_name");