MM-63411 Don't focus thread textbox automatically when it has a draft (#31250)
* MM-63411 Don't focus thread textbox automatically when it has a draft * Add E2E test * Add test files forgotten in previous commit --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
a19eb5b9ef
Коммит
6517fa2fd1
12
e2e-tests/cypress/tests/support/chai.d.ts
поставляемый
Обычный файл
12
e2e-tests/cypress/tests/support/chai.d.ts
поставляемый
Обычный файл
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/// <reference types="cypress" />
|
||||
|
||||
declare namespace Cypress {
|
||||
interface Chainer<Subject> {
|
||||
(chainer: 'be.focusVisible', {exactStyles}: {exactStyles?: boolean}): Chainable<Subject>;
|
||||
|
||||
(chainer: 'not.be.focusVisible', {exactStyles}: {exactStyles?: boolean}): Chainable<Subject>;
|
||||
}
|
||||
}
|
||||
36
e2e-tests/cypress/tests/support/chai.ts
Обычный файл
36
e2e-tests/cypress/tests/support/chai.ts
Обычный файл
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
chai.use((chai: Chai.ChaiStatic) => {
|
||||
function assertIsFoo({exactStyles = true} = {}) {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
const obj = this._obj as JQuery<HTMLElement>;
|
||||
|
||||
this.assert(
|
||||
obj.hasClass('a11y--active'),
|
||||
'expected #{this} to have a11y--active class',
|
||||
'expected #{this} to not have a11y--active class',
|
||||
obj,
|
||||
);
|
||||
|
||||
// These should match the styles set on :focus-visible in sass/utils/_modifiers.scss
|
||||
this.assert(
|
||||
exactStyles ? obj.css('box-shadow').includes('0px 0px 1px 3px') : Boolean(obj.css('box-shadow')),
|
||||
'expected #{this} to have focused element style (box-shadow)',
|
||||
'expected #{this} to not have focused element style (box-shadow)',
|
||||
obj.css('box-shadow'),
|
||||
);
|
||||
|
||||
this.assert(
|
||||
exactStyles ? obj.css('border-radius') === '4px' : Boolean(obj.css('border-radius')),
|
||||
'expected #{this} to have focused element style (border-radius)',
|
||||
'expected #{this} to not have focused element style (border-radius)',
|
||||
obj.css('border-radius'),
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
/* eslint-enable no-underscore-dangle */
|
||||
|
||||
chai.Assertion.addMethod('a11yVisible', assertIsFoo);
|
||||
});
|
||||
@@ -34,10 +34,11 @@ export class TestBrowser {
|
||||
const systemConsolePage = new pages.SystemConsolePage(page);
|
||||
const scheduledPostsPage = new pages.ScheduledPostsPage(page);
|
||||
const draftsPage = new pages.DraftsPage(page);
|
||||
const threadsPage = new pages.ThreadsPage(page);
|
||||
|
||||
this.context = context;
|
||||
|
||||
return {context, page, channelsPage, systemConsolePage, scheduledPostsPage, draftsPage};
|
||||
return {context, page, channelsPage, systemConsolePage, scheduledPostsPage, draftsPage, threadsPage};
|
||||
}
|
||||
|
||||
async close() {
|
||||
|
||||
@@ -9,6 +9,7 @@ import SignupPage from './signup';
|
||||
import SystemConsolePage from './system_console';
|
||||
import ScheduledPostsPage from './scheduled_posts';
|
||||
import DraftsPage from './drafts';
|
||||
import ThreadsPage from './threads';
|
||||
|
||||
const pages = {
|
||||
ChannelsPage,
|
||||
@@ -19,6 +20,7 @@ const pages = {
|
||||
ScheduledPostsPage,
|
||||
SystemConsolePage,
|
||||
DraftsPage,
|
||||
ThreadsPage,
|
||||
};
|
||||
|
||||
export {
|
||||
|
||||
46
e2e-tests/playwright/lib/src/ui/pages/threads.ts
Обычный файл
46
e2e-tests/playwright/lib/src/ui/pages/threads.ts
Обычный файл
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Page, expect} from '@playwright/test';
|
||||
|
||||
import {ChannelsPost} from '@/ui/components';
|
||||
|
||||
export default class ThreadsPage {
|
||||
readonly page: Page;
|
||||
|
||||
readonly threadsList;
|
||||
|
||||
readonly noThreadSelected;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
|
||||
this.threadsList = page.locator('#threads-list');
|
||||
|
||||
this.noThreadSelected = page.locator('.no-results__title', {
|
||||
hasText: /Looks like you’re all caught up|Catch up on your threads/,
|
||||
});
|
||||
}
|
||||
|
||||
async goto(teamName: string) {
|
||||
await this.page.goto(`/${teamName}/threads`);
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.threadsList).toBeVisible();
|
||||
}
|
||||
|
||||
async toHaveThreadSelected() {
|
||||
await expect(this.noThreadSelected).not.toBeAttached();
|
||||
}
|
||||
|
||||
async toNotHaveThreadSelected() {
|
||||
await expect(this.noThreadSelected).toBeVisible();
|
||||
}
|
||||
|
||||
async getLastPost() {
|
||||
const lastPost = this.page.getByTestId('rhsPostView').last();
|
||||
await lastPost.waitFor();
|
||||
return new ChannelsPost(lastPost);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {test} from '@mattermost/playwright-lib';
|
||||
|
||||
test('Should be able to change threads with arrow keys', async ({pw}, testInfo) => {
|
||||
test.skip(testInfo.project.name === 'ipad');
|
||||
|
||||
const {team, user} = await pw.initSetup();
|
||||
|
||||
const {channelsPage, page, threadsPage} = await pw.testBrowser.login(user);
|
||||
|
||||
await channelsPage.goto();
|
||||
await channelsPage.toBeVisible();
|
||||
|
||||
// # Start some threads, and leave a draft in one of them
|
||||
await channelsPage.centerView.postCreate.postMessage('aaa');
|
||||
await (await channelsPage.getLastPost()).openAThread();
|
||||
await channelsPage.sidebarRight.postMessage('aaa reply');
|
||||
|
||||
await channelsPage.centerView.postCreate.postMessage('bbb');
|
||||
await (await channelsPage.getLastPost()).openAThread();
|
||||
await channelsPage.sidebarRight.postMessage('bbb reply');
|
||||
await channelsPage.sidebarRight.postCreate.writeMessage('bbb second reply');
|
||||
|
||||
await channelsPage.centerView.postCreate.postMessage('ccc');
|
||||
await (await channelsPage.getLastPost()).openAThread();
|
||||
await channelsPage.sidebarRight.postMessage('ccc reply');
|
||||
|
||||
// * Ensure that there's a draft
|
||||
await channelsPage.sidebarLeft.draftsVisible();
|
||||
|
||||
// # Switch to the threads list
|
||||
await threadsPage.goto(team.name);
|
||||
await threadsPage.toBeVisible();
|
||||
|
||||
// * Ensure no thread starts selected
|
||||
await threadsPage.toNotHaveThreadSelected();
|
||||
|
||||
// # Press the down arrow to select a thread
|
||||
await page.keyboard.press('ArrowDown');
|
||||
|
||||
// * Ensure the latest thread was selected
|
||||
await threadsPage.toHaveThreadSelected();
|
||||
(await threadsPage.getLastPost()).toContainText('ccc reply');
|
||||
|
||||
// # Press the down arrow again
|
||||
await page.keyboard.press('ArrowDown');
|
||||
|
||||
// * Ensure the latest thread was selected
|
||||
await threadsPage.toHaveThreadSelected();
|
||||
(await threadsPage.getLastPost()).toContainText('bbb reply');
|
||||
|
||||
await threadsPage.threadsList.focus();
|
||||
|
||||
// # Press the down arrow again
|
||||
await page.keyboard.press('ArrowDown');
|
||||
|
||||
// * Ensure the latest thread was selected
|
||||
await threadsPage.toHaveThreadSelected();
|
||||
(await threadsPage.getLastPost()).toContainText('aaa reply');
|
||||
|
||||
// # Press the up arrow
|
||||
await page.keyboard.press('ArrowUp');
|
||||
|
||||
// * Ensure the latest thread was selected
|
||||
await threadsPage.toHaveThreadSelected();
|
||||
(await threadsPage.getLastPost()).toContainText('bbb reply');
|
||||
|
||||
// # Press the up arrow
|
||||
await page.keyboard.press('ArrowUp');
|
||||
|
||||
// * Ensure the latest thread was selected
|
||||
await threadsPage.toHaveThreadSelected();
|
||||
(await threadsPage.getLastPost()).toContainText('ccc reply');
|
||||
});
|
||||
@@ -523,7 +523,7 @@ const AdvancedTextEditor = ({
|
||||
// Update the caret position in the input box when changed by a side effect
|
||||
useEffect(() => {
|
||||
const textbox: HTMLInputElement | HTMLTextAreaElement | undefined = textboxRef.current?.getInputBox();
|
||||
if (textbox && textbox.selectionStart !== caretPosition) {
|
||||
if (textbox && textbox === document.activeElement && textbox.selectionStart !== caretPosition) {
|
||||
Utils.setCaretPosition(textbox, caretPosition);
|
||||
}
|
||||
}, [caretPosition]);
|
||||
|
||||
Ссылка в новой задаче
Block a user