[MM-55285]: Screen reader speaking wrong item in list in Find Channels modal (#29552)
* [MA-11]: Fix Screen reader speaking wrong item in list in Find Channels modal * [MA-11]: Update types across files * [MA-11]: Minor refactoring * [MA-11]: Fix e2e test * [MA-11]: Fix E2E tests * [MA-11]: Update role and id * [MA-11]: Fix playwright tests --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
540408545a
Коммит
132c27fb34
@@ -57,7 +57,7 @@ describe('Leave an archived channel', () => {
|
|||||||
|
|
||||||
// * The archived channel appears in channel switcher search results
|
// * The archived channel appears in channel switcher search results
|
||||||
cy.get('#suggestionList').should('be.visible');
|
cy.get('#suggestionList').should('be.visible');
|
||||||
cy.get('#suggestionList').find(`#switchChannel_${testChannel.name}`).should('be.visible');
|
cy.get('#suggestionList').find(`#quickSwitchInput_${testChannel.id}`).should('be.visible');
|
||||||
|
|
||||||
// # Reload the app (refresh the web page)
|
// # Reload the app (refresh the web page)
|
||||||
cy.reload().then(() => {
|
cy.reload().then(() => {
|
||||||
@@ -68,7 +68,7 @@ describe('Leave an archived channel', () => {
|
|||||||
cy.get('#quickSwitchInput').type(testChannel.display_name).then(() => {
|
cy.get('#quickSwitchInput').type(testChannel.display_name).then(() => {
|
||||||
// * The archived channel appears in channel switcher search results
|
// * The archived channel appears in channel switcher search results
|
||||||
cy.get('#suggestionList').should('be.visible');
|
cy.get('#suggestionList').should('be.visible');
|
||||||
cy.get('#suggestionList').find(`#switchChannel_${testChannel.name}`).should('be.visible');
|
cy.get('#suggestionList').find(`#quickSwitchInput_${testChannel.id}`).should('be.visible');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ describe('Autocomplete with Database - Users', () => {
|
|||||||
|
|
||||||
// # Open quick channel switcher
|
// # Open quick channel switcher
|
||||||
cy.typeCmdOrCtrl().type('k');
|
cy.typeCmdOrCtrl().type('k');
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).should('be.visible');
|
cy.findByRole('combobox', {name: 'quick switch input'}).should('be.visible');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ function getPostTextboxInput() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getQuickChannelSwitcherInput() {
|
function getQuickChannelSwitcherInput() {
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).
|
cy.findByRole('combobox', {name: 'quick switch input'}).
|
||||||
should('be.visible').
|
should('be.visible').
|
||||||
as('input').
|
as('input').
|
||||||
clear();
|
clear();
|
||||||
@@ -158,7 +158,7 @@ function searchForChannel(name: string) {
|
|||||||
cy.typeCmdOrCtrl().type('k').wait(TIMEOUTS.ONE_SEC);
|
cy.typeCmdOrCtrl().type('k').wait(TIMEOUTS.ONE_SEC);
|
||||||
|
|
||||||
// # Clear out and type in the name
|
// # Clear out and type in the name
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).
|
cy.findByRole('combobox', {name: 'quick switch input'}).
|
||||||
should('be.visible').
|
should('be.visible').
|
||||||
as('input').
|
as('input').
|
||||||
clear().
|
clear().
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ describe('Channel Switcher', () => {
|
|||||||
// # Start typing channel name in the "Switch Channels" modal message box
|
// # Start typing channel name in the "Switch Channels" modal message box
|
||||||
// # Use up/down arrow keys to highlight second channel
|
// # Use up/down arrow keys to highlight second channel
|
||||||
// # Press ENTER
|
// # Press ENTER
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).
|
cy.findByRole('combobox', {name: 'quick switch input'}).
|
||||||
type(`${channelDisplayNamePrefix} `).
|
type(`${channelDisplayNamePrefix} `).
|
||||||
type('{downarrow}{downarrow}{enter}');
|
type('{downarrow}{downarrow}{enter}');
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ describe('Channel Switcher', () => {
|
|||||||
cy.typeCmdOrCtrl().type('K', {release: true});
|
cy.typeCmdOrCtrl().type('K', {release: true});
|
||||||
|
|
||||||
// # Start typing channel name in the "Switch Channels" modal message box
|
// # Start typing channel name in the "Switch Channels" modal message box
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).type(`${channelDisplayNamePrefix} `);
|
cy.findByRole('combobox', {name: 'quick switch input'}).type(`${channelDisplayNamePrefix} `);
|
||||||
|
|
||||||
cy.get(`[data-testid^=${channelNamePrefix}-c] > span`).click();
|
cy.get(`[data-testid^=${channelNamePrefix}-c] > span`).click();
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ describe('Channel Switcher', () => {
|
|||||||
cy.typeCmdOrCtrl().type('K', {release: true});
|
cy.typeCmdOrCtrl().type('K', {release: true});
|
||||||
|
|
||||||
// # Type invalid channel name in the "Switch Channels" modal message box
|
// # Type invalid channel name in the "Switch Channels" modal message box
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).type('there-is-no-spoon');
|
cy.findByRole('combobox', {name: 'quick switch input'}).type('there-is-no-spoon');
|
||||||
|
|
||||||
// * Expect 'nothing found' message
|
// * Expect 'nothing found' message
|
||||||
cy.get('.no-results__title > span').should('be.visible');
|
cy.get('.no-results__title > span').should('be.visible');
|
||||||
@@ -91,10 +91,10 @@ describe('Channel Switcher', () => {
|
|||||||
cy.typeCmdOrCtrl().type('K', {release: true});
|
cy.typeCmdOrCtrl().type('K', {release: true});
|
||||||
|
|
||||||
// # Press ESC
|
// # Press ESC
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).type('{esc}');
|
cy.findByRole('combobox', {name: 'quick switch input'}).type('{esc}');
|
||||||
|
|
||||||
// * Expect the dialog to be closed
|
// * Expect the dialog to be closed
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).should('not.exist');
|
cy.findByRole('combobox', {name: 'quick switch input'}).should('not.exist');
|
||||||
|
|
||||||
// * Expect staying in the same channel
|
// * Expect staying in the same channel
|
||||||
cy.url().should('contain', 'off-topic');
|
cy.url().should('contain', 'off-topic');
|
||||||
@@ -106,7 +106,7 @@ describe('Channel Switcher', () => {
|
|||||||
cy.get('.modal').click({force: true});
|
cy.get('.modal').click({force: true});
|
||||||
|
|
||||||
// * Expect the dialog to be closed
|
// * Expect the dialog to be closed
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).should('not.exist');
|
cy.findByRole('combobox', {name: 'quick switch input'}).should('not.exist');
|
||||||
|
|
||||||
// * Expect staying in the same channel
|
// * Expect staying in the same channel
|
||||||
cy.url().should('contain', 'off-topic');
|
cy.url().should('contain', 'off-topic');
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export function searchForChannel(name: string) {
|
|||||||
cy.typeCmdOrCtrl().type('k').wait(TIMEOUTS.ONE_SEC);
|
cy.typeCmdOrCtrl().type('k').wait(TIMEOUTS.ONE_SEC);
|
||||||
|
|
||||||
// # Clear out and type in the name
|
// # Clear out and type in the name
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).
|
cy.findByRole('combobox', {name: 'quick switch input'}).
|
||||||
should('be.visible').
|
should('be.visible').
|
||||||
as('input').
|
as('input').
|
||||||
clear().
|
clear().
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ describe('Autocomplete with Elasticsearch - Users', () => {
|
|||||||
|
|
||||||
// # Open quick channel switcher
|
// # Open quick channel switcher
|
||||||
cy.typeCmdOrCtrl().type('k');
|
cy.typeCmdOrCtrl().type('k');
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).should('be.visible');
|
cy.findByRole('combobox', {name: 'quick switch input'}).should('be.visible');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ describe('Verify Guest User Identification in different screens', () => {
|
|||||||
cy.uiOpenFindChannels();
|
cy.uiOpenFindChannels();
|
||||||
|
|
||||||
// # Type the guest user name on Channel switcher input
|
// # Type the guest user name on Channel switcher input
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).type(guestUser.username).wait(TIMEOUTS.HALF_SEC);
|
cy.findByRole('combobox', {name: 'quick switch input'}).type(guestUser.username).wait(TIMEOUTS.HALF_SEC);
|
||||||
|
|
||||||
// * Verify if Guest badge is displayed for the guest user in the Switch Channel Dialog
|
// * Verify if Guest badge is displayed for the guest user in the Switch Channel Dialog
|
||||||
cy.get('#suggestionList').should('be.visible');
|
cy.get('#suggestionList').should('be.visible');
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ context('ldap', () => {
|
|||||||
cy.wait(TIMEOUTS.THREE_SEC);
|
cy.wait(TIMEOUTS.THREE_SEC);
|
||||||
|
|
||||||
// # Type channel display name on Channel switcher input
|
// # Type channel display name on Channel switcher input
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).type(publicChannel.display_name);
|
cy.findByRole('combobox', {name: 'quick switch input'}).type(publicChannel.display_name);
|
||||||
cy.wait(TIMEOUTS.HALF_SEC);
|
cy.wait(TIMEOUTS.HALF_SEC);
|
||||||
|
|
||||||
// * Should open up suggestion list for channels
|
// * Should open up suggestion list for channels
|
||||||
@@ -433,7 +433,7 @@ context('ldap', () => {
|
|||||||
cy.wait(TIMEOUTS.THREE_SEC);
|
cy.wait(TIMEOUTS.THREE_SEC);
|
||||||
|
|
||||||
// # Type channel display name on Channel switcher input
|
// # Type channel display name on Channel switcher input
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).type(publicChannel.display_name);
|
cy.findByRole('combobox', {name: 'quick switch input'}).type(publicChannel.display_name);
|
||||||
cy.wait(TIMEOUTS.HALF_SEC);
|
cy.wait(TIMEOUTS.HALF_SEC);
|
||||||
|
|
||||||
// * Should open up suggestion list for channels
|
// * Should open up suggestion list for channels
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ describe('Interactive Dialog', () => {
|
|||||||
cy.wrap($elForm).find('.suggestion-list__item').first().should('be.visible');
|
cy.wrap($elForm).find('.suggestion-list__item').first().should('be.visible');
|
||||||
cy.wrap($elForm).find('.form-control').type('{uparrow}', {force: true});
|
cy.wrap($elForm).find('.form-control').type('{uparrow}', {force: true});
|
||||||
cy.wrap($elForm).find('.form-control').type('{downarrow}'.repeat(10), {force: true});
|
cy.wrap($elForm).find('.form-control').type('{downarrow}'.repeat(10), {force: true});
|
||||||
cy.wrap($elForm).find('.suggestion-list__item').first().should('not.be.visible');
|
cy.wrap($elForm).find('.suggestion-list__item').should('not.exist');
|
||||||
cy.wrap($elForm).find('.form-control').type('{uparrow}'.repeat(10), {force: true});
|
cy.wrap($elForm).find('.form-control').type('{uparrow}'.repeat(10), {force: true});
|
||||||
cy.wrap($elForm).find('.suggestion-list__item').first().should('be.visible');
|
cy.wrap($elForm).find('.suggestion-list__item').first().should('be.visible');
|
||||||
} else if (index === 1) {
|
} else if (index === 1) {
|
||||||
@@ -94,7 +94,7 @@ describe('Interactive Dialog', () => {
|
|||||||
cy.wrap($elForm).find('.suggestion-list__item').first().should('be.visible');
|
cy.wrap($elForm).find('.suggestion-list__item').first().should('be.visible');
|
||||||
cy.wrap($elForm).find('.form-control').type('{uparrow}', {force: true});
|
cy.wrap($elForm).find('.form-control').type('{uparrow}', {force: true});
|
||||||
cy.wrap($elForm).find('.form-control').type('{downarrow}'.repeat(10), {force: true});
|
cy.wrap($elForm).find('.form-control').type('{downarrow}'.repeat(10), {force: true});
|
||||||
cy.wrap($elForm).find('.suggestion-list__item').first().should('not.be.visible');
|
cy.wrap($elForm).find('.suggestion-list__item').should('not.exist');
|
||||||
cy.wrap($elForm).find('.form-control').type('{uparrow}'.repeat(10), {force: true});
|
cy.wrap($elForm).find('.form-control').type('{uparrow}'.repeat(10), {force: true});
|
||||||
cy.wrap($elForm).find('.suggestion-list__item').first().should('be.visible');
|
cy.wrap($elForm).find('.suggestion-list__item').first().should('be.visible');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ describe('Keyboard Shortcuts', () => {
|
|||||||
cy.typeCmdOrCtrl().type('K', {release: true});
|
cy.typeCmdOrCtrl().type('K', {release: true});
|
||||||
|
|
||||||
// # Start typing the name of other user
|
// # Start typing the name of other user
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).type(this.otherUser.username);
|
cy.findByRole('combobox', {name: 'quick switch input'}).type(this.otherUser.username);
|
||||||
|
|
||||||
// # Select other user from the list
|
// # Select other user from the list
|
||||||
cy.findByTestId(this.otherUser.username).should('not.exist');
|
cy.findByTestId(this.otherUser.username).should('not.exist');
|
||||||
@@ -104,7 +104,7 @@ function verifyUserIsFoundAndDMOpensOnClick(user) {
|
|||||||
cy.typeCmdOrCtrl().type('K', {release: true});
|
cy.typeCmdOrCtrl().type('K', {release: true});
|
||||||
|
|
||||||
// # Start typing the name of other user
|
// # Start typing the name of other user
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).type(user.username);
|
cy.findByRole('combobox', {name: 'quick switch input'}).type(user.username);
|
||||||
|
|
||||||
// # Select other user from the list
|
// # Select other user from the list
|
||||||
cy.findByTestId(user.username).should('be.visible');
|
cy.findByTestId(user.username).should('be.visible');
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ describe('Keyboard Shortcuts', () => {
|
|||||||
cy.apiAddUserToTeam(testTeam.id, tempUser.id);
|
cy.apiAddUserToTeam(testTeam.id, tempUser.id);
|
||||||
|
|
||||||
// # In the "Switch Channels" modal type the first chars of the test channel name
|
// # In the "Switch Channels" modal type the first chars of the test channel name
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).should('be.focused').type(testChannel.name.substring(0, 3)).wait(TIMEOUTS.HALF_SEC);
|
cy.findByRole('combobox', {name: 'quick switch input'}).should('be.focused').type(testChannel.name.substring(0, 3)).wait(TIMEOUTS.HALF_SEC);
|
||||||
|
|
||||||
// # Verify that the list of users and channels suggestions is present
|
// # Verify that the list of users and channels suggestions is present
|
||||||
cy.get('#suggestionList').should('be.visible').within(() => {
|
cy.get('#suggestionList').should('be.visible').within(() => {
|
||||||
@@ -360,7 +360,7 @@ describe('Keyboard Shortcuts', () => {
|
|||||||
cy.uiGetPostTextBox().cmdOrCtrlShortcut('K').then(() => {
|
cy.uiGetPostTextBox().cmdOrCtrlShortcut('K').then(() => {
|
||||||
// * Channel switcher hint should be visible and focused on
|
// * Channel switcher hint should be visible and focused on
|
||||||
cy.get('#quickSwitchHint').should('be.visible');
|
cy.get('#quickSwitchHint').should('be.visible');
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).should('be.focused');
|
cy.findByRole('combobox', {name: 'quick switch input'}).should('be.focused');
|
||||||
});
|
});
|
||||||
|
|
||||||
// # Type CTRL/CMD+K to close 'Switch Channels' modal
|
// # Type CTRL/CMD+K to close 'Switch Channels' modal
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ describe('Messaging', () => {
|
|||||||
cy.uiGetPostTextBox().cmdOrCtrlShortcut('K');
|
cy.uiGetPostTextBox().cmdOrCtrlShortcut('K');
|
||||||
|
|
||||||
// # In the "Switch Channels" modal type the first 6 characters of the username
|
// # In the "Switch Channels" modal type the first 6 characters of the username
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).should('be.focused').type(secondUser.username.substring(0, 6)).wait(TIMEOUTS.HALF_SEC);
|
cy.findByRole('combobox', {name: 'quick switch input'}).should('be.focused').type(secondUser.username.substring(0, 6)).wait(TIMEOUTS.HALF_SEC);
|
||||||
|
|
||||||
// # Verify that the list of users and channels suggestions is present
|
// # Verify that the list of users and channels suggestions is present
|
||||||
cy.get('#suggestionList').should('be.visible').within(() => {
|
cy.get('#suggestionList').should('be.visible').within(() => {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ describe('Messaging', () => {
|
|||||||
cy.get('#quickSwitchHint').should('be.visible');
|
cy.get('#quickSwitchHint').should('be.visible');
|
||||||
|
|
||||||
// # Type channel name and select it
|
// # Type channel name and select it
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).type(testChannelName).wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
cy.findByRole('combobox', {name: 'quick switch input'}).type(testChannelName).wait(TIMEOUTS.HALF_SEC).type('{enter}');
|
||||||
|
|
||||||
// * Verify that it redirected into selected channel
|
// * Verify that it redirected into selected channel
|
||||||
cy.get('#channelHeaderTitle').should('be.visible').should('contain', testChannelName);
|
cy.get('#channelHeaderTitle').should('be.visible').should('contain', testChannelName);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ describe('Message Draft and Switch Channels', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('MM-T131 Message Draft Pencil Icon - CTRL/CMD+K & "Jump to"', () => {
|
it('MM-T131 Message Draft Pencil Icon - CTRL/CMD+K & "Jump to"', () => {
|
||||||
const {name, display_name: displayName} = testChannel;
|
const {name, display_name: displayName, id} = testChannel;
|
||||||
const message = 'message draft test';
|
const message = 'message draft test';
|
||||||
|
|
||||||
// * Validate if the draft icon is not visible at LHS before making a draft
|
// * Validate if the draft icon is not visible at LHS before making a draft
|
||||||
@@ -55,10 +55,10 @@ describe('Message Draft and Switch Channels', () => {
|
|||||||
// * Suggestion list is visible
|
// * Suggestion list is visible
|
||||||
cy.get('#suggestionList').should('be.visible').within(() => {
|
cy.get('#suggestionList').should('be.visible').within(() => {
|
||||||
// * A pencil icon before the channel name in the filtered list is visible
|
// * A pencil icon before the channel name in the filtered list is visible
|
||||||
cy.get(`#switchChannel_${name}`).find('.icon-pencil-outline').should('be.visible');
|
cy.get(`#switchChannel_${id}`).find('.icon-pencil-outline').should('be.visible');
|
||||||
|
|
||||||
// # Click to switch back to the test channel
|
// # Click to switch back to the test channel
|
||||||
cy.get(`#switchChannel_${name}`).click({force: true});
|
cy.get(`#switchChannel_${id}`).click({force: true});
|
||||||
});
|
});
|
||||||
|
|
||||||
// * Draft is saved in the text input box of the test channel
|
// * Draft is saved in the text input box of the test channel
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ describe('Messaging - Opening a private channel using keyboard shortcuts', () =>
|
|||||||
// # Type the first letter of a private channel in the "Switch Channels" modal message box
|
// # Type the first letter of a private channel in the "Switch Channels" modal message box
|
||||||
// # Use up/down arrow keys to highlight a private channel
|
// # Use up/down arrow keys to highlight a private channel
|
||||||
// # Press ENTER
|
// # Press ENTER
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).type('Pr').type('{downarrow}').type('{enter}');
|
cy.findByRole('combobox', {name: 'quick switch input'}).type('Pr').type('{downarrow}').type('{enter}');
|
||||||
|
|
||||||
// * Private channel opens
|
// * Private channel opens
|
||||||
cy.get('#channelHeaderTitle').should('be.visible').should('contain', 'Private').wait(TIMEOUTS.HALF_SEC);
|
cy.get('#channelHeaderTitle').should('be.visible').should('contain', 'Private').wait(TIMEOUTS.HALF_SEC);
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ function searchAndVerifyChannel(channel) {
|
|||||||
cy.typeCmdOrCtrl().type('k');
|
cy.typeCmdOrCtrl().type('k');
|
||||||
|
|
||||||
// # Search for channel's display name
|
// # Search for channel's display name
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).
|
cy.findByRole('combobox', {name: 'quick switch input'}).
|
||||||
should('be.visible').
|
should('be.visible').
|
||||||
as('input').
|
as('input').
|
||||||
clear().
|
clear().
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ describe('Settings > Sidebar > Channel Switcher', () => {
|
|||||||
cy.get('#quickSwitchHint').should('be.visible').should('contain', 'Type to find a channel. Use UP/DOWN to browse, ENTER to select, ESC to dismiss.');
|
cy.get('#quickSwitchHint').should('be.visible').should('contain', 'Type to find a channel. Use UP/DOWN to browse, ENTER to select, ESC to dismiss.');
|
||||||
|
|
||||||
// # Type CTRL/CMD+shift+L
|
// # Type CTRL/CMD+shift+L
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).cmdOrCtrlShortcut('{shift}L');
|
cy.findByRole('combobox', {name: 'quick switch input'}).cmdOrCtrlShortcut('{shift}L');
|
||||||
|
|
||||||
// * Suggestion list should not be visible
|
// * Suggestion list should not be visible
|
||||||
cy.get('#suggestionList').should('not.exist');
|
cy.get('#suggestionList').should('not.exist');
|
||||||
@@ -56,7 +56,7 @@ describe('Settings > Sidebar > Channel Switcher', () => {
|
|||||||
cy.get('#quickSwitchHint').should('be.visible').should('contain', 'Type to find a channel. Use UP/DOWN to browse, ENTER to select, ESC to dismiss.');
|
cy.get('#quickSwitchHint').should('be.visible').should('contain', 'Type to find a channel. Use UP/DOWN to browse, ENTER to select, ESC to dismiss.');
|
||||||
|
|
||||||
// # Type CTRL/CMD+shift+m
|
// # Type CTRL/CMD+shift+m
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).cmdOrCtrlShortcut('{shift}M');
|
cy.findByRole('combobox', {name: 'quick switch input'}).cmdOrCtrlShortcut('{shift}M');
|
||||||
|
|
||||||
// * Suggestion list should not be visible
|
// * Suggestion list should not be visible
|
||||||
cy.get('#suggestionList').should('not.exist');
|
cy.get('#suggestionList').should('not.exist');
|
||||||
|
|||||||
@@ -50,14 +50,14 @@ function verifyChannelSwitch(team, channel) {
|
|||||||
cy.get('#quickSwitchHint').should('be.visible').should('contain', 'Type to find a channel. Use UP/DOWN to browse, ENTER to select, ESC to dismiss.');
|
cy.get('#quickSwitchHint').should('be.visible').should('contain', 'Type to find a channel. Use UP/DOWN to browse, ENTER to select, ESC to dismiss.');
|
||||||
|
|
||||||
// # Type channel display name on Channel switcher input
|
// # Type channel display name on Channel switcher input
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).type(channel.display_name);
|
cy.findByRole('combobox', {name: 'quick switch input'}).type(channel.display_name);
|
||||||
cy.wait(TIMEOUTS.HALF_SEC);
|
cy.wait(TIMEOUTS.HALF_SEC);
|
||||||
|
|
||||||
// * Suggestion list should be visible
|
// * Suggestion list should be visible
|
||||||
cy.get('#suggestionList').should('be.visible');
|
cy.get('#suggestionList').should('be.visible');
|
||||||
|
|
||||||
// # Press enter
|
// # Press enter
|
||||||
cy.findByRole('textbox', {name: 'quick switch input'}).type('{enter}');
|
cy.findByRole('combobox', {name: 'quick switch input'}).type('{enter}');
|
||||||
|
|
||||||
// * Verify that it redirected into "channel-switcher" as selected channel
|
// * Verify that it redirected into "channel-switcher" as selected channel
|
||||||
cy.url().should('include', `/${team.name}/channels/${channel.name}`);
|
cy.url().should('include', `/${team.name}/channels/${channel.name}`);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default class FindChannelsModal {
|
|||||||
constructor(container: Locator) {
|
constructor(container: Locator) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
|
|
||||||
this.input = container.getByRole('textbox', {name: 'quick switch input'});
|
this.input = container.getByRole('combobox', {name: 'quick switch input'});
|
||||||
this.searchList = container.locator('.suggestion-list__item');
|
this.searchList = container.locator('.suggestion-list__item');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,13 +32,17 @@ exports[`components/search_bar/SearchBar should match snapshot with search 1`] =
|
|||||||
class="input-wrapper"
|
class="input-wrapper"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
|
aria-autocomplete="list"
|
||||||
|
aria-controls="suggestionList"
|
||||||
aria-describedby="searchbar-help-popup"
|
aria-describedby="searchbar-help-popup"
|
||||||
|
aria-expanded="false"
|
||||||
aria-label="Search"
|
aria-label="Search"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="search-bar form-control a11y__region"
|
class="search-bar form-control a11y__region"
|
||||||
data-a11y-sort-order="9"
|
data-a11y-sort-order="9"
|
||||||
id="searchBox"
|
id="searchBox"
|
||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
|
role="combobox"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
type="search"
|
type="search"
|
||||||
value="test"
|
value="test"
|
||||||
@@ -103,13 +107,17 @@ exports[`components/search_bar/SearchBar should match snapshot with search, with
|
|||||||
class="input-wrapper"
|
class="input-wrapper"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
|
aria-autocomplete="list"
|
||||||
|
aria-controls="suggestionList"
|
||||||
aria-describedby="searchbar-help-popup"
|
aria-describedby="searchbar-help-popup"
|
||||||
|
aria-expanded="false"
|
||||||
aria-label="Search"
|
aria-label="Search"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="search-bar form-control a11y__region"
|
class="search-bar form-control a11y__region"
|
||||||
data-a11y-sort-order="9"
|
data-a11y-sort-order="9"
|
||||||
id="searchBox"
|
id="searchBox"
|
||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
|
role="combobox"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
type="search"
|
type="search"
|
||||||
value="test"
|
value="test"
|
||||||
@@ -166,13 +174,17 @@ exports[`components/search_bar/SearchBar should match snapshot without search 1`
|
|||||||
class="input-wrapper"
|
class="input-wrapper"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
|
aria-autocomplete="list"
|
||||||
|
aria-controls="suggestionList"
|
||||||
aria-describedby="searchbar-help-popup"
|
aria-describedby="searchbar-help-popup"
|
||||||
|
aria-expanded="false"
|
||||||
aria-label="Search"
|
aria-label="Search"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="search-bar form-control a11y__region"
|
class="search-bar form-control a11y__region"
|
||||||
data-a11y-sort-order="9"
|
data-a11y-sort-order="9"
|
||||||
id="searchBox"
|
id="searchBox"
|
||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
|
role="combobox"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
type="search"
|
type="search"
|
||||||
value=""
|
value=""
|
||||||
@@ -225,13 +237,17 @@ exports[`components/search_bar/SearchBar should match snapshot without search, w
|
|||||||
class="input-wrapper"
|
class="input-wrapper"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
|
aria-autocomplete="list"
|
||||||
|
aria-controls="suggestionList"
|
||||||
aria-describedby="searchbar-help-popup"
|
aria-describedby="searchbar-help-popup"
|
||||||
|
aria-expanded="false"
|
||||||
aria-label="Search"
|
aria-label="Search"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="search-bar form-control a11y__region"
|
class="search-bar form-control a11y__region"
|
||||||
data-a11y-sort-order="9"
|
data-a11y-sort-order="9"
|
||||||
id="searchBox"
|
id="searchBox"
|
||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
|
role="combobox"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
type="search"
|
type="search"
|
||||||
value=""
|
value=""
|
||||||
@@ -276,13 +292,17 @@ exports[`components/search_bar/SearchBar should match snapshot without search, w
|
|||||||
class="input-wrapper"
|
class="input-wrapper"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
|
aria-autocomplete="list"
|
||||||
|
aria-controls="suggestionList"
|
||||||
aria-describedby="searchbar-help-popup"
|
aria-describedby="searchbar-help-popup"
|
||||||
|
aria-expanded="false"
|
||||||
aria-label="Search"
|
aria-label="Search"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="search-bar form-control a11y__region"
|
class="search-bar form-control a11y__region"
|
||||||
data-a11y-sort-order="9"
|
data-a11y-sort-order="9"
|
||||||
id="searchBox"
|
id="searchBox"
|
||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
|
role="combobox"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
type="search"
|
type="search"
|
||||||
value=""
|
value=""
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ exports[`at mention suggestion Should display nick name of non signed in user 1`
|
|||||||
onMouseMove={[MockFunction]}
|
onMouseMove={[MockFunction]}
|
||||||
term="@user"
|
term="@user"
|
||||||
>
|
>
|
||||||
<div
|
<li
|
||||||
className="suggestion-list__item"
|
className="suggestion-list__item"
|
||||||
data-testid="mentionSuggestion_user2"
|
data-testid="mentionSuggestion_user2"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
@@ -88,7 +88,7 @@ exports[`at mention suggestion Should display nick name of non signed in user 1`
|
|||||||
<div />
|
<div />
|
||||||
</Component>
|
</Component>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</li>
|
||||||
</SuggestionContainer>
|
</SuggestionContainer>
|
||||||
</AtMentionSuggestion>
|
</AtMentionSuggestion>
|
||||||
`;
|
`;
|
||||||
@@ -129,7 +129,7 @@ exports[`at mention suggestion Should not display nick name of the signed in use
|
|||||||
onMouseMove={[MockFunction]}
|
onMouseMove={[MockFunction]}
|
||||||
term="@user"
|
term="@user"
|
||||||
>
|
>
|
||||||
<div
|
<li
|
||||||
className="suggestion-list__item"
|
className="suggestion-list__item"
|
||||||
data-testid="mentionSuggestion_user"
|
data-testid="mentionSuggestion_user"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
@@ -191,7 +191,7 @@ exports[`at mention suggestion Should not display nick name of the signed in use
|
|||||||
<div />
|
<div />
|
||||||
</Component>
|
</Component>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</li>
|
||||||
</SuggestionContainer>
|
</SuggestionContainer>
|
||||||
</AtMentionSuggestion>
|
</AtMentionSuggestion>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ interface Group extends Item {
|
|||||||
member_count: number;
|
member_count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AtMentionSuggestion = React.forwardRef<HTMLDivElement, SuggestionProps<Item>>((props, ref) => {
|
const AtMentionSuggestion = React.forwardRef<HTMLLIElement, SuggestionProps<Item>>((props, ref) => {
|
||||||
const {item} = props;
|
const {item} = props;
|
||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ type WrappedChannel = {
|
|||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChannelMentionSuggestion = React.forwardRef<HTMLDivElement, SuggestionProps<WrappedChannel>>((props, ref) => {
|
export const ChannelMentionSuggestion = React.forwardRef<HTMLLIElement, SuggestionProps<WrappedChannel>>((props, ref) => {
|
||||||
const {item} = props;
|
const {item} = props;
|
||||||
const channelIsArchived = item.channel && item.channel.delete_at && item.channel.delete_at !== 0;
|
const channelIsArchived = item.channel && item.channel.delete_at && item.channel.delete_at !== 0;
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const EXECUTE_CURRENT_COMMAND_ITEM_ID = Constants.Integrations.EXECUTE_CURRENT_C
|
|||||||
const OPEN_COMMAND_IN_MODAL_ITEM_ID = Constants.Integrations.OPEN_COMMAND_IN_MODAL_ITEM_ID;
|
const OPEN_COMMAND_IN_MODAL_ITEM_ID = Constants.Integrations.OPEN_COMMAND_IN_MODAL_ITEM_ID;
|
||||||
const COMMAND_SUGGESTION_ERROR = Constants.Integrations.COMMAND_SUGGESTION_ERROR;
|
const COMMAND_SUGGESTION_ERROR = Constants.Integrations.COMMAND_SUGGESTION_ERROR;
|
||||||
|
|
||||||
const CommandSuggestion = React.forwardRef<HTMLDivElement, SuggestionProps<AutocompleteSuggestion>>((props, ref) => {
|
const CommandSuggestion = React.forwardRef<HTMLLIElement, SuggestionProps<AutocompleteSuggestion>>((props, ref) => {
|
||||||
const {item} = props;
|
const {item} = props;
|
||||||
|
|
||||||
let symbolSpan = <span>{'/'}</span>;
|
let symbolSpan = <span>{'/'}</span>;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ type EmojiItem = {
|
|||||||
|
|
||||||
const suggestionTypeEmoji = 'emoji';
|
const suggestionTypeEmoji = 'emoji';
|
||||||
|
|
||||||
const EmoticonSuggestion = React.forwardRef<HTMLDivElement, SuggestionProps<EmojiItem>>((props, ref) => {
|
const EmoticonSuggestion = React.forwardRef<HTMLLIElement, SuggestionProps<EmojiItem>>((props, ref) => {
|
||||||
const text = props.term;
|
const text = props.term;
|
||||||
const emoji = props.item.emoji;
|
const emoji = props.item.emoji;
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import type {SuggestionProps} from './suggestion';
|
|||||||
|
|
||||||
type ChannelSearchFunc = (term: string, success: (channels: Channel[]) => void, error?: (err: ServerError) => void) => (ActionResult | Promise<ActionResult | ActionResult[]>);
|
type ChannelSearchFunc = (term: string, success: (channels: Channel[]) => void, error?: (err: ServerError) => void) => (ActionResult | Promise<ActionResult | ActionResult[]>);
|
||||||
|
|
||||||
const GenericChannelSuggestion = React.forwardRef<HTMLDivElement, SuggestionProps<Channel>>((props, ref) => {
|
const GenericChannelSuggestion = React.forwardRef<HTMLLIElement, SuggestionProps<Channel>>((props, ref) => {
|
||||||
const {item} = props;
|
const {item} = props;
|
||||||
|
|
||||||
const channelName = item.display_name;
|
const channelName = item.display_name;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import type {ResultsCallback} from './provider';
|
|||||||
import {SuggestionContainer} from './suggestion';
|
import {SuggestionContainer} from './suggestion';
|
||||||
import type {SuggestionProps} from './suggestion';
|
import type {SuggestionProps} from './suggestion';
|
||||||
|
|
||||||
const GenericUserSuggestion = React.forwardRef<HTMLDivElement, SuggestionProps<UserProfile>>((props, ref) => {
|
const GenericUserSuggestion = React.forwardRef<HTMLLIElement, SuggestionProps<UserProfile>>((props, ref) => {
|
||||||
const {item} = props;
|
const {item} = props;
|
||||||
|
|
||||||
const username = item.username;
|
const username = item.username;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ interface MenuAction {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MenuActionSuggestion = React.forwardRef<HTMLDivElement, SuggestionProps<MenuAction>>((props, ref) => {
|
const MenuActionSuggestion = React.forwardRef<HTMLLIElement, SuggestionProps<MenuAction>>((props, ref) => {
|
||||||
const {item} = props;
|
const {item} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ type Props = SuggestionProps<Channel> & {
|
|||||||
teammateIsBot: boolean;
|
teammateIsBot: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchChannelSuggestion = React.forwardRef<HTMLDivElement, Props>((props, ref) => {
|
const SearchChannelSuggestion = React.forwardRef<HTMLLIElement, Props>((props, ref) => {
|
||||||
const {item, teammateIsBot, currentUserId} = props;
|
const {item, teammateIsBot, currentUserId} = props;
|
||||||
|
|
||||||
const nameObject = itemToName(item, currentUserId);
|
const nameObject = itemToName(item, currentUserId);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ interface WrappedChannel {
|
|||||||
|
|
||||||
type ChannelSearchFunction = (teamId: string, channelPrefix: string) => Promise<ActionResult>
|
type ChannelSearchFunction = (teamId: string, channelPrefix: string) => Promise<ActionResult>
|
||||||
|
|
||||||
const SearchChannelWithPermissionsSuggestion = React.forwardRef<HTMLDivElement, SuggestionProps<WrappedChannel>>((props, ref) => {
|
const SearchChannelWithPermissionsSuggestion = React.forwardRef<HTMLLIElement, SuggestionProps<WrappedChannel>>((props, ref) => {
|
||||||
const {item} = props;
|
const {item} = props;
|
||||||
const channel = item.channel;
|
const channel = item.channel;
|
||||||
const channelIsArchived = channel.delete_at && channel.delete_at !== 0;
|
const channelIsArchived = channel.delete_at && channel.delete_at !== 0;
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export default class SearchSuggestionList extends SuggestionList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getContent = () => {
|
getContent = () => {
|
||||||
return this.itemsContainerRef?.current?.parentNode as HTMLDivElement | null;
|
return this.itemsContainerRef?.current?.parentNode as HTMLUListElement | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
renderChannelDivider(type: string) {
|
renderChannelDivider(type: string) {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import type {ResultsCallback} from './provider';
|
|||||||
import {SuggestionContainer} from './suggestion';
|
import {SuggestionContainer} from './suggestion';
|
||||||
import type {SuggestionProps} from './suggestion';
|
import type {SuggestionProps} from './suggestion';
|
||||||
|
|
||||||
export const SearchUserSuggestion = React.forwardRef<HTMLDivElement, SuggestionProps<UserProfile>>((props, ref) => {
|
export const SearchUserSuggestion = React.forwardRef<HTMLLIElement, SuggestionProps<UserProfile>>((props, ref) => {
|
||||||
const {item} = props;
|
const {item} = props;
|
||||||
|
|
||||||
const username = item.username;
|
const username = item.username;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, {useCallback} from 'react';
|
import React, {useCallback} from 'react';
|
||||||
|
|
||||||
export interface SuggestionProps<Item> extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onClick' | 'onMouseMove'> {
|
export interface SuggestionProps<Item> extends Omit<React.HTMLAttributes<HTMLLIElement>, 'onClick' | 'onMouseMove'> {
|
||||||
// eslint-disable-next-line react/no-unused-prop-types
|
// eslint-disable-next-line react/no-unused-prop-types
|
||||||
item: Item;
|
item: Item;
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ export interface SuggestionProps<Item> extends Omit<React.HTMLAttributes<HTMLDiv
|
|||||||
onMouseMove: (term: string) => void;
|
onMouseMove: (term: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SuggestionContainer = React.forwardRef<HTMLDivElement, SuggestionProps<unknown>>((props, ref) => {
|
const SuggestionContainer = React.forwardRef<HTMLLIElement, SuggestionProps<unknown>>((props, ref) => {
|
||||||
const {
|
const {
|
||||||
children,
|
children,
|
||||||
term,
|
term,
|
||||||
@@ -47,7 +47,7 @@ const SuggestionContainer = React.forwardRef<HTMLDivElement, SuggestionProps<unk
|
|||||||
}, [onMouseMove, term]);
|
}, [onMouseMove, term]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<li
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={classNames('suggestion-list__item', {'suggestion--selected': isSelection})}
|
className={classNames('suggestion-list__item', {'suggestion--selected': isSelection})}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
@@ -57,7 +57,7 @@ const SuggestionContainer = React.forwardRef<HTMLDivElement, SuggestionProps<unk
|
|||||||
{...otherProps}
|
{...otherProps}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</li>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -820,6 +820,12 @@ export default class SuggestionBox extends React.PureComponent {
|
|||||||
ref={this.inputRef}
|
ref={this.inputRef}
|
||||||
autoComplete='off'
|
autoComplete='off'
|
||||||
{...props}
|
{...props}
|
||||||
|
aria-controls='suggestionList'
|
||||||
|
role='combobox'
|
||||||
|
{...(this.state.selection && {'aria-activedescendant': `${props.id}_${this.state.selection}`}
|
||||||
|
)}
|
||||||
|
aria-autocomplete='list'
|
||||||
|
aria-expanded={this.state.focused || this.props.forceSuggestionsWhenBlur}
|
||||||
onInput={this.handleChange}
|
onInput={this.handleChange}
|
||||||
onCompositionStart={this.handleCompositionStart}
|
onCompositionStart={this.handleCompositionStart}
|
||||||
onCompositionUpdate={this.handleCompositionUpdate}
|
onCompositionUpdate={this.handleCompositionUpdate}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ describe('SuggestionBox', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Start with no suggestions rendered
|
// Start with no suggestions rendered
|
||||||
expect(screen.queryByRole('list')).not.toBeInTheDocument();
|
expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
|
||||||
|
|
||||||
// Typing some text should cause a suggestion to be shown
|
// Typing some text should cause a suggestion to be shown
|
||||||
userEvent.click(screen.getByPlaceholderText('test input'));
|
userEvent.click(screen.getByPlaceholderText('test input'));
|
||||||
@@ -103,9 +103,9 @@ describe('SuggestionBox', () => {
|
|||||||
expect(providerSpy).toHaveBeenCalledTimes(1);
|
expect(providerSpy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(screen.queryByRole('list')).toBeVisible();
|
expect(screen.queryByRole('listbox')).toBeVisible();
|
||||||
|
|
||||||
expect(screen.queryByRole('list')).toBeVisible();
|
expect(screen.queryByRole('listbox')).toBeVisible();
|
||||||
expect(screen.getByText('Suggestion: testtest')).toBeVisible();
|
expect(screen.getByText('Suggestion: testtest')).toBeVisible();
|
||||||
|
|
||||||
// Typing more text should cause the suggestion to be updaetd
|
// Typing more text should cause the suggestion to be updaetd
|
||||||
@@ -115,13 +115,13 @@ describe('SuggestionBox', () => {
|
|||||||
expect(providerSpy).toHaveBeenCalledTimes(2);
|
expect(providerSpy).toHaveBeenCalledTimes(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(screen.queryByRole('list')).toBeVisible();
|
expect(screen.queryByRole('listbox')).toBeVisible();
|
||||||
expect(screen.getByText('Suggestion: testwordstestwords')).toBeVisible();
|
expect(screen.getByText('Suggestion: testwordstestwords')).toBeVisible();
|
||||||
|
|
||||||
// Clearing the textbox hides all suggestions
|
// Clearing the textbox hides all suggestions
|
||||||
await userEvent.clear(screen.getByPlaceholderText('test input'));
|
await userEvent.clear(screen.getByPlaceholderText('test input'));
|
||||||
|
|
||||||
expect(screen.queryByRole('list')).not.toBeInTheDocument();
|
expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should hide suggestions on pressing escape', async () => {
|
test('should hide suggestions on pressing escape', async () => {
|
||||||
@@ -135,20 +135,20 @@ describe('SuggestionBox', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Start with no suggestions rendered
|
// Start with no suggestions rendered
|
||||||
expect(screen.queryByRole('list')).not.toBeInTheDocument();
|
expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
|
||||||
|
|
||||||
// Typing some text should cause a suggestion to be shown
|
// Typing some text should cause a suggestion to be shown
|
||||||
userEvent.click(screen.getByPlaceholderText('test input'));
|
userEvent.click(screen.getByPlaceholderText('test input'));
|
||||||
await userEvent.keyboard('test');
|
await userEvent.keyboard('test');
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(screen.getByRole('list')).toBeVisible();
|
expect(screen.getByRole('listbox')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pressing escape hides all suggestions
|
// Pressing escape hides all suggestions
|
||||||
await userEvent.keyboard('{escape}');
|
await userEvent.keyboard('{escape}');
|
||||||
|
|
||||||
expect(screen.queryByRole('list')).not.toBeInTheDocument();
|
expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should autocomplete suggestions by pressing enter', async () => {
|
test('should autocomplete suggestions by pressing enter', async () => {
|
||||||
@@ -166,7 +166,7 @@ describe('SuggestionBox', () => {
|
|||||||
await userEvent.keyboard('test');
|
await userEvent.keyboard('test');
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(screen.queryByRole('list')).toBeVisible();
|
expect(screen.queryByRole('listbox')).toBeVisible();
|
||||||
expect(screen.getByText('Suggestion: testtest')).toBeVisible();
|
expect(screen.getByText('Suggestion: testtest')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ describe('SuggestionBox', () => {
|
|||||||
expect(screen.getByPlaceholderText('test input')).toHaveValue('testtest ');
|
expect(screen.getByPlaceholderText('test input')).toHaveValue('testtest ');
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(screen.queryByRole('list')).not.toBeInTheDocument();
|
expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('MM-57320 completing text with enter and calling resultCallback twice should not erase text following caret', async () => {
|
test('MM-57320 completing text with enter and calling resultCallback twice should not erase text following caret', async () => {
|
||||||
@@ -203,14 +203,14 @@ describe('SuggestionBox', () => {
|
|||||||
onSuggestionsReceived.mockClear();
|
onSuggestionsReceived.mockClear();
|
||||||
|
|
||||||
expect(screen.getByPlaceholderText('test input')).toHaveValue('This is important');
|
expect(screen.getByPlaceholderText('test input')).toHaveValue('This is important');
|
||||||
expect(screen.getByRole('list')).toBeVisible();
|
expect(screen.getByRole('listbox')).toBeVisible();
|
||||||
expect(screen.getByText('Suggestion: This is importantThis is important')).toBeVisible();
|
expect(screen.getByText('Suggestion: This is importantThis is important')).toBeVisible();
|
||||||
|
|
||||||
// Move the caret back to the start of the textbox and then use escape to clear the suggestions because
|
// Move the caret back to the start of the textbox and then use escape to clear the suggestions because
|
||||||
// we don't support moving the caret with the autocomplete open yet
|
// we don't support moving the caret with the autocomplete open yet
|
||||||
await userEvent.keyboard('{home}{escape}');
|
await userEvent.keyboard('{home}{escape}');
|
||||||
|
|
||||||
expect(screen.queryByRole('list')).not.toBeInTheDocument();
|
expect(screen.queryByRole('listbox')).not.toBeInTheDocument();
|
||||||
|
|
||||||
// Type a space and then start typing something again to show results
|
// Type a space and then start typing something again to show results
|
||||||
onSuggestionsReceived.mockClear();
|
onSuggestionsReceived.mockClear();
|
||||||
@@ -221,7 +221,7 @@ describe('SuggestionBox', () => {
|
|||||||
expect(onSuggestionsReceived).toHaveBeenCalledTimes(2);
|
expect(onSuggestionsReceived).toHaveBeenCalledTimes(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(screen.getByRole('list')).toBeVisible();
|
expect(screen.getByRole('listbox')).toBeVisible();
|
||||||
expect(screen.getByText('Suggestion: @us@us')).toBeVisible();
|
expect(screen.getByText('Suggestion: @us@us')).toBeVisible();
|
||||||
|
|
||||||
onSuggestionsReceived.mockClear();
|
onSuggestionsReceived.mockClear();
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export default class SuggestionList extends React.PureComponent<Props> {
|
|||||||
renderDividers: [],
|
renderDividers: [],
|
||||||
renderNoResults: false,
|
renderNoResults: false,
|
||||||
};
|
};
|
||||||
contentRef: React.RefObject<HTMLDivElement>;
|
contentRef: React.RefObject<HTMLUListElement>;
|
||||||
wrapperRef: React.RefObject<HTMLDivElement>;
|
wrapperRef: React.RefObject<HTMLDivElement>;
|
||||||
itemRefs: Map<string, any>;
|
itemRefs: Map<string, any>;
|
||||||
currentLabel: string | null;
|
currentLabel: string | null;
|
||||||
@@ -209,6 +209,7 @@ export default class SuggestionList extends React.PureComponent<Props> {
|
|||||||
<div
|
<div
|
||||||
key={type + '-divider'}
|
key={type + '-divider'}
|
||||||
className='suggestion-list__divider'
|
className='suggestion-list__divider'
|
||||||
|
role='separator'
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
<FormattedMessage id={id}/>
|
<FormattedMessage id={id}/>
|
||||||
@@ -219,7 +220,7 @@ export default class SuggestionList extends React.PureComponent<Props> {
|
|||||||
|
|
||||||
renderNoResults() {
|
renderNoResults() {
|
||||||
return (
|
return (
|
||||||
<div
|
<ul
|
||||||
key='list-no-results'
|
key='list-no-results'
|
||||||
className='suggestion-list__no-results'
|
className='suggestion-list__no-results'
|
||||||
ref={this.contentRef}
|
ref={this.contentRef}
|
||||||
@@ -232,7 +233,7 @@ export default class SuggestionList extends React.PureComponent<Props> {
|
|||||||
b: (chunks: string) => <b>{chunks}</b>,
|
b: (chunks: string) => <b>{chunks}</b>,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</ul>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,10 +297,10 @@ export default class SuggestionList extends React.PureComponent<Props> {
|
|||||||
ref={this.wrapperRef}
|
ref={this.wrapperRef}
|
||||||
className={mainClass}
|
className={mainClass}
|
||||||
>
|
>
|
||||||
<div
|
<ul
|
||||||
id='suggestionList'
|
id='suggestionList'
|
||||||
data-testid='suggestionList'
|
data-testid='suggestionList'
|
||||||
role='list'
|
role='listbox'
|
||||||
ref={this.contentRef}
|
ref={this.contentRef}
|
||||||
style={{
|
style={{
|
||||||
maxHeight: this.maxHeight,
|
maxHeight: this.maxHeight,
|
||||||
@@ -309,7 +310,7 @@ export default class SuggestionList extends React.PureComponent<Props> {
|
|||||||
onMouseDown={this.props.preventClose}
|
onMouseDown={this.props.preventClose}
|
||||||
>
|
>
|
||||||
{items}
|
{items}
|
||||||
</div>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,9 +121,10 @@ type Props = SuggestionProps<WrappedChannel> & WrappedComponentProps & {
|
|||||||
isPartOfOnlyOneTeam: boolean;
|
isPartOfOnlyOneTeam: boolean;
|
||||||
status?: string;
|
status?: string;
|
||||||
team?: Team;
|
team?: Team;
|
||||||
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SwitchChannelSuggestion = React.forwardRef<HTMLDivElement, Props>((props, ref) => {
|
const SwitchChannelSuggestion = React.forwardRef<HTMLLIElement, Props>((props, ref) => {
|
||||||
const {item, status, collapsedThreads, team, isPartOfOnlyOneTeam} = props;
|
const {item, status, collapsedThreads, team, isPartOfOnlyOneTeam} = props;
|
||||||
const channel = item.channel;
|
const channel = item.channel;
|
||||||
const channelIsArchived = channel.delete_at && channel.delete_at !== 0;
|
const channelIsArchived = channel.delete_at && channel.delete_at !== 0;
|
||||||
@@ -255,18 +256,31 @@ const SwitchChannelSuggestion = React.forwardRef<HTMLDivElement, Props>((props,
|
|||||||
}
|
}
|
||||||
const showSlug = (isPartOfOnlyOneTeam || channel.type === Constants.DM_CHANNEL) && channel.type !== Constants.THREADS;
|
const showSlug = (isPartOfOnlyOneTeam || channel.type === Constants.DM_CHANNEL) && channel.type !== Constants.THREADS;
|
||||||
|
|
||||||
|
const getId = () => {
|
||||||
|
if (channel.type === Constants.DM_CHANNEL) {
|
||||||
|
if (prefix) {
|
||||||
|
return `quickSwitchInput_${(channel as FakeDirectChannel).userId}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return `quickSwitchInput_${channel.id}`;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SuggestionContainer
|
<SuggestionContainer
|
||||||
ref={ref}
|
ref={ref}
|
||||||
id={`switchChannel_${channel.name}`}
|
|
||||||
data-testid={channel.name}
|
data-testid={channel.name}
|
||||||
role='listitem'
|
role='option'
|
||||||
|
aria-labelledby={`${name.toLowerCase().replaceAll(' ', '-')}-item-name`}
|
||||||
{...props}
|
{...props}
|
||||||
|
id={getId()}
|
||||||
>
|
>
|
||||||
{icon}
|
{icon}
|
||||||
<div className='suggestion-list__ellipsis suggestion-list__flex'>
|
<div className='suggestion-list__ellipsis suggestion-list__flex'>
|
||||||
<span className='suggestion-list__main'>
|
<span className='suggestion-list__main'>
|
||||||
<span className={classNames({'suggestion-list__unread': item.unread && !channelIsArchived})}>{name}</span>
|
<span
|
||||||
|
className={classNames({'suggestion-list__unread': item.unread && !channelIsArchived})}
|
||||||
|
id={`${name.toLowerCase().replaceAll(' ', '-')}-item-name`}
|
||||||
|
>{name}</span>
|
||||||
{showSlug && description && <span className='ml-2 suggestion-list__desc'>{description}</span>}
|
{showSlug && description && <span className='ml-2 suggestion-list__desc'>{description}</span>}
|
||||||
</span>
|
</span>
|
||||||
{customStatus}
|
{customStatus}
|
||||||
@@ -316,6 +330,8 @@ function mapStateToPropsForSwitchChannelSuggestion(state: GlobalState, ownProps:
|
|||||||
collapsedThreads,
|
collapsedThreads,
|
||||||
team,
|
team,
|
||||||
isPartOfOnlyOneTeam,
|
isPartOfOnlyOneTeam,
|
||||||
|
|
||||||
|
// id: 'quickSwitchInput',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,7 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
max-height: 292px;
|
max-height: 292px;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
|
padding-left: 0;
|
||||||
border: 1px solid rgba(var(--center-channel-color-rgb), 0.16);
|
border: 1px solid rgba(var(--center-channel-color-rgb), 0.16);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background-color: functions.v(center-channel-bg);
|
background-color: functions.v(center-channel-bg);
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user