snapshot of https://github.com/mattermost/mattermost.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
Server CI Nightly Race / Build Environment (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-16 00:29:55 +05:00
commit 240db4e2a7
15309 changed files with 2173406 additions and 0 deletions

View File

@@ -0,0 +1,188 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @scroll
import * as MESSAGES from '@/fixtures/messages';
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Scroll', () => {
let testTeam;
let testChannel;
let otherUser;
beforeEach(() => {
// # Create new team and new user and visit Town Square channel
cy.apiInitSetup().then(({team, channel}) => {
testTeam = team;
testChannel = channel;
cy.apiCreateUser().then(({user: user2}) => {
otherUser = user2;
cy.apiAddUserToTeam(testTeam.id, otherUser.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, otherUser.id);
});
});
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
});
});
it('MM-T2378 Channel with only a few posts opens at the bottom', () => {
// # Post a starting message with user 1
cy.postMessage('This is the first post');
// # Post as few as messages so that scroll bar appears as channel name scroll hidden
Cypress._.times(20, (postIndex) => {
cy.postMessage(`p-${postIndex + 1}`);
});
// # Post the last message
cy.postMessage('This is the last post');
// # Reload the browser
cy.reload();
// * Verify that the top of the channel is scrolled past hidden
cy.findByText(`Beginning of ${testChannel.display_name}`).should('exist').and('not.be.visible');
// * Verify that the last message is visible implying that channel scrolled to bottom on reload
cy.findByText('This is the last post').should('exist').and('be.visible');
});
it('MM-T2382 Center channel scroll', () => {
// # Post a starting message with user 1
cy.postMessage('This is the first post');
// # Make enough posts so that first post is scrolled past hidden
Cypress._.times(30, (postIndex) => {
cy.postMessage(`p-${postIndex + 1}`);
});
// * Verify that we are the bottom of the channel
cy.findByText('This is the first post').should('exist').and('not.be.visible');
// * Make post from another user and verify that channel is scrolled down as post appear
Cypress._.times(3, (postIndex) => {
postMessageAndcheckIfTopMessagesAreScrolled(postIndex + 1, otherUser, testChannel.id);
});
});
it('MM-T2367 Compact view', () => {
const message = 'This is the first post';
// # Set display mode to standard
cy.apiSaveMessageDisplayPreference('clean');
// # Post a starting message with user 1
Cypress._.times(2, () => {
cy.postMessage(message);
});
// * Verify that messages do no have user's name in post
cy.getLastPostId().then((parentMessageId) => {
cy.get(`#${parentMessageId}_message`).invoke('text').then((text) => {
expect(text).to.equal(message);
expect(text).to.not.have.string('sysadmin');
});
});
// # Set display mode to compact
cy.apiSaveMessageDisplayPreference('compact');
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// * Verify that messages have user's name in post
cy.getLastPostId().then((parentMessageId) => {
cy.get(`#${parentMessageId}_message`).parent().invoke('text').then((text) => {
expect(text).to.contain('sysadmin');
expect(text).to.contain(message);
});
});
});
// https://automation-test-cases.vercel.app/test/MM-T2374
it('MM-T2374 System Messages', () => {
const firstPost = '<< This is the first post><';
const lastPost = '<< This is the last post><';
// # Make an opening first post
cy.postMessage(firstPost);
// # Make enough post so the channel can scroll sufficiently
Cypress._.times(6, () => {
cy.uiPostMessageQuickly(MESSAGES.LARGE);
cy.uiPostMessageQuickly(MESSAGES.MEDIUM);
});
// # Make a final post
cy.postMessage(lastPost);
// # Scroll to top
cy.get('div.post-list__dynamic').should('be.visible').scrollTo('top', {duration: TIMEOUTS.ONE_SEC}).wait(TIMEOUTS.ONE_SEC);
// * Verify we are on the top of the channel
cy.findByText(firstPost).should('exist').and('be.visible');
cy.findByText(lastPost).should('exist').and('not.be.visible');
// # Add few users to the same channel
cy.apiCreateUser().then(({user: userAddRemove1}) => {
cy.apiAddUserToTeam(testTeam.id, userAddRemove1.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, userAddRemove1.id);
cy.wait(TIMEOUTS.THREE_SEC);
cy.apiCreateUser().then(({user: userAddRemove2}) => {
cy.apiAddUserToTeam(testTeam.id, userAddRemove2.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, userAddRemove2.id);
cy.wait(TIMEOUTS.THREE_SEC);
cy.apiCreateUser().then(({user: userAddRemove3}) => {
cy.apiAddUserToTeam(testTeam.id, userAddRemove3.id).then(() => {
cy.apiAddUserToChannel(testChannel.id, userAddRemove3.id);
// # Wait a little before we can start removing
cy.wait(TIMEOUTS.FIVE_SEC);
// # Remove few users from the same channel
cy.removeUserFromChannel(testChannel.id, userAddRemove1.id);
cy.wait(TIMEOUTS.THREE_SEC);
cy.removeUserFromChannel(testChannel.id, userAddRemove2.id);
// # Wait a little after we removed the users
cy.wait(TIMEOUTS.FIVE_SEC);
});
});
});
});
});
});
// * Verify we are still on the top of the channel and no scrolling occured
cy.findByText(firstPost).should('exist').and('be.visible');
cy.findByText(lastPost).should('exist').and('not.be.visible');
});
});
function postMessageAndcheckIfTopMessagesAreScrolled(postIndex, sender, channelId) {
// # Make posts from other user
cy.postMessageAs({sender, message: `Other users p-${postIndex}`, channelId});
cy.get('#post-list').should('exist').within(() => {
// * Verify that top post are hidden behind scroll
cy.findByText(`p-${postIndex}`).should('exist').and('not.be.visible');
cy.findByText(`p-${postIndex + 1}`).should('exist').and('not.be.visible');
// * Also verify that latest messages from the other user are visible
cy.findByText(`Other users p-${postIndex}`).should('exist').and('be.visible');
});
}

View File

@@ -0,0 +1,62 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
describe('Scroll', () => {
before(() => {
// # Create new team and new user and visit Town Square channel
cy.apiInitSetup({loginAfter: true}).then(({offTopicUrl}) => {
// # Switch the settings for the test user to have images collapsed by default
cy.apiSaveCollapsePreviewsPreference('true');
cy.visit(offTopicUrl);
// # Post at least 10 messages in a channel
Cypress._.times(10, (index) => cy.postMessage(index));
});
});
it('MM-T2370 Default images to collapsed', () => {
const filename = 'huge-image.jpg';
// # Post an image in center channel
cy.get('#advancedTextEditorCell').find('#fileUploadInput').attachFile(filename);
cy.get('.post-image').should('be.visible');
cy.uiGetPostTextBox().clear().type('{enter}');
// * Observe image preview is collapsed
cy.uiGetFileThumbnail(filename).should('not.exist');
// # Save height of the last post
cy.getLastPost().then((lastPost) => {
cy.wrap(parseInt(lastPost[0].clientHeight, 10)).as('lastPostHeight');
});
// # Refresh the browser
cy.reload();
// * Verify that the last post is still the same after reload
cy.getLastPost().then((lastPost) => {
cy.get('@lastPostHeight').then((lastPostHeight) => {
expect(parseInt(lastPost[0].clientHeight, 10)).to.equal(lastPostHeight);
});
});
// * Observe image preview is collapsed after reloading the page
cy.uiGetFileThumbnail(filename).should('not.exist');
// # Sanity check that it's visible when collapsed preview is disabled
cy.apiSaveCollapsePreviewsPreference('false');
cy.reload();
cy.uiGetFileThumbnail(filename).should('be.visible');
});
});

View File

@@ -0,0 +1,83 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @scroll
import {deletePostAndVerifyScroll, postListOfMessages, scrollCurrentChannelFromTop} from './helpers';
describe('Scroll', () => {
let testChannelId;
let testChannelLink;
let mainUser;
let otherUser;
beforeEach(() => {
cy.apiAdminLogin();
cy.apiInitSetup().then(({user, team, channel}) => {
mainUser = user;
testChannelId = channel.id;
testChannelLink = `/${team.name}/channels/${channel.name}`;
cy.apiCreateUser().then(({user: user2}) => {
otherUser = user2;
cy.apiAddUserToTeam(team.id, otherUser.id).then(() => {
cy.apiAddUserToChannel(testChannelId, otherUser.id);
});
});
});
});
it('MM-T2373_1 Post list does not scroll when the offscreen-above post with image attachment is deleted', () => {
cy.apiLogin(otherUser);
cy.visit(testChannelLink);
// # Other user posts a messages with image attachment
postMessageWithImageAttachment().then((attachmentPostId) => {
// # Other user posts a few messages so that the first message is hidden
postListOfMessages({sender: otherUser, channelId: testChannelId});
cy.apiLogin(mainUser);
cy.visit(testChannelLink);
// # Main user scrolls to the top to load all the messages
scrollCurrentChannelFromTop(0);
// # Main user scrolls to the middle so that post with attachment is offscreen above
scrollCurrentChannelFromTop('90%');
// * Delete the message with image attachment, and verify that the channel did not scroll
deletePostAndVerifyScroll(attachmentPostId, {user: otherUser});
});
});
it('MM-T2373_2 Post list does not scroll when the offscreen-below post with image attachment is deleted', () => {
cy.apiLogin(otherUser);
cy.visit(testChannelLink);
// # Other user posts a few messages so that the first message is hidden
postListOfMessages({sender: otherUser, channelId: testChannelId});
// # Other user posts a messages with image attachment
postMessageWithImageAttachment().then((attachmentPostId) => {
cy.apiLogin(mainUser);
cy.visit(testChannelLink);
// # Main user scrolls to the middle so that post with attachment is offscreen below
scrollCurrentChannelFromTop('65%');
// * Delete the message with image attachment, and verify that the channel did not scroll
deletePostAndVerifyScroll(attachmentPostId, {user: otherUser});
});
});
});
function postMessageWithImageAttachment() {
cy.get('#fileUploadInput').attachFile('huge-image.jpg');
cy.postMessage('Bla-bla-bla');
return cy.getLastPostId();
}

View File

@@ -0,0 +1,53 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @scroll
import {deletePostAndVerifyScroll, postListOfMessages, scrollCurrentChannelFromTop} from './helpers';
describe('Scroll', () => {
let testChannelId;
let testChannelLink;
let otherUser;
const multilineString = `A
multiline
message`;
before(() => {
cy.apiInitSetup().then(({team, channel}) => {
testChannelId = channel.id;
testChannelLink = `/${team.name}/channels/${channel.name}`;
cy.apiCreateUser().then(({user: user2}) => {
otherUser = user2;
cy.apiAddUserToTeam(team.id, otherUser.id).then(() => {
cy.apiAddUserToChannel(testChannelId, otherUser.id);
});
});
cy.visit(testChannelLink);
});
});
it('MM-T2372 Post list does not scroll when the offscreen post is deleted', () => {
// # Other user posts a multiline message
cy.postMessageAs({sender: otherUser, message: multilineString, channelId: testChannelId});
cy.getLastPostId().then((multilineMessageID) => {
// # Main user posts a few messages so that the first message is hidden
postListOfMessages({sender: otherUser, channelId: testChannelId});
// # Main user scrolls to the middle so that multiline post is offscreen
scrollCurrentChannelFromTop('100%');
// * Delete the multiline message and verify that the channel did not scroll
deletePostAndVerifyScroll(multilineMessageID, {user: otherUser});
});
});
});

View File

@@ -0,0 +1,85 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @scroll
import {postListOfMessages, scrollCurrentChannelFromTop} from './helpers';
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Scroll', () => {
let firstPostBeforeScroll;
let lastPostBeforeScroll;
let testChannelId;
let testChannelLink;
let otherUser;
const multilineString = `A
multiline
message`;
const newMultilineMessage = `This
is
a new
multiline
message`;
before(() => {
cy.apiCreateUser().then(({user}) => {
otherUser = user;
});
cy.apiInitSetup().then(({team, channel}) => {
testChannelId = channel.id;
testChannelLink = `/${team.name}/channels/${channel.name}`;
cy.apiAddUserToTeam(team.id, otherUser.id).then(() => {
cy.apiAddUserToChannel(testChannelId, otherUser.id);
cy.visit(testChannelLink);
});
});
});
it('MM-T2371 Post list does not scroll when the offscreen post is edited', () => {
// # Other user posts a multiline message
cy.postMessageAs({sender: otherUser, message: multilineString, channelId: testChannelId});
cy.getLastPostId().then((postId) => {
const multilineMessageID = postId;
postListOfMessages({sender: otherUser, channelId: testChannelId});
scrollCurrentChannelFromTop('100%');
// # Get the text of the first visible post
cy.get('.post-message__text:visible').first().then((postMessage) => {
firstPostBeforeScroll = postMessage.text();
});
// # Get the text of the last visible post
cy.get('.post-message__text:visible').last().then((postMessage) => {
lastPostBeforeScroll = postMessage.text();
});
// # Edit a multiline message from the other user
cy.externalRequest({user: otherUser, method: 'PUT', path: `posts/${multilineMessageID}`, data: {id: multilineMessageID, message: newMultilineMessage}});
// # Wait for the message to be edited
cy.wait(TIMEOUTS.FIVE_SEC);
// * Verify the first post is the same after the editing
cy.get('.post-message__text:visible').first().then((firstPostAfterScroll) => {
expect(firstPostAfterScroll.text()).equal(firstPostBeforeScroll);
});
// * Verify the last post is the same after the editing
cy.get('.post-message__text:visible').last().then((lastPostAfterScroll) => {
expect(lastPostAfterScroll.text()).equal(lastPostBeforeScroll);
});
});
});
});

View File

@@ -0,0 +1,163 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
const timeouts = require('@/fixtures/timeouts');
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @scroll
describe('Scroll', () => {
let testTeam;
let testChannel;
before(() => {
cy.apiUpdateConfig({
ServiceSettings: {
EnableLinkPreviews: true,
},
});
cy.apiInitSetup().then(({team, channel}) => {
testTeam = team;
testChannel = channel;
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
});
});
it('MM-T2368 Fixed width', () => {
const link = 'https://www.bbc.com/news/uk-wales-45142614';
const gifLink = '![gif](http://i.giphy.com/xNrM4cGJ8u3ao.gif)';
const firstMessage = 'This is the first post';
const lastMessage = 'This is the last post';
// Assigning alias to posted message ids
cy.postMessage(firstMessage);
cy.getLastPostId().as('firstPostId');
cy.postMessage(link);
cy.getLastPostId().as('linkPreviewPostId');
cy.postMessage(gifLink);
cy.getLastPostId().as('gifLinkPostId');
// Posting different type of images and videos
const commonTypeFiles = [
'jpg-image-file.jpg',
'gif-image-file.gif',
'mp3-audio-file.mp3',
'mpeg-video-file.mpg',
];
commonTypeFiles.forEach((file) => {
cy.get('#fileUploadInput').selectFile(`tests/fixtures/${file}`, {force: true}).wait(timeouts.HALF_SEC);
cy.postMessage(`Attached with ${file}`);
cy.getLastPostId().as(`${file}PostId`);
});
cy.postMessage(lastMessage);
cy.getLastPostId().as('lastPostId');
// Getting height of each post before applying 'Fixed width, centered' option and assigning to alias
cy.get('button.user-popover.style--none').eq(0).invoke('height').then((height) => {
cy.wrap(height).as('initialUserNameHeight');
});
getComponentByText('@firstPostId', firstMessage).invoke('height').then((height) => {
cy.wrap(height).as('initialFirstPostHeight');
});
getFileThumbnail('mp3-audio-file.mp3').invoke('height').then((height) => {
cy.wrap(height).as('initialMp3Height');
});
getFileThumbnail('mpeg-video-file.mpg').invoke('height').then((height) => {
cy.wrap(height).as('initialMpgHeight');
});
getImageThumbnail('gif-image-file.gif').invoke('height').then((height) => {
cy.wrap(height).as('initialGifHeight');
});
getImageThumbnail('jpg-image-file.jpg').invoke('height').then((height) => {
cy.wrap(height).as('initialJpgHeight');
});
getComponentBySelector('@linkPreviewPostId', '.PostAttachmentOpenGraph__image').invoke('height').then((height) => {
cy.wrap(height).as('initialAttachmentHeight');
});
getComponentBySelector('@gifLinkPostId', 'img[aria-label="file thumbnail"]').invoke('height').then((height) => {
cy.wrap(height).as('initialInlineImgHeight');
});
getComponentByText('@lastPostId', lastMessage).invoke('height').then((height) => {
cy.wrap(height).as('initialLastPostHeight');
});
// # Switch the settings for the test user to enable Fixed width center
cy.uiOpenSettingsModal('Display').within(() => {
cy.findByText('Display', {timeout: timeouts.ONE_MIN}).click();
cy.findByText('Channel Display').click();
cy.findByLabelText('Fixed width, centered').click();
cy.uiSaveAndClose();
});
// # Browse to Channel
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
// * Verify All posts are displayed correctly
cy.findAllByTestId('postContent').should('have.length', '9').and('have.class', 'post__content center');
// * Verify there is no scroll pop
cy.get('#post-list').should('exist').within(() => {
cy.get('@initialUserNameHeight').then((originalHeight) => {
cy.get('button.user-popover.style--none').eq(0).invoke('height').should('be.equal', originalHeight);
});
cy.get('@initialFirstPostHeight').then((originalHeight) => {
getComponentByText('@firstPostId', firstMessage).invoke('height').should('be.equal', originalHeight);
});
cy.get('@initialLastPostHeight').then((originalHeight) => {
getComponentByText('@lastPostId', lastMessage).invoke('height').should('be.equal', originalHeight);
});
cy.get('@initialMp3Height').then((originalHeight) => {
getFileThumbnail('mp3-audio-file.mp3').invoke('height').should('be.equal', originalHeight);
});
cy.get('@initialMpgHeight').then((originalHeight) => {
getFileThumbnail('mpeg-video-file.mpg').invoke('height').should('be.equal', originalHeight);
});
cy.get('@initialGifHeight').then((originalHeight) => {
getImageThumbnail('gif-image-file.gif').invoke('height').should('be.equal', originalHeight);
});
cy.get('@initialJpgHeight').then((originalHeight) => {
getImageThumbnail('jpg-image-file.jpg').invoke('height').should('be.equal', originalHeight);
});
cy.get('@initialInlineImgHeight').then((originalHeight) => {
getComponentBySelector('@gifLinkPostId', 'img[aria-label="file thumbnail"]').invoke('height').should('be.equal', originalHeight);
});
cy.get('@initialAttachmentHeight').then((originalHeight) => {
getComponentBySelector('@linkPreviewPostId', '.PostAttachmentOpenGraph__image').invoke('height').should('be.equal', originalHeight);
});
});
});
// Get thumbnail component based on filename
const getFileThumbnail = (filename) => {
return cy.get(`@${filename}PostId`).then((postId) => {
cy.get(`#${postId}_message a.post-image__name`);
});
};
// Get image component based on filename
const getImageThumbnail = (filename) => {
return cy.get(`@${filename}PostId`).then((postId) => {
cy.get(`#${postId}_message`).findByLabelText(`file thumbnail ${filename}`);
});
};
// Get component by alias and selector
const getComponentBySelector = (alias, selector) => {
return cy.get(alias).then((postId) => {
cy.get(`#${postId}_message`).find(selector);
});
};
// Get component by alias and text
const getComponentByText = (alias, text) => {
return cy.get(alias).then((postId) => {
cy.get(`#${postId}_message`).findByText(text);
});
};
});

View File

@@ -0,0 +1,50 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as TIMEOUTS from '@/fixtures/timeouts';
// # Other user posts a few messages so that the first message is hidden
export function postListOfMessages({sender, channelId, numberOfMessages = 30}) {
Cypress._.times(numberOfMessages, (postIndex) => {
cy.postMessageAs({sender, message: `Other users p-${postIndex}`, channelId});
cy.wait(TIMEOUTS.ONE_SEC);
});
}
// # Scroll above the last few messages
export function scrollCurrentChannelFromTop(listPercentageRatio) {
cy.get('div.post-list__dynamic', {timeout: TIMEOUTS.ONE_SEC}).should('be.visible').
scrollTo(0, listPercentageRatio, {duration: TIMEOUTS.ONE_SEC}).
wait(TIMEOUTS.ONE_SEC);
}
export function deletePostAndVerifyScroll(postId, options) {
let firstPostBeforeScroll;
let lastPostBeforeScroll;
// # Get the text of the first visible post
cy.get('.post-message__text:visible').first().then((postMessage) => {
firstPostBeforeScroll = postMessage.text();
});
// # Get the text of the last visible post
cy.get('.post-message__text:visible').last().then((postMessage) => {
lastPostBeforeScroll = postMessage.text();
});
// # Remove the message
cy.externalRequest({...options, method: 'DELETE', path: `posts/${postId}`});
// # Wait for the message to be deleted
cy.wait(TIMEOUTS.ONE_SEC);
// * Verify the first post is the same after the deleting
cy.get('.post-message__text:visible').first().then((firstPostAfterScroll) => {
expect(firstPostAfterScroll.text()).equal(firstPostBeforeScroll);
});
// * Verify the last post is the same after the deleting
cy.get('.post-message__text:visible').last().then((lastPostAfterScroll) => {
expect(lastPostAfterScroll.text()).equal(lastPostBeforeScroll);
});
}

View File

@@ -0,0 +1,95 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
describe('Scroll', () => {
let testTeam;
beforeEach(() => {
// # Create new team and new user and visit Town Square channel
cy.apiInitSetup().then(({team, channel}) => {
testTeam = team;
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
});
});
it('MM-T2369 Aspect Ratio is preserved in RHS', () => {
const uploadedImages = [
{
file: 'image-small-height.png',
width: 340,
height: 25,
},
{
file: 'image-small-width.png',
width: 22,
height: 352,
},
];
uploadedImages.forEach((uploadedImage) => {
// # Upload the image
cy.intercept('POST', '**/api/v4/files').as('uploadFile');
cy.get('#fileUploadInput').should('exist').attachFile(uploadedImage.file);
cy.wait('@uploadFile').its('response.statusCode').should('be.oneOf', [200, 201]);
// * Verify the file preview is shown
cy.get('[data-testid="file-preview-item"]').should('be.visible');
// # Post the image
cy.postMessage(uploadedImage.file);
// * Verify the last post includes the uploaded file
cy.findAllByTestId('postView').last().should(($post) => {
expect($post.find('.file-view--single').length, 'file attach').to.be.greaterThan(0);
});
cy.getLastPostId().then((postId) => {
// # Get uploaded image in the center
cy.get(`#post_${postId}`).within(() => {
cy.contains(uploadedImage.file).should('be.visible');
// * Verify image was uploaded and its aspect ratio is unchanged
verifyImageAspectRatioCorrectness(uploadedImage);
});
// # Open the message with image in RHS
cy.clickPostCommentIcon(postId);
// # Go to RHS where image is now opened
cy.get('#rhsContainer').within(() => {
// * Verify image in the RHS has correct aspect ratio
verifyImageAspectRatioCorrectness(uploadedImage);
});
cy.uiCloseRHS();
});
});
});
});
function verifyImageAspectRatioCorrectness(originalImage) {
const expected = originalImage.width / originalImage.height;
cy.get('.file-view--single').then(($view) => {
const $toggle = $view.find('.single-image-view__toggle');
if ($toggle.length && $toggle.attr('data-expanded') === 'false') {
cy.wrap($toggle).click({force: true});
}
});
cy.get('.file-view--single .image-loaded img').
should('be.visible').
and(($img) => {
const img = $img[0];
expect(img.complete, 'decoded').to.equal(true);
expect(img.naturalWidth, 'loaded').to.be.greaterThan(0);
expect(img.naturalWidth / img.naturalHeight).to.be.closeTo(expected, 0.02);
});
}