Bug 1912579 - Fix intermittent comm/mail/test/browser/message-reader/browser_imageOverflow.js | The message display needs to be less than 400px wide - 832 < 400. r=tobyp

There were a bunch of issues with this test.
Simplified the real code to make it more understandable (and using boolean attributes).

Differential Revision: https://phabricator.services.mozilla.com/D228603

--HG--
rename : mail/test/browser/message-reader/data/Image sizing test.eml => mail/test/browser/message-reader/data/image_sizing_test.eml
extra : moz-landing-system : lando
This commit is contained in:
Magnus Melin 2024-11-17 00:49:00 +00:00
Родитель 0208da7cda
Коммит f2ed6688f0
6 изменённых файлов: 171 добавлений и 162 удалений

Просмотреть файл

@ -50,7 +50,10 @@ function getMessagePaneBrowser() {
return document.getElementById("messagepane");
}
function messagePaneOnResize() {
/**
* Handle "resize" events on the messagepane.
*/
async function messagePaneOnResize() {
const doc = getMessagePaneBrowser().contentDocument;
// Bail out if it's http content or we don't have images.
if (doc?.URL.startsWith("http") || !doc?.images) {
@ -62,22 +65,29 @@ function messagePaneOnResize() {
window.visualViewport.width
);
const adjustImg = img => {
if (img.hasAttribute("shrinktofit")) {
// overflowing: Whether the image is overflowing visible area.
img.toggleAttribute("overflowing", img.naturalWidth > img.clientWidth);
} else if (img.hasAttribute("overflowing")) {
const isOverflowing = img.clientWidth >= availableWidth;
img.toggleAttribute("overflowing", isOverflowing);
img.toggleAttribute("shrinktofit", !isOverflowing);
}
};
for (const img of doc.querySelectorAll(
"img:is([shrinktofit],[overflowing])"
)) {
if (!img.complete || img.closest("[href]")) {
if (img.closest("[href]")) {
continue;
}
if (img.hasAttribute("shrinktofit")) {
// Determine if the image could be enlarged.
img.toggleAttribute("overflowing", img.naturalWidth > img.clientWidth);
} else if (
img.hasAttribute("overflowing") &&
img.clientWidth < availableWidth
) {
// Handle zoomed images that are no longer overflowing after a resize.
img.removeAttribute("overflowing");
img.setAttribute("shrinktofit", "true");
if (!img.complete) {
img.addEventListener("load", event => adjustImg(event.target), {
once: true,
});
} else {
adjustImg(img);
}
}
}

Просмотреть файл

@ -145,14 +145,7 @@ function contentAreaClick(aEvent) {
// Is it an image?
if (target.localName == "img" && target.hasAttribute("overflowing")) {
if (target.hasAttribute("shrinktofit")) {
// Currently shrunk to fit, so unshrink it.
target.removeAttribute("shrinktofit");
} else {
// User wants to shrink now.
target.setAttribute("shrinktofit", true);
}
target.toggleAttribute("shrinktofit");
return false;
}
}

Просмотреть файл

@ -895,8 +895,10 @@ var messageProgressListener = {
* OnStateChange event for STATE_STOP. This is the same event that
* generates the "msgLoaded" property flag change event. This best
* corresponds to the end of the streaming process.
*
* @param {nsIMsgMailNewsUrl} url
*/
onEndMsgDownload(url) {
async onEndMsgDownload(url) {
const browser = getMessagePaneBrowser();
// If we have no attachments, we hide the attachment icon in the message
@ -929,9 +931,7 @@ var messageProgressListener = {
currentAttachments.length &&
Services.prefs.getBoolPref("mail.inline_attachments") &&
FeedUtils.isFeedMessage(gMessage) &&
browser &&
browser.contentDocument &&
browser.contentDocument.body
browser.contentDocument?.body
) {
for (const img of browser.contentDocument.body.getElementsByClassName(
"moz-attached-image"
@ -944,23 +944,108 @@ var messageProgressListener = {
break;
}
}
img.addEventListener(
"load",
function () {
if (this.clientWidth > this.parentNode.clientWidth) {
img.setAttribute("overflowing", "true");
img.setAttribute("shrinktofit", "true");
}
},
{ once: true }
);
}
}
OnMsgParsed(url);
// browser doesn't do this, but I thought it could be a useful thing to test out...
// If the find bar is visible and we just loaded a new message, re-run
// the find command. This means the new message will get highlighted and
// we'll scroll to the first word in the message that matches the find text.
const findBar = document.getElementById("FindToolbar");
if (!findBar.hidden) {
findBar.onFindAgainCommand(false);
}
// Run the phishing detector on the message if it hasn't been marked as not
// a scam already.
if (
gMessage &&
!gMessage.getUint32Property("notAPhishMessage") &&
PhishingDetector.analyzeMsgForPhishingURLs(url, browser)
) {
gMessageNotificationBar.setPhishingMsg();
}
// Notify anyone (e.g., extensions) who's interested in when a message is loaded.
Services.obs.notifyObservers(null, "MsgMsgDisplayed", gMessageURI);
// Rewrite any anchor elements' href attribute to reflect that the loaded
// document is a mailnews url. This will cause docShell to scroll to the
// element in the document rather than opening the link externally.
for (const linkNode of browser.contentDocument.links) {
if (!linkNode.hash) {
continue;
}
// We have a ref fragment which may reference a node in this document.
// Ensure html in mail anchors work as expected.
const anchorId = linkNode.hash.replace("#", "");
// Continue if an id (html5) or name attribute value for the ref is not
// found in this document.
try {
if (
!linkNode.ownerDocument.querySelector(
`#${anchorId},[name='${anchorId}']`
)
) {
continue;
}
} catch (ex) {
// invalid selector
continue;
}
// Then check if the href url matches the document baseURL.
if (
makeURI(linkNode.href).specIgnoringRef !=
makeURI(linkNode.baseURI).specIgnoringRef
) {
continue;
}
// Finally, if the document url is a message url, and the anchor href is
// http, it needs to be adjusted so docShell finds the node.
const messageURI = makeURI(linkNode.ownerDocument.URL);
if (
messageURI instanceof Ci.nsIMsgMailNewsUrl &&
linkNode.href.startsWith("http")
) {
linkNode.href = messageURI.specIgnoringRef + linkNode.hash;
}
}
if (browser.contentDocument.readyState != "complete") {
await new Promise(resolve => {
browser.contentWindow.addEventListener("load", resolve, {
once: true,
});
});
}
// Scale any overflowing images, exclude http content.
if (!browser.contentDocument.URL.startsWith("http")) {
const adjustImg = img => {
img.toggleAttribute("overflowing", img.naturalWidth > img.clientWidth);
};
for (const img of browser.contentDocument.images) {
// No zooming for children of clickable links.
if (img.closest("[href]")) {
continue;
}
img.toggleAttribute("shrinktofit", true);
if (!img.complete) {
img.addEventListener("load", event => adjustImg(event.target), {
once: true,
});
} else {
adjustImg(img);
}
}
}
},
/**
* @param {nsIMsgMailNewsUrl} url
*/
onEndMsgHeaders(url) {
if (!url.errorCode) {
// Should not mark a message as read if failed to load.
@ -4148,110 +4233,6 @@ function ClearPendingReadTimer() {
}
}
// this is called when layout is actually finished rendering a
// mail message. OnMsgLoaded is called when libmime is done parsing the message
function OnMsgParsed(aUrl) {
// browser doesn't do this, but I thought it could be a useful thing to test out...
// If the find bar is visible and we just loaded a new message, re-run
// the find command. This means the new message will get highlighted and
// we'll scroll to the first word in the message that matches the find text.
const findBar = document.getElementById("FindToolbar");
if (!findBar.hidden) {
findBar.onFindAgainCommand(false);
}
const browser = getMessagePaneBrowser();
// Run the phishing detector on the message if it hasn't been marked as not
// a scam already.
if (
gMessage &&
!gMessage.getUint32Property("notAPhishMessage") &&
PhishingDetector.analyzeMsgForPhishingURLs(aUrl, browser)
) {
gMessageNotificationBar.setPhishingMsg();
}
// Notify anyone (e.g., extensions) who's interested in when a message is loaded.
Services.obs.notifyObservers(null, "MsgMsgDisplayed", gMessageURI);
const doc =
browser && browser.contentDocument ? browser.contentDocument : null;
// Rewrite any anchor elements' href attribute to reflect that the loaded
// document is a mailnews url. This will cause docShell to scroll to the
// element in the document rather than opening the link externally.
const links = doc && doc.links ? doc.links : [];
for (const linkNode of links) {
if (!linkNode.hash) {
continue;
}
// We have a ref fragment which may reference a node in this document.
// Ensure html in mail anchors work as expected.
const anchorId = linkNode.hash.replace("#", "");
// Continue if an id (html5) or name attribute value for the ref is not
// found in this document.
const selector = "#" + anchorId + ", [name='" + anchorId + "']";
try {
if (!linkNode.ownerDocument.querySelector(selector)) {
continue;
}
} catch (ex) {
continue;
}
// Then check if the href url matches the document baseURL.
if (
makeURI(linkNode.href).specIgnoringRef !=
makeURI(linkNode.baseURI).specIgnoringRef
) {
continue;
}
// Finally, if the document url is a message url, and the anchor href is
// http, it needs to be adjusted so docShell finds the node.
const messageURI = makeURI(linkNode.ownerDocument.URL);
if (
messageURI instanceof Ci.nsIMsgMailNewsUrl &&
linkNode.href.startsWith("http")
) {
linkNode.href = messageURI.specIgnoringRef + linkNode.hash;
}
}
const stylesReadyPromise = new Promise(resolve => {
if (doc.readyState === "complete") {
resolve();
return;
}
browser.contentWindow.addEventListener("load", resolve, {
once: true,
});
});
const applyOverflowingToImg = async img => {
img.setAttribute("shrinktofit", "true");
if (!img.complete) {
await new Promise(resolve => {
img.addEventListener("load", resolve, { once: true });
});
}
await stylesReadyPromise;
if (img.naturalWidth > img.clientWidth) {
img.setAttribute("overflowing", "true");
}
};
// Scale any overflowing images, exclude http content.
const imgs = doc && !doc.URL.startsWith("http") ? doc.images : [];
for (const img of imgs) {
// No zooming for children of clickable links.
if (img.closest("[href]")) {
continue;
}
applyOverflowingToImg(img);
}
}
function OnMsgLoaded(aUrl) {
window.msgLoaded = true;
window.dispatchEvent(

Просмотреть файл

@ -15,14 +15,18 @@ let msgc;
add_setup(async () => {
Services.prefs.setBoolPref("mail.inline_attachments", true);
const file = new FileUtils.File(
getTestFilePath("data/Image sizing test.eml")
getTestFilePath("data/image_sizing_test.eml")
);
msgc = await open_message_from_file(file);
if (window.screen.availWidth > msgc.outerWidth && msgc.outerWidth < 500) {
const resizePromise = BrowserTestUtils.waitForEvent(msgc, "resize");
msgc.resizeTo(Math.min(window.screen.availWidth, 550), msgc.outerHeight);
const w = Math.min(window.screen.availWidth, 550);
const h = msgc.outerHeight;
info(`Resizing window... to ${w}x${h}...`);
msgc.resizeTo(w, h);
await resizePromise;
info("... resized!");
await TestUtils.waitForTick();
}
@ -38,18 +42,21 @@ add_task(async function test_imageOverflow() {
const msgDoc =
aboutMessage.document.getElementById("messagepane").contentDocument;
const messageDisplayWidth = msgDoc.body.clientWidth;
Assert.less(
messageDisplayWidth,
5000,
"The message display needs to be less than 5000px wide"
await TestUtils.waitForCondition(
() => msgDoc.body.clientWidth < 5000,
`The message display needs to be less than 5000px wide: ${msgDoc.body.clientWidth}`
);
await TestUtils.waitForCondition(() =>
Array.from(msgDoc.querySelectorAll("img")).every(img => img.complete)
);
Assert.equal(msgDoc.body.scrollWidth, messageDisplayWidth, "No scrollbars");
const messageDisplayWidth = msgDoc.body.clientWidth;
Assert.equal(
msgDoc.body.scrollWidth,
messageDisplayWidth,
"msg doc should not have scrollbars"
);
const imageIds = [];
@ -102,7 +109,6 @@ add_task(async function test_imageOverflow() {
},
() => !image.hasAttribute("shrinktofit")
);
Assert.ok(
image.hasAttribute("overflowing"),
"Click should keep overflowing attribute"
@ -131,7 +137,6 @@ add_task(async function test_imageOverflow() {
},
() => image.hasAttribute("shrinktofit")
);
Assert.ok(
image.hasAttribute("overflowing"),
"Click should keep overflowing attribute"
@ -167,23 +172,35 @@ add_task(async function test_imageUnderflow() {
if (initialWidth > 350) {
const resizePromise = BrowserTestUtils.waitForEvent(msgc, "resize");
info(`Initial width too large; resizing to 350x${msgc.outerHeight}...`);
msgc.resizeTo(350, msgc.outerHeight);
await resizePromise;
info("... resized!");
//Assert.equal(msgc.outerWidth, 350, "resizeTo should have worked");
await TestUtils.waitForTick();
}
const messageDisplayWidth = msgDoc.body.clientWidth;
await TestUtils.waitForCondition(
() => msgDoc.body.clientWidth < 400,
`The message display needs to be less than 400px wide: ${msgDoc.body.clientWidth}`
);
Assert.less(
messageDisplayWidth,
msgDoc.body.clientWidth,
400,
"The message display needs to be less than 400px wide"
"message display width should be less than 400"
);
await TestUtils.waitForCondition(() =>
Array.from(msgDoc.querySelectorAll("img")).every(img => img.complete)
await TestUtils.waitForCondition(
() => Array.from(msgDoc.querySelectorAll("img")).every(img => img.complete),
"Every image should complete loading"
);
Assert.equal(msgDoc.body.scrollWidth, messageDisplayWidth, "No scrollbars");
const messageDisplayWidth = msgDoc.body.clientWidth;
Assert.equal(
msgDoc.body.scrollWidth,
messageDisplayWidth,
"msg doc should not have scrollbars"
);
msgDoc.defaultView.scrollBy({
top: 5000,
@ -191,8 +208,12 @@ add_task(async function test_imageUnderflow() {
});
const image = msgDoc.getElementById("stretched");
EventUtils.synthesizeMouse(image, 1, 1, {}, msgDoc.defaultView);
Assert.ok(
image.hasAttribute("shrinktofit"),
"img#stretched should have attr shrinktofit"
);
info("Zooming image #stretched");
EventUtils.synthesizeMouse(image, 1, 1, {}, image.ownerGlobal);
await BrowserTestUtils.waitForMutationCondition(
image,
{
@ -200,11 +221,12 @@ add_task(async function test_imageUnderflow() {
},
() => !image.hasAttribute("shrinktofit")
);
info("Zoomed on the image");
info("... zoomed on the image #stretched");
info(`Resizing window to 450x${msgc.outerHeight}...`);
const resizePromise2 = BrowserTestUtils.waitForEvent(msgc, "resize");
msgc.resizeTo(450, msgc.outerHeight);
info("Resizing window...");
await resizePromise2;
await BrowserTestUtils.waitForMutationCondition(
image,
{
@ -218,7 +240,10 @@ add_task(async function test_imageUnderflow() {
"Image should no longer be overflowing"
);
const resizePromise3 = BrowserTestUtils.waitForEvent(msgc, "resize");
info(`Resizing window to ${initialWidth}x${msgc.outerHeight}...`);
msgc.resizeTo(initialWidth, msgc.outerHeight);
await resizePromise3;
msgDoc.defaultView.scrollTo({
top: 0,
behavior: "instant",

Просмотреть файл

@ -1009,7 +1009,7 @@ static char* mime_image_make_image_html(MimeClosure image_closure) {
/* Wouldn't it be nice if attributes were case-sensitive? */
const char* scaledPrefix =
"<DIV CLASS=\"moz-attached-image-container\"><IMG "
"CLASS=\"moz-attached-image\" shrinktofit=\"yes\" SRC=\"";
"CLASS=\"moz-attached-image\" SRC=\"";
const char* suffix = "\"></DIV>";
// Thunderbird doesn't have this pref.
#ifdef MOZ_SUITE