From ae21466973007d67a7e2381355dfa320670279af Mon Sep 17 00:00:00 2001 From: Ahona Salsabil Date: Thu, 1 Oct 2026 22:13:58 -0700 Subject: [PATCH 1/2] fix: stop message actions from inheriting response label Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 068c5ef2-5e03-4d29-8666-f2b34b1bcc92 --- CHANGELOG.md | 1 + .../html2/accessibility/messageActions.html | 146 ++++++++++++++++++ .../component/src/Activity/StackedLayout.tsx | 9 -- .../src/Activity/StackedLayoutRoot.tsx | 5 +- 4 files changed, 148 insertions(+), 13 deletions(-) create mode 100644 __tests__/html2/accessibility/messageActions.html diff --git a/CHANGELOG.md b/CHANGELOG.md index 3304cea8fe..afffdb9420 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ Legends: ### Fixed +- Fixed screen readers repeating the full bot response when focus enters message actions such as Copy, Like, or Dislike, resolving [#5849](https://github.com/microsoft/BotFramework-WebChat/issues/5849), by [@asalsa](https://github.com/asalsa) - Fixed an error when a failed activity is present when Web Chat mounts, resolving [#5812](https://github.com/microsoft/BotFramework-WebChat/issues/5812), in PR [#5848](https://github.com/microsoft/BotFramework-WebChat/pull/5848), by [@OEvgeny](https://github.com/OEvgeny) ## [4.19.1] - 2026-06-09 diff --git a/__tests__/html2/accessibility/messageActions.html b/__tests__/html2/accessibility/messageActions.html new file mode 100644 index 0000000000..bdb356b3fb --- /dev/null +++ b/__tests__/html2/accessibility/messageActions.html @@ -0,0 +1,146 @@ + + + + + + + + + + + + + +
+ + + diff --git a/packages/component/src/Activity/StackedLayout.tsx b/packages/component/src/Activity/StackedLayout.tsx index e5219be34d..fdb35b8a64 100644 --- a/packages/component/src/Activity/StackedLayout.tsx +++ b/packages/component/src/Activity/StackedLayout.tsx @@ -19,7 +19,6 @@ import ScreenReaderText from '../ScreenReaderText'; import isZeroOrPositive from '../Utils/isZeroOrPositive'; import getFirstBaseOfSoftwareSourceCode from '../Utils/orgSchema/getFirstBaseOfSoftwareSourceCode'; import textFormatToContentType from '../Utils/textFormatToContentType'; -import useUniqueId from '../hooks/internal/useUniqueId'; import { useGetLogicalGroupKey } from '../providers/ActivityLogicalGrouping'; import AttachmentRow from './AttachmentRow'; import Bubble from './Bubble'; @@ -41,7 +40,6 @@ type StackedLayoutInnerProps = Readonly<{ hasAvatar: boolean; hasDisplayText: boolean; hasNub: boolean; - id: string; renderAvatar?: false | (() => Exclude) | undefined; renderBubbleContent: (title?: string | undefined, showStatus?: boolean) => ReactNode; showAvatar?: boolean | undefined; @@ -56,7 +54,6 @@ const StackedLayoutInner = memo( hasAvatar, hasDisplayText, hasNub, - id, renderAvatar, renderBubbleContent, showAvatar, @@ -77,9 +74,6 @@ const StackedLayoutInner = memo(
@@ -122,7 +116,6 @@ const StackedLayout = ({ const [styleOptions] = useStyleOptions(); const [{ initials: botInitials }] = useAvatarForBot(); const [{ initials: userInitials }] = useAvatarForUser(); - const ariaLabelId = useUniqueId('webchat__stacked-layout__id'); const localize = useLocalizer(); const classNames = useStyles(styles); @@ -280,7 +273,6 @@ const StackedLayout = ({ return ( ; const StackedLayoutRoot = memo((props: StackedLayoutRootProps) => { const { - ariaLabelId, children, extraTrailing, fromUser, @@ -46,7 +44,6 @@ const StackedLayoutRoot = memo((props: StackedLayoutRootProps) => { return (
Date: Fri, 2 Oct 2026 00:02:00 -0700 Subject: [PATCH 2/2] test: validate message action accessibility tree Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 068c5ef2-5e03-4d29-8666-f2b34b1bcc92 --- __tests__/html2/accessibility/messageActions.html | 11 +++++------ packages/component/src/Activity/StackedLayout.tsx | 6 +----- packages/test/harness/src/browser/proxies/host.js | 1 + packages/test/harness/src/host/common/host/index.js | 2 ++ .../src/host/common/host/sendAndGetDevToolsCommand.js | 4 ++++ 5 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 packages/test/harness/src/host/common/host/sendAndGetDevToolsCommand.js diff --git a/__tests__/html2/accessibility/messageActions.html b/__tests__/html2/accessibility/messageActions.html index bdb356b3fb..094c8f84ca 100644 --- a/__tests__/html2/accessibility/messageActions.html +++ b/__tests__/html2/accessibility/messageActions.html @@ -68,8 +68,7 @@ type: 'https://schema.org/Message' } ], - text: - 'This is a deliberately long bot response. It contains multiple sentences so duplicate narration is easy to detect. The message action should be announced without repeating this response.', + text: 'This is a deliberately long bot response. It contains multiple sentences so duplicate narration is easy to detect. The message action should be announced without repeating this response.', type: 'message' }); @@ -78,11 +77,11 @@ const getAccessibilityNode = async expression => { const { result: { objectId } - } = await host.sendDevToolsCommand('Runtime.evaluate', { expression }); + } = await host.sendAndGetDevToolsCommand('Runtime.evaluate', { expression }); const { node: { backendNodeId } - } = await host.sendDevToolsCommand('DOM.describeNode', { objectId }); - const { nodes } = await host.sendDevToolsCommand('Accessibility.getPartialAXTree', { + } = await host.sendAndGetDevToolsCommand('DOM.describeNode', { objectId }); + const { nodes } = await host.sendAndGetDevToolsCommand('Accessibility.getPartialAXTree', { backendNodeId, fetchRelatives: false }); @@ -131,6 +130,7 @@ await host.clickAt(1, 1, pageElements.transcriptScrollable()); expect(pageElements.focusedActivity()).toBe(pageElements.activities()[0]); + expect(pageElements.activeActivity().contains(messageGroup)).toBe(true); pageElements.activeActivity().setAttribute('data-a11y-transcript-article', ''); @@ -139,7 +139,6 @@ ); expect(transcriptArticleAccessibilityNode.role.value).toBe('article'); - expect(transcriptArticleAccessibilityNode.name.value).toContain(responseText); }); diff --git a/packages/component/src/Activity/StackedLayout.tsx b/packages/component/src/Activity/StackedLayout.tsx index fdb35b8a64..a2f8f533d4 100644 --- a/packages/component/src/Activity/StackedLayout.tsx +++ b/packages/component/src/Activity/StackedLayout.tsx @@ -71,11 +71,7 @@ const StackedLayoutInner = memo( return ( {!!(hasDisplayText || messageThing?.abstract[0]) && ( -
+
{}, release: () => {}, sendAccessKey: () => {}, + sendAndGetDevToolsCommand: () => {}, sendDevToolsCommand: () => {}, sendKeys: () => {}, sendShiftTab: () => {}, diff --git a/packages/test/harness/src/host/common/host/index.js b/packages/test/harness/src/host/common/host/index.js index 292cf3aba4..c40923dcd6 100644 --- a/packages/test/harness/src/host/common/host/index.js +++ b/packages/test/harness/src/host/common/host/index.js @@ -14,6 +14,7 @@ const pressAndHold = require('./pressAndHold'); const ready = require('./ready'); const release = require('./release'); const sendAccessKey = require('./sendAccessKey'); +const sendAndGetDevToolsCommand = require('./sendAndGetDevToolsCommand'); const sendDevToolsCommand = require('./sendDevToolsCommand'); const sendKeys = require('./sendKeys'); const sendShiftTab = require('./sendShiftTab'); @@ -45,6 +46,7 @@ module.exports = function createHost(webDriver) { readyPromise: readyWithResolvers.promise, release: release(webDriver), sendAccessKey: sendAccessKey(webDriver), + sendAndGetDevToolsCommand: sendAndGetDevToolsCommand(webDriver), sendDevToolsCommand: sendDevToolsCommand(webDriver), sendKeys: sendKeys(webDriver), sendShiftTab: sendShiftTab(webDriver), diff --git a/packages/test/harness/src/host/common/host/sendAndGetDevToolsCommand.js b/packages/test/harness/src/host/common/host/sendAndGetDevToolsCommand.js new file mode 100644 index 0000000000..000396185e --- /dev/null +++ b/packages/test/harness/src/host/common/host/sendAndGetDevToolsCommand.js @@ -0,0 +1,4 @@ +module.exports = webDriver => + function sendAndGetDevToolsCommand(command, options) { + return webDriver.sendAndGetDevToolsCommand(command, options); + };