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
7 changes: 7 additions & 0 deletions .changelog/6050-fix-css-modules-overlays-file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### Changed

- Converted the scroll to end button and the file attachment to CSS Modules with `webchat__` class names and their style options to custom properties, in PR [#6050](https://github.com/microsoft/BotFramework-WebChat/pull/6050), by [@OEvgeny](https://github.com/OEvgeny)

### Removed

- 💥 Deprecated the `fileContent` and `scrollToEndButton` style set entries, which no longer affect rendering, and removed the `webchat__fileContent__downloadIcon--rtl` class, in PR [#6050](https://github.com/microsoft/BotFramework-WebChat/pull/6050), by [@OEvgeny](https://github.com/OEvgeny)
Binary file modified __tests__/html2/attachment/file.noName.fluent.html.snap-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 60 additions & 0 deletions __tests__/html2/rtl/fileContent.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!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": {
"botframework-webchat": "/__dist__/packages/bundle/static/botframework-webchat.js",
"react": "/__dist__/packages/bundle/static/react.js",
"react-dom": "/__dist__/packages/bundle/static/react-dom.js"
}
}
</script>
<script type="module">
import '/test-harness.mjs';
import '/test-page-object.mjs';

import { createStoreWithOptions, renderWebChat } from 'botframework-webchat';

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

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

// GIVEN: Web Chat in Hebrew (right-to-left) on a left-to-right page.
renderWebChat(
{ directLine, locale: 'he-IL', store, styleOptions: { hideSendBox: true } },
document.getElementById('webchat')
);

await pageConditions.uiConnected();

// WHEN: The bot sends a downloadable file with a long name and its size.
await directLine.emulateIncomingActivity({
attachments: [
{
contentType: 'application/pdf',
contentUrl: 'https://example.com/report.pdf',
name: 'דוח-רבעוני-מפורט-של-מחלקת-הכספים-לשנת-2026-כולל-נספחים.pdf' // Long, to show the margin next to the icon.
}
],
channelData: { attachmentSizes: [12345] },
from: { role: 'bot' },
type: 'message'
});

await pageConditions.numActivitiesShown(1);

expect(document.querySelector('.webchat__fileContent').matches(':dir(rtl)')).toBe(true);

// THEN: The file name and size are on the right, the download icon on the left, 10 pixels away from the file name.
await host.snapshot('local');
});
</script>
</body>
</html>
Binary file added __tests__/html2/rtl/fileContent.html.snap-1.png
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/scrollToEndButton/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": {
"botframework-webchat": "/__dist__/packages/bundle/static/botframework-webchat.js",
"react": "/__dist__/packages/bundle/static/react.js",
"react-dom": "/__dist__/packages/bundle/static/react-dom.js"
}
}
</script>
<script type="module">
import '/test-harness.mjs';
import '/test-page-object.mjs';

import { createStoreWithOptions, renderWebChat } from 'botframework-webchat';

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

run(async function () {
// GIVEN: A high contrast theme is active before Web Chat renders.
await host.sendDevToolsCommand('Emulation.setEmulatedMedia', {
features: [{ name: 'forced-colors', value: 'active' }]
});

expect(window.matchMedia('(forced-colors: active)').matches).toBe(true);

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

renderWebChat(
{
directLine,
store,
styleOptions: {
hideSendBox: true,
scrollToEndButtonBehavior: 'any' // Shows the button whenever the transcript is not at the end.
}
},
document.getElementById('webchat')
);

await pageConditions.uiConnected();

// GIVEN: Enough messages to scroll the transcript.
for (let index = 1; index <= 20; index++) {
// eslint-disable-next-line no-await-in-loop
await directLine.emulateIncomingActivity({
from: { role: 'bot' },
text: `Message ${index}`,
type: 'message'
});
}

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

// WHEN: The user scrolls to the top.
await pageObjects.scrollToTop();
await pageConditions.scrollToEndButtonShown();
await pageConditions.scrollStabilized(0);

// THEN: The "More messages" button has an outset border in the system button text color.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified __tests__/html2/side-by-side/codeblock.navigation.html.snap-4.png
Binary file modified __tests__/html2/side-by-side/feedback.navigation.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/feedback.navigation.html.snap-5.png
Binary file modified __tests__/html2/side-by-side/feedback.navigation.html.snap-7.png
Binary file modified __tests__/html2/side-by-side/fluent.dark.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/fluent.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/index.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-3.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-4.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-5.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-6.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-7.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-8.png
Binary file modified __tests__/html2/side-by-side/pre-chat.navigation.html.snap-9.png
Binary file modified __tests__/html2/side-by-side/pre-liner.dark.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/pre-liner.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/streaming.dark.html.snap-1.png
Binary file modified __tests__/html2/side-by-side/streaming.html.snap-1.png
81 changes: 81 additions & 0 deletions __tests__/html2/styleOptions/fileContent.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<!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",
"react": "/__dist__/packages/bundle/static/react.js",
"react-dom": "/__dist__/packages/bundle/static/react-dom.js"
}
}
</script>
<script type="module">
import '/test-harness.mjs';
import '/test-page-object.mjs';

import { waitFor } from '@testduet/wait-for';
import { createStoreWithOptions, renderWebChat } from 'botframework-webchat';

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

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

// GIVEN: Every style option of the file attachment set to a value other than its default.
renderWebChat(
{
directLine,
store,
styleOptions: {
accent: 'Green',
bubbleTextColor: 'Purple',
hideSendBox: true,
paddingRegular: 20, // Numbers are in pixels.
primaryFont: 'serif'
}
},
document.getElementById('webchat')
);

await pageConditions.uiConnected();

// WHEN: The bot sends a downloadable file with a long name and its size, and a file without a URL.
await directLine.emulateIncomingActivity({
attachments: [
{
contentType: 'application/pdf',
contentUrl: 'https://example.com/report.pdf',
name: 'quarterly-report-with-every-appendix-and-the-detailed-tables.pdf' // Long, to show the margin next to the icon.
},
{ contentType: 'application/octet-stream', name: 'notes.bin' } // No URL: not downloadable.
],
channelData: { attachmentSizes: [12345, 678] },
from: { role: 'bot' },
type: 'message'
});

await pageConditions.numActivitiesShown(1);

// THEN: Green file names and download icon, purple sizes, a serif font, 20 pixels of padding and of margin before the icon.
await host.snapshot('local');

// WHEN: The download link is focused.
document.querySelector('.webchat__fileContent__buttonLink').focus();

await waitFor(() =>
expect(document.activeElement).toBe(document.querySelector('.webchat__fileContent__buttonLink'))
);

// THEN: The download link has a light gray background.
await host.snapshot('local');
});
</script>
</body>
</html>
102 changes: 102 additions & 0 deletions __tests__/html2/styleOptions/transcriptOverlayButton.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!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",
"react": "/__dist__/packages/bundle/static/react.js",
"react-dom": "/__dist__/packages/bundle/static/react-dom.js"
}
}
</script>
<script type="module">
import '/test-harness.mjs';
import '/test-page-object.mjs';

import { waitFor } from '@testduet/wait-for';
import { createStoreWithOptions, renderWebChat } from 'botframework-webchat';

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

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

// GIVEN: Every style option of the scroll to end button set to a value other than its default.
renderWebChat(
{
directLine,
store,
styleOptions: {
hideSendBox: true,
scrollToEndButtonBehavior: 'any', // Shows the button whenever the transcript is not at the end.
scrollToEndButtonFontSize: '1.25em', // Strings are used as is.
transcriptOverlayButtonBackground: 'Navy',
transcriptOverlayButtonBackgroundOnFocus: 'Purple',
transcriptOverlayButtonBackgroundOnHover: 'Green',
transcriptOverlayButtonColor: 'Yellow',
transcriptOverlayButtonColorOnFocus: 'Aqua',
transcriptOverlayButtonColorOnHover: 'White'
}
},
document.getElementById('webchat')
);

await pageConditions.uiConnected();

// GIVEN: Enough messages to scroll the transcript.
for (let index = 1; index <= 20; index++) {
// eslint-disable-next-line no-await-in-loop
await directLine.emulateIncomingActivity({
from: { role: 'bot' },
text: `Message ${index}`,
type: 'message'
});
}

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

// WHEN: The user scrolls to the top.
await pageObjects.scrollToTop();
await pageConditions.scrollToEndButtonShown();
await pageConditions.scrollStabilized(0);

// THEN: A navy "More messages" button with yellow text, in a larger font.
await host.snapshot('local');

// WHEN: The button is focused.
pageElements.scrollToEndButton().focus();

await waitFor(() => expect(document.activeElement).toBe(pageElements.scrollToEndButton()));

// THEN: The button is purple with aqua text.
await host.snapshot('local');

// WHEN: The focused button is hovered.
await host.hover(pageElements.scrollToEndButton());

await waitFor(() => expect(pageElements.scrollToEndButton().matches(':focus:hover')).toBe(true));

// THEN: No change, still purple with aqua text: focus wins over hover.
await host.snapshot('local');

// WHEN: The hovered button loses focus.
pageElements.scrollToEndButton().blur();

await waitFor(() => expect(pageElements.scrollToEndButton().matches(':focus')).toBe(false));

expect(pageElements.scrollToEndButton().matches(':hover')).toBe(true);

// THEN: The button is green with white text.
await host.snapshot('local');
});
</script>
</body>
</html>
Loading
Loading