diff --git a/packages/component/src/Transcript/ActivityRow.spec.tsx b/packages/component/src/Transcript/ActivityRow.spec.tsx new file mode 100644 index 0000000000..7c76ab6a8f --- /dev/null +++ b/packages/component/src/Transcript/ActivityRow.spec.tsx @@ -0,0 +1,65 @@ +/** @jest-environment @happy-dom/jest-environment */ +import React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { act } from 'react-dom/test-utils'; +import ActivityRow from './ActivityRow'; + +// Mock hooks +jest.mock('botframework-webchat-api', () => ({ + hooks: { + useActivityKeysByRead: jest.fn(() => [[], () => { }]), + useGetHasAcknowledgedByActivityKey: jest.fn(() => () => true), + useGetKeyByActivity: jest.fn(() => (activity) => activity.id) + } +}), { virtual: true }); + +jest.mock('../providers/TranscriptFocus/useActiveDescendantId', () => jest.fn(() => [null])); +jest.mock('../providers/TranscriptFocus/useFocusByActivityKey', () => jest.fn(() => () => { })); +jest.mock('../providers/TranscriptFocus/useGetDescendantIdByActivityKey', () => jest.fn(() => () => 'descendant-id')); +jest.mock('./useActivityAccessibleName', () => jest.fn(() => ['Accessible Name'])); +jest.mock('../hooks/internal/styleToEmotionObject', () => ({ + useStyleToEmotionObject: jest.fn(() => () => 'mock-class-name') +})); + +jest.mock('./TranscriptFocus', () => ({ + TranscriptFocusContent: ({ children, ...props }) =>
{children}
, + TranscriptFocusContentActiveDescendant: ({ children, ...props }) =>
{children}
, + TranscriptFocusContentOverlay: ({ children }) =>
{children}
, + TranscriptFocusIndicator: () =>
+})); + +jest.mock('./FocusTrap', () => ({ children }) =>
{children}
); +jest.mock('../Activity/Speak', () => () => null); + +describe('ActivityRow', () => { + let container: HTMLDivElement; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + afterEach(() => { + unmountComponentAtNode(container); + container.remove(); + container = null; + }); + + it('should render an h6 header with accessible name', () => { + const activity = { + id: 'activity-1', + type: 'message', + text: 'Hello World' + }; + + act(() => { + render(, container); + }); + + const header = container.querySelector('h6'); + expect(header).toBeTruthy(); + expect(header.textContent).toBe('Accessible Name'); + expect(header.getAttribute('aria-hidden')).toBeNull(); + expect(header.className).toBe('mock-class-name'); + }); +}); diff --git a/packages/component/src/Transcript/ActivityRow.tsx b/packages/component/src/Transcript/ActivityRow.tsx index 31cb68c755..cfde0eb044 100644 --- a/packages/component/src/Transcript/ActivityRow.tsx +++ b/packages/component/src/Transcript/ActivityRow.tsx @@ -11,6 +11,7 @@ import ScreenReaderText from '../ScreenReaderText'; import { android } from '../Utils/detectBrowser'; import FocusTrap from './FocusTrap'; import useActivityAccessibleName from './useActivityAccessibleName'; +import { useStyleToEmotionObject } from '../hooks/internal/styleToEmotionObject'; import type { WebChatActivity } from 'botframework-webchat-core'; import type { MouseEventHandler, PropsWithChildren } from 'react'; @@ -22,6 +23,16 @@ import { TranscriptFocusIndicator } from './TranscriptFocus'; +const ROOT_STYLE = { + color: 'transparent', + height: 1, + overflow: 'hidden', + position: 'absolute', + top: 0, + whiteSpace: 'nowrap', + width: 1 +}; + const { useActivityKeysByRead, useGetHasAcknowledgedByActivityKey, useGetKeyByActivity } = hooks; type ActivityRowProps = PropsWithChildren<{ activity: WebChatActivity }>; @@ -41,7 +52,9 @@ const ActivityRow = forwardRef(({ activity, child const acknowledged = useGetHasAcknowledgedByActivityKey()(activityKey); const activityKeyRef = useRefFrom(activityKey); const descendantId = useGetDescendantIdByActivityKey()(activityKey); + const descendantLabelId = `webchat__basic-transcript__active-descendant-label--${activityKey}`; + const rootClassName = useStyleToEmotionObject()(ROOT_STYLE) + ''; const isActiveDescendant = descendantId === activeDescendantId; const read = readActivityKeys.includes(activityKey); @@ -152,7 +165,10 @@ const ActivityRow = forwardRef(({ activity, child id={descendantId} role="article" > - + +
+ {accessibleName} +
)}