From bb9fad6e4c34218f868ab42e128bcdcd86be497c Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 30 Jul 2026 18:32:40 +0000 Subject: [PATCH 1/4] e2e: wait for loaded SizeAwareImage before opening media preview Mattermost 11.10.0-rc2 (MM-69174) ignores thumbnail clicks until the real image has loaded and keeps a placeholder control visible meanwhile. MM-T4054 was clicking too early, so update the helper to wait for a visible loaded .file-preview__button and avoid placeholder targets. Co-authored-by: yasser khan --- e2e/specs/mattermost/media_preview.test.ts | 112 +++++++++++++++++---- 1 file changed, 91 insertions(+), 21 deletions(-) diff --git a/e2e/specs/mattermost/media_preview.test.ts b/e2e/specs/mattermost/media_preview.test.ts index 6ed370f753b..b8e00731874 100644 --- a/e2e/specs/mattermost/media_preview.test.ts +++ b/e2e/specs/mattermost/media_preview.test.ts @@ -20,16 +20,64 @@ const PREVIEW_MODAL_SELECTOR = [ ].join(', '); const POSTED_IMAGE_SELECTOR = [ + '.file-preview__button', '.post-image .small-image__container', '.post-image .image-loaded-container', '.post-image__image', - '.post-image img', + '.post-image img:not(.image-loading__placeholder)', '.file-viewer-touch', '.file-attachment', - '.post--attachment img', - 'img[src*="/api/v4/files/"]', + '.post--attachment img:not(.image-loading__placeholder)', + 'img[src*="/api/v4/files/"]:not(.image-loading__placeholder)', ].join(', '); +/** + * Mattermost 11.10+ (MM-69174) SizeAwareImage ignores clicks until the real image has + * loaded, and keeps a visible placeholder button while the clickable control is + * display:none. Wait for a visible, loaded non-placeholder control before opening. + */ +async function waitForLoadedImagePreviewControl(serverWin: ServerView): Promise { + await expect.poll(async () => serverWin.runInRenderer(` + const posts = Array.from(document.querySelectorAll('.post')); + for (let index = posts.length - 1; index >= 0; index--) { + const post = posts[index]; + const buttons = Array.from(post.querySelectorAll('.file-preview__button')); + for (const button of buttons) { + if (!(button instanceof HTMLElement)) { + continue; + } + if (window.getComputedStyle(button).display === 'none') { + continue; + } + const loadedImg = button.querySelector('img:not(.image-loading__placeholder)'); + if (!(loadedImg instanceof HTMLImageElement)) { + continue; + } + if (loadedImg.complete && loadedImg.naturalWidth > 0) { + button.scrollIntoView({block: 'center'}); + return true; + } + } + + // Legacy servers without .file-preview__button + const legacyImg = post.querySelector( + '.post-image img:not(.image-loading__placeholder), .post--attachment img:not(.image-loading__placeholder), img[src*="/api/v4/files/"]:not(.image-loading__placeholder)', + ); + if (legacyImg instanceof HTMLImageElement && + legacyImg.complete && + legacyImg.naturalWidth > 0 && + window.getComputedStyle(legacyImg).display !== 'none') { + legacyImg.scrollIntoView({block: 'center'}); + return true; + } + } + return false; + `, true), { + timeout: 60_000, + message: 'Uploaded image must finish loading into a visible file-preview control before it can be opened', + }).toBe(true); +} + async function submitComposerPost(serverWin: ServerView): Promise { const sent = await serverWin.runInRenderer(` const sendButton = document.querySelector( @@ -109,6 +157,7 @@ async function uploadAndPostPng(serverWin: ServerView): Promise { await recoverInteractiveChannel(serverWin, {channelItem: '#sidebarItem_town-square'}); await waitForPostedAttachment(serverWin); + await waitForLoadedImagePreviewControl(serverWin); } async function isImagePreviewOpen(serverWin: ServerView): Promise { @@ -126,12 +175,11 @@ async function isImagePreviewOpen(serverWin: ServerView): Promise { async function openImagePreview(serverWin: ServerView): Promise { return serverWin.runInRenderer(` - const attachmentSelector = ${JSON.stringify(POSTED_IMAGE_SELECTOR)}; const posts = Array.from(document.querySelectorAll('.post')); let root = null; for (let index = posts.length - 1; index >= 0; index--) { const post = posts[index]; - if (post.querySelector(attachmentSelector) || + if (post.querySelector('.file-preview__button, .post-image, .post--attachment, .file-attachment') || post.querySelector('[aria-label*="e2e-preview.png" i], [aria-label*="file thumbnail" i]')) { root = post; break; @@ -141,30 +189,52 @@ async function openImagePreview(serverWin: ServerView): Promise { return false; } + const isVisible = (el) => el instanceof HTMLElement && window.getComputedStyle(el).display !== 'none'; + const isLoadedImg = (el) => el instanceof HTMLImageElement && + !el.classList.contains('image-loading__placeholder') && + el.complete && + el.naturalWidth > 0 && + isVisible(el); + + // Prefer the visible SizeAwareImage control (11.10+/MM-69174); clicks on the + // placeholder button are intentionally ignored until the real image loads. + const previewButtons = Array.from(root.querySelectorAll('.file-preview__button')).filter(isVisible); + for (const button of previewButtons) { + const loadedImg = button.querySelector('img:not(.image-loading__placeholder)'); + if (loadedImg instanceof HTMLImageElement && loadedImg.complete && loadedImg.naturalWidth > 0) { + button.scrollIntoView({block: 'center', inline: 'center'}); + button.click(); + return true; + } + } + const clickTargets = [ - root.querySelector('[aria-label*="e2e-preview.png" i]'), - root.querySelector('[aria-label*="file thumbnail" i]'), - root.querySelector('.post-image .small-image__container'), + ...Array.from(root.querySelectorAll('[aria-label*="e2e-preview.png" i]')), + ...Array.from(root.querySelectorAll('[aria-label*="file thumbnail" i]')), + ...Array.from(root.querySelectorAll('.post-image img:not(.image-loading__placeholder)')), + ...Array.from(root.querySelectorAll('.post--attachment img:not(.image-loading__placeholder)')), + ...Array.from(root.querySelectorAll('img[src*="/api/v4/files/"]:not(.image-loading__placeholder)')), root.querySelector('.post-image .image-loaded-container'), + root.querySelector('.post-image .small-image__container'), root.querySelector('.post-image__image'), - root.querySelector('.post-image img'), root.querySelector('.file-viewer-touch'), - root.querySelector('.file-attachment'), - root.querySelector('.post--attachment img'), - root.querySelector('img[src*="/api/v4/files/"]'), - root.querySelector('.post-image'), - root.querySelector('.post--attachment'), - ].filter(Boolean); + ].filter((target) => { + if (!target) { + return false; + } + if (target instanceof HTMLImageElement) { + return isLoadedImg(target); + } + return isVisible(target) && Boolean(target.querySelector?.('img:not(.image-loading__placeholder)')); + }); const target = clickTargets[0]; - if (!target) { + if (!(target instanceof HTMLElement)) { return false; } target.scrollIntoView({block: 'center', inline: 'center'}); - if (target instanceof HTMLElement) { - target.click(); - } + target.click(); return true; `, true); } @@ -185,8 +255,8 @@ async function getPreviewFileId(serverWin: ServerView): Promise { const sources = [ document.querySelector('[data-testid="imagePreview"]')?.getAttribute('src'), document.querySelector('.file-preview-modal img')?.getAttribute('src'), - document.querySelector('.post-image img[src*="/files/"]')?.getAttribute('src'), - document.querySelector('img[src*="/api/v4/files/"]')?.getAttribute('src'), + document.querySelector('.post-image img[src*="/files/"]:not(.image-loading__placeholder)')?.getAttribute('src'), + document.querySelector('img[src*="/api/v4/files/"]:not(.image-loading__placeholder)')?.getAttribute('src'), ].filter(Boolean); for (const source of sources) { From b1f2da5fec88cc416c657ef39cbeecb07e0fc3a1 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 30 Jul 2026 18:38:22 +0000 Subject: [PATCH 2/4] e2e: replace invalid media preview PNG fixture The previous base64 PNG was rejected by Mattermost's image decoder, so no thumbnail/preview was generated. Combined with SizeAwareImage's load-gated clicks in 11.10+, MM-T4054 could never open the modal. Co-authored-by: yasser khan --- e2e/specs/mattermost/media_preview.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/e2e/specs/mattermost/media_preview.test.ts b/e2e/specs/mattermost/media_preview.test.ts index b8e00731874..beed4f3ef2b 100644 --- a/e2e/specs/mattermost/media_preview.test.ts +++ b/e2e/specs/mattermost/media_preview.test.ts @@ -9,8 +9,10 @@ import {prepareMattermostServerView} from '../../helpers/prepareServerView'; import {getFilePublicLink, isPublicLinkEnabled} from '../../helpers/server_api/publicLinks'; import type {ServerView} from '../../helpers/serverView'; -// 64x64 PNG — above Mattermost's 48px inline-image minimum so thumbnails render visibly. -const PREVIEW_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAf0lEQVR4nNXOQREAIAzAsFJJ8y8FMYjgsWsU5NwZyiRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4iRO4twO/HqSogHAzFmDswAAAABJRU5ErkJggg=='; +// Valid 128x128 PNG. The previous fixture was rejected by the server decoder +// ("png: invalid format: too much pixel data"), so no preview was generated and +// SizeAwareImage (MM-69174 / 11.10+) ignored clicks until load forever. +const PREVIEW_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAACx0lEQVR4nO3dsVEbQRhH8ZWHOuyAHogcEVAClTgmcGpX4hIIlNgRPRC4EjnYmRuNYARrab/3P/R+kQMh43333Z1kFm12u10b8eXnn6HH//321ec/4tPQo3V2BoAZAGYAmAFgBoAZAGYAmAFgBoAZAGYAmAFgBoAZAHaV9v74pT2/EwAzAMwAMAPADAAzAMwAMAPADAAzAMwAMAPADAAzAMwAsM3q9gdsf30//oDrp8dTnv/A7P8/uBp6NOXNRd/3fHO3/Pl4jATRAYbW/VVLjNgSoQFOX/oDvURghrgAZ1/6fc83d9vWbu8f5v0Vo7LugvZP3/NMbTwqZQJqln7RGySMQsQEFK/+ImEU+ADU6nd4AzgAu/od24AMkLD6HdgAC5Cz+h3VgAmQtvod0gAIkLn6XX0D/i7owlUHSD78u+Ih2Hz+8XvoC055fxy/6X6/5W079wd8cHUBVnT4t8JTpRMAKwqwrsO/qxkCJwBmAFhFgDWef7qCs5ATADMAzACw6QHWewHoZn//TgDMADADwAwAm74/YO0X4Tb4I71+fsDKGABmAJgBYAaATQ8QuCtoyOzv3wmAGQBmAFhFgPVeBgo2kTkBMAPAigKs8SxUs4nVCYDVBVjXEJTt4S79/IDt0Feiln/mh9ofkPCrAd6jclirrwH5DYpPlV6EYUCA5CGov1NgJiCzAXKfhp2C0hpQd8nkNSCnAfgaBb4IJzRgXyHyd0FsA/z1OR+gcQ3w1W85v7SvNyj7OcaEpe8iJmBRMwo5q9/SArTWrp8e5y3Q7f1D1Oq3nFPQgb5MZ9wlmnC79arQAN1ytP53idh1X/j5AW/w8wMOHRzUowuUJu4ifGkMADMAzAAwA8AMADMAzAAwA8AMADMAzAAwA8AMACvdH+Dzv+QEwAwAMwDMADADwAwAMwDMADADwAwAMwDMADADwAwAMwDsH5fw4xGXqkx/AAAAAElFTkSuQmCC'; const PREVIEW_MODAL_SELECTOR = [ '.file-preview-modal', From 8257a5bce1d5a5ec0232622dcd1b97f308ec69c7 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 30 Jul 2026 18:46:18 +0000 Subject: [PATCH 3/4] e2e: share media preview selector helpers across wait/open paths Address CodeRabbit nitpick: extract loaded-image selectors and visible/loaded predicates into PREVIEW_IMAGE_UTILS so wait and click paths stay in sync. Co-authored-by: yasser khan --- e2e/specs/mattermost/media_preview.test.ts | 93 +++++++++++----------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/e2e/specs/mattermost/media_preview.test.ts b/e2e/specs/mattermost/media_preview.test.ts index beed4f3ef2b..8184e317cf3 100644 --- a/e2e/specs/mattermost/media_preview.test.ts +++ b/e2e/specs/mattermost/media_preview.test.ts @@ -21,18 +21,45 @@ const PREVIEW_MODAL_SELECTOR = [ '#viewImageModalLabel', ].join(', '); +const LOADED_IMAGE_SELECTOR = [ + '.post-image img:not(.image-loading__placeholder)', + '.post--attachment img:not(.image-loading__placeholder)', + 'img[src*="/api/v4/files/"]:not(.image-loading__placeholder)', +].join(', '); + const POSTED_IMAGE_SELECTOR = [ '.file-preview__button', '.post-image .small-image__container', '.post-image .image-loaded-container', '.post-image__image', - '.post-image img:not(.image-loading__placeholder)', + LOADED_IMAGE_SELECTOR, '.file-viewer-touch', '.file-attachment', - '.post--attachment img:not(.image-loading__placeholder)', - 'img[src*="/api/v4/files/"]:not(.image-loading__placeholder)', ].join(', '); +// Shared helpers injected into renderer scripts (same pattern as DOM_UTILS in serverView.ts). +const PREVIEW_IMAGE_UTILS = ` +const LOADED_IMAGE_SELECTOR = ${JSON.stringify(LOADED_IMAGE_SELECTOR)}; +const isPreviewControlVisible = (el) => el instanceof HTMLElement && window.getComputedStyle(el).display !== 'none'; +const isLoadedPreviewImage = (el) => el instanceof HTMLImageElement && + !el.classList.contains('image-loading__placeholder') && + el.complete && + el.naturalWidth > 0 && + isPreviewControlVisible(el); +const findVisibleLoadedPreviewButton = (root) => { + for (const button of root.querySelectorAll('.file-preview__button')) { + if (!isPreviewControlVisible(button)) { + continue; + } + const loadedImg = button.querySelector('img:not(.image-loading__placeholder)'); + if (loadedImg instanceof HTMLImageElement && loadedImg.complete && loadedImg.naturalWidth > 0) { + return button; + } + } + return null; +}; +`; + /** * Mattermost 11.10+ (MM-69174) SizeAwareImage ignores clicks until the real image has * loaded, and keeps a visible placeholder button while the clickable control is @@ -40,35 +67,19 @@ const POSTED_IMAGE_SELECTOR = [ */ async function waitForLoadedImagePreviewControl(serverWin: ServerView): Promise { await expect.poll(async () => serverWin.runInRenderer(` + ${PREVIEW_IMAGE_UTILS} const posts = Array.from(document.querySelectorAll('.post')); for (let index = posts.length - 1; index >= 0; index--) { const post = posts[index]; - const buttons = Array.from(post.querySelectorAll('.file-preview__button')); - for (const button of buttons) { - if (!(button instanceof HTMLElement)) { - continue; - } - if (window.getComputedStyle(button).display === 'none') { - continue; - } - const loadedImg = button.querySelector('img:not(.image-loading__placeholder)'); - if (!(loadedImg instanceof HTMLImageElement)) { - continue; - } - if (loadedImg.complete && loadedImg.naturalWidth > 0) { - button.scrollIntoView({block: 'center'}); - return true; - } + const previewButton = findVisibleLoadedPreviewButton(post); + if (previewButton) { + previewButton.scrollIntoView({block: 'center'}); + return true; } // Legacy servers without .file-preview__button - const legacyImg = post.querySelector( - '.post-image img:not(.image-loading__placeholder), .post--attachment img:not(.image-loading__placeholder), img[src*="/api/v4/files/"]:not(.image-loading__placeholder)', - ); - if (legacyImg instanceof HTMLImageElement && - legacyImg.complete && - legacyImg.naturalWidth > 0 && - window.getComputedStyle(legacyImg).display !== 'none') { + const legacyImg = post.querySelector(LOADED_IMAGE_SELECTOR); + if (isLoadedPreviewImage(legacyImg)) { legacyImg.scrollIntoView({block: 'center'}); return true; } @@ -177,6 +188,7 @@ async function isImagePreviewOpen(serverWin: ServerView): Promise { async function openImagePreview(serverWin: ServerView): Promise { return serverWin.runInRenderer(` + ${PREVIEW_IMAGE_UTILS} const posts = Array.from(document.querySelectorAll('.post')); let root = null; for (let index = posts.length - 1; index >= 0; index--) { @@ -191,31 +203,19 @@ async function openImagePreview(serverWin: ServerView): Promise { return false; } - const isVisible = (el) => el instanceof HTMLElement && window.getComputedStyle(el).display !== 'none'; - const isLoadedImg = (el) => el instanceof HTMLImageElement && - !el.classList.contains('image-loading__placeholder') && - el.complete && - el.naturalWidth > 0 && - isVisible(el); - // Prefer the visible SizeAwareImage control (11.10+/MM-69174); clicks on the // placeholder button are intentionally ignored until the real image loads. - const previewButtons = Array.from(root.querySelectorAll('.file-preview__button')).filter(isVisible); - for (const button of previewButtons) { - const loadedImg = button.querySelector('img:not(.image-loading__placeholder)'); - if (loadedImg instanceof HTMLImageElement && loadedImg.complete && loadedImg.naturalWidth > 0) { - button.scrollIntoView({block: 'center', inline: 'center'}); - button.click(); - return true; - } + const previewButton = findVisibleLoadedPreviewButton(root); + if (previewButton) { + previewButton.scrollIntoView({block: 'center', inline: 'center'}); + previewButton.click(); + return true; } const clickTargets = [ ...Array.from(root.querySelectorAll('[aria-label*="e2e-preview.png" i]')), ...Array.from(root.querySelectorAll('[aria-label*="file thumbnail" i]')), - ...Array.from(root.querySelectorAll('.post-image img:not(.image-loading__placeholder)')), - ...Array.from(root.querySelectorAll('.post--attachment img:not(.image-loading__placeholder)')), - ...Array.from(root.querySelectorAll('img[src*="/api/v4/files/"]:not(.image-loading__placeholder)')), + ...Array.from(root.querySelectorAll(LOADED_IMAGE_SELECTOR)), root.querySelector('.post-image .image-loaded-container'), root.querySelector('.post-image .small-image__container'), root.querySelector('.post-image__image'), @@ -225,9 +225,10 @@ async function openImagePreview(serverWin: ServerView): Promise { return false; } if (target instanceof HTMLImageElement) { - return isLoadedImg(target); + return isLoadedPreviewImage(target); } - return isVisible(target) && Boolean(target.querySelector?.('img:not(.image-loading__placeholder)')); + return isPreviewControlVisible(target) && + Boolean(target.querySelector?.('img:not(.image-loading__placeholder)')); }); const target = clickTargets[0]; From dd2810b1b409d79c7b0d9a150a4eb4724eb7de94 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 30 Jul 2026 18:55:53 +0000 Subject: [PATCH 4/4] e2e: bind media preview wait/click to e2e-preview.png post Address CodeRabbit feedback: locate the fixture attachment post by filename and only wait on / click that post's loaded preview control, so unrelated attachments cannot satisfy readiness. Co-authored-by: yasser khan --- e2e/specs/mattermost/media_preview.test.ts | 94 +++++++++++----------- 1 file changed, 46 insertions(+), 48 deletions(-) diff --git a/e2e/specs/mattermost/media_preview.test.ts b/e2e/specs/mattermost/media_preview.test.ts index 8184e317cf3..1bb921349e7 100644 --- a/e2e/specs/mattermost/media_preview.test.ts +++ b/e2e/specs/mattermost/media_preview.test.ts @@ -27,25 +27,36 @@ const LOADED_IMAGE_SELECTOR = [ 'img[src*="/api/v4/files/"]:not(.image-loading__placeholder)', ].join(', '); -const POSTED_IMAGE_SELECTOR = [ - '.file-preview__button', - '.post-image .small-image__container', - '.post-image .image-loaded-container', - '.post-image__image', - LOADED_IMAGE_SELECTOR, - '.file-viewer-touch', - '.file-attachment', -].join(', '); +const PREVIEW_FILE_NAME = 'e2e-preview.png'; // Shared helpers injected into renderer scripts (same pattern as DOM_UTILS in serverView.ts). const PREVIEW_IMAGE_UTILS = ` const LOADED_IMAGE_SELECTOR = ${JSON.stringify(LOADED_IMAGE_SELECTOR)}; +const PREVIEW_FILE_NAME = ${JSON.stringify(PREVIEW_FILE_NAME)}; const isPreviewControlVisible = (el) => el instanceof HTMLElement && window.getComputedStyle(el).display !== 'none'; const isLoadedPreviewImage = (el) => el instanceof HTMLImageElement && !el.classList.contains('image-loading__placeholder') && el.complete && el.naturalWidth > 0 && isPreviewControlVisible(el); +const postHasPreviewFixture = (post) => { + if (post.querySelector('[aria-label*="' + PREVIEW_FILE_NAME + '" i]')) { + return true; + } + // Filename can also appear in attachment headers before the image aria-label mounts. + const attachment = post.querySelector('.post-image, .post--attachment, .file-attachment, .file-preview__button'); + return Boolean(attachment && (attachment.textContent || '').toLowerCase().includes(PREVIEW_FILE_NAME)); +}; +const findPreviewFixturePost = () => { + const posts = Array.from(document.querySelectorAll('.post')); + for (let index = posts.length - 1; index >= 0; index--) { + const post = posts[index]; + if (postHasPreviewFixture(post)) { + return post; + } + } + return null; +}; const findVisibleLoadedPreviewButton = (root) => { for (const button of root.querySelectorAll('.file-preview__button')) { if (!isPreviewControlVisible(button)) { @@ -68,26 +79,27 @@ const findVisibleLoadedPreviewButton = (root) => { async function waitForLoadedImagePreviewControl(serverWin: ServerView): Promise { await expect.poll(async () => serverWin.runInRenderer(` ${PREVIEW_IMAGE_UTILS} - const posts = Array.from(document.querySelectorAll('.post')); - for (let index = posts.length - 1; index >= 0; index--) { - const post = posts[index]; - const previewButton = findVisibleLoadedPreviewButton(post); - if (previewButton) { - previewButton.scrollIntoView({block: 'center'}); - return true; - } + const post = findPreviewFixturePost(); + if (!post) { + return false; + } - // Legacy servers without .file-preview__button - const legacyImg = post.querySelector(LOADED_IMAGE_SELECTOR); - if (isLoadedPreviewImage(legacyImg)) { - legacyImg.scrollIntoView({block: 'center'}); - return true; - } + const previewButton = findVisibleLoadedPreviewButton(post); + if (previewButton) { + previewButton.scrollIntoView({block: 'center'}); + return true; + } + + // Legacy servers without .file-preview__button + const legacyImg = post.querySelector(LOADED_IMAGE_SELECTOR); + if (isLoadedPreviewImage(legacyImg)) { + legacyImg.scrollIntoView({block: 'center'}); + return true; } return false; `, true), { timeout: 60_000, - message: 'Uploaded image must finish loading into a visible file-preview control before it can be opened', + message: 'Uploaded e2e-preview.png must finish loading into a visible file-preview control before it can be opened', }).toBe(true); } @@ -110,24 +122,20 @@ async function submitComposerPost(serverWin: ServerView): Promise { async function waitForPostedAttachment(serverWin: ServerView): Promise { await expect.poll(async () => serverWin.runInRenderer(` - const attachmentSelector = ${JSON.stringify(POSTED_IMAGE_SELECTOR)}; + ${PREVIEW_IMAGE_UTILS} const composer = document.querySelector('#post-create, .AdvancedTextEditor, .post-create, [data-testid="post-create"]'); const draftAttachment = composer?.querySelector('.file-preview, .file-preview__container, .attachment-preview'); if (draftAttachment) { return false; } - const posts = Array.from(document.querySelectorAll('.post')); - for (let index = posts.length - 1; index >= 0; index--) { - const post = posts[index]; - if (post.querySelector(attachmentSelector) || - post.querySelector('[aria-label*="e2e-preview.png" i], [aria-label*="file thumbnail" i]')) { - post.scrollIntoView({block: 'center'}); - return true; - } + const post = findPreviewFixturePost(); + if (!post) { + return false; } - return false; - `, true), {timeout: 60_000, message: 'Uploaded image must appear in the channel post list'}).toBe(true); + post.scrollIntoView({block: 'center'}); + return true; + `, true), {timeout: 60_000, message: 'Uploaded e2e-preview.png must appear in the channel post list'}).toBe(true); } async function uploadAndPostPng(serverWin: ServerView): Promise { @@ -138,7 +146,7 @@ async function uploadAndPostPng(serverWin: ServerView): Promise { for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } - const file = new File([bytes], 'e2e-preview.png', {type: 'image/png'}); + const file = new File([bytes], ${JSON.stringify(PREVIEW_FILE_NAME)}, {type: 'image/png'}); const input = document.querySelector('#fileUploadInput, input[type="file"]'); if (!(input instanceof HTMLInputElement)) { @@ -189,16 +197,7 @@ async function isImagePreviewOpen(serverWin: ServerView): Promise { async function openImagePreview(serverWin: ServerView): Promise { return serverWin.runInRenderer(` ${PREVIEW_IMAGE_UTILS} - const posts = Array.from(document.querySelectorAll('.post')); - let root = null; - for (let index = posts.length - 1; index >= 0; index--) { - const post = posts[index]; - if (post.querySelector('.file-preview__button, .post-image, .post--attachment, .file-attachment') || - post.querySelector('[aria-label*="e2e-preview.png" i], [aria-label*="file thumbnail" i]')) { - root = post; - break; - } - } + const root = findPreviewFixturePost(); if (!root) { return false; } @@ -213,8 +212,7 @@ async function openImagePreview(serverWin: ServerView): Promise { } const clickTargets = [ - ...Array.from(root.querySelectorAll('[aria-label*="e2e-preview.png" i]')), - ...Array.from(root.querySelectorAll('[aria-label*="file thumbnail" i]')), + ...Array.from(root.querySelectorAll('[aria-label*="' + PREVIEW_FILE_NAME + '" i]')), ...Array.from(root.querySelectorAll(LOADED_IMAGE_SELECTOR)), root.querySelector('.post-image .image-loaded-container'), root.querySelector('.post-image .small-image__container'),