Skip to content

Commit d2928bf

Browse files
CopilotOEvgeny
andauthored
Merge remote-tracking branch 'origin/main' into OEvgeny/dev-readable-weekend-tests
# Conflicts: # __tests__/html2/richCard/animationCard.gif.fluent.html.snap-4.png # __tests__/html2/richCard/animationCard.gif.html Co-authored-by: OEvgeny <2841858+OEvgeny@users.noreply.github.com>
2 parents f252b3d + a002cbf commit d2928bf

46 files changed

Lines changed: 916 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ Legends:
6666
- 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)
6767
- 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)
6868
- 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)
69+
- 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)
6970

7071
## [4.19.2] - 2026-10-08
7172

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<!doctype html>
2+
<html lang="en-US">
3+
<head>
4+
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
5+
<style>
6+
.fui-FluentProvider {
7+
height: 100%;
8+
}
9+
</style>
10+
</head>
11+
<body>
12+
<main id="webchat"></main>
13+
<script type="importmap">
14+
{
15+
"imports": {
16+
"@fluentui/react-provider": "/__dist__/packages/test/test-assets/out/@fluentui/react-provider.js",
17+
"@fluentui/tokens": "/__dist__/packages/test/test-assets/out/@fluentui/tokens.js",
18+
"@testduet/wait-for": "https://esm.sh/@testduet/wait-for",
19+
"botframework-webchat": "/__dist__/packages/bundle/static/botframework-webchat.js",
20+
"botframework-webchat/": "/__dist__/packages/bundle/static/botframework-webchat/",
21+
"botframework-webchat-fluent-theme": "/__dist__/packages/fluent-theme/static/botframework-webchat-fluent-theme.js",
22+
"react": "/__dist__/packages/bundle/static/react.js",
23+
"react-dom": "/__dist__/packages/bundle/static/react-dom.js",
24+
"react-dom/client": "/__dist__/packages/bundle/static/react-dom/client.js",
25+
"react-jsx-runtime": "/__dist__/packages/bundle/static/react/jsx-runtime.js"
26+
}
27+
}
28+
</script>
29+
<script type="module">
30+
import '/test-harness.mjs';
31+
import '/test-page-object.mjs';
32+
33+
import { FluentProvider } from '@fluentui/react-provider';
34+
import { webDarkTheme } from '@fluentui/tokens';
35+
import { waitFor } from '@testduet/wait-for';
36+
import { createStoreWithOptions, ReactWebChat } from 'botframework-webchat';
37+
import { FluentThemeProvider } from 'botframework-webchat-fluent-theme';
38+
import { createElement } from 'react';
39+
import { createRoot } from 'react-dom/client';
40+
41+
// TODO: This is for `createDirectLineEmulator` only, should find ways to eliminate this line.
42+
window.WebChat = { createStoreWithOptions };
43+
44+
run(async function () {
45+
// GIVEN: A dark high contrast theme (such as "Aquatic" on Windows) is active before Web Chat renders.
46+
await host.sendDevToolsCommand('Emulation.setEmulatedMedia', {
47+
features: [
48+
{ name: 'forced-colors', value: 'active' },
49+
{ name: 'prefers-color-scheme', value: 'dark' },
50+
{ name: 'prefers-reduced-motion', value: 'reduce' } // Skips the color transition on hover.
51+
]
52+
});
53+
54+
expect(window.matchMedia('(forced-colors: active) and (prefers-color-scheme: dark)').matches).toBe(true);
55+
56+
const { directLine, store } = testHelpers.createDirectLineEmulator();
57+
58+
createRoot(document.getElementById('webchat')).render(
59+
createElement(
60+
FluentProvider,
61+
{ theme: webDarkTheme },
62+
createElement(
63+
FluentThemeProvider,
64+
{ variant: 'fluent' },
65+
createElement(ReactWebChat, { directLine, store })
66+
)
67+
)
68+
);
69+
70+
await pageConditions.uiConnected();
71+
72+
// GIVEN: A message with a citation.
73+
await directLine.emulateIncomingActivity({
74+
entities: [
75+
{
76+
'@context': 'https://schema.org',
77+
'@id': 'cite:1',
78+
'@type': 'Claim',
79+
name: 'Benefits overview',
80+
text: 'Benefits start on your first day.',
81+
type: 'https://schema.org/Claim'
82+
}
83+
],
84+
from: { role: 'bot' },
85+
// [1] points to the "cite:1" claim above, so it is rendered as a citation button.
86+
text: 'Your benefits start on your first day[1].\n\n[1]: cite:1 "Benefits overview"',
87+
type: 'message'
88+
});
89+
90+
await pageConditions.numActivitiesShown(1);
91+
await pageConditions.scrollToBottomCompleted();
92+
93+
const citation = pageElements.activities()[0].querySelector('.render-markdown__citation');
94+
95+
expect(citation.tagName).toBe('BUTTON');
96+
97+
// WHEN: The pointer hovers over the citation.
98+
await host.hover(citation);
99+
100+
// THEN: The citation should be hovered.
101+
await waitFor(() => expect(citation.matches(':hover')).toBe(true));
102+
103+
// THEN: The hovered citation "1" and its border should stay in the link color, same as the reference chip below.
104+
// THEN: The message should have a border.
105+
await host.snapshot('local');
106+
});
107+
</script>
108+
</body>
109+
</html>
11.5 KB
Loading
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<script>
5+
location = './icons.forcedColors?fluent-theme=dark';
6+
</script>
7+
</head>
8+
<body></body>
9+
</html>
22.6 KB
Loading
21.3 KB
Loading
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
<!doctype html>
2+
<html lang="en-US">
3+
<head>
4+
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
5+
<style>
6+
.fui-FluentProvider {
7+
height: 100%;
8+
}
9+
</style>
10+
</head>
11+
<body>
12+
<main id="webchat"></main>
13+
<script type="importmap">
14+
{
15+
"imports": {
16+
"@fluentui/react-provider": "/__dist__/packages/test/test-assets/out/@fluentui/react-provider.js",
17+
"@fluentui/tokens": "/__dist__/packages/test/test-assets/out/@fluentui/tokens.js",
18+
"@testduet/wait-for": "https://esm.sh/@testduet/wait-for",
19+
"botframework-webchat": "/__dist__/packages/bundle/static/botframework-webchat.js",
20+
"botframework-webchat/": "/__dist__/packages/bundle/static/botframework-webchat/",
21+
"botframework-webchat-fluent-theme": "/__dist__/packages/fluent-theme/static/botframework-webchat-fluent-theme.js",
22+
"react": "/__dist__/packages/bundle/static/react.js",
23+
"react-dom": "/__dist__/packages/bundle/static/react-dom.js",
24+
"react-dom/client": "/__dist__/packages/bundle/static/react-dom/client.js",
25+
"react-jsx-runtime": "/__dist__/packages/bundle/static/react/jsx-runtime.js"
26+
}
27+
}
28+
</script>
29+
<script type="module">
30+
import '/test-harness.mjs';
31+
import '/test-page-object.mjs';
32+
33+
import { FluentProvider } from '@fluentui/react-provider';
34+
import { webDarkTheme } from '@fluentui/tokens';
35+
import { waitFor } from '@testduet/wait-for';
36+
import { createStoreWithOptions, ReactWebChat } from 'botframework-webchat';
37+
import { FluentThemeProvider, testIds } from 'botframework-webchat-fluent-theme';
38+
import { createElement } from 'react';
39+
import { createRoot } from 'react-dom/client';
40+
41+
// TODO: This is for `createDirectLineEmulator` only, should find ways to eliminate this line.
42+
window.WebChat = { createStoreWithOptions };
43+
44+
run(async function () {
45+
const colorScheme = new URLSearchParams(location.search).get('fluent-theme') === 'dark' ? 'dark' : 'light';
46+
47+
// GIVEN: A light or dark high contrast theme (such as "Desert" or "Aquatic" on Windows) is active before Web Chat renders.
48+
await host.sendDevToolsCommand('Emulation.setEmulatedMedia', {
49+
features: [
50+
{ name: 'forced-colors', value: 'active' },
51+
{ name: 'prefers-color-scheme', value: colorScheme },
52+
{ name: 'prefers-reduced-motion', value: 'reduce' }
53+
]
54+
});
55+
56+
expect(window.matchMedia(`(forced-colors: active) and (prefers-color-scheme: ${colorScheme})`).matches).toBe(
57+
true
58+
);
59+
60+
const { directLine, store } = testHelpers.createDirectLineEmulator();
61+
62+
const webChatElement = createElement(
63+
FluentThemeProvider,
64+
{ variant: 'fluent' },
65+
createElement(ReactWebChat, { directLine, store, styleOptions: { hideTelephoneKeypadButton: false } })
66+
);
67+
68+
// GIVEN: With a dark color scheme, the page uses the dark Fluent UI theme.
69+
createRoot(document.getElementById('webchat')).render(
70+
colorScheme === 'dark'
71+
? createElement(FluentProvider, { theme: webDarkTheme }, webChatElement)
72+
: webChatElement
73+
);
74+
75+
await pageConditions.uiConnected();
76+
77+
// WHEN: The bot sends a pre-chat message with a starter prompt with an image.
78+
await directLine.emulateIncomingActivity({
79+
entities: [
80+
{
81+
'@context': 'https://schema.org',
82+
'@id': '',
83+
'@type': 'Message',
84+
author: {
85+
'@context': 'https://schema.org',
86+
'@type': 'Person',
87+
description: 'Select one of the suggestions below to get started.',
88+
image: '/assets/bot-avatar.jpg',
89+
name: 'Onboarding Buddy',
90+
type: 'https://schema.org/Person'
91+
},
92+
keywords: ['PreChatMessage'],
93+
type: 'https://schema.org/Message'
94+
}
95+
],
96+
suggestedActions: {
97+
actions: [
98+
{
99+
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>')}`,
100+
text: 'Track new hire tasks.',
101+
title: 'Checklist',
102+
type: 'messageBack'
103+
}
104+
],
105+
to: []
106+
},
107+
type: 'message'
108+
});
109+
110+
await pageConditions.numActivitiesShown(1);
111+
112+
// THEN: The send box should show the "Telephone keypad", "Upload file", and "Send" buttons.
113+
await expect(
114+
Promise.all(
115+
[testIds.sendBoxTelephoneKeypadToolbarButton, testIds.sendBoxUploadButton, testIds.sendBoxSendButton].map(
116+
testId => testHelpers.getAccessibleName(document.querySelector(`[data-testid="${testId}"]`))
117+
)
118+
)
119+
).resolves.toEqual(['Telephone keypad', 'Upload file', 'Send']);
120+
121+
// THEN: The icons of the starter prompt and of the send box buttons should be visible.
122+
await host.snapshot('local');
123+
124+
// WHEN: A file is dragged into the page.
125+
const dataTransfer = new DataTransfer();
126+
127+
dataTransfer.items.add(new File(['Hello, World!'], 'hello.txt', { type: 'text/plain' }));
128+
document.dispatchEvent(new DragEvent('dragenter', { bubbles: true, dataTransfer }));
129+
130+
// THEN: The drop zone should be shown.
131+
await waitFor(() =>
132+
expect(document.querySelector(`[data-testid="${testIds.sendBoxDropZone}"]`)).toHaveProperty(
133+
'textContent',
134+
'Drop files'
135+
)
136+
);
137+
138+
// THEN: The icon of the drop zone should be visible.
139+
await host.snapshot('local');
140+
});
141+
</script>
142+
</body>
143+
</html>
22.7 KB
Loading
21.3 KB
Loading
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<!doctype html>
2+
<html lang="en-US">
3+
<head>
4+
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
5+
</head>
6+
<body>
7+
<main id="webchat"></main>
8+
<script type="importmap">
9+
{
10+
"imports": {
11+
"@testduet/wait-for": "https://esm.sh/@testduet/wait-for",
12+
"botframework-webchat": "/__dist__/packages/bundle/static/botframework-webchat.js",
13+
"botframework-webchat/": "/__dist__/packages/bundle/static/botframework-webchat/",
14+
"botframework-webchat-fluent-theme": "/__dist__/packages/fluent-theme/static/botframework-webchat-fluent-theme.js",
15+
"react": "/__dist__/packages/bundle/static/react.js",
16+
"react-dom": "/__dist__/packages/bundle/static/react-dom.js",
17+
"react-dom/client": "/__dist__/packages/bundle/static/react-dom/client.js"
18+
}
19+
}
20+
</script>
21+
<script type="module">
22+
import '/test-harness.mjs';
23+
import '/test-page-object.mjs';
24+
25+
import { waitFor } from '@testduet/wait-for';
26+
import { createStoreWithOptions, ReactWebChat } from 'botframework-webchat';
27+
import { FluentThemeProvider, testIds } from 'botframework-webchat-fluent-theme';
28+
import { createElement } from 'react';
29+
import { createRoot } from 'react-dom/client';
30+
31+
// TODO: This is for `createDirectLineEmulator` only, should find ways to eliminate this line.
32+
window.WebChat = { createStoreWithOptions };
33+
34+
run(async function () {
35+
// GIVEN: A high contrast theme (such as "Desert" on Windows) is active before Web Chat renders.
36+
await host.sendDevToolsCommand('Emulation.setEmulatedMedia', {
37+
features: [
38+
{ name: 'forced-colors', value: 'active' },
39+
{ name: 'prefers-color-scheme', value: 'light' },
40+
{ name: 'prefers-reduced-motion', value: 'reduce' }
41+
]
42+
});
43+
44+
expect(window.matchMedia('(forced-colors: active) and (prefers-color-scheme: light)').matches).toBe(true);
45+
46+
const { directLine, store } = testHelpers.createDirectLineEmulator();
47+
48+
createRoot(document.getElementById('webchat')).render(
49+
createElement(
50+
FluentThemeProvider,
51+
{ variant: 'fluent' },
52+
createElement(ReactWebChat, { directLine, store, styleOptions: { hideTelephoneKeypadButton: false } })
53+
)
54+
);
55+
56+
await pageConditions.uiConnected();
57+
58+
// WHEN: The telephone keypad button is clicked.
59+
await host.click(document.querySelector(`[data-testid="${testIds.sendBoxTelephoneKeypadToolbarButton}"]`));
60+
61+
// THEN: The telephone keypad should be shown with button "1" focused.
62+
await waitFor(() =>
63+
expect(document.activeElement).toBe(
64+
document.querySelector(`[data-testid="${testIds.sendBoxTelephoneKeypadButton1}"]`)
65+
)
66+
);
67+
68+
// THEN: The icon of the "Only supports single-digit input" message should be visible.
69+
await host.snapshot('local');
70+
});
71+
</script>
72+
</body>
73+
</html>

0 commit comments

Comments
 (0)