Files
1325e23fc6 MM-66561 Add distinct archive icon for private channels (#34736)
* MM-66561 Add distinct archive icon for private channels

Archived private channels now display an archive-lock icon instead of the standard archive icon to better indicate their original privacy level. Implemented utility functions to centralize icon selection logic across all channel list views, sidebars, headers, and suggestion providers.

* MM-66561 Fix linting and TypeScript errors

Fix ESLint and TypeScript issues introduced in the archive icon implementation:
- Remove extra blank lines to comply with no-multiple-empty-lines rule
- Remove unused container variables in test files
- Fix import order to comply with import/order rule
- Remove unused React import
- Fix TypeScript type errors by using General.OPEN_CHANNEL/PRIVATE_CHANNEL from mattermost-redux/constants which preserves literal types

* MM-66561 Fix test failures for archive icon changes

Update test snapshots and fix test data issues related to the new distinct archive icons for public and private channels.

- Update snapshots for channel list components to include new channelType prop and data-testid attributes
- Fix channel_mention_provider test by preserving actual module exports in mock
- Add missing purpose field to searchable_channel_list test data
- Fix async state handling in new_channel_modal test using waitFor instead of act

* MM-66561 Fix remaining Cypress E2E test failures for archive icons

Fix three failing Cypress tests related to archive icon changes:

1. join_archived_channel_spec.ts (MM-T1682, MM-T1683)
   - Add data-testid to archive icon in channel header
   - Update test to use findByTestId instead of CSS class selector
   - Compass icon components render as SVG, not <i> with classes

2. archived_channels_spec.js (system console tests)
   - Add "000-" prefix to private channel name/display name
   - Ensures proper alphabetical sorting on first page of results

3. long_draft_spec.js (MM-T211)
   - Fix Cypress alias timing issues in nested then() callbacks
   - Use local variable to track height changes during iteration
   - Replace cy.get('@alias').should() with direct expect() assertions

All tests now pass with the distinct archive icons for private channels.

* fix lint issue

* MM-66561 Refine archive icon styling and search results display

- Restore CSS classes on channel header icon for proper color and size
- Fix icon alignment by removing top offset in channel header context
- Replace "Archived" text with icon-only tooltip in search results
- Add context-specific styling to prevent conflicts between header and search

* tweaks to css and move withtooltip to wrap the span

* lint fix

* lint fix

* Fix archived channel icons visual test API usage

Update test to use correct Playwright API patterns:
- Use adminClient.createChannel with pw.random.channel for channel creation
- Use adminClient.deleteChannel instead of pw.apiClient.deleteChannel
- Use pw.testBrowser.login(adminUser) instead of loginAsAdmin
- Remove channelsPage.toBeVisible check for archived channels since they lack post-create element

* Apply prettier formatting to archived channel icons test

* Fix timing issue in MM-T633 Elasticsearch webhook attachment search test

The test was intermittently failing because it searched immediately after posting the webhook, before Elasticsearch had time to index the new post. Added explicit wait for post to appear and increased indexing wait time to 3 seconds to ensure the attachment text is indexed before performing the search.

---------

Co-authored-by: Matthew Birtch <[email protected]>

Co-authored-by: Hanzo Dev <[email protected]>
2026-01-14 15:35:27 +00:00

120 lines
4.4 KiB
JavaScript

// 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 @messaging
import * as TIMEOUTS from '../../../fixtures/timeouts';
describe('Messaging', () => {
let otherChannelName;
let otherChannelUrl;
let initialHeight = 0;
before(() => {
// # Make sure the viewport is the expected one, so written lines always create new lines
cy.viewport(1000, 660);
// # Login as test user and visit off-topic
cy.apiInitSetup({loginAfter: true}).then((out) => {
otherChannelName = out.channel.name;
otherChannelUrl = out.channelUrl;
cy.visit(out.offTopicUrl);
cy.postMessage('hello');
cy.uiGetPostTextBox().invoke('height').then((height) => {
initialHeight = height;
// # Get the height before starting to write
// Setting alias based on reference to element seemed to be problematic with Cypress (regression)
// Quick hack to reference based on value
cy.wrap(initialHeight).as('initialHeight');
cy.wrap(initialHeight).as('previousHeight');
});
});
});
it('MM-T211 Leave a long draft in the main input box', () => {
const lines = [
'Lorem ipsum dolor sit amet,',
'consectetur adipiscing elit.',
'Nulla ac consectetur quam.',
'Phasellus libero lorem,',
'facilisis in purus sed, auctor.',
];
// # Write all lines
writeLinesToPostTextBox(lines);
// # Visit a different channel and verify textbox
cy.get(`#sidebarItem_${otherChannelName}`).click({force: true}).wait(TIMEOUTS.THREE_SEC);
verifyPostTextbox('@initialHeight', '');
// # Return to the channel and verify textbox
cy.get('#sidebarItem_off-topic').click({force: true}).wait(TIMEOUTS.THREE_SEC);
verifyPostTextbox('@previousHeight', lines.join('\n'));
// # Clear the textbox
cy.uiGetPostTextBox().clear();
cy.postMessage('World!');
// # Write all lines again
cy.wrap(initialHeight).as('previousHeight');
writeLinesToPostTextBox(lines);
// # Visit a different channel by URL and verify textbox
cy.visit(otherChannelUrl).wait(TIMEOUTS.THREE_SEC);
verifyPostTextbox('@initialHeight', '');
// # Should have returned to the channel by URL. However, Cypress is clearing storage for some reason.
// # Does not happened on actual user interaction.
// * Verify textbox
cy.get('#sidebarItem_off-topic').click({force: true}).wait(TIMEOUTS.THREE_SEC);
verifyPostTextbox('@previousHeight', lines.join('\n'));
});
});
function writeLinesToPostTextBox(lines) {
let previousHeight;
// Get the initial previous height from the alias
cy.get('@previousHeight').then((height) => {
previousHeight = height;
});
Cypress._.forEach(lines, (line, i) => {
// # Add the text
cy.uiGetPostTextBox().type(line, {delay: TIMEOUTS.ONE_HUNDRED_MILLIS}).wait(TIMEOUTS.HALF_SEC);
if (i < lines.length - 1) {
// # Add new line
cy.uiGetPostTextBox().type('{shift}{enter}').wait(TIMEOUTS.HALF_SEC);
// * Verify new height
cy.uiGetPostTextBox().invoke('height').then((height) => {
const currentHeight = parseInt(height, 10);
// * Verify previous height should be lower than the current height
expect(previousHeight).to.be.lessThan(currentHeight);
// # Store the current height as the previous height for the next loop
previousHeight = currentHeight;
cy.wrap(currentHeight).as('previousHeight');
});
}
});
cy.wait(TIMEOUTS.THREE_SEC);
}
function verifyPostTextbox(heightSelector, text) {
cy.uiGetPostTextBox().and('have.text', text).invoke('height').then((currentHeight) => {
cy.get(heightSelector).should('be.gte', currentHeight);
});
}