MM-53813: Fix(accessibility): on channels page (#24122)
* fix(accessibility): on channels page * fix lint and update dynamic-virtualized-list * fix snapshot and update per feedback * fix e2e tests * fix test --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
a47af39d80
Коммит
93a2c3281a
@@ -15,6 +15,12 @@
|
|||||||
"env": {
|
"env": {
|
||||||
"cypress/globals": true
|
"cypress/globals": true
|
||||||
},
|
},
|
||||||
|
"settings": {
|
||||||
|
"react": {
|
||||||
|
"pragma": "React",
|
||||||
|
"version": "detect"
|
||||||
|
}
|
||||||
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"header/header": [
|
"header/header": [
|
||||||
2,
|
2,
|
||||||
|
|||||||
@@ -137,10 +137,11 @@ describe('Verify Accessibility keyboard usability across different regions in th
|
|||||||
cy.clickPostCommentIcon(postId);
|
cy.clickPostCommentIcon(postId);
|
||||||
|
|
||||||
// * Verify Screen reader should not switch to virtual cursor mode. This is handled by adding a role=application attribute
|
// * Verify Screen reader should not switch to virtual cursor mode. This is handled by adding a role=application attribute
|
||||||
const regions = ['#sidebar-left', '#rhsContainer .post-right__content', '.search__form', '#advancedTextEditorCell'];
|
const regions = ['#sidebar-left', '#rhsContainer .post-right__content', '#advancedTextEditorCell'];
|
||||||
regions.forEach((region) => {
|
regions.forEach((region) => {
|
||||||
cy.get(region).should('have.attr', 'role', 'application');
|
cy.get(region).should('have.attr', 'role', 'application');
|
||||||
});
|
});
|
||||||
|
cy.get('.search__form').should('have.attr', 'role', 'search');
|
||||||
cy.get(`#post_${postId}`).children('.post__content').eq(0).should('have.attr', 'role', 'application');
|
cy.get(`#post_${postId}`).children('.post__content').eq(0).should('have.attr', 'role', 'application');
|
||||||
cy.get(`#rhsPost_${postId}`).children('.post__content').eq(0).should('have.attr', 'role', 'application');
|
cy.get(`#rhsPost_${postId}`).children('.post__content').eq(0).should('have.attr', 'role', 'application');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ describe('Verify Accessibility Support in Post', () => {
|
|||||||
cy.focused().tab();
|
cy.focused().tab();
|
||||||
|
|
||||||
// * Verify focus is on the post text
|
// * Verify focus is on the post text
|
||||||
cy.get(`#postMessageText_${postId}`).should('be.focused').and('have.attr', 'aria-readonly', 'true');
|
cy.get(`#postMessageText_${postId}`).should('be.focused');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -231,7 +231,7 @@ describe('Verify Accessibility Support in Post', () => {
|
|||||||
cy.getLastPostId().then((postId) => {
|
cy.getLastPostId().then((postId) => {
|
||||||
cy.get(`#rhsPost_${postId}`).within(() => {
|
cy.get(`#rhsPost_${postId}`).within(() => {
|
||||||
// * Verify focus is on the post text
|
// * Verify focus is on the post text
|
||||||
cy.get(`#rhsPostMessageText_${postId}`).should('be.focused').and('have.attr', 'aria-readonly', 'true');
|
cy.get(`#rhsPostMessageText_${postId}`).should('be.focused');
|
||||||
cy.focused().tab({shift: true});
|
cy.focused().tab({shift: true});
|
||||||
|
|
||||||
// * Verify focus is on the more button
|
// * Verify focus is on the more button
|
||||||
|
|||||||
@@ -24,6 +24,20 @@ describe('MM-T3156 DM category', () => {
|
|||||||
cy.apiInitSetup({loginAfter: true, promoteNewUserAsAdmin: true}).then(({team, user}) => {
|
cy.apiInitSetup({loginAfter: true, promoteNewUserAsAdmin: true}).then(({team, user}) => {
|
||||||
testUser = user;
|
testUser = user;
|
||||||
cy.visit(`/${team.name}/channels/town-square`);
|
cy.visit(`/${team.name}/channels/town-square`);
|
||||||
|
|
||||||
|
const usersPrefixes = ['a', 'c', 'd', 'j', 'p', 'u', 'x', 'z'];
|
||||||
|
usersPrefixes.forEach((prefix) => {
|
||||||
|
// # Create users with prefixes in alphabetical order
|
||||||
|
cy.apiCreateUser({prefix}).then(({user: newUser}) => {
|
||||||
|
cy.apiCreateDirectChannel([testUser.id, newUser.id]).then(({channel}) => {
|
||||||
|
// # Post message in The DM channel
|
||||||
|
cy.postMessageAs({sender: newUser, message: 'test', channelId: channel.id});
|
||||||
|
|
||||||
|
// add usernames in array for reference
|
||||||
|
usernames.push(newUser.username);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -36,20 +50,6 @@ describe('MM-T3156 DM category', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('MM-T3156_2 should order DMs based on recent interactions', () => {
|
it('MM-T3156_2 should order DMs based on recent interactions', () => {
|
||||||
const usersPrefixes = ['a', 'c', 'd', 'j', 'p', 'u', 'x', 'z'];
|
|
||||||
usersPrefixes.forEach((prefix) => {
|
|
||||||
// # Create users with prefixes in alphabetical order
|
|
||||||
cy.apiCreateUser({prefix}).then(({user: newUser}) => {
|
|
||||||
cy.apiCreateDirectChannel([testUser.id, newUser.id]).then(({channel}) => {
|
|
||||||
// # Post message in The DM channel
|
|
||||||
cy.postMessageAs({sender: newUser, message: 'test', channelId: channel.id});
|
|
||||||
|
|
||||||
// add usernames in array for reference
|
|
||||||
usernames.push(newUser.username);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// get DM category group
|
// get DM category group
|
||||||
cy.findByLabelText('DIRECT MESSAGES').parents('.SidebarChannelGroup').within(() => {
|
cy.findByLabelText('DIRECT MESSAGES').parents('.SidebarChannelGroup').within(() => {
|
||||||
const usernamesReversed = [...usernames].reverse();
|
const usernamesReversed = [...usernames].reverse();
|
||||||
@@ -68,15 +68,14 @@ describe('MM-T3156 DM category', () => {
|
|||||||
|
|
||||||
// # Change sorting to be alphabetical
|
// # Change sorting to be alphabetical
|
||||||
cy.findByText('Sort').trigger('mouseover');
|
cy.findByText('Sort').trigger('mouseover');
|
||||||
cy.findByText('Alphabetically').click();
|
cy.findByText('Alphabetically').click().wait(TIMEOUTS.ONE_SEC);
|
||||||
|
|
||||||
cy.findByLabelText('DIRECT MESSAGES').should('be.visible').
|
cy.findByLabelText('DIRECT MESSAGES').parents('.SidebarChannelGroup').within(() => {
|
||||||
parents('.SidebarChannelGroup').within(() => {
|
cy.get('.NavGroupContent').children().each(($el, index) => {
|
||||||
cy.get('.NavGroupContent').children().each(($el, index) => {
|
// * Verify that the usernames are in alphabetical order
|
||||||
// * Verify that the usernames are in alphabetical order
|
cy.wrap($el).findByText(usernames[index]).should('be.visible');
|
||||||
cy.wrap($el).findByText(usernames[index]).should('be.visible');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('MM-T3156_4 should not be able to rearrange DMs', () => {
|
it('MM-T3156_4 should not be able to rearrange DMs', () => {
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ describe('Guest Accounts', () => {
|
|||||||
children().should('have.length', 1).
|
children().should('have.length', 1).
|
||||||
eq(0).should('contain', testChannel.name).click();
|
eq(0).should('contain', testChannel.name).click();
|
||||||
|
|
||||||
cy.get('#inviteGuestButton').scrollIntoView().click();
|
cy.findByTestId('inviteButton').scrollIntoView().click();
|
||||||
cy.findByTestId('confirm-done').should('be.visible').click();
|
cy.findByTestId('confirm-done').should('be.visible').click();
|
||||||
|
|
||||||
// # Get invitation link.
|
// # Get invitation link.
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ describe('Guest Account - Guest User Invitation Flow', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// * Verify Invite Guests button is disabled by default
|
// * Verify Invite Guests button is disabled by default
|
||||||
cy.get('#inviteGuestButton').scrollIntoView().should('be.visible').and('be.disabled');
|
cy.findByTestId('inviteButton').scrollIntoView().should('be.visible').and('be.disabled');
|
||||||
|
|
||||||
// * Verify Invite People field
|
// * Verify Invite People field
|
||||||
const email = `temp-${getRandomId()}@mattermost.com`;
|
const email = `temp-${getRandomId()}@mattermost.com`;
|
||||||
@@ -141,7 +141,7 @@ describe('Guest Account - Guest User Invitation Flow', () => {
|
|||||||
invitePeople(email, 1, email, 'Town Square', false);
|
invitePeople(email, 1, email, 'Town Square', false);
|
||||||
|
|
||||||
// * Verify Invite Guests button is disabled
|
// * Verify Invite Guests button is disabled
|
||||||
cy.get('#inviteGuestButton').should('be.disabled');
|
cy.findByTestId('inviteButton').should('be.disabled');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('MM-T4449 Invite Guest via Email containing upper case letters', () => {
|
it('MM-T4449 Invite Guest via Email containing upper case letters', () => {
|
||||||
@@ -177,7 +177,7 @@ describe('Guest Account - Guest User Invitation Flow', () => {
|
|||||||
children().should('have.length', 1).eq(0).should('contain', newUser.username).click();
|
children().should('have.length', 1).eq(0).should('contain', newUser.username).click();
|
||||||
|
|
||||||
// # Click Invite Members
|
// # Click Invite Members
|
||||||
cy.get('#inviteMembersButton').scrollIntoView().click();
|
cy.findByTestId('inviteButton').scrollIntoView().click();
|
||||||
|
|
||||||
// * Verify the content and error message in the Invitation Modal
|
// * Verify the content and error message in the Invitation Modal
|
||||||
cy.findByTestId('invitationModal').within(() => {
|
cy.findByTestId('invitationModal').within(() => {
|
||||||
@@ -218,7 +218,7 @@ describe('Guest Account - Guest User Invitation Flow', () => {
|
|||||||
cy.get('.users-emails-input__menu').children().should('have.length', 1).eq(0).should('contain', email).click();
|
cy.get('.users-emails-input__menu').children().should('have.length', 1).eq(0).should('contain', email).click();
|
||||||
|
|
||||||
// # Click Invite Guests Button
|
// # Click Invite Guests Button
|
||||||
cy.get('#inviteGuestButton').scrollIntoView().click();
|
cy.findByTestId('inviteButton').scrollIntoView().click();
|
||||||
|
|
||||||
// * Verify invite more button is present
|
// * Verify invite more button is present
|
||||||
cy.findByTestId('invite-more').should('be.visible');
|
cy.findByTestId('invite-more').should('be.visible');
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export function invitePeople(typeText: string, resultsCount: number, verifyText:
|
|||||||
|
|
||||||
if (clickInvite) {
|
if (clickInvite) {
|
||||||
// # Click Invite Guests Button
|
// # Click Invite Guests Button
|
||||||
cy.get('#inviteGuestButton').scrollIntoView().click();
|
cy.findByTestId('inviteButton').scrollIntoView().click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ describe('Guest Account - Member Invitation Flow', () => {
|
|||||||
|
|
||||||
cy.get('@clipboard').its('contents').should('eq', `${baseUrl}/signup_user_complete/?id=${testTeam.invite_id}`);
|
cy.get('@clipboard').its('contents').should('eq', `${baseUrl}/signup_user_complete/?id=${testTeam.invite_id}`);
|
||||||
|
|
||||||
cy.get('#inviteMembersButton').scrollIntoView().should('be.visible').and('be.disabled');
|
cy.findByTestId('inviteButton').scrollIntoView().should('be.visible').and('be.disabled');
|
||||||
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
cy.get('.users-emails-input__control').should('be.visible').within(() => {
|
||||||
// * Verify the input placeholder text
|
// * Verify the input placeholder text
|
||||||
cy.get('.users-emails-input__placeholder').should('have.text', 'Enter a name or email address');
|
cy.get('.users-emails-input__placeholder').should('have.text', 'Enter a name or email address');
|
||||||
@@ -224,7 +224,7 @@ describe('Guest Account - Member Invitation Flow', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// # Click Invite Members
|
// # Click Invite Members
|
||||||
cy.get('#inviteMembersButton').scrollIntoView().click();
|
cy.findByTestId('inviteButton').scrollIntoView().click();
|
||||||
|
|
||||||
// * Verify the content and message in the Invitation Modal
|
// * Verify the content and message in the Invitation Modal
|
||||||
cy.findByTestId('invitationModal').within(() => {
|
cy.findByTestId('invitationModal').within(() => {
|
||||||
@@ -267,7 +267,7 @@ function invitePeople(typeText, resultsCount, verifyText, clickInvite = true) {
|
|||||||
|
|
||||||
// # Click Invite Members
|
// # Click Invite Members
|
||||||
if (clickInvite) {
|
if (clickInvite) {
|
||||||
cy.get('#inviteMembersButton').scrollIntoView().click();
|
cy.findByTestId('inviteButton').scrollIntoView().click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ describe('Group Synced Team - Bot invitation flow', () => {
|
|||||||
click();
|
click();
|
||||||
|
|
||||||
// # Invite the bot
|
// # Invite the bot
|
||||||
cy.get('#inviteMembersButton').click();
|
cy.findByTestId('inviteButton').click();
|
||||||
|
|
||||||
// * Ensure that the response message was not an error
|
// * Ensure that the response message was not an error
|
||||||
cy.get('.InviteResultRow').find('.reason').should('not.contain', 'Error');
|
cy.get('.InviteResultRow').find('.reason').should('not.contain', 'Error');
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const webhookUtils = require('../../../../utils/webhook_utils');
|
|||||||
|
|
||||||
describe('Interactive Dialog', () => {
|
describe('Interactive Dialog', () => {
|
||||||
const inputTypes = {
|
const inputTypes = {
|
||||||
realname: 'input',
|
realname: 'text',
|
||||||
someemail: 'email',
|
someemail: 'email',
|
||||||
somenumber: 'number',
|
somenumber: 'number',
|
||||||
somepassword: 'password',
|
somepassword: 'password',
|
||||||
@@ -101,7 +101,7 @@ describe('Interactive Dialog', () => {
|
|||||||
cy.wrap($elForm).find('#suggestionList').scrollIntoView().should('be.visible');
|
cy.wrap($elForm).find('#suggestionList').scrollIntoView().should('be.visible');
|
||||||
|
|
||||||
// # Click field label to close any opened drop-downs
|
// # Click field label to close any opened drop-downs
|
||||||
cy.wrap($elForm).find('label.control-label').scrollIntoView().click();
|
cy.wrap($elForm).find('label.control-label').scrollIntoView().click({force: true});
|
||||||
} else if (element.name === 'someradiooptions') {
|
} else if (element.name === 'someradiooptions') {
|
||||||
cy.wrap($elForm).find('input').should('be.visible').and('have.length', optionsLength[element.name]);
|
cy.wrap($elForm).find('input').should('be.visible').and('have.length', optionsLength[element.name]);
|
||||||
|
|
||||||
|
|||||||
@@ -44,21 +44,29 @@ describe('Interactive Menu', () => {
|
|||||||
|
|
||||||
// # Post an incoming webhook
|
// # Post an incoming webhook
|
||||||
cy.postIncomingWebhook({url: incomingWebhook.url, data: payload, waitFor: 'attachment-pretext'});
|
cy.postIncomingWebhook({url: incomingWebhook.url, data: payload, waitFor: 'attachment-pretext'});
|
||||||
|
cy.waitUntil(() => cy.findAllByTestId('postContent').then((el) => {
|
||||||
|
if (el.length > 0) {
|
||||||
|
return el[1].innerText.includes(payload.attachments[0].actions[0].name);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
|
||||||
// # Click on "Skip Parsing" button
|
// # Click on "Skip Parsing" button
|
||||||
cy.findByText('Skip Parsing').should('be.visible').click({force: true});
|
cy.findByText(payload.attachments[0].actions[0].name).should('be.visible').click({force: true});
|
||||||
cy.wait(TIMEOUTS.HALF_SEC);
|
cy.wait(TIMEOUTS.HALF_SEC);
|
||||||
|
|
||||||
// * Verify that it renders original "spoiler" text
|
// * Verify that it renders original "spoiler" text
|
||||||
|
cy.uiWaitUntilMessagePostedIncludes('a < a | b > a');
|
||||||
cy.getLastPostId().then((postId) => {
|
cy.getLastPostId().then((postId) => {
|
||||||
cy.get(`#postMessageText_${postId}`).should('have.html', '<p>a < a | b > a</p>');
|
cy.get(`#postMessageText_${postId}`).should('have.html', '<p>a < a | b > a</p>');
|
||||||
});
|
});
|
||||||
|
|
||||||
// # Click on "Do Parsing" button
|
// # Click on "Do Parsing" button
|
||||||
cy.findByText('Do Parsing').should('be.visible').click({force: true});
|
cy.findByText(payload.attachments[0].actions[1].name).should('be.visible').click({force: true});
|
||||||
cy.wait(TIMEOUTS.HALF_SEC);
|
cy.wait(TIMEOUTS.HALF_SEC);
|
||||||
|
|
||||||
// * Verify that it renders markdown with link
|
// * Verify that it renders markdown with link
|
||||||
|
cy.uiWaitUntilMessagePostedIncludes('a b a');
|
||||||
cy.getLastPostId().then((postId) => {
|
cy.getLastPostId().then((postId) => {
|
||||||
cy.get(`#postMessageText_${postId}`).should('have.html', '<p>a <a class="theme markdown__link" href="http://a" rel="noreferrer" target="_blank"><span> b </span></a> a</p>');
|
cy.get(`#postMessageText_${postId}`).should('have.html', '<p>a <a class="theme markdown__link" href="http://a" rel="noreferrer" target="_blank"><span> b </span></a> a</p>');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ describe('Keyboard Shortcuts', () => {
|
|||||||
cy.uiClose();
|
cy.uiClose();
|
||||||
|
|
||||||
// # Open invite members full-page screen
|
// # Open invite members full-page screen
|
||||||
cy.get('#introTextInvite').click();
|
cy.findByLabelText('Invite Users').click();
|
||||||
|
|
||||||
// # Press ctrl/cmd+shift+l
|
// # Press ctrl/cmd+shift+l
|
||||||
cy.get('body').cmdOrCtrlShortcut('{shift+l}');
|
cy.get('body').cmdOrCtrlShortcut('{shift+l}');
|
||||||
|
|||||||
@@ -103,6 +103,6 @@ describe('Onboarding', () => {
|
|||||||
cy.findByRole('textbox', {name: 'Add or Invite People'}).
|
cy.findByRole('textbox', {name: 'Add or Invite People'}).
|
||||||
typeWithForce(email).wait(TIMEOUTS.HALF_SEC).
|
typeWithForce(email).wait(TIMEOUTS.HALF_SEC).
|
||||||
typeWithForce('{enter}');
|
typeWithForce('{enter}');
|
||||||
cy.get('#inviteMembersButton').click();
|
cy.findByTestId('inviteButton').click();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ describe('Team Settings', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cy.findByRole('textbox', {name: 'Add or Invite People'}).type(email, {force: true}).wait(TIMEOUTS.HALF_SEC).type('{enter}', {force: true});
|
cy.findByRole('textbox', {name: 'Add or Invite People'}).type(email, {force: true}).wait(TIMEOUTS.HALF_SEC).type('{enter}', {force: true});
|
||||||
cy.get('#inviteMembersButton').click();
|
cy.findByTestId('inviteButton').click();
|
||||||
|
|
||||||
// # Wait for a while to ensure that email notification is sent and logout from sysadmin account
|
// # Wait for a while to ensure that email notification is sent and logout from sysadmin account
|
||||||
cy.wait(TIMEOUTS.FIVE_SEC);
|
cy.wait(TIMEOUTS.FIVE_SEC);
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export const inviteUserByEmail = (email) => {
|
|||||||
typeWithForce(email).
|
typeWithForce(email).
|
||||||
wait(TIMEOUTS.HALF_SEC).
|
wait(TIMEOUTS.HALF_SEC).
|
||||||
typeWithForce('{enter}');
|
typeWithForce('{enter}');
|
||||||
cy.get('#inviteMembersButton').click();
|
cy.findByTestId('inviteButton').click();
|
||||||
|
|
||||||
// # Wait for a while to ensure that email notification is sent
|
// # Wait for a while to ensure that email notification is sent
|
||||||
cy.wait(TIMEOUTS.TWO_SEC);
|
cy.wait(TIMEOUTS.TWO_SEC);
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ function inviteUser(user) {
|
|||||||
cy.get('.users-emails-input__menu').children().eq(0).should('contain', user.username).click();
|
cy.get('.users-emails-input__menu').children().eq(0).should('contain', user.username).click();
|
||||||
|
|
||||||
// # Click Invite Members
|
// # Click Invite Members
|
||||||
cy.get('#inviteMembersButton').scrollIntoView().click();
|
cy.findByTestId('inviteButton').scrollIntoView().click();
|
||||||
}
|
}
|
||||||
|
|
||||||
function inviteUserToTeamAsMember(testUser, testTeam, user) {
|
function inviteUserToTeamAsMember(testUser, testTeam, user) {
|
||||||
|
|||||||
@@ -82,6 +82,6 @@ describe('Team Settings', () => {
|
|||||||
typeWithForce(email).
|
typeWithForce(email).
|
||||||
wait(TIMEOUTS.HALF_SEC).
|
wait(TIMEOUTS.HALF_SEC).
|
||||||
typeWithForce('{enter}');
|
typeWithForce('{enter}');
|
||||||
cy.get('#inviteMembersButton').click();
|
cy.findByTestId('inviteButton').click();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ describe('Teams Suite', () => {
|
|||||||
click();
|
click();
|
||||||
|
|
||||||
// # Click "Invite Members" button, then "Done" button
|
// # Click "Invite Members" button, then "Done" button
|
||||||
cy.get('#inviteMembersButton').click();
|
cy.findByTestId('inviteButton').click();
|
||||||
cy.findByTestId('confirm-done').click();
|
cy.findByTestId('confirm-done').click();
|
||||||
|
|
||||||
// * As sysadmin, verify system message posts in Town Square and Off-Topic
|
// * As sysadmin, verify system message posts in Town Square and Off-Topic
|
||||||
|
|||||||
@@ -325,10 +325,10 @@ const verifyInitialAndStatusPostInBroadcast = (testTeam, channelName, runName, i
|
|||||||
should('exist').
|
should('exist').
|
||||||
within(() => {
|
within(() => {
|
||||||
// * Thread should have two posts
|
// * Thread should have two posts
|
||||||
cy.findAllByRole('listitem').should('have.length', 2);
|
cy.findAllByTestId('postContent').should('have.length', 2);
|
||||||
|
|
||||||
// * The first should be announcement
|
// * The first should be announcement
|
||||||
cy.findAllByRole('listitem').eq(0).contains(initialMessage);
|
cy.findAllByTestId('postContent').eq(0).contains(initialMessage);
|
||||||
|
|
||||||
// * Latest post should be update
|
// * Latest post should be update
|
||||||
cy.get(`#rhsPost_${lastPostId}`).contains(
|
cy.get(`#rhsPost_${lastPostId}`).contains(
|
||||||
@@ -354,7 +354,7 @@ const deleteLatestPostRoot = (testTeam, channelName) => {
|
|||||||
cy.get('#rhsContainer').
|
cy.get('#rhsContainer').
|
||||||
should('exist').
|
should('exist').
|
||||||
within(() => {
|
within(() => {
|
||||||
cy.findAllByRole('listitem').eq(0).then((root) => {
|
cy.findAllByTestId('postContent').eq(0).parent().then((root) => {
|
||||||
const rootId = root.attr('id').slice(8);
|
const rootId = root.attr('id').slice(8);
|
||||||
|
|
||||||
// # Click root's post dot menu.
|
// # Click root's post dot menu.
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Cypress.Commands.add('uiInviteMemberToCurrentTeam', (username) => {
|
|||||||
cy.get('.users-emails-input__control input').typeWithForce(username).as('input');
|
cy.get('.users-emails-input__control input').typeWithForce(username).as('input');
|
||||||
cy.get('.users-emails-input__option ').contains(`@${username}`);
|
cy.get('.users-emails-input__option ').contains(`@${username}`);
|
||||||
cy.get('@input').typeWithForce('{enter}');
|
cy.get('@input').typeWithForce('{enter}');
|
||||||
cy.get('#inviteMembersButton').click();
|
cy.findByTestId('inviteButton').click();
|
||||||
|
|
||||||
// * Verify user invited to team
|
// * Verify user invited to team
|
||||||
cy.get('.invitation-modal-confirm--sent .InviteResultRow').
|
cy.get('.invitation-modal-confirm--sent .InviteResultRow').
|
||||||
|
|||||||
@@ -19,8 +19,9 @@ type ExtendedFixtures = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const test = base.extend<ExtendedFixtures>({
|
export const test = base.extend<ExtendedFixtures>({
|
||||||
axe: async ({page}, use) => {
|
// eslint-disable-next-line no-empty-pattern
|
||||||
const ab = new AxeBuilderExtended(page);
|
axe: async ({}, use) => {
|
||||||
|
const ab = new AxeBuilderExtended();
|
||||||
await use(ab);
|
await use(ab);
|
||||||
},
|
},
|
||||||
pw: async ({browser, viewport}, use) => {
|
pw: async ({browser, viewport}, use) => {
|
||||||
@@ -93,24 +94,15 @@ class PlaywrightExtended {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AxeBuilderExtended {
|
class AxeBuilderExtended {
|
||||||
/**
|
readonly builder: (page: Page, disableRules?: string[]) => AxeBuilder;
|
||||||
* Each page should have its own Axe Builder to specifically list known issues
|
|
||||||
* which are to be excluded from being scanned until issues are fixed.
|
|
||||||
* Excluded element should have a corresponding ticket.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// '<site_url>/login'
|
|
||||||
readonly loginPage: () => AxeBuilder;
|
|
||||||
|
|
||||||
// See https://github.com/dequelabs/axe-core/blob/master/doc/API.md#axe-core-tags
|
// See https://github.com/dequelabs/axe-core/blob/master/doc/API.md#axe-core-tags
|
||||||
readonly tags: string[] = ['wcag2a', 'wcag2aa'];
|
readonly tags: string[] = ['wcag2a', 'wcag2aa'];
|
||||||
|
|
||||||
// See https://github.com/dequelabs/axe-core/blob/master/doc/rule-descriptions.md#wcag-20-level-a--aa-rules
|
constructor() {
|
||||||
readonly disabledRules: string[] = [];
|
// See https://github.com/dequelabs/axe-core/blob/master/doc/rule-descriptions.md#wcag-20-level-a--aa-rules
|
||||||
|
this.builder = (page: Page, disableRules?: string[]) => {
|
||||||
constructor(page: Page) {
|
return new AxeBuilder({page}).withTags(this.tags).disableRules(disableRules || []);
|
||||||
this.loginPage = () => {
|
|
||||||
return new AxeBuilder({page}).withTags(this.tags).disableRules(this.disabledRules);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {expect, test} from '@e2e-support/test_fixture';
|
||||||
|
|
||||||
|
test('Intro to channel', async ({pw, pages, axe}) => {
|
||||||
|
// Create and sign in a new user
|
||||||
|
const {user} = await pw.initSetup();
|
||||||
|
|
||||||
|
// Log in a user in new browser context
|
||||||
|
const {page} = await pw.testBrowser.login(user);
|
||||||
|
|
||||||
|
// Visit a default channel page
|
||||||
|
const channelsPage = new pages.ChannelsPage(page);
|
||||||
|
await channelsPage.goto();
|
||||||
|
await channelsPage.toBeVisible();
|
||||||
|
await channelsPage.postMessage('hello');
|
||||||
|
await channelsPage.sendMessage();
|
||||||
|
|
||||||
|
// # Analyze the page
|
||||||
|
// Disable 'color-contrast' to be addressed by MM-53814
|
||||||
|
const accessibilityScanResults = await axe.builder(page, ['color-contrast']).analyze();
|
||||||
|
|
||||||
|
// * Should have no violation
|
||||||
|
expect(accessibilityScanResults.violations).toHaveLength(0);
|
||||||
|
});
|
||||||
@@ -12,7 +12,7 @@ test('/login', async ({pw, pages, page, axe}) => {
|
|||||||
await loginPage.toBeVisible();
|
await loginPage.toBeVisible();
|
||||||
|
|
||||||
// # Analyze the page
|
// # Analyze the page
|
||||||
const accessibilityScanResults = await axe.loginPage().analyze();
|
const accessibilityScanResults = await axe.builder(loginPage.page).analyze();
|
||||||
|
|
||||||
// * Should have no violation
|
// * Should have no violation
|
||||||
expect(accessibilityScanResults.violations).toHaveLength(0);
|
expect(accessibilityScanResults.violations).toHaveLength(0);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
"crypto-browserify": "3.12.0",
|
"crypto-browserify": "3.12.0",
|
||||||
"css-vars-ponyfill": "2.4.8",
|
"css-vars-ponyfill": "2.4.8",
|
||||||
"date-fns": "2.29.3",
|
"date-fns": "2.29.3",
|
||||||
"dynamic-virtualized-list": "github:mattermost/dynamic-virtualized-list#1c330717d6778315a40e70137ace38247c6a1d0f",
|
"dynamic-virtualized-list": "github:mattermost/dynamic-virtualized-list#3fe918b41de4cb08dbf43f1207bb58827b38e833",
|
||||||
"emoji-regex": "10.2.1",
|
"emoji-regex": "10.2.1",
|
||||||
"exif2css": "1.3.0",
|
"exif2css": "1.3.0",
|
||||||
"fast-deep-equal": "3.1.3",
|
"fast-deep-equal": "3.1.3",
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ exports[`components/SearchableChannelList should match init snapshot 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="more-modal__list"
|
className="more-modal__list"
|
||||||
role="application"
|
role="search"
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ exports[`components/ChannelHeader should match snapshot with last active display
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -380,7 +379,6 @@ exports[`components/ChannelHeader should match snapshot with no last active disp
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -676,7 +674,6 @@ exports[`components/ChannelHeader should render active channel files 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -978,7 +975,6 @@ exports[`components/ChannelHeader should render active flagged posts 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -1280,7 +1276,6 @@ exports[`components/ChannelHeader should render active mentions posts 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -1582,7 +1577,6 @@ exports[`components/ChannelHeader should render active pinned posts 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -1887,7 +1881,6 @@ exports[`components/ChannelHeader should render archived view 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -2155,7 +2148,6 @@ exports[`components/ChannelHeader should render correct menu when muted 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -2489,7 +2481,6 @@ exports[`components/ChannelHeader should render not active channel files 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -2799,7 +2790,6 @@ exports[`components/ChannelHeader should render properly when custom status is e
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -3123,7 +3113,6 @@ exports[`components/ChannelHeader should render properly when custom status is s
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -3459,7 +3448,6 @@ exports[`components/ChannelHeader should render properly when empty 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -3761,7 +3749,6 @@ exports[`components/ChannelHeader should render properly when populated 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -4063,7 +4050,6 @@ exports[`components/ChannelHeader should render properly when populated with cha
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -4396,7 +4382,6 @@ exports[`components/ChannelHeader should render shared view 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
@@ -4700,7 +4685,6 @@ exports[`components/ChannelHeader should render the pinned icon with the pinned
|
|||||||
</span>
|
</span>
|
||||||
</strong>
|
</strong>
|
||||||
<span
|
<span
|
||||||
aria-label="dropdown icon"
|
|
||||||
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
className="icon icon-chevron-down header-dropdown-chevron-icon"
|
||||||
id="channelHeaderDropdownIcon"
|
id="channelHeaderDropdownIcon"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -785,7 +785,6 @@ class ChannelHeader extends React.PureComponent<Props, State> {
|
|||||||
<span
|
<span
|
||||||
id='channelHeaderDropdownIcon'
|
id='channelHeaderDropdownIcon'
|
||||||
className='icon icon-chevron-down header-dropdown-chevron-icon'
|
className='icon icon-chevron-down header-dropdown-chevron-icon'
|
||||||
aria-label={formatMessage({id: 'generic_icons.dropdown', defaultMessage: 'Dropdown Icon'}).toLowerCase()}
|
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ export default function InviteView(props: Props) {
|
|||||||
disabled={!isInviteValid}
|
disabled={!isInviteValid}
|
||||||
onClick={props.invite}
|
onClick={props.invite}
|
||||||
className={'btn btn-primary'}
|
className={'btn btn-primary'}
|
||||||
id={props.inviteType === InviteType.MEMBER ? 'inviteMembersButton' : 'inviteGuestButton'}
|
data-testid={'inviteButton'}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='invite_modal.invite'
|
id='invite_modal.invite'
|
||||||
|
|||||||
@@ -513,7 +513,6 @@ const PostComponent = (props: Props): JSX.Element => {
|
|||||||
{(isSearchResultItem || (props.location !== Locations.CENTER && (props.isPinnedPosts || props.isFlaggedPosts))) && <DateSeparator date={currentPostDay}/>}
|
{(isSearchResultItem || (props.location !== Locations.CENTER && (props.isPinnedPosts || props.isFlaggedPosts))) && <DateSeparator date={currentPostDay}/>}
|
||||||
<PostAriaLabelDiv
|
<PostAriaLabelDiv
|
||||||
ref={postRef}
|
ref={postRef}
|
||||||
role='listitem'
|
|
||||||
id={getTestId()}
|
id={getTestId()}
|
||||||
data-testid={props.location === 'CENTER' ? 'postView' : ''}
|
data-testid={props.location === 'CENTER' ? 'postView' : ''}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
|
|||||||
@@ -253,7 +253,6 @@ exports[`components/post_edit_history should match snapshot 1`] = `
|
|||||||
style="max-height: 600px;"
|
style="max-height: 600px;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-readonly="true"
|
|
||||||
class="post-message__text"
|
class="post-message__text"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
id="rhsPostMessageText_post_id"
|
id="rhsPostMessageText_post_id"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React, {memo, useCallback, useState} from 'react';
|
import React, {memo, useCallback, useState} from 'react';
|
||||||
import {FormattedMessage} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import {
|
import {
|
||||||
FloatingFocusManager,
|
FloatingFocusManager,
|
||||||
@@ -41,19 +41,16 @@ function PostPriorityPickerOverlay({
|
|||||||
onClose,
|
onClose,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [pickerOpen, setPickerOpen] = useState(false);
|
const [pickerOpen, setPickerOpen] = useState(false);
|
||||||
|
const {formatMessage} = useIntl();
|
||||||
|
|
||||||
|
const messagePriority = formatMessage({id: 'shortcuts.msgs.formatting_bar.post_priority', defaultMessage: 'Message priority'});
|
||||||
const {
|
const {
|
||||||
reference: tooltipRef,
|
reference: tooltipRef,
|
||||||
getReferenceProps: getTooltipReferenceProps,
|
getReferenceProps: getTooltipReferenceProps,
|
||||||
tooltip,
|
tooltip,
|
||||||
} = useTooltip({
|
} = useTooltip({
|
||||||
placement: 'top',
|
placement: 'top',
|
||||||
message: (
|
message: messagePriority,
|
||||||
<FormattedMessage
|
|
||||||
id='shortcuts.msgs.formatting_bar.post_priority'
|
|
||||||
defaultMessage={'Message priority'}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleClose = useCallback(() => {
|
const handleClose = useCallback(() => {
|
||||||
@@ -104,6 +101,7 @@ function PostPriorityPickerOverlay({
|
|||||||
className={classNames({control: true, active: pickerOpen})}
|
className={classNames({control: true, active: pickerOpen})}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
type='button'
|
type='button'
|
||||||
|
aria-label={messagePriority}
|
||||||
{...getPickerReferenceProps()}
|
{...getPickerReferenceProps()}
|
||||||
>
|
>
|
||||||
<AlertCircleOutlineIcon
|
<AlertCircleOutlineIcon
|
||||||
|
|||||||
@@ -642,7 +642,6 @@ export default class PostList extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
role='list'
|
|
||||||
className='a11y__region'
|
className='a11y__region'
|
||||||
data-a11y-sort-order='1'
|
data-a11y-sort-order='1'
|
||||||
data-a11y-focus-child={true}
|
data-a11y-focus-child={true}
|
||||||
@@ -664,12 +663,10 @@ export default class PostList extends React.PureComponent<Props, State> {
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
role='presentation'
|
|
||||||
className='post-list-holder-by-time'
|
className='post-list-holder-by-time'
|
||||||
key={'postlist-' + channelId}
|
key={'postlist-' + channelId}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
role='presentation'
|
|
||||||
className='post-list__table'
|
className='post-list__table'
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ exports[`components/post_view/PostAttachment should match snapshot 1`] = `
|
|||||||
text="post message"
|
text="post message"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-readonly="true"
|
|
||||||
className="post-message__text"
|
className="post-message__text"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
id="postMessageText_post_id"
|
id="postMessageText_post_id"
|
||||||
@@ -46,7 +45,6 @@ exports[`components/post_view/PostAttachment should match snapshot, on Show Less
|
|||||||
text="post message"
|
text="post message"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-readonly="true"
|
|
||||||
className="post-message__text"
|
className="post-message__text"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
id="postMessageText_post_id"
|
id="postMessageText_post_id"
|
||||||
@@ -86,7 +84,6 @@ exports[`components/post_view/PostAttachment should match snapshot, on Show More
|
|||||||
text="post message"
|
text="post message"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-readonly="true"
|
|
||||||
className="post-message__text"
|
className="post-message__text"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
id="postMessageText_post_id"
|
id="postMessageText_post_id"
|
||||||
@@ -144,7 +141,6 @@ exports[`components/post_view/PostAttachment should match snapshot, on edited po
|
|||||||
text="post message"
|
text="post message"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-readonly="true"
|
|
||||||
className="post-message__text"
|
className="post-message__text"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
id="postMessageText_post_id"
|
id="postMessageText_post_id"
|
||||||
@@ -185,7 +181,6 @@ exports[`components/post_view/PostAttachment should match snapshot, on ephemeral
|
|||||||
text="post message"
|
text="post message"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-readonly="true"
|
|
||||||
className="post-message__text"
|
className="post-message__text"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
id="postMessageText_post_id"
|
id="postMessageText_post_id"
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ export default class PostMessageView extends React.PureComponent<Props, State> {
|
|||||||
maxHeight={maxHeight}
|
maxHeight={maxHeight}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-readonly='true'
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
id={id}
|
id={id}
|
||||||
className='post-message__text'
|
className='post-message__text'
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ exports[`components/search_bar/SearchBar should match snapshot with search 1`] =
|
|||||||
aria-labelledby="searchBox"
|
aria-labelledby="searchBox"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="search__form"
|
class="search__form"
|
||||||
role="application"
|
role="search"
|
||||||
style="overflow: visible;"
|
style="overflow: visible;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -70,7 +70,7 @@ exports[`components/search_bar/SearchBar should match snapshot with search, with
|
|||||||
aria-labelledby="searchBox"
|
aria-labelledby="searchBox"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="search__form"
|
class="search__form"
|
||||||
role="application"
|
role="search"
|
||||||
style="overflow: visible;"
|
style="overflow: visible;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -138,7 +138,7 @@ exports[`components/search_bar/SearchBar should match snapshot without search 1`
|
|||||||
aria-labelledby="searchBox"
|
aria-labelledby="searchBox"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="search__form"
|
class="search__form"
|
||||||
role="application"
|
role="search"
|
||||||
style="overflow: visible;"
|
style="overflow: visible;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -187,7 +187,7 @@ exports[`components/search_bar/SearchBar should match snapshot without search, w
|
|||||||
aria-labelledby="searchBox"
|
aria-labelledby="searchBox"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="search__form"
|
class="search__form"
|
||||||
role="application"
|
role="search"
|
||||||
style="overflow: visible;"
|
style="overflow: visible;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -244,7 +244,7 @@ exports[`components/search_bar/SearchBar should match snapshot without search, w
|
|||||||
aria-labelledby="searchBox"
|
aria-labelledby="searchBox"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="search__form"
|
class="search__form"
|
||||||
role="application"
|
role="search"
|
||||||
style="overflow: visible;"
|
style="overflow: visible;"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ const SearchBar: React.FunctionComponent<Props> = (props: Props): JSX.Element =>
|
|||||||
className='search-form__container'
|
className='search-form__container'
|
||||||
>
|
>
|
||||||
<form
|
<form
|
||||||
role='application'
|
role='search'
|
||||||
className={classNames(['search__form', {'search__form--focused': isFocused}])}
|
className={classNames(['search__form', {'search__form--focused': isFocused}])}
|
||||||
onSubmit={props.handleSubmit}
|
onSubmit={props.handleSubmit}
|
||||||
style={style.searchForm}
|
style={style.searchForm}
|
||||||
|
|||||||
@@ -463,7 +463,7 @@ export default class SearchableChannelList extends React.PureComponent<Props, St
|
|||||||
{input}
|
{input}
|
||||||
{dropDownContainer}
|
{dropDownContainer}
|
||||||
<div
|
<div
|
||||||
role='application'
|
role='search'
|
||||||
className='more-modal__list'
|
className='more-modal__list'
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ exports[`components/new_channel_modal should match snapshot 1`] = `
|
|||||||
id="addChannelsCta"
|
id="addChannelsCta"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<li
|
<div
|
||||||
aria-label="Add channels"
|
aria-label="Add channels"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
@@ -22,7 +22,7 @@ exports[`components/new_channel_modal should match snapshot 1`] = `
|
|||||||
<span>
|
<span>
|
||||||
Add Channels
|
Add Channels
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<Menu
|
<Menu
|
||||||
ariaLabel="Add Channels Dropdown"
|
ariaLabel="Add Channels Dropdown"
|
||||||
@@ -63,7 +63,7 @@ exports[`components/new_channel_modal should match snapshot when user has only j
|
|||||||
id="addChannelsCta"
|
id="addChannelsCta"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<li
|
<div
|
||||||
aria-label="Add channels"
|
aria-label="Add channels"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
@@ -72,6 +72,6 @@ exports[`components/new_channel_modal should match snapshot when user has only j
|
|||||||
<span>
|
<span>
|
||||||
Add Channels
|
Add Channels
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ exports[`components/sidebar/invite_members_button should match snapshot 1`] = `
|
|||||||
teamId="team_id2sss"
|
teamId="team_id2sss"
|
||||||
>
|
>
|
||||||
<Connect(ToggleModalButton)
|
<Connect(ToggleModalButton)
|
||||||
ariaLabel="Invite Users"
|
ariaLabel="Invite Members"
|
||||||
className="intro-links color--link cursor--pointer"
|
className="intro-links color--link cursor--pointer"
|
||||||
dialogType={
|
dialogType={
|
||||||
Object {
|
Object {
|
||||||
@@ -48,7 +48,7 @@ exports[`components/sidebar/invite_members_button should match snapshot 1`] = `
|
|||||||
"type": [Function],
|
"type": [Function],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
id="introTextInvite"
|
id="inviteMembersButton"
|
||||||
modalId="invitation"
|
modalId="invitation"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
@@ -58,7 +58,7 @@ exports[`components/sidebar/invite_members_button should match snapshot 1`] = `
|
|||||||
"openModal": [Function],
|
"openModal": [Function],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ariaLabel="Invite Users"
|
ariaLabel="Invite Members"
|
||||||
className="intro-links color--link cursor--pointer"
|
className="intro-links color--link cursor--pointer"
|
||||||
dialogType={
|
dialogType={
|
||||||
Object {
|
Object {
|
||||||
@@ -68,17 +68,17 @@ exports[`components/sidebar/invite_members_button should match snapshot 1`] = `
|
|||||||
"type": [Function],
|
"type": [Function],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
id="introTextInvite"
|
id="inviteMembersButton"
|
||||||
modalId="invitation"
|
modalId="invitation"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-label="Invite Users dialog"
|
aria-label="Invite Members dialog"
|
||||||
className="style--none intro-links color--link cursor--pointer"
|
className="style--none intro-links color--link cursor--pointer"
|
||||||
id="introTextInvite"
|
id="inviteMembersButton"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
>
|
>
|
||||||
<li
|
<div
|
||||||
aria-label="Invite Members"
|
aria-label="Invite Members"
|
||||||
className="SidebarChannelNavigator__inviteMembersLhsButton"
|
className="SidebarChannelNavigator__inviteMembersLhsButton"
|
||||||
>
|
>
|
||||||
@@ -93,7 +93,7 @@ exports[`components/sidebar/invite_members_button should match snapshot 1`] = `
|
|||||||
Invite Members
|
Invite Members
|
||||||
</span>
|
</span>
|
||||||
</FormattedMessage>
|
</FormattedMessage>
|
||||||
</li>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</ToggleModalButton>
|
</ToggleModalButton>
|
||||||
</Connect(ToggleModalButton)>
|
</Connect(ToggleModalButton)>
|
||||||
|
|||||||
@@ -117,14 +117,14 @@ const AddChannelsCtaButton = (): JSX.Element | null => {
|
|||||||
aria-label={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.dropdownAriaLabel', defaultMessage: 'Add Channel Dropdown'})}
|
aria-label={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.dropdownAriaLabel', defaultMessage: 'Add Channel Dropdown'})}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
<li
|
<div
|
||||||
aria-label={intl.formatMessage({id: 'sidebar_left.sidebar_channel_navigator.addChannelsCta', defaultMessage: 'Add channels'})}
|
aria-label={intl.formatMessage({id: 'sidebar_left.sidebar_channel_navigator.addChannelsCta', defaultMessage: 'Add channels'})}
|
||||||
>
|
>
|
||||||
<i className='icon-plus-box'/>
|
<i className='icon-plus-box'/>
|
||||||
<span>
|
<span>
|
||||||
{intl.formatMessage({id: 'sidebar_left.addChannelsCta', defaultMessage: 'Add Channels'})}
|
{intl.formatMessage({id: 'sidebar_left.addChannelsCta', defaultMessage: 'Add Channels'})}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,14 +43,14 @@ const InviteMembersButton = (props: Props): JSX.Element | null => {
|
|||||||
permissions={[Permissions.ADD_USER_TO_TEAM, Permissions.INVITE_GUEST]}
|
permissions={[Permissions.ADD_USER_TO_TEAM, Permissions.INVITE_GUEST]}
|
||||||
>
|
>
|
||||||
<ToggleModalButton
|
<ToggleModalButton
|
||||||
ariaLabel={intl.formatMessage({id: 'sidebar_left.inviteUsers', defaultMessage: 'Invite Users'})}
|
ariaLabel={intl.formatMessage({id: 'sidebar_left.inviteMembers', defaultMessage: 'Invite Members'})}
|
||||||
id='introTextInvite'
|
id='inviteMembersButton'
|
||||||
className={`intro-links color--link cursor--pointer${props.className ? ` ${props.className}` : ''}`}
|
className={`intro-links color--link cursor--pointer${props.className ? ` ${props.className}` : ''}`}
|
||||||
modalId={ModalIdentifiers.INVITATION}
|
modalId={ModalIdentifiers.INVITATION}
|
||||||
dialogType={InvitationModal}
|
dialogType={InvitationModal}
|
||||||
onClick={handleButtonClick}
|
onClick={handleButtonClick}
|
||||||
>
|
>
|
||||||
<li
|
<div
|
||||||
className='SidebarChannelNavigator__inviteMembersLhsButton'
|
className='SidebarChannelNavigator__inviteMembersLhsButton'
|
||||||
aria-label={intl.formatMessage({id: 'sidebar_left.sidebar_channel_navigator.inviteUsers', defaultMessage: 'Invite Members'})}
|
aria-label={intl.formatMessage({id: 'sidebar_left.sidebar_channel_navigator.inviteUsers', defaultMessage: 'Invite Members'})}
|
||||||
>
|
>
|
||||||
@@ -59,7 +59,7 @@ const InviteMembersButton = (props: Props): JSX.Element | null => {
|
|||||||
id={'sidebar_left.inviteMembers'}
|
id={'sidebar_left.inviteMembers'}
|
||||||
defaultMessage='Invite Members'
|
defaultMessage='Invite Members'
|
||||||
/>
|
/>
|
||||||
</li>
|
</div>
|
||||||
</ToggleModalButton>
|
</ToggleModalButton>
|
||||||
</TeamPermissionGate>
|
</TeamPermissionGate>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -40,6 +40,14 @@ type Props = StaticProps & {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const SidebarCategoryHeader = React.forwardRef((props: Props, ref?: React.Ref<HTMLButtonElement>) => {
|
export const SidebarCategoryHeader = React.forwardRef((props: Props, ref?: React.Ref<HTMLButtonElement>) => {
|
||||||
|
const {dragHandleProps} = props;
|
||||||
|
|
||||||
|
// (Accessibility) Ensures interactive controls are not nested as they are not always announced
|
||||||
|
// by screen readers or can cause focus problems for assistive technologies.
|
||||||
|
if (dragHandleProps && dragHandleProps.role) {
|
||||||
|
Reflect.deleteProperty(dragHandleProps, 'role');
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames('SidebarChannelGroupHeader', {
|
className={classNames('SidebarChannelGroupHeader', {
|
||||||
@@ -61,7 +69,7 @@ export const SidebarCategoryHeader = React.forwardRef((props: Props, ref?: React
|
|||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className='SidebarChannelGroupHeader_text'
|
className='SidebarChannelGroupHeader_text'
|
||||||
{...props.dragHandleProps}
|
{...dragHandleProps}
|
||||||
>
|
>
|
||||||
{wrapEmojis(props.displayName)}
|
{wrapEmojis(props.displayName)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4788,7 +4788,6 @@
|
|||||||
"sidebar_left.channel_navigator.goForwardLabel": "Forward",
|
"sidebar_left.channel_navigator.goForwardLabel": "Forward",
|
||||||
"sidebar_left.channel_navigator.jumpTo": "Find channel",
|
"sidebar_left.channel_navigator.jumpTo": "Find channel",
|
||||||
"sidebar_left.inviteMembers": "Invite Members",
|
"sidebar_left.inviteMembers": "Invite Members",
|
||||||
"sidebar_left.inviteUsers": "Invite Users",
|
|
||||||
"sidebar_left.sidebar_category_menu.createCategory": "Create New Category",
|
"sidebar_left.sidebar_category_menu.createCategory": "Create New Category",
|
||||||
"sidebar_left.sidebar_category_menu.deleteCategory": "Delete Category",
|
"sidebar_left.sidebar_category_menu.deleteCategory": "Delete Category",
|
||||||
"sidebar_left.sidebar_category_menu.dropdownAriaLabel": "Edit category menu",
|
"sidebar_left.sidebar_category_menu.dropdownAriaLabel": "Edit category menu",
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ exports[`plugins/PostMessageView should match snapshot with no extended post typ
|
|||||||
text="this is some text"
|
text="this is some text"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-readonly="true"
|
|
||||||
className="post-message__text"
|
className="post-message__text"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
id="postMessageText_post_id"
|
id="postMessageText_post_id"
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ $sidebarOpacityAnimationDuration: 0.15s;
|
|||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
background: none;
|
background: none;
|
||||||
|
|
||||||
li {
|
div {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
@@ -753,7 +753,7 @@ $sidebarOpacityAnimationDuration: 0.15s;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#introTextInvite,
|
#inviteMembersButton,
|
||||||
#addChannelsCta {
|
#addChannelsCta {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
14
webapp/package-lock.json
сгенерированный
14
webapp/package-lock.json
сгенерированный
@@ -78,7 +78,7 @@
|
|||||||
"crypto-browserify": "3.12.0",
|
"crypto-browserify": "3.12.0",
|
||||||
"css-vars-ponyfill": "2.4.8",
|
"css-vars-ponyfill": "2.4.8",
|
||||||
"date-fns": "2.29.3",
|
"date-fns": "2.29.3",
|
||||||
"dynamic-virtualized-list": "github:mattermost/dynamic-virtualized-list#1c330717d6778315a40e70137ace38247c6a1d0f",
|
"dynamic-virtualized-list": "github:mattermost/dynamic-virtualized-list#3fe918b41de4cb08dbf43f1207bb58827b38e833",
|
||||||
"emoji-regex": "10.2.1",
|
"emoji-regex": "10.2.1",
|
||||||
"exif2css": "1.3.0",
|
"exif2css": "1.3.0",
|
||||||
"fast-deep-equal": "3.1.3",
|
"fast-deep-equal": "3.1.3",
|
||||||
@@ -9623,8 +9623,8 @@
|
|||||||
},
|
},
|
||||||
"node_modules/dynamic-virtualized-list": {
|
"node_modules/dynamic-virtualized-list": {
|
||||||
"version": "1.0.0-beta",
|
"version": "1.0.0-beta",
|
||||||
"resolved": "git+ssh://git@github.com/mattermost/dynamic-virtualized-list.git#1c330717d6778315a40e70137ace38247c6a1d0f",
|
"resolved": "git+ssh://git@github.com/mattermost/dynamic-virtualized-list.git#3fe918b41de4cb08dbf43f1207bb58827b38e833",
|
||||||
"integrity": "sha512-L07ABAHYAd/47wdSEQTvaGWf+Ar+VzFjQH/n9+RvRy9Au+ncsE9QMmx/ObaDLvNeRgvrJon/mCe1toLarxpUXg==",
|
"integrity": "sha512-xvrcAQ+zZoxChBDKZnOB9a6qK7T36FMDJXL5YhdpcjWLrmW2AlEepRFSPDWi6MXObLjtJ0iK2gh6ldF6vlr/DQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.0.0",
|
"@babel/runtime": "^7.0.0",
|
||||||
@@ -30654,9 +30654,9 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"dynamic-virtualized-list": {
|
"dynamic-virtualized-list": {
|
||||||
"version": "git+ssh://git@github.com/mattermost/dynamic-virtualized-list.git#1c330717d6778315a40e70137ace38247c6a1d0f",
|
"version": "git+ssh://git@github.com/mattermost/dynamic-virtualized-list.git#3fe918b41de4cb08dbf43f1207bb58827b38e833",
|
||||||
"integrity": "sha512-L07ABAHYAd/47wdSEQTvaGWf+Ar+VzFjQH/n9+RvRy9Au+ncsE9QMmx/ObaDLvNeRgvrJon/mCe1toLarxpUXg==",
|
"integrity": "sha512-xvrcAQ+zZoxChBDKZnOB9a6qK7T36FMDJXL5YhdpcjWLrmW2AlEepRFSPDWi6MXObLjtJ0iK2gh6ldF6vlr/DQ==",
|
||||||
"from": "dynamic-virtualized-list@github:mattermost/dynamic-virtualized-list#1c330717d6778315a40e70137ace38247c6a1d0f",
|
"from": "dynamic-virtualized-list@github:mattermost/dynamic-virtualized-list#3fe918b41de4cb08dbf43f1207bb58827b38e833",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.0.0",
|
"@babel/runtime": "^7.0.0",
|
||||||
"memoize-one": "^3.1.1"
|
"memoize-one": "^3.1.1"
|
||||||
@@ -35367,7 +35367,7 @@
|
|||||||
"crypto-browserify": "3.12.0",
|
"crypto-browserify": "3.12.0",
|
||||||
"css-vars-ponyfill": "2.4.8",
|
"css-vars-ponyfill": "2.4.8",
|
||||||
"date-fns": "2.29.3",
|
"date-fns": "2.29.3",
|
||||||
"dynamic-virtualized-list": "github:mattermost/dynamic-virtualized-list#1c330717d6778315a40e70137ace38247c6a1d0f",
|
"dynamic-virtualized-list": "github:mattermost/dynamic-virtualized-list#3fe918b41de4cb08dbf43f1207bb58827b38e833",
|
||||||
"emoji-datasource": "6.1.1",
|
"emoji-datasource": "6.1.1",
|
||||||
"emoji-datasource-apple": "6.1.1",
|
"emoji-datasource-apple": "6.1.1",
|
||||||
"emoji-datasource-google": "6.1.1",
|
"emoji-datasource-google": "6.1.1",
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user