Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Legends:
- Fixed screen readers not saying "Click to interact." for messages with links, in PR [#5927](https://github.com/microsoft/BotFramework-WebChat/pull/5927), by [@OEvgeny](https://github.com/OEvgeny)
- Fixed carousel cards focused with <kbd>TAB</kbd> staying partially out of view, in PR [#5926](https://github.com/microsoft/BotFramework-WebChat/pull/5926), by [@OEvgeny](https://github.com/OEvgeny)
- Fixed <kbd>LEFT</kbd>/<kbd>RIGHT</kbd> on a button inside a carousel card scrolling the carousel, in PR [#5917](https://github.com/microsoft/BotFramework-WebChat/pull/5917), by [@OEvgeny](https://github.com/OEvgeny)
- Fixed icons being invisible, link references not using the link color, and Fluent messages and Copy button having no border in forced colors, fixes [#4906](https://github.com/microsoft/BotFramework-WebChat/issues/4906) and [#4907](https://github.com/microsoft/BotFramework-WebChat/issues/4907), in PR [#5907](https://github.com/microsoft/BotFramework-WebChat/pull/5907), by [@OEvgeny](https://github.com/OEvgeny)

## [4.19.2] - 2026-10-08

Expand Down
109 changes: 109 additions & 0 deletions __tests__/html2/fluentTheme/citation.hover.forcedColors.dark.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<style>
.fui-FluentProvider {
height: 100%;
}
</style>
</head>
<body>
<main id="webchat"></main>
<script type="importmap">
{
"imports": {
"@fluentui/react-provider": "/__dist__/packages/test/test-assets/out/@fluentui/react-provider.js",
"@fluentui/tokens": "/__dist__/packages/test/test-assets/out/@fluentui/tokens.js",
"@testduet/wait-for": "https://esm.sh/@testduet/wait-for",
"botframework-webchat": "/__dist__/packages/bundle/static/botframework-webchat.js",
"botframework-webchat/": "/__dist__/packages/bundle/static/botframework-webchat/",
"botframework-webchat-fluent-theme": "/__dist__/packages/fluent-theme/static/botframework-webchat-fluent-theme.js",
"react": "/__dist__/packages/bundle/static/react.js",
"react-dom": "/__dist__/packages/bundle/static/react-dom.js",
"react-dom/client": "/__dist__/packages/bundle/static/react-dom/client.js",
"react-jsx-runtime": "/__dist__/packages/bundle/static/react/jsx-runtime.js"
}
}
</script>
<script type="module">
import '/test-harness.mjs';
import '/test-page-object.mjs';

import { FluentProvider } from '@fluentui/react-provider';
import { webDarkTheme } from '@fluentui/tokens';
import { waitFor } from '@testduet/wait-for';
import { createStoreWithOptions, ReactWebChat } from 'botframework-webchat';
import { FluentThemeProvider } from 'botframework-webchat-fluent-theme';
import { createElement } from 'react';
import { createRoot } from 'react-dom/client';

// TODO: This is for `createDirectLineEmulator` only, should find ways to eliminate this line.
window.WebChat = { createStoreWithOptions };

run(async function () {
// GIVEN: A dark high contrast theme (such as "Aquatic" on Windows) is active before Web Chat renders.
await host.sendDevToolsCommand('Emulation.setEmulatedMedia', {
features: [
{ name: 'forced-colors', value: 'active' },
{ name: 'prefers-color-scheme', value: 'dark' },
{ name: 'prefers-reduced-motion', value: 'reduce' } // Skips the color transition on hover.
]
});

expect(window.matchMedia('(forced-colors: active) and (prefers-color-scheme: dark)').matches).toBe(true);

const { directLine, store } = testHelpers.createDirectLineEmulator();

createRoot(document.getElementById('webchat')).render(
createElement(
FluentProvider,
{ theme: webDarkTheme },
createElement(
FluentThemeProvider,
{ variant: 'fluent' },
createElement(ReactWebChat, { directLine, store })
)
)
);

await pageConditions.uiConnected();

// GIVEN: A message with a citation.
await directLine.emulateIncomingActivity({
entities: [
{
'@context': 'https://schema.org',
'@id': 'cite:1',
'@type': 'Claim',
name: 'Benefits overview',
text: 'Benefits start on your first day.',
type: 'https://schema.org/Claim'
}
],
from: { role: 'bot' },
// [1] points to the "cite:1" claim above, so it is rendered as a citation button.
text: 'Your benefits start on your first day[1].\n\n[1]: cite:1 "Benefits overview"',
type: 'message'
});

await pageConditions.numActivitiesShown(1);
await pageConditions.scrollToBottomCompleted();

const citation = pageElements.activities()[0].querySelector('.render-markdown__citation');

expect(citation.tagName).toBe('BUTTON');

// WHEN: The pointer hovers over the citation.
await host.hover(citation);

// THEN: The citation should be hovered.
await waitFor(() => expect(citation.matches(':hover')).toBe(true));

// THEN: The hovered citation "1" and its border should stay in the link color, same as the reference chip below.
// THEN: The message should have a border.
await host.snapshot('local');
});
</script>
</body>
</html>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly sure, maybe the "1 reference" should not be in yellow or not.

Let's try browser native <summary> to see if it is yellow or not.

Because what I feel (from other screenshots) is that "yellow is for hyperlink", for example, the send button is an action and is not yellow.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is how it looks like with the details:
image

It doesn't have frame around, but for the frame I imagine we do benefit from a different color

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. That would translate to "yellow" for <summary> is correct color.

The following screenshot is "Aquatic" on Windows, note the color of button is white.

Image

This one is "Night sky", the color of button is yellow.

Image

Editing "Aquatic" and "Night sky" theme, I don't think "Aquatic" is a good theme for accessibility testing (anyway, we are using Linux.)

Image Image

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions __tests__/html2/fluentTheme/icons.forcedColors.dark.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!doctype html>
<html>
<head>
<script>
location = './icons.forcedColors?fluent-theme=dark';
</script>
</head>
<body></body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
143 changes: 143 additions & 0 deletions __tests__/html2/fluentTheme/icons.forcedColors.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<style>
.fui-FluentProvider {
height: 100%;
}
</style>
</head>
<body>
<main id="webchat"></main>
<script type="importmap">
{
"imports": {
"@fluentui/react-provider": "/__dist__/packages/test/test-assets/out/@fluentui/react-provider.js",
"@fluentui/tokens": "/__dist__/packages/test/test-assets/out/@fluentui/tokens.js",
"@testduet/wait-for": "https://esm.sh/@testduet/wait-for",
"botframework-webchat": "/__dist__/packages/bundle/static/botframework-webchat.js",
"botframework-webchat/": "/__dist__/packages/bundle/static/botframework-webchat/",
"botframework-webchat-fluent-theme": "/__dist__/packages/fluent-theme/static/botframework-webchat-fluent-theme.js",
"react": "/__dist__/packages/bundle/static/react.js",
"react-dom": "/__dist__/packages/bundle/static/react-dom.js",
"react-dom/client": "/__dist__/packages/bundle/static/react-dom/client.js",
"react-jsx-runtime": "/__dist__/packages/bundle/static/react/jsx-runtime.js"
}
}
</script>
<script type="module">
import '/test-harness.mjs';
import '/test-page-object.mjs';

import { FluentProvider } from '@fluentui/react-provider';
import { webDarkTheme } from '@fluentui/tokens';
import { waitFor } from '@testduet/wait-for';
import { createStoreWithOptions, ReactWebChat } from 'botframework-webchat';
import { FluentThemeProvider, testIds } from 'botframework-webchat-fluent-theme';
import { createElement } from 'react';
import { createRoot } from 'react-dom/client';

// TODO: This is for `createDirectLineEmulator` only, should find ways to eliminate this line.
window.WebChat = { createStoreWithOptions };

run(async function () {
const colorScheme = new URLSearchParams(location.search).get('fluent-theme') === 'dark' ? 'dark' : 'light';

// GIVEN: A light or dark high contrast theme (such as "Desert" or "Aquatic" on Windows) is active before Web Chat renders.
await host.sendDevToolsCommand('Emulation.setEmulatedMedia', {
features: [
{ name: 'forced-colors', value: 'active' },
{ name: 'prefers-color-scheme', value: colorScheme },
{ name: 'prefers-reduced-motion', value: 'reduce' }
]
});

expect(window.matchMedia(`(forced-colors: active) and (prefers-color-scheme: ${colorScheme})`).matches).toBe(
true
);

const { directLine, store } = testHelpers.createDirectLineEmulator();

const webChatElement = createElement(
FluentThemeProvider,
{ variant: 'fluent' },
createElement(ReactWebChat, { directLine, store, styleOptions: { hideTelephoneKeypadButton: false } })
);

// GIVEN: With a dark color scheme, the page uses the dark Fluent UI theme.
createRoot(document.getElementById('webchat')).render(
colorScheme === 'dark'
? createElement(FluentProvider, { theme: webDarkTheme }, webChatElement)
: webChatElement
);

await pageConditions.uiConnected();

// WHEN: The bot sends a pre-chat message with a starter prompt with an image.
await directLine.emulateIncomingActivity({
entities: [
{
'@context': 'https://schema.org',
'@id': '',
'@type': 'Message',
author: {
'@context': 'https://schema.org',
'@type': 'Person',
description: 'Select one of the suggestions below to get started.',
image: '/assets/bot-avatar.jpg',
name: 'Onboarding Buddy',
type: 'https://schema.org/Person'
},
keywords: ['PreChatMessage'],
type: 'https://schema.org/Message'
}
],
suggestedActions: {
actions: [
{
image: `data:image/svg+xml;utf8,${encodeURIComponent('<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 4.5C2 4.22 2.22 4 2.5 4h11c.28 0 .5.22.5.5s-.22.5-.5.5h-11a.5.5 0 0 1-.5-.5Zm0 5c0-.28.22-.5.5-.5h15c.28 0 .5.22.5.5s-.22.5-.5.5h-15a.5.5 0 0 1-.5-.5Zm.5 4.5a.5.5 0 0 0 0 1h9a.5.5 0 0 0 0-1h-9Z" fill="#707070"/></svg>')}`,
text: 'Track new hire tasks.',
title: 'Checklist',
type: 'messageBack'
}
],
to: []
},
type: 'message'
});

await pageConditions.numActivitiesShown(1);

// THEN: The send box should show the "Telephone keypad", "Upload file", and "Send" buttons.
await expect(
Promise.all(
[testIds.sendBoxTelephoneKeypadToolbarButton, testIds.sendBoxUploadButton, testIds.sendBoxSendButton].map(
testId => testHelpers.getAccessibleName(document.querySelector(`[data-testid="${testId}"]`))
)
)
).resolves.toEqual(['Telephone keypad', 'Upload file', 'Send']);

// THEN: The icons of the starter prompt and of the send box buttons should be visible.
await host.snapshot('local');

// WHEN: A file is dragged into the page.
const dataTransfer = new DataTransfer();

dataTransfer.items.add(new File(['Hello, World!'], 'hello.txt', { type: 'text/plain' }));
document.dispatchEvent(new DragEvent('dragenter', { bubbles: true, dataTransfer }));

// THEN: The drop zone should be shown.
await waitFor(() =>
expect(document.querySelector(`[data-testid="${testIds.sendBoxDropZone}"]`)).toHaveProperty(
'textContent',
'Drop files'
)
);

// THEN: The icon of the drop zone should be visible.
await host.snapshot('local');
});
</script>
</body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 73 additions & 0 deletions __tests__/html2/fluentTheme/telephoneKeypad.forcedColors.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
</head>
<body>
<main id="webchat"></main>
<script type="importmap">
{
"imports": {
"@testduet/wait-for": "https://esm.sh/@testduet/wait-for",
"botframework-webchat": "/__dist__/packages/bundle/static/botframework-webchat.js",
"botframework-webchat/": "/__dist__/packages/bundle/static/botframework-webchat/",
"botframework-webchat-fluent-theme": "/__dist__/packages/fluent-theme/static/botframework-webchat-fluent-theme.js",
"react": "/__dist__/packages/bundle/static/react.js",
"react-dom": "/__dist__/packages/bundle/static/react-dom.js",
"react-dom/client": "/__dist__/packages/bundle/static/react-dom/client.js"
}
}
</script>
<script type="module">
import '/test-harness.mjs';
import '/test-page-object.mjs';

import { waitFor } from '@testduet/wait-for';
import { createStoreWithOptions, ReactWebChat } from 'botframework-webchat';
import { FluentThemeProvider, testIds } from 'botframework-webchat-fluent-theme';
import { createElement } from 'react';
import { createRoot } from 'react-dom/client';

// TODO: This is for `createDirectLineEmulator` only, should find ways to eliminate this line.
window.WebChat = { createStoreWithOptions };

run(async function () {
// GIVEN: A high contrast theme (such as "Desert" on Windows) is active before Web Chat renders.
await host.sendDevToolsCommand('Emulation.setEmulatedMedia', {
features: [
{ name: 'forced-colors', value: 'active' },
{ name: 'prefers-color-scheme', value: 'light' },
{ name: 'prefers-reduced-motion', value: 'reduce' }
]
});

expect(window.matchMedia('(forced-colors: active) and (prefers-color-scheme: light)').matches).toBe(true);

const { directLine, store } = testHelpers.createDirectLineEmulator();

createRoot(document.getElementById('webchat')).render(
createElement(
FluentThemeProvider,
{ variant: 'fluent' },
createElement(ReactWebChat, { directLine, store, styleOptions: { hideTelephoneKeypadButton: false } })
)
);

await pageConditions.uiConnected();

// WHEN: The telephone keypad button is clicked.
await host.click(document.querySelector(`[data-testid="${testIds.sendBoxTelephoneKeypadToolbarButton}"]`));

// THEN: The telephone keypad should be shown with button "1" focused.
await waitFor(() =>
expect(document.activeElement).toBe(
document.querySelector(`[data-testid="${testIds.sendBoxTelephoneKeypadButton1}"]`)
)
);

// THEN: The icon of the "Only supports single-digit input" message should be visible.
await host.snapshot('local');
});
</script>
</body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions __tests__/html2/linkDefinition/forcedColors.dark.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!doctype html>
<html>
<head>
<script>
location = './forcedColors?color-scheme=dark';
</script>
</head>
<body></body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!doctype html>
<html>
<head>
<script>
location = './forcedColors?color-scheme=dark&variant=fluent';
</script>
</head>
<body></body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions __tests__/html2/linkDefinition/forcedColors.fluent.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!doctype html>
<html>
<head>
<script>
location = './forcedColors?variant=fluent';
</script>
</head>
<body></body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading