Files
e10ee3a228 Fix RHS reply input focus issues (#33965)
* extend shift+up e2e-test

* fix: MM-T203 Focus does not move when it has already been set elsewhere

* focus_move_spec: add coverage for replying to a reply

* Fix RHS reply input focus issues

- Addresses focus not shifting to RHS reply input when replying to messages
- Fixes issue where focus remains in center channel instead of RHS
- Related to MM-64520

* use requestAnimationFrame

* simplify

---------

Co-authored-by: Mattermost Build <[email protected]>
2025-09-29 18:18:59 +00:00

212 lines
7.5 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 offTopicUrl;
let testChannelName;
let user;
before(() => {
// # Login as test user
cy.apiInitSetup({loginAfter: true}).then((out) => {
offTopicUrl = out.offTopicUrl;
testChannelName = out.channel.display_name;
user = out.user;
});
});
beforeEach(() => {
cy.visit(offTopicUrl);
});
it('MM-T200 Focus move to main input box when a character key is selected', () => {
// # Post a message
cy.postMessage('Hello');
// # Click the save icon to move focus out of the main input box
cy.uiGetSavedPostButton().click();
cy.uiGetPostTextBox().should('not.be.focused');
// # Push a character key such as "A"
// # Expect to have "A" value in main input
cy.get('body').type('A');
cy.uiGetPostTextBox().should('be.focused');
// # Click the @-mention icon to move focus out of the main input box
cy.uiGetRecentMentionButton().click();
cy.uiGetPostTextBox().should('not.be.focused');
// # Push a character key such as "B"
// # Expect to have "B" value in main input
cy.get('body').type('B');
cy.uiGetPostTextBox().should('be.focused');
});
it('MM-T204 Focus will move to main input box after a new channel has been opened', () => {
// # Post a new message
cy.postMessage('new post');
// # Open the reply thread on the most recent post
cy.clickPostCommentIcon();
// # Place the focus inside the RHS input box
cy.uiGetReplyTextBox().focus().should('be.focused');
// # Use CTRL+K or CMD+K to open the channel switcher depending on OS
cy.typeCmdOrCtrl().type('K', {release: true});
// * Verify channel switcher is visible
cy.get('#quickSwitchHint').should('be.visible');
// # Type channel name and select it
cy.findByRole('combobox', {name: 'quick switch input'}).type(testChannelName).wait(TIMEOUTS.HALF_SEC).type('{enter}');
// * Verify that it redirected into selected channel
cy.get('#channelHeaderTitle').should('be.visible').should('contain', testChannelName);
// * Verify focus is moved to main input box when the channel is opened
cy.uiGetPostTextBox().should('be.focused');
});
it('MM-T205 Focus to remain in RHS textbox each time Reply arrow is clicked', () => {
// # Post a new message
cy.postMessage('new post');
// # Open the reply thread on the most recent post
cy.clickPostCommentIcon();
// * Verify RHS textbox is focused the first time Reply arrow is clicked
cy.uiGetReplyTextBox().should('be.focused');
// # Focus away from RHS textbox
cy.get('#rhsContainer .post-right__content').click();
// # Click reply arrow on post in same thread
cy.clickPostCommentIcon();
// * Verify RHS textbox is again focused the second time, when already open
cy.uiGetReplyTextBox().should('be.focused');
});
it('MM-T205 Focus to remain in RHS textbox when replying to reply post in center channel (CRT disabled)', () => {
// # Ensure collapsed reply threads is disabled
cy.apiSaveCRTPreference(user.id, 'off');
// # Post a thread root message
cy.postMessage('Thread root message');
// # Open RHS and post a reply
cy.clickPostCommentIcon();
cy.uiGetReplyTextBox().type('First reply{enter}');
// # Close RHS
cy.get('#rhsCloseButton').click();
// * Verify RHS is closed
cy.get('.sidebar--right__header').should('not.exist');
// # Get the reply post ID and click its comment icon
cy.getLastPostId().then((postId) => {
// # Click the reply arrow on the reply post
cy.clickPostCommentIcon(postId);
// * Verify RHS opens and textbox is focused
cy.get('.sidebar--right__header').should('be.visible');
cy.uiGetReplyTextBox().should('be.focused');
// # Focus away from RHS textbox
cy.get('#rhsContainer .post-right__content').click();
// # Click reply arrow on the same reply post again
cy.clickPostCommentIcon(postId);
});
// * Verify RHS textbox is focused again
cy.uiGetReplyTextBox().should('be.focused');
});
it('MM-T203 Focus does not move when it has already been set elsewhere', () => {
// # Verify Focus in add channel member modal
verifyFocusInAddChannelMemberModal();
});
it('MM-T202 Focus does not move for non-character keys', () => {
// # Post a message
cy.postMessage('Hello');
// # Click the save icon to move focus out of the main input box
cy.uiGetSavedPostButton().click();
cy.uiGetPostTextBox().should('not.be.focused');
// Keycodes for keys that don't have a special character sequence for cypress.type()
const numLockKeycode = 144;
const f7Keycode = 118;
const windowsKeycode = 91;
[numLockKeycode, f7Keycode, windowsKeycode].forEach((keycode) => {
// # Trigger keydown event using keycode
cy.get('body').trigger('keydown', {keyCode: keycode, which: keycode});
// # Make sure main input is not focused
cy.uiGetPostTextBox().should('not.be.focused');
});
// For other keys we can use cypress.type() with a special character sequence.
['{downarrow}', '{pagedown}', '{shift}', '{pageup}', '{enter}'].forEach((key) => {
// # Type special character key using Cypress special character sequence
cy.get('body').type(key);
// # Make sure main input is not focused
cy.uiGetPostTextBox().should('not.be.focused');
});
});
});
function verifyFocusInAddChannelMemberModal() {
// # Click to access the Channel menu
cy.get('#channelHeaderTitle').click();
// * The dropdown menu of the channel header should be visible;
cy.get('#channelLeaveChannel').should('be.visible');
// # Click 'Add Members'
cy.get('#channelMembers').click();
cy.uiGetButton('Add').click();
// * Assert that modal appears
cy.get('#addUsersToChannelModal').should('be.visible');
// * Assert that the input box is in focus
cy.get('#selectItems input').should('be.focused');
// # Push a character key such as "A"
cy.focused().typeWithForce('A');
// * Check that input box has character A
cy.get('#selectItems input').should('have.value', 'A');
// # Remove the focus from the input box
cy.get('#selectItems input').blur();
// * Note the focus has been removed from the search box
cy.get('#selectItems input').should('not.be.focused');
// # Push a character key such as "A"
cy.get('body').type('A');
// * Focus is not moved anywhere. Neither the search box or main input box has the focus
cy.get('#selectItems input').should('not.be.focused').and('have.value', 'A');
cy.uiGetPostTextBox().should('not.be.focused');
}