From 405bcc320f70daa29a355feb62d8d33ec52b88b3 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Thu, 12 Nov 2026 16:28:20 -0800 Subject: [PATCH 1/5] Add React 19 tests for the Fluent typing indicator image in Strict Mode and after hide and show --- .../fluentTheme.typingIndicator.activity.html | 134 ++++++++++++++++++ ...e.typingIndicator.activity.html.snap-1.png | Bin 0 -> 3098 bytes ...e.typingIndicator.activity.html.snap-2.png | Bin 0 -> 3110 bytes ...luentTheme.typingIndicator.strictMode.html | 96 +++++++++++++ ...typingIndicator.strictMode.html.snap-1.png | Bin 0 -> 3110 bytes 5 files changed, 230 insertions(+) create mode 100644 __tests__/html2/react19/fluentTheme.typingIndicator.activity.html create mode 100644 __tests__/html2/react19/fluentTheme.typingIndicator.activity.html.snap-1.png create mode 100644 __tests__/html2/react19/fluentTheme.typingIndicator.activity.html.snap-2.png create mode 100644 __tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html create mode 100644 __tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html.snap-1.png diff --git a/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html b/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html new file mode 100644 index 0000000000..f866c2f6fb --- /dev/null +++ b/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html @@ -0,0 +1,134 @@ + + + + React 19 <Activity>: the Fluent typing indicator shows its image after hide and show + + + +
+ + + + diff --git a/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html.snap-1.png b/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html.snap-1.png new file mode 100644 index 0000000000000000000000000000000000000000..7211a9c95efdb6bd3838d0b1cc05c6a38fc95144 GIT binary patch literal 3098 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 V4Gq=)s?c%)jvq@&YB`#D?OzZWTe$!L literal 0 HcmV?d00001 diff --git a/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html b/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html new file mode 100644 index 0000000000..dd7bf9073d --- /dev/null +++ b/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html @@ -0,0 +1,96 @@ + + + + React 19 in Strict Mode: the Fluent typing indicator shows its image + + + +
+ + + + diff --git a/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html.snap-1.png b/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html.snap-1.png new file mode 100644 index 0000000000000000000000000000000000000000..ada591ab06d0f582e51f89e223199157a889fc04 GIT binary patch literal 3110 zcmeI!=}(gf0LSqMU3Bqc(FHdxvPBbO+*X;>RxNfjIOZ|BOM#&l=7AK-Q?3^2@oZ*m zv!N6ZzzUWuM4CVbgi1NfBQVMwiop)F6iN^2)6zaq`?S&n+CF1{#NLtoUVUGFUj2Uk zDkXX2x^3$K0N8l^i==M=AnFPLtorfIRmbvlc%bkjxZ9QR1bpH|qJQo~` zU_xcG942&I<7TFGQ#2C__IWjMe*x+tr)-j{G{Fy3swL7+P1fC%n4Q`Bxq#UgYiVw- z)(@W^L3Z@G2D9r!?pYCcTE;dwjJ2SX(AQKzT@=1?P)!!h8{oi`SOz~#hs)d$lP<~y zNmkf*@$7Wowyoci{UbSNX+wojwkrJRg*#o|i=+;Dy6I&i8V{S?B_Rk{LWGA+MopR6?rgHu4jtyl zgZ-+o1X9U`CR;f{6(W0v#s@e8DjMbpTz^mQtAE$n(zd^t;>*VfTV`;PY`7D=H-~~K zD0gE#zoH@Net2r&;h}8&%tvE!$V__01_vIbY0Ctbx(tg#uf?~whDyEX*S3Z)8d{Y> zgdA)J^W>ZWIy%I%YLSCN+nfW=8)iK%ao7Z}Y_@=heVarW`J>$mEi>^0W#=a?^4Dl* zV{_^Ovg|x`>7dSY-ohyi&P8D{al1%E^ReHvUw})oBb50z5h5u`7MJW7FN|mPsXul! zC@hwAVT^@mU?1$46EA4k=R)!6y^Rap#6oVd?i#a$Dq3u&jLFVev`hEZeFOG!|NYIP z!@^2V9mGKfExis3gd2{yA4jw0Zhj3`3wgSVzD&68Kznw(_Vs^VXR28E%ii=#&Y<;Q zZJj}^^{Fa_wqwZLR1^mldVem8wUT`jI@hEzm`uINy<4*x0_-QL z$Yd(u`k3>1Jm2q91Fwy@mw1^VKUF)sTco8_C>y+JSLAsCw-^~%?}s^dGeS=s8!Mw= zn3EQEl+M$=8?Q;i_X9PY1F8vaHj^s*&JiZD0)D2Uy5YL4R@=)g!xgaEmBZJPJ zQp17A7o?12iiGK8tbO4MXc90ipDxTn$V?J>+J_bioHEm5B(%j|n$HthwR&jL+@?JI z=v-DP6FMCws$oY1H#vZ8Wh(+J0xJS50xJS50{@SIjvNI51Tj*dl(zi#*Zg<$R|Bl! V4Gq=)s?c%)jvq@&YB`#D?OzZWTe$!L literal 0 HcmV?d00001 From cea1bd482c45282f2be03c205abf98b1c17a3250 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Thu, 12 Nov 2026 16:28:20 -0800 Subject: [PATCH 2/5] Keep the Fluent sliding dots image URLs for the page lifetime instead of revoking them in an effect cleanup --- .../src/components/assets/AssetComposer.tsx | 58 +++++++++---------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/packages/fluent-theme/src/components/assets/AssetComposer.tsx b/packages/fluent-theme/src/components/assets/AssetComposer.tsx index 6d64a67d5e..18b42530ee 100644 --- a/packages/fluent-theme/src/components/assets/AssetComposer.tsx +++ b/packages/fluent-theme/src/components/assets/AssetComposer.tsx @@ -1,4 +1,4 @@ -import React, { memo, useEffect, useMemo, type ReactNode } from 'react'; +import React, { memo, type ReactNode } from 'react'; import { type AssetName } from './AssetName'; import Context, { type ContextType } from './private/Context'; @@ -15,37 +15,31 @@ const SLIDING_DOTS_REDUCED_MOTION_SVG_STRING = SLIDING_DOTS_SVG_STRING.replaceAl 'repeatCount="0.01" fill="freeze"' ); -const AssetComposer = memo(({ children }: AssetComposerProps) => { - const slidingDotsURL = useMemo( - // Content is hardcoded. - // eslint-disable-next-line no-restricted-properties - () => URL.createObjectURL(new Blob([SLIDING_DOTS_SVG_STRING], { type: 'image/svg+xml' })), - [] - ); - - const slidingDotsReducedMotionURL = useMemo( - // Content is hardcoded. - // eslint-disable-next-line no-restricted-properties - () => URL.createObjectURL(new Blob([SLIDING_DOTS_REDUCED_MOTION_SVG_STRING], { type: 'image/svg+xml' })), - [] - ); - - useEffect(() => () => URL.revokeObjectURL(slidingDotsURL), [slidingDotsURL]); - useEffect(() => () => URL.revokeObjectURL(slidingDotsReducedMotionURL), [slidingDotsReducedMotionURL]); - - const context = useMemo( - () => - Object.freeze({ - urlStateMap: new Map([ - ['sliding dots', Object.freeze([new URL(slidingDotsURL)])], - ['sliding dots reduced-motion', Object.freeze([new URL(slidingDotsReducedMotionURL)])] - ]) - }), - [slidingDotsURL, slidingDotsReducedMotionURL] - ); - - return {children}; -}); +function createSVGURLState(svg: string): readonly [URL] { + // Content is hardcoded. + // eslint-disable-next-line no-restricted-properties + return Object.freeze([new URL(URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' })))]); +} + +// Created on first use and never revoked, shared by every instance: the images are small and constant. +// Revoking in an effect cleanup broke them, as React 19 and run cleanups and effects again without rendering. +let context: ContextType | undefined; + +function getContext(): ContextType { + context || + (context = Object.freeze({ + urlStateMap: new Map([ + ['sliding dots', createSVGURLState(SLIDING_DOTS_SVG_STRING)], + ['sliding dots reduced-motion', createSVGURLState(SLIDING_DOTS_REDUCED_MOTION_SVG_STRING)] + ]) + })); + + return context; +} + +const AssetComposer = memo(({ children }: AssetComposerProps) => ( + {children} +)); AssetComposer.displayName = 'AssetComposer'; From 6ad6d5f656bd0034302fe84defb24f5715ef02b3 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Thu, 12 Nov 2026 16:49:46 -0800 Subject: [PATCH 3/5] Name react-scroll-to-bottom as the styles still lost in the React 19 typing indicator tests --- .../html2/react19/fluentTheme.typingIndicator.activity.html | 2 +- .../html2/react19/fluentTheme.typingIndicator.strictMode.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html b/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html index f866c2f6fb..40eb20b68f 100644 --- a/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html +++ b/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html @@ -126,7 +126,7 @@ await expectTypingIndicatorImageLoaded(); // THEN: The typing indicator shows the sliding dots. - // They are at the top: the transcript loses its emotion styles after hide and show, a separate issue. + // They are at the top: react-scroll-to-bottom loses its styles after hide and show, a separate issue. await host.snapshot('local'); }); diff --git a/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html b/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html index dd7bf9073d..1a11e4a109 100644 --- a/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html +++ b/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html @@ -88,7 +88,7 @@ expect(image.naturalWidth).toBeGreaterThan(0); // THEN: The typing indicator shows the sliding dots. - // They are at the top: in Strict Mode, the transcript loses its emotion styles, a separate issue. + // They are at the top: in Strict Mode, react-scroll-to-bottom loses its styles, a separate issue. await host.snapshot('local'); }); From 6cfd05d740f028a05fce9f1aeae138fff64d570e Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Thu, 12 Nov 2026 17:04:37 -0800 Subject: [PATCH 4/5] Remove the snapshots from the React 19 typing indicator tests until react-scroll-to-bottom keeps its styles --- .../fluentTheme.typingIndicator.activity.html | 19 ++---------------- ...e.typingIndicator.activity.html.snap-1.png | Bin 3098 -> 0 bytes ...e.typingIndicator.activity.html.snap-2.png | Bin 3110 -> 0 bytes ...luentTheme.typingIndicator.strictMode.html | 16 ++------------- ...typingIndicator.strictMode.html.snap-1.png | Bin 3110 -> 0 bytes 5 files changed, 4 insertions(+), 31 deletions(-) delete mode 100644 __tests__/html2/react19/fluentTheme.typingIndicator.activity.html.snap-1.png delete mode 100644 __tests__/html2/react19/fluentTheme.typingIndicator.activity.html.snap-2.png delete mode 100644 __tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html.snap-1.png diff --git a/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html b/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html index 40eb20b68f..c7ff5aba26 100644 --- a/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html +++ b/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html @@ -34,11 +34,6 @@ // TODO: This is for `createDirectLineEmulator` and `pageElements` only, should find ways to eliminate this line. window.WebChat = { createStoreWithOptions, testIds }; - // The reduced-motion image stops on its first frame, for a stable snapshot. - await host.sendDevToolsCommand('Emulation.setEmulatedMedia', { - features: [{ name: 'prefers-reduced-motion', value: 'reduce' }] - }); - const { directLine, store } = testHelpers.createDirectLineEmulator(); let numMounts = 0; let numUnmounts = 0; @@ -65,11 +60,7 @@ Activity, { mode: visible ? 'visible' : 'hidden' }, createElement(MountCounter), - createElement( - FluentThemeProvider, - {}, - createElement(ReactWebChat, { directLine, store, styleOptions: { hideSendBox: true } }) - ) + createElement(FluentThemeProvider, {}, createElement(ReactWebChat, { directLine, store })) ); }; @@ -99,9 +90,6 @@ // THEN: The typing indicator image should load. await expectTypingIndicatorImageLoaded(); - // THEN: The typing indicator shows the sliding dots. - await host.snapshot('local'); - // WHEN: The bot stops typing. await directLine.emulateIncomingActivity({ channelData: { webChat: { styleOptions: { typingAnimationDuration: 0 } } }, @@ -123,11 +111,8 @@ await emulateTyping('a-00002'); // THEN: The new typing indicator image should load. + // No snapshot until react-scroll-to-bottom keeps its styles after hide and show: the transcript layout is lost. await expectTypingIndicatorImageLoaded(); - - // THEN: The typing indicator shows the sliding dots. - // They are at the top: react-scroll-to-bottom loses its styles after hide and show, a separate issue. - await host.snapshot('local'); }); diff --git a/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html.snap-1.png b/__tests__/html2/react19/fluentTheme.typingIndicator.activity.html.snap-1.png deleted file mode 100644 index 7211a9c95efdb6bd3838d0b1cc05c6a38fc95144..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3098 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 V4Gq=)s?c%)jvq@&YB`#D?OzZWTe$!L diff --git a/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html b/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html index 1a11e4a109..b6b71d3511 100644 --- a/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html +++ b/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html @@ -34,11 +34,6 @@ // TODO: This is for `createDirectLineEmulator` and `pageElements` only, should find ways to eliminate this line. window.WebChat = { createStoreWithOptions, testIds }; - // The reduced-motion image stops on its first frame, for a stable snapshot. - await host.sendDevToolsCommand('Emulation.setEmulatedMedia', { - features: [{ name: 'prefers-reduced-motion', value: 'reduce' }] - }); - const { directLine, store } = testHelpers.createDirectLineEmulator(); let numMounts = 0; @@ -59,11 +54,7 @@ StrictMode, {}, createElement(MountCounter), - createElement( - FluentThemeProvider, - {}, - createElement(ReactWebChat, { directLine, store, styleOptions: { hideSendBox: true } }) - ) + createElement(FluentThemeProvider, {}, createElement(ReactWebChat, { directLine, store })) ) ); @@ -84,12 +75,9 @@ const image = pageElements.typingIndicator().querySelector('img'); // THEN: The typing indicator image should load: a revoked `blob:` URL completes with a width of 0. + // No snapshot until react-scroll-to-bottom keeps its styles in Strict Mode: the transcript layout is lost. await waitFor(() => expect(image.complete).toBe(true)); expect(image.naturalWidth).toBeGreaterThan(0); - - // THEN: The typing indicator shows the sliding dots. - // They are at the top: in Strict Mode, react-scroll-to-bottom loses its styles, a separate issue. - await host.snapshot('local'); }); diff --git a/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html.snap-1.png b/__tests__/html2/react19/fluentTheme.typingIndicator.strictMode.html.snap-1.png deleted file mode 100644 index ada591ab06d0f582e51f89e223199157a889fc04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3110 zcmeI!=}(gf0LSqMU3Bqc(FHdxvPBbO+*X;>RxNfjIOZ|BOM#&l=7AK-Q?3^2@oZ*m zv!N6ZzzUWuM4CVbgi1NfBQVMwiop)F6iN^2)6zaq`?S&n+CF1{#NLtoUVUGFUj2Uk zDkXX2x^3$K0N8l^i==M=AnFPLtorfIRmbvlc%bkjxZ9QR1bpH|qJQo~` zU_xcG942&I<7TFGQ#2C__IWjMe*x+tr)-j{G{Fy3swL7+P1fC%n4Q`Bxq#UgYiVw- z)(@W^L3Z@G2D9r!?pYCcTE;dwjJ2SX(AQKzT@=1?P)!!h8{oi`SOz~#hs)d$lP<~y zNmkf*@$7Wowyoci{UbSNX+wojwkrJRg*#o|i=+;Dy6I&i8V{S?B_Rk{LWGA+MopR6?rgHu4jtyl zgZ-+o1X9U`CR;f{6(W0v#s@e8DjMbpTz^mQtAE$n(zd^t;>*VfTV`;PY`7D=H-~~K zD0gE#zoH@Net2r&;h}8&%tvE!$V__01_vIbY0Ctbx(tg#uf?~whDyEX*S3Z)8d{Y> zgdA)J^W>ZWIy%I%YLSCN+nfW=8)iK%ao7Z}Y_@=heVarW`J>$mEi>^0W#=a?^4Dl* zV{_^Ovg|x`>7dSY-ohyi&P8D{al1%E^ReHvUw})oBb50z5h5u`7MJW7FN|mPsXul! zC@hwAVT^@mU?1$46EA4k=R)!6y^Rap#6oVd?i#a$Dq3u&jLFVev`hEZeFOG!|NYIP z!@^2V9mGKfExis3gd2{yA4jw0Zhj3`3wgSVzD&68Kznw(_Vs^VXR28E%ii=#&Y<;Q zZJj}^^{Fa_wqwZLR1^mldVem8wUT`jI@hEzm`uINy<4*x0_-QL z$Yd(u`k3>1Jm2q91Fwy@mw1^VKUF)sTco8_C>y+JSLAsCw-^~%?}s^dGeS=s8!Mw= zn3EQEl+M$=8?Q;i_X9PY1F8vaHj^s*&JiZD0)D2Uy5YL4R@=)g!xgaEmBZJPJ zQp17A7o?12iiGK8tbO4MXc90ipDxTn$V?J>+J_bioHEm5B(%j|n$HthwR&jL+@?JI z=v-DP6FMCws$oY1H#vZ8Wh(+J0xJS50xJS50{@SIjvNI51Tj*dl(zi#*Zg<$R|Bl! V4Gq=)s?c%)jvq@&YB`#D?OzZWTe$!L From 4400dcf3fb2051f537d299ac89a9508102a9d546 Mon Sep 17 00:00:00 2001 From: Eugene Olonov Date: Thu, 12 Nov 2026 17:08:52 -0800 Subject: [PATCH 5/5] Add the changelog fragment --- .changelog/6051-fix-fluent-asset-urls.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/6051-fix-fluent-asset-urls.md diff --git a/.changelog/6051-fix-fluent-asset-urls.md b/.changelog/6051-fix-fluent-asset-urls.md new file mode 100644 index 0000000000..f6d8fa9f96 --- /dev/null +++ b/.changelog/6051-fix-fluent-asset-urls.md @@ -0,0 +1,3 @@ +### Fixed + +- Fixed Fluent typing indicator image broken with React 19 Strict Mode or ``, in PR [#6051](https://github.com/microsoft/BotFramework-WebChat/pull/6051), by [@OEvgeny](https://github.com/OEvgeny)