Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -423,6 +423,7 @@ Breaking changes in this release:
- Fixed Fluent/Copilot typing indicator animation background color, in PR [#5770](https://github.com/microsoft/BotFramework-WebChat/pull/5770), by [@OEvgeny](https://github.com/OEvgeny)
- Fixed `<AddFullBundle>` should not re-render when `attachment[ForScreenReader]Middleware` is updated without noticeable different (`iterateEquals`), by [@compulim](https://github.com/compulim), in PR [#5779](https://github.com/microsoft/BotFramework-WebChat/pull/5779)
- Fixed send box should narrate `aria-label` prop, by [@compulim](https://github.com/compulim), in PR [#5805](https://github.com/microsoft/BotFramework-WebChat/pull/5805)
- Fixed polymiddleware error should not propagate to React runtime if `<DebugProvider>` is not mounted, by [@compulim](https://github.com/compulim), in PR [#5833](https://github.com/microsoft/BotFramework-WebChat/pull/5833)

## [4.18.0] - 2024-07-10

Expand Down
96 changes: 96 additions & 0 deletions __tests__/html2/adaptiveCard/renderError.withoutDebug.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<script>
const warn = console.warn.bind(console);

// We need to fake the mock ourselves without using jest-mock.
// jest-mock is ESM and cannot mock before Web Chat.
console.warn = (...args) => {
console.warn.mock.calls.push(args);

warn(...args);
};

console.warn._isMockFunction = true;
console.warn.getMockName = () => 'warn';
console.warn.mock = { calls: [] };
</script>
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@18.3.1",
"react-dom": "https://esm.sh/react-dom@18.3.1",
"react-dom/": "https://esm.sh/react-dom@18.3.1/"
}
}
</script>
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script type="module">
import React from 'react';

window.React = React;
</script>
<script crossorigin="anonymous" defer src="/__dist__/webchat-es5.js"></script>
<script crossorigin="anonymous" defer src="/__dist__/botframework-webchat-debug-theme.development.js"></script>
</head>
<body>
<main id="webchat"></main>
<script type="module">
import React, { createElement } from 'react';
import { createRoot } from 'react-dom/client';

run(async function () {
const {
testHelpers: { createStore },
WebChat: { ReactWebChat }
} = window;

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

// GIVEN: Web Chat is being rendered without <DebugProvider>.
createRoot(document.getElementById('webchat')).render(createElement(ReactWebChat, { directLine, store }));

await pageConditions.uiConnected();

await directLine.emulateIncomingActivity({
attachments: [
{
contentType: 'application/vnd.microsoft.card.adaptive',
content: {
// WHEN: We want to render a failing Adaptive Cards, adding "*" here to fail the renderer.
type: '*AdaptiveCard*',
$schema: 'http://adaptivecards.io/schemas/adaptive-card.json',
version: '1.5',
body: [
{
text: 'Hello, World!',
type: 'TextBlock'
}
]
}
}
],
type: 'message'
});

// THEN: Should have "render Adaptive Cards" error message.
expect(console.warn).toHaveBeenCalledWith(
expect.stringContaining('Failed to render Adaptive Cards.'),
expect.anything()
);

// THEN: Should not show RCoR error as we have injected catchall.
expect(console.warn).not.toHaveBeenCalledWith(
expect.stringContaining('the request has fall through all middleware, set "fallbackComponent" as a catchall'),
expect.anything()
);

// THEN: Should not show red box.
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.
18 changes: 15 additions & 3 deletions packages/api-middleware/src/errorBoxPolymiddleware.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { validateProps } from '@msinternal/botframework-webchat-react-valibot';
import React, { memo, useMemo } from 'react';
import React, { memo, useCallback, useMemo } from 'react';
import { object, pipe, readonly, string, unknown, type InferInput } from 'valibot';

import templatePolymiddleware, {
Expand All @@ -18,7 +18,7 @@ const {
Provider: ErrorBoxPolymiddlewareProvider,
Proxy,
reactComponent: errorBoxComponent,
useBuildRenderCallback: useBuildRenderErrorBoxCallback
useBuildRenderCallback
} = templatePolymiddleware<{ readonly error: unknown; readonly where: string }, { readonly children?: never }>(
'ErrorBox'
);
Expand All @@ -41,15 +41,27 @@ const ErrorBoxPolymiddlewareProxyPropsSchema = pipe(

type ErrorBoxPolymiddlewareProxyProps = Readonly<InferInput<typeof ErrorBoxPolymiddlewareProxyPropsSchema>>;

// If no error box is defined, do not fallthrough into RCoR and it would error out. Render nothing instead.
const NullComponent = () => null;

// A friendlier version than the organic <Proxy>.
const ErrorBoxPolymiddlewareProxy = memo(function ErrorBoxPolymiddlewareProxy(props: ErrorBoxPolymiddlewareProxyProps) {
const { error, where } = validateProps(ErrorBoxPolymiddlewareProxyPropsSchema, props);

const request = useMemo(() => ({ error, where }), [error, where]);

return <Proxy request={request} />;
return <Proxy fallbackComponent={NullComponent} request={request} />;
});

const useBuildRenderErrorBoxCallback: typeof useBuildRenderCallback = () => {
const buildRenderCallback = useBuildRenderCallback();

return useCallback(
(request, options) => buildRenderCallback(request, Object.freeze({ fallbackComponent: NullComponent, ...options })),
[buildRenderCallback]
);
Comment thread
compulim marked this conversation as resolved.
};

export {
createErrorBoxPolymiddleware,
errorBoxComponent,
Expand Down
Loading