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 1s
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,78 @@
// 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 @channel
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Archived channels', () => {
before(() => {
// # Login as test user and visit created channel
cy.apiInitSetup({loginAfter: true}).then(({team, channel}) => {
cy.visit(`/${team.name}/channels/${channel.name}`);
});
});
it('MM-T1720 Cannot add reactions to existing reactions', () => {
const messageText = 'Test add reaction in archive channels';
// # Post a message in the channel
cy.postMessage(messageText);
// # Get the last post for reference of ID
cy.getLastPostId().then((postId) => {
// # Click the add reaction icon
cy.clickPostReactionIcon(postId);
// # Search for the emoji in emoji search bar
cy.findByPlaceholderText('Search emojis').should('exist').and('be.visible').
clear().
type('slightly_frowning_face', {delay: TIMEOUTS.QUARTER_SEC, force: true});
// # Choose "slightly_frowning_face" emoji
cy.clickEmojiInEmojiPicker('slightly_frowning_face');
// * Should have added the reaction with count
cy.get(`#postReaction-${postId}-slightly_frowning_face .Reaction__number--display`).should('have.text', '1');
// * Should have add reaction button
cy.get(`#addReaction-${postId}`).should('exist');
// # Archive the channel
cy.uiArchiveChannel();
// * Should not have add reaction button
cy.get(`#addReaction-${postId}`).should('not.exist');
// # Click on existing "slightly_frowning_face" emoji
cy.get(`#postReaction-${postId}-slightly_frowning_face`).click();
// * Reaction count should not have incremented
cy.get(`#postReaction-${postId}-slightly_frowning_face .Reaction__number--display`).should('have.text', '1');
// # Remove focus so we can open RHS
cy.get('#channel_view').click();
// # Open RHS for the post
cy.clickPostCommentIcon(postId);
cy.get(`#rhsPost_${postId}`).within(() => {
// * Should not have add reaction button
cy.get(`#addReaction-${postId}`).should('not.exist');
// # Click on existing "slightly_frowning_face" emoji
cy.get(`#postReaction-${postId}-slightly_frowning_face`).click();
// * Reaction count should not have incremented
cy.get(`#postReaction-${postId}-slightly_frowning_face .Reaction__number--display`).should('have.text', '1');
});
});
});
});

View File

@@ -0,0 +1,82 @@
// 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 @channel
describe('Archive channel header spec', () => {
before(() => {
cy.visit('/admin_console/user_management/permissions/system_scheme');
// # Click reset to defaults and confirm
cy.findByTestId('resetPermissionsToDefault').click();
cy.get('#confirmModalButton').click();
// # Ensure permissions for converting channel to private is enabled
cy.findByTestId('all_users-public_channel-convert_public_channel_to_private-checkbox').then((el) => {
if (!el.hasClass('checked')) {
el.click();
}
});
// # Save the settings
cy.uiSave();
cy.uiSaveButton().should('be.visible');
// # Login as test user and visit create channel
cy.apiInitSetup({loginAfter: true}).then(({channelUrl}) => {
cy.visit(channelUrl);
});
});
it('MM-T1717 Archived channel details cannot be edited', () => {
// # click on channel drop-down menu
cy.get('#channelHeaderTitle').click();
// * The dropdown menu of the channel header should be visible;
cy.get('#channelLeaveChannel').should('be.visible');
// * Channel Settings submenu should be visible;
cy.get('#channelSettings').should('be.visible');
// * Archive channel menu option should be visible;
cy.get('#channelArchiveChannel').should('be.visible');
// * Members menu option should be visible;
cy.get('#channelMembers').should('be.visible');
// * Notification preferences option should be visible;
cy.get('#channelNotificationPreferences').should('be.visible');
// # Close the channel dropdown menu using keyboard escape
cy.get('body').type('{esc}{esc}');
// # Archive the channel
cy.uiArchiveChannel();
// # click on channel drop-down menu
cy.get('#channelHeaderTitle').click();
// * Archive channel menu option should not be visible;
cy.get('#channelArchiveChannel').should('not.exist');
// * Channel Settings submenu should be visible;
cy.get('#channelSettings').should('not.exist');
// * Members menu option should be visible;
// as it now displays in RHS
cy.get('#channelMembers').should('be.visible');
// * Notification preferences option should not be visible;
cy.get('#channelNotificationPreferences').should('not.exist');
// # Close the channel dropdown menu using keyboard escape
cy.get('body').type('{esc}{esc}');
});
});

View File

@@ -0,0 +1,43 @@
// 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 @channel
describe('Archive channel members spec', () => {
before(() => {
// # Login as test user and visit create channel
cy.apiInitSetup({loginAfter: true, promoteNewUserAsAdmin: true}).then(({team, channel}) => {
cy.visit(`/${team.name}/channels/${channel.name}`);
});
});
it('MM-T1719 Archived channel members cannot be managed', () => {
// # click on channel drop-down menu
cy.get('#channelHeaderTitle').click();
// * Members menu option should be visible;
cy.get('#channelMembers').should('be.visible');
// # Close the channel dropdown menu
cy.get('body').type('{esc}{esc}');
// # Archive the channel
cy.uiArchiveChannel();
// # click on channel drop-down menu
cy.get('#channelHeaderTitle').click();
// # click on view members menu option;
cy.get('#channelMembers').should('be.visible').click();
// * Ensure there are no options to change channel roles or membership
cy.uiGetRHS().findByText('Manage').should('not.exist');
});
});

View File

@@ -0,0 +1,71 @@
// 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 @channel
import * as TIMEOUTS from '@/fixtures/timeouts';
describe('Archived channels', () => {
before(() => {
// # Login as test user and visit created channel
cy.apiInitSetup({loginAfter: true}).then(({team, channel}) => {
cy.visit(`/${team.name}/channels/${channel.name}`);
});
});
it('MM-T1718 Reaction icon should not be visible for archived channel posts', () => {
const messageText = 'Test archive reaction';
// # Post a message in the channel
cy.postMessage(messageText);
// # Get the last post for reference of ID
cy.getLastPostId().then((postId) => {
// # Click on post dot menu so we can check for reaction icon
cy.clickPostDotMenu();
// * Reaction icon should be visible as channel is not archived
cy.wait(TIMEOUTS.HALF_SEC).get(`#CENTER_reaction_${postId}`).should('be.visible');
// # Archive the channel
cy.get('body').type('{esc}');
cy.uiArchiveChannel();
// # Click on post dot menu so we can check for reaction icon
cy.clickPostDotMenu(postId);
// * Reaction icon on center channel post should not be visible anymore
cy.wait(TIMEOUTS.HALF_SEC).get(`#CENTER_reaction_${postId}`).should('not.exist');
// # Remove focus so we can open RHS
cy.get('body').type('{esc}');
// # Open RHS for the post
cy.clickPostCommentIcon(postId);
// # Click on post dot menu so we can check for reaction icon
cy.clickPostDotMenu(postId, 'RHS_ROOT');
// * Reaction icon on post in RHS should not be visible anymore
cy.wait(TIMEOUTS.HALF_SEC).get(`#RHS_ROOT_reaction_${postId}`).should('not.exist');
// # Search for "Test archive reaction"
cy.get('body').type('{esc}');
cy.uiGetSearchContainer().click();
cy.uiGetSearchBox().should('be.visible').type(messageText).type('{enter}');
// # Click on post dot menu so we can check for reaction icon
cy.clickPostDotMenu(postId, 'SEARCH');
// * Reaction icon on post in search results should not be visible anymore
cy.wait(TIMEOUTS.HALF_SEC).get(`#searchResult_reaction_${postId}`).should('not.exist');
});
});
});

View File

@@ -0,0 +1,120 @@
// 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 @channel
import {createArchivedChannel} from './helpers';
import {getRandomId} from '@/utils';
describe('archive channel search tests', () => {
let testTeam: Cypress.Team;
let testChannel: Cypress.Channel;
let testUser: Cypress.UserProfile;
const testArchivedMessage = `this is an archived post ${getRandomId()}`;
before(() => {
// # Login as test user and visit test channel
cy.apiInitSetup().then(({team, channel, user}) => {
testTeam = team;
testChannel = channel;
testUser = user;
cy.apiCreateUser({prefix: 'second'}).then(({user: second}) => {
cy.apiAddUserToTeam(testTeam.id, second.id);
});
cy.visit(`/${team.name}/channels/${testChannel.name}`);
});
});
it('MM-T1707 Unarchived channels can be searched the same as before they where archived', () => {
// # Post some text in the channel such as "Pineapple"
const messageText = `pineapple ${getRandomId()}`;
// # Archive the channel
createArchivedChannel({prefix: 'pineapple-'}, [messageText]).then(() => {
// # Unarchive the channel
cy.uiUnarchiveChannel().then(() => {
cy.visit(`/${testTeam.name}/channels/off-topic`);
cy.contains('#channelHeaderTitle', 'Off-Topic');
cy.postMessage(getRandomId());
// # Search for the post from step 1')
cy.uiGetSearchContainer().click();
cy.uiGetSearchBox().clear().type(`${messageText}{enter}`);
// * Post is returned by search, since it's not archived anymore
cy.get('#searchContainer').should('be.visible');
cy.get('.search-item-snippet').first().contains(messageText);
});
});
});
it('MM-T1708 An archived channel can be searched since archived channels are always viewable', () => {
cy.apiLogin(testUser);
// # Open a channel other than Town Square
cy.visit(`/${testTeam.name}/channels/off-topic`);
cy.contains('#channelHeaderTitle', 'Off-Topic');
// # Create or locate a channel you're a member of
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
cy.get('#channelHeaderTitle').should('be.visible');
// # Post distinctive text in the channel such as "I like pineapples"
cy.postMessageAs({sender: testUser, message: testArchivedMessage, channelId: testChannel.id});
// # Select Archive Channel from the header menu
cy.uiArchiveChannel();
// # Search for the archived message
cy.uiGetSearchContainer().click();
cy.uiGetSearchBox().clear().type(`${testArchivedMessage}{enter}`);
// * Post is returned by search since archived channels are always viewable
cy.get('#searchContainer').should('be.visible');
cy.get('.search-item-snippet').first().contains(testArchivedMessage);
});
it('MM-T1709 Archive a channel while search results are displayed in RHS', () => {
const messageText = `search ${getRandomId()} pineapples`;
// # Post a unique string of text in a channel
cy.uiCreateChannel({prefix: 'archive-while-searching'}).then(() => {
cy.postMessage(messageText);
// # Search for the string of text from step 1
cy.uiGetSearchContainer().click();
cy.uiGetSearchBox().clear().type(`${messageText}{enter}`);
// * Post is returned by search, since it's not archived anymore
cy.get('#searchContainer').should('be.visible');
// # Observe the post is displayed in RHS results
cy.get('.search-item-snippet').first().should('contain.text', messageText);
// # While the RHS is still open with the results, archive the channel the post was made in
cy.uiArchiveChannel();
cy.get('#searchContainer').should('be.visible');
// * Search results should remain visible since archived channels are always viewable
cy.get('.search-item-snippet').first().should('contain.text', messageText);
});
});
it('MM-T1710 archived channels are not listed on the "in:" autocomplete', () => {
// # Archive a channel and make a mental note of the channel name
// # Type "in:" and note the list of channels that appear
cy.uiGetSearchContainer().click();
cy.uiGetSearchBox().clear().type(`in:${testChannel.name}`);
cy.findByTestId(testChannel.name).should('not.exist');
});
});

View File

@@ -0,0 +1,24 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as TIMEOUTS from '@/fixtures/timeouts';
export function createArchivedChannel(channelOptions: Record<string, unknown>, messages: string[], memberUsernames?: string[]) {
return cy.uiCreateChannel(channelOptions).then((newChannel) => {
if (memberUsernames) {
cy.uiAddUsersToCurrentChannel(memberUsernames);
}
messages.forEach((message) => {
cy.postMessage(message);
});
cy.uiArchiveChannel();
// # Wait for sometime and verify that the archived message is shown
cy.wait(TIMEOUTS.FIVE_SEC);
cy.get('#channelArchivedMessage', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible');
return cy.wrap({name: newChannel.name});
});
}

View File

@@ -0,0 +1,121 @@
// 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 @channel
import {getAdminAccount} from '@/support/env';
import {getRandomId} from '@/utils';
describe('Archived channels', () => {
let testTeam: Cypress.Team;
let testUser: Cypress.UserProfile;
before(() => {
cy.apiInitSetup().then(({team, user}) => {
testTeam = team;
testUser = user;
});
});
it('MM-T1682 Join an archived public channel by selecting a permalink to one of its posts', () => {
// # Log in as another user
cy.apiAdminLogin();
// # Create a new channel
cy.apiCreateChannel(testTeam.id, 'channel', 'channel').then(({channel}) => {
// # Make a post in the new channel and get a permalink for it
cy.postMessageAs({
sender: getAdminAccount(),
message: 'post',
channelId: channel.id,
}).then((post) => {
const permalink = `/${testTeam.name}/pl/${post.id}`;
// # Visit the channel
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
// # Archive the channel
cy.uiArchiveChannel();
// # Log out and back in as the test user
cy.apiLogin(testUser);
// # Visit the permalink
cy.visit(permalink);
// * Verify that we've logged in as the test user
verifyUsername(testUser.username);
verifyViewingArchivedChannel(channel);
});
});
});
it('MM-T1683 Join an archived channel by selecting a link to channel', () => {
// # Log in as another user
cy.apiAdminLogin();
// # Create a new channel
cy.apiCreateChannel(testTeam.id, 'channel', 'channel').then(({channel}) => {
const channelLink = `/${testTeam.name}/channels/${channel.name}`;
// # Visit the channel and archive it
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
cy.uiArchiveChannel();
// # Visit off-topic
cy.visit(`/${testTeam.name}/channels/off-topic`);
// # Make a post linking to the archived channel
const linkText = `link ${getRandomId()}`;
cy.getCurrentChannelId().then((currentChannelId) => {
cy.postMessageAs({
sender: getAdminAccount(),
message: `This is a link: [${linkText}](${channelLink})`,
channelId: currentChannelId,
});
});
// # Log out and back in as the test user
cy.apiLogin(testUser);
// # Visit off-topic
cy.visit(`/${testTeam.name}/channels/off-topic`);
// * Verify that we've logged in as the test user
verifyUsername(testUser.username);
// * Verify that the link exists and then click on it
cy.contains('a', linkText).should('be.visible').click();
verifyViewingArchivedChannel(channel);
});
});
});
function verifyViewingArchivedChannel(channel: Cypress.Channel) {
// * Verify that we've switched to the correct channel and that the header contains the archived icon
cy.get('#channelHeaderTitle').should('contain', channel.display_name);
cy.findByTestId('channel-header-archive-icon').should('be.visible');
// * Verify that the channel is visible in the sidebar with the archived icon
cy.get(`#sidebarItem_${channel.name}`).should('be.visible').
find('.icon-archive-outline').should('be.visible');
// * Verify that the archived channel banner is visible at the bottom of the channel view
cy.get('#channelArchivedMessage').should('be.visible');
}
function verifyUsername(username: string) {
// * Verify that we've logged in as the test user
cy.uiOpenUserMenu().findByText(`@${username}`);
// # Close the user menu
cy.get('body').type('{esc}');
}

View File

@@ -0,0 +1,55 @@
// 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 @channel
describe('Leaving archived channels', () => {
let testTeam: Cypress.Team;
before(() => {
cy.apiInitSetup({loginAfter: true}).then(({team}) => {
testTeam = team;
});
});
it('MM-T1685 User can leave archived public channel', () => {
// # Create a new public channel
cy.apiCreateChannel(testTeam.id, 'channel', 'channel').then(({channel}) => {
// # Visit the channel
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
// # Archive the channel
cy.uiArchiveChannel();
// # Leave the channel
cy.uiLeaveChannel();
// * Verify that we've switched to Town Square
cy.url().should('include', '/channels/town-square');
});
});
it('MM-T1686 User can leave archived private channel', () => {
// # Create a new private channel
cy.apiCreateChannel(testTeam.id, 'channel', 'channel', 'P').then(({channel}) => {
// # Visit the channel
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
// # Archive the channel
cy.uiArchiveChannel();
// # Leave the channel
cy.uiLeaveChannel(true);
// * Verify that we've switched to Town Square
cy.url().should('include', '/channels/town-square');
});
});
});