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
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:
@@ -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');
|
||||
});
|
||||
}
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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 = '';
|
||||
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);
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user