Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
9a1bec9
Add tests
compulim Oct 8, 2026
97fc298
Add doc
compulim Oct 8, 2026
ab97545
Add TODOs
compulim Oct 8, 2026
7423d40
Add tests
compulim Oct 9, 2026
5e2eab7
Add doc
compulim Oct 9, 2026
cb043d5
Add doc
compulim Oct 9, 2026
63befa0
Fix indent
compulim Oct 9, 2026
c3ba32d
Add replyToId in hero card
compulim Oct 9, 2026
9ca8ae7
Hero card to export type
compulim Oct 9, 2026
84fe37c
Add InferReactProps
compulim Oct 9, 2026
96e65e7
Add animation card
compulim Oct 9, 2026
af05465
Add rationale
compulim Oct 9, 2026
d3ae1ba
Add audio card
compulim Oct 9, 2026
a60bc5c
Fix card action import
compulim Oct 9, 2026
1c6913c
Add OAuth card
compulim Oct 9, 2026
a18a7dd
Export prop types
compulim Oct 9, 2026
344f475
Add receipt card
compulim Oct 9, 2026
6d92b9f
Add sign-in card
compulim Oct 9, 2026
24f7c67
Add thumbnail card
compulim Oct 9, 2026
eb62084
Add video card
compulim Oct 9, 2026
6c15952
Fix coalesce
compulim Oct 9, 2026
97c2fae
Export prop types
compulim Oct 9, 2026
65d4b69
Add entry
compulim Oct 9, 2026
fe22b44
Update entry
compulim Oct 9, 2026
83fe7ca
Add snapshots
compulim Oct 9, 2026
bf34055
Add PR number
compulim Oct 9, 2026
4eb682d
Conditionally render AudioCardContent based on content
compulim Oct 9, 2026
4f1b393
Change content type from animation to audio card
compulim Oct 9, 2026
76c93b5
Revise cardActionMiddleware documentation
compulim Oct 9, 2026
db38c13
Remove TODO comments about content prop validation
compulim Oct 9, 2026
11e0511
Fix HTML entity encoding in OAuthCardAttachment
compulim Oct 9, 2026
dfcab3b
Unify typing
compulim Oct 9, 2026
995cd87
Update usePerformCardAction type definition
compulim Oct 9, 2026
bf2ff12
Fix tap action
compulim Oct 9, 2026
7182567
Fix Prettier
compulim Oct 12, 2026
63f4625
Allow more complex type
compulim Oct 12, 2026
50f3a84
Hide video controls
compulim Oct 12, 2026
22cfc74
Fix flakiness
compulim Oct 12, 2026
8bec5b1
Fix broken test
compulim Oct 12, 2026
43d1c99
Mark value as optional
compulim Oct 12, 2026
3f8ac03
Fix snapshots
compulim Oct 12, 2026
31f690d
Fix flakiness
compulim Oct 12, 2026
303ae34
Fix Prettier
compulim Oct 12, 2026
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Legends:
- ~~Refer to [this test](./__tests__/html2/adaptiveCard/signInAction.html) for the reference payload~~
- ~~Note: this implementation is based on observation of how Microsoft Teams behave and could deviate from their official implementation~~
- Obsoleted in favor of PR [#5862](https://github.com/microsoft/BotFramework-WebChat/pull/5862)
- Added card action `webchat:callURL` and [Adaptive Card action `Action.OpenUrlDialog`](https://adaptivecards.microsoft.com/?topic=Action.OpenUrlDialog)
- Added card action `webchat:callURL` and [Adaptive Card action `Action.OpenUrlDialog`](https://adaptivecards.microsoft.com/?topic=Action.OpenUrlDialog), in PR [#5862](https://github.com/microsoft/BotFramework-WebChat/pull/5862) and PR [#5863](https://github.com/microsoft/BotFramework-WebChat/pull/5863), by [@compulim](https://github.com/compulim)
- The card action is designed to host popup for authentication and authorization (call-and-return pattern), it can optionally send a postback message to the bot
- Open in popup, in PR [#5862](https://github.com/microsoft/BotFramework-WebChat/pull/5862), by [@compulim](https://github.com/compulim)
- Added `styleOptions.callURLActionPopupWindowHeight/Width` for sizing the popup window
Expand All @@ -49,6 +49,7 @@ Legends:
- Postback is only accepted within 5 minutes after the popup window is opened and from a trusted origin
- Each popup window can only send at most one postback, subsequent postbacks are ignored
- `replyToId` will be automatically filled in by the ID of the originating activity
- Rich cards: added fill-in of `replyToId` for "post back" card actions, in PR [#5871](https://github.com/microsoft/BotFramework-WebChat/pull/5871), by [@compulim](https://github.com/compulim)

### Fixed

Expand Down
1 change: 1 addition & 0 deletions __tests__/html2/avatar/layout.default.oneSide.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@

await pageObjects.sendMessageViaSendBox('normal');
await pageConditions.numActivitiesShown(2);
await pageConditions.allOutgoingActivitiesSent();

await host.snapshot('local', { skipCheckAccessibility: true });

Expand Down
71 changes: 71 additions & 0 deletions __tests__/html2/hooks/usePerformCardAction.replyToId.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<!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",
"botframework-webchat/": "/__dist__/packages/bundle/static/botframework-webchat/",
"jest-mock": "https://esm.sh/jest-mock",
"react": "https://esm.sh/react@18",
"react-dom": "https://esm.sh/react-dom@18",
"react-dom/": "https://esm.sh/react-dom@18/"
}
}
</script>
<script type="module">
import '/test-harness.mjs';
import '/test-page-object.mjs';

import { createStoreWithOptions, testIds } from 'botframework-webchat';
import { usePerformCardAction } from 'botframework-webchat/hook.js';
import { fn, spyOn } from 'jest-mock';
import createRenderHook from '/assets/esm/createRenderHook.js';

const { createDirectLineEmulator } = window.testHelpers;

window.WebChat = { createStoreWithOptions, testIds };

const cardActionEnhancerMock = fn();

run(async function () {
const { directLine, store } = createDirectLineEmulator();
const renderHook = createRenderHook(
document.getElementById('webchat'),
{
cardActionMiddleware:
({ dispatch }) =>
next =>
(...args) =>
cardActionEnhancerMock(...args),
directLine,
store
},
{ renderWebChat: true }
);

await renderHook();
await pageConditions.uiConnected();

const performCardAction = await renderHook(() => usePerformCardAction());

performCardAction({ type: 'postback', value: 'Hello, World!' }, undefined, { replyToId: 'a-00001' });

expect(cardActionEnhancerMock).toHaveBeenCalledTimes(1);
expect(cardActionEnhancerMock).toHaveBeenNthCalledWith(
1,
expect.objectContaining({
cardAction: { type: 'postback', value: 'Hello, World!' },
Comment on lines +56 to +62

// THEN: Must contain "replyToId" in the request.
replyToId: 'a-00001'
})
);
});
</script>
</body>
</html>
84 changes: 84 additions & 0 deletions __tests__/html2/hooks/useSendPostBack.replyToId.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<!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",
"botframework-webchat/": "/__dist__/packages/bundle/static/botframework-webchat/",
"react": "https://esm.sh/react@18",
"react-dom": "https://esm.sh/react-dom@18",
"react-dom/": "https://esm.sh/react-dom@18/"
}
}
</script>
<script type="module">
import '/test-harness.mjs';
import '/test-page-object.mjs';

import { createStoreWithOptions, testIds } from 'botframework-webchat';
import { useSendPostBack } from 'botframework-webchat/hook.js';
import createRenderHook from '/assets/esm/createRenderHook.js';

const {
testHelpers: { createDirectLineEmulator }
} = window;

window.WebChat = { createStoreWithOptions, testIds };

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

const renderHook = createRenderHook(
document.getElementById('webchat'),
{ directLine, store },
{ renderWebChat: true }
);

const sendPostBack = await renderHook(() => useSendPostBack());

await pageConditions.uiConnected();

const { activity, resolveAll } = await directLine.actPostActivity(async () =>
sendPostBack({ hello: 'World!' }, { replyToId: 'a-00001' })
);

expect(activity).toEqual(
expect.objectContaining({
channelData: expect.objectContaining({ postBack: true }),
replyToId: 'a-00001',
type: 'message',
value: { hello: 'World!' }
})
);

await resolveAll();

directLine.emulateIncomingActivity(
`\`\`\`\n${JSON.stringify(
{
...activity,
channelData: { ...activity.channelData, clientActivityID: '...' },
from: '...',
localTimestamp: '...',
localTimezone: '...'
},
null,
2
)}\n\`\`\``
);

await pageConditions.numActivitiesShown(1);

await host.snapshot('local');
},
{ ignoreErrors: true }
);
</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.
85 changes: 85 additions & 0 deletions __tests__/html2/hooks/useSendPostBack.text.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<!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",
"botframework-webchat/": "/__dist__/packages/bundle/static/botframework-webchat/",
"react": "https://esm.sh/react@18",
"react-dom": "https://esm.sh/react-dom@18",
"react-dom/": "https://esm.sh/react-dom@18/"
}
}
</script>
<script type="module">
import '/test-harness.mjs';
import '/test-page-object.mjs';

import { createStoreWithOptions, testIds } from 'botframework-webchat';
import { useSendPostBack } from 'botframework-webchat/hook.js';
import createRenderHook from '/assets/esm/createRenderHook.js';

const {
testHelpers: { createDirectLineEmulator }
} = window;

window.WebChat = { createStoreWithOptions, testIds };

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

const renderHook = createRenderHook(
document.getElementById('webchat'),
{ directLine, store },
{ renderWebChat: true }
);

const sendPostBack = await renderHook(() => useSendPostBack());

await pageConditions.uiConnected();

const { activity, resolveAll } = await directLine.actPostActivity(async () =>
sendPostBack('Hello, World!', { replyToId: 'a-00001' })
);

expect(activity).toEqual(
expect.objectContaining({
channelData: expect.objectContaining({ postBack: true }),
replyToId: 'a-00001',
// THEN: Should use "text" instead of "value".
text: 'Hello, World!',
type: 'message'
})
);

await resolveAll();

directLine.emulateIncomingActivity(
`\`\`\`\n${JSON.stringify(
{
...activity,
channelData: { ...activity.channelData, clientActivityID: '...' },
from: '...',
localTimestamp: '...',
localTimezone: '...'
},
null,
2
)}\n\`\`\``
);

await pageConditions.numActivitiesShown(1);

await host.snapshot('local');
},
{ ignoreErrors: true }
);
</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.
111 changes: 111 additions & 0 deletions __tests__/html2/replyToId/cardAction/adaptiveCard.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<!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",
"botframework-webchat/": "/__dist__/packages/bundle/static/botframework-webchat/",
"react": "https://esm.sh/react@18",
"react-dom": "https://esm.sh/react-dom@18",
"react-dom/": "https://esm.sh/react-dom@18/"
}
}
</script>
<script type="module">
import '/test-harness.mjs';
import '/test-page-object.mjs';

import { createStoreWithOptions, testIds } from 'botframework-webchat';
import { usePerformCardAction } from 'botframework-webchat/hook.js';
import createRenderHook from '/assets/esm/createRenderHook.js';

const { createDirectLineEmulator } = window.testHelpers;

window.WebChat = { createStoreWithOptions, testIds };

run(async function () {
const { directLine, store } = createDirectLineEmulator();
const renderHook = createRenderHook(
document.getElementById('webchat'),
{
directLine,
store
},
{ renderWebChat: true }
);

await renderHook();
await pageConditions.uiConnected();

await directLine.emulateIncomingActivity({
attachments: [
{
// TODO: Change to rich card instead of AC.
contentType: 'application/vnd.microsoft.card.adaptive',
content: {
$schema: 'https://microsoft.github.io/AdaptiveCards/schemas/adaptive-card.json',
version: '1.0',
type: 'AdaptiveCard',
body: [
{
type: 'Container',
items: [
{
choices: [{ title: 'Aloha!', value: 'Aloha!' }],
id: 'hello',
label: 'Value',
type: 'Input.ChoiceSet',
value: 'Aloha!'
}
]
}
],
actions: [{ type: 'Action.Submit', title: 'Submit' }]
}
}
],
id: 'a-00001',
type: 'message'
});

const submitButton = pageElements.activities()[0].querySelector('.ac-pushButton');

const { activity, resolveAll } = await directLine.actPostActivity(() => host.click(submitButton));

await resolveAll();

directLine.emulateIncomingActivity(
`\`\`\`\n${JSON.stringify(
{
...activity,
channelData: { ...activity.channelData, clientActivityID: '...' },
entities: activity.entities ? '{ ... }' : undefined,
from: '...',
localTimestamp: '...',
localTimezone: '...'
},
null,
2
)}\n\`\`\``
);

expect(activity).toEqual(
expect.objectContaining({
channelData: expect.objectContaining({ postBack: true }),
replyToId: 'a-00001',
type: 'message',
value: { hello: 'Aloha!' }
})
);

await pageConditions.scrollStabilized();
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
Loading