1+ <!doctype html>
2+ < html lang ="en-US ">
3+
4+ < head >
5+ < title > Citation URL</ title >
6+ < link href ="/assets/index.css " rel ="stylesheet " type ="text/css " />
7+ < script type ="importmap ">
8+ {
9+ "imports" : {
10+ "@fluentui/react-provider" : "https://esm.sh/@fluentui/react-provider?deps=react@18&exports=FluentProvider" ,
11+ "@fluentui/tokens" : "https://esm.sh/@fluentui/tokens?deps=react@18&exports=createDarkTheme,webLightTheme" ,
12+ "@testduet/wait-for" : "https://unpkg.com/@testduet/wait-for@main/dist/wait-for.mjs" ,
13+ "botframework-webchat" : "/__dist__/packages/bundle/static/botframework-webchat.js" ,
14+ "botframework-webchat/decorator" : "/__dist__/packages/bundle/static/botframework-webchat/decorator.js" ,
15+ "botframework-webchat/internal" : "/__dist__/packages/bundle/static/botframework-webchat/internal.js" ,
16+ "botframework-webchat-fluent-theme" : "/__dist__/packages/fluent-theme/static/botframework-webchat-fluent-theme.js" ,
17+ "react" : "https://esm.sh/react@18" ,
18+ "react-dom" : "https://esm.sh/react-dom@18" ,
19+ "react-dom/" : "https://esm.sh/react-dom@18/"
20+ }
21+ }
22+ </ script >
23+ < script crossorigin ="anonymous " src ="/test-harness.js "> </ script >
24+ < script crossorigin ="anonymous " src ="/test-page-object.js "> </ script >
25+ < style type ="text/css ">
26+ # webchat {
27+ width : 640px ;
28+ }
29+
30+ .fui-FluentProvider {
31+ height : 100% ;
32+ }
33+
34+ .theme .variant-copilot {
35+ --webchat__color--surface : var (--colorGrey98 );
36+ }
37+ </ style >
38+ </ head >
39+
40+ < body >
41+ < main id ="webchat "> </ main >
42+ < script type ="module ">
43+ import '/test-harness.mjs' ;
44+ import '/test-page-object.mjs' ;
45+
46+ import { createDarkTheme , webLightTheme } from '@fluentui/tokens' ;
47+ import { FluentProvider } from '@fluentui/react-provider' ;
48+ import { waitFor } from '@testduet/wait-for' ;
49+ import { createDirectLine , createStoreWithOptions , ReactWebChat } from 'botframework-webchat' ;
50+ import { FluentThemeProvider } from 'botframework-webchat-fluent-theme' ;
51+ import { createElement } from 'react' ;
52+ import { createRoot } from 'react-dom/client' ;
53+
54+ const {
55+ testHelpers : { createDirectLineEmulator }
56+ } = window ;
57+
58+ // TODO: This is for `createDirectLineEmulator` only, should find ways to eliminate this line.
59+ window . WebChat = { createStoreWithOptions } ;
60+
61+ // run = fn => fn();
62+ run ( async function ( ) {
63+ const { directLine, store } = createDirectLineEmulator ( ) ;
64+
65+ const searchParams = new URLSearchParams ( location . search ) ;
66+ const variant = searchParams . get ( 'variant' ) ;
67+ const theme = searchParams . get ( 'fluent-theme' ) ;
68+
69+ await host . windowSize ( 480 , 760 , document . getElementById ( 'webchat' ) ) ;
70+ await host . sendDevToolsCommand ( 'Emulation.setEmulatedMedia' , {
71+ features : [
72+ { name : 'prefers-reduced-motion' , value : 'reduce' } ,
73+ ...( theme === 'dark' || theme === 'light'
74+ ? [ { name : 'prefers-color-scheme' , value : theme } ]
75+ : [ ] )
76+ ]
77+ } ) ;
78+
79+ const root = createRoot ( document . getElementById ( 'webchat' ) ) ;
80+
81+ let fluentTheme ;
82+ let codeBlockTheme ;
83+
84+ if ( theme === 'dark' || window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches && theme !== 'light' ) {
85+ fluentTheme = {
86+ ...createDarkTheme ( {
87+ 10 : '#12174c' ,
88+ 20 : '#1a1f5b' ,
89+ 30 : '#21276a' ,
90+ 40 : '#293079' ,
91+ 50 : '#303788' ,
92+ 60 : '#384097' ,
93+ 70 : '#4049a7' ,
94+ 80 : '#151e80' ,
95+ 90 : '#4f59c5' ,
96+ 100 : '#5661d4' ,
97+ 110 : '#5e69e3' ,
98+ 120 : '#7982e8' ,
99+ 130 : '#949bec' ,
100+ 140 : '#afb5f1' ,
101+ 150 : '#c9cdf6' ,
102+ 160 : '#e4e6fa'
103+ } ) ,
104+ colorNeutralBackground1Disabled : '#101010' ,
105+ colorNeutralBackground1Hover : '#101010' ,
106+ colorNeutralForeground5 : '#424242' ,
107+ colorGrey98 : '#1b1b1b'
108+ } ;
109+ codeBlockTheme = 'github-dark-default' ;
110+ } else {
111+ fluentTheme = {
112+ ...webLightTheme ,
113+ colorNeutralForeground1 : '#1b1b1b' ,
114+ colorGrey98 : '#fafafa'
115+ } ;
116+ codeBlockTheme = 'github-light-default' ;
117+ }
118+
119+ if ( variant ) {
120+ window . checkAccessibility = async ( ) => { }
121+ }
122+
123+ const webChatProps = { directLine, store, styleOptions : { codeBlockTheme } } ;
124+
125+ root . render (
126+ variant === 'copilot' || variant === 'fluent' ?
127+ createElement (
128+ FluentProvider ,
129+ { className : 'fui-FluentProvider' , theme : fluentTheme } ,
130+ createElement (
131+ FluentThemeProvider ,
132+ { variant : variant } ,
133+ createElement ( ReactWebChat , webChatProps )
134+ )
135+ ) :
136+ createElement ( ReactWebChat , webChatProps )
137+ ) ;
138+
139+ await pageConditions . uiConnected ( ) ;
140+
141+ await directLine . emulateIncomingActivity (
142+ {
143+ "type" : "message" ,
144+ "id" : "00000000-0000-0000-0000-000000000001" ,
145+ "timestamp" : "2025-10-09T00:00:00.0000000+00:00" ,
146+ "channelId" : "test" ,
147+ "from" : {
148+ "id" : "bot-anon" ,
149+ "name" : "test_agent" ,
150+ "role" : "bot"
151+ } ,
152+ "conversation" : { "id" : "conv-anon" } ,
153+ "recipient" : { "id" : "user-anon" , "role" : "user" } ,
154+ "textFormat" : "markdown" ,
155+ "locale" : "en-US" ,
156+ "text" : "Verify that citation **[9]** renders correctly.\n\n- **2025 Product Area Review [Template]** [9]\n\n[9]: https://example.sharepoint.com/sites/Docs/2025%20Product%20Area%20Review%20[Template].pptx \"2025 Product Area Review [Template].pptx\"" ,
157+ "entities" : [
158+ {
159+ "type" : "https://schema.org/Message" ,
160+ "@type" : "Message" ,
161+ "@context" : "https://schema.org" ,
162+ "citation" : [
163+ {
164+ "appearance" : {
165+ "text" : "" ,
166+ "abstract" : "2025 Product Area Review [Template].pptx" ,
167+ "@type" : "DigitalDocument" ,
168+ "name" : "2025 Product Area Review [Template].pptx" ,
169+ "url" : "https://example.sharepoint.com/sites/Docs/2025%20Product%20Area%20Review%20[Template].pptx"
170+ } ,
171+ "position" : 9 ,
172+ "@type" : "Claim" ,
173+ "@id" : "SPO_XYZ_claim_id_only_for_test_9"
174+ }
175+ ]
176+ } ,
177+ {
178+ "type" : "https://schema.org/Claim" ,
179+ "@type" : "Claim" ,
180+ "@context" : "https://schema.org" ,
181+ "@id" : "SPO_XYZ_claim_id_only_for_test_9" ,
182+ "text" : "" ,
183+ "name" : "2025 Product Area Review [Template].pptx"
184+ }
185+ ]
186+ }
187+ ) ;
188+
189+ await directLine . emulateIncomingActivity ( {
190+ "type" : "message" ,
191+ "id" : "00000000-0000-0000-0000-000000000102" ,
192+ "timestamp" : "2025-10-09T00:00:00.0000000+00:00" ,
193+ "channelId" : "test" ,
194+ "from" : { "id" : "bot-anon" , "name" : "test_agent" , "role" : "bot" } ,
195+ "conversation" : { "id" : "conv-anon" } ,
196+ "recipient" : { "id" : "user-anon" , "role" : "user" } ,
197+ "textFormat" : "markdown" ,
198+ "locale" : "en-US" ,
199+ "text" : "Verify array-style query params and nested redirect. **Search results (tags)**. [2]\n\n[2]: https://files.example.com/search?tags%5B%5D=a&tags%5B%5D=a%2Fb&redirect=https%3A%2F%2Fexample.com%2Fx%3Fy%3Dz \"search with tags[] and redirect\"" ,
200+ "entities" : [
201+ {
202+ "type" : "https://schema.org/Message" ,
203+ "@type" : "Message" ,
204+ "@context" : "https://schema.org" ,
205+ "citation" : [
206+ {
207+ "appearance" : {
208+ "text" : "" ,
209+ "abstract" : "search with tags[] and redirect" ,
210+ "@type" : "DigitalDocument" ,
211+ "name" : "search with tags[] and redirect" ,
212+ "url" : "https://files.example.com/search?tags%5B%5D=a&tags%5B%5D=a%2Fb&redirect=https%3A%2F%2Fexample.com%2Fx%3Fy%3Dz"
213+ } ,
214+ "position" : 2 ,
215+ "@type" : "Claim" ,
216+ "@id" : "CLAIM_TEST_102"
217+ }
218+ ]
219+ } ,
220+ { "type" : "https://schema.org/Claim" , "@type" : "Claim" , "@context" : "https://schema.org" , "@id" : "CLAIM_TEST_102" , "text" : "" , "name" : "search with tags[] and redirect" }
221+ ]
222+ } ) ;
223+
224+ await directLine . emulateIncomingActivity ( {
225+ "type" : "message" ,
226+ "id" : "00000000-0000-0000-0000-000000000103" ,
227+ "timestamp" : "2025-10-09T00:00:00.0000000+00:00" ,
228+ "channelId" : "test" ,
229+ "from" : { "id" : "bot-anon" , "name" : "test_agent" , "role" : "bot" } ,
230+ "conversation" : { "id" : "conv-anon" } ,
231+ "recipient" : { "id" : "user-anon" , "role" : "user" } ,
232+ "textFormat" : "markdown" ,
233+ "locale" : "en-US" ,
234+ "text" : "Verify UTF-8 encoding in path. **Отчёт - план 📄**. [3]\n\n[3]: https://docs.example.com/reports/%D0%9E%D1%82%D1%87%D1%91%D1%82%20%E2%80%94%20%D0%BF%D0%BB%D0%B0%D0%BD%20%F0%9F%93%84.pdf \"Отчёт - план 📄.pdf\"" ,
235+ "entities" : [
236+ {
237+ "type" : "https://schema.org/Message" ,
238+ "@type" : "Message" ,
239+ "@context" : "https://schema.org" ,
240+ "citation" : [
241+ {
242+ "appearance" : {
243+ "text" : "" ,
244+ "abstract" : "Отчёт - план 📄.pdf" ,
245+ "@type" : "DigitalDocument" ,
246+ "name" : "Отчёт - план 📄.pdf" ,
247+ "url" : "https://docs.example.com/reports/%D0%9E%D1%82%D1%87%D1%91%D1%82%20%E2%80%94%20%D0%BF%D0%BB%D0%B0%D0%BD%20%F0%9F%93%84.pdf"
248+ } ,
249+ "position" : 3 ,
250+ "@type" : "Claim" ,
251+ "@id" : "CLAIM_TEST_103"
252+ }
253+ ]
254+ } ,
255+ { "type" : "https://schema.org/Claim" , "@type" : "Claim" , "@context" : "https://schema.org" , "@id" : "CLAIM_TEST_103" , "text" : "" , "name" : "Отчёт - план 📄.pdf" }
256+ ]
257+ } ) ;
258+
259+ await directLine . emulateIncomingActivity ( {
260+ "type" : "message" ,
261+ "id" : "00000000-0000-0000-0000-000000000105" ,
262+ "timestamp" : "2025-10-09T00:00:00.0000000+00:00" ,
263+ "channelId" : "test" ,
264+ "from" : { "id" : "bot-anon" , "name" : "test_agent" , "role" : "bot" } ,
265+ "conversation" : { "id" : "conv-anon" } ,
266+ "recipient" : { "id" : "user-anon" , "role" : "user" } ,
267+ "textFormat" : "markdown" ,
268+ "locale" : "en-US" ,
269+ "text" : "Verify mailto with plus-addressing and encoded query. **Email owner**. [5]\n\n[5]: mailto:support+roadmap@example.com?subject=Roadmap%20Review%20%5BTemplate%5D&body=Please%20review%20slide%203.%0AThanks%21 \"mailto with + and encoded subject/body\"" ,
270+ "entities" : [
271+ {
272+ "type" : "https://schema.org/Message" ,
273+ "@type" : "Message" ,
274+ "@context" : "https://schema.org" ,
275+ "citation" : [
276+ {
277+ "appearance" : {
278+ "text" : "" ,
279+ "abstract" : "mailto with + and encoded subject/body" ,
280+ "@type" : "DigitalDocument" ,
281+ "name" : "mailto with + and encoded subject/body" ,
282+ "url" : "mailto:support+roadmap@example.com?subject=Roadmap%20Review%20%5BTemplate%5D&body=Please%20review%20slide%203.%0AThanks%21"
283+ } ,
284+ "position" : 5 ,
285+ "@type" : "Claim" ,
286+ "@id" : "CLAIM_TEST_105"
287+ }
288+ ]
289+ } ,
290+ { "type" : "https://schema.org/Claim" , "@type" : "Claim" , "@context" : "https://schema.org" , "@id" : "CLAIM_TEST_105" , "text" : "" , "name" : "mailto with + and encoded subject/body" }
291+ ]
292+ } ) ;
293+
294+ await directLine . emulateIncomingActivity ( {
295+ "type" : "message" ,
296+ "id" : "00000000-0000-0000-0000-000000000106" ,
297+ "timestamp" : "2025-10-09T00:00:00.0000000+00:00" ,
298+ "channelId" : "test" ,
299+ "from" : { "id" : "bot-anon" , "name" : "test_agent" , "role" : "bot" } ,
300+ "conversation" : { "id" : "conv-anon" } ,
301+ "recipient" : { "id" : "user-anon" , "role" : "user" } ,
302+ "textFormat" : "markdown" ,
303+ "locale" : "en-US" ,
304+ "text" : "Verify `%23` for literal hash in filename. **Q1#1 Plan**. [6]\n\n[6]: https://example.sharepoint.com/sites/Docs/Q1%231%20Plan.pptx \"Q1#1 Plan.pptx\"" ,
305+ "entities" : [
306+ {
307+ "type" : "https://schema.org/Message" ,
308+ "@type" : "Message" ,
309+ "@context" : "https://schema.org" ,
310+ "citation" : [
311+ {
312+ "appearance" : {
313+ "text" : "" ,
314+ "abstract" : "Q1#1 Plan.pptx" ,
315+ "@type" : "DigitalDocument" ,
316+ "name" : "Q1#1 Plan.pptx" ,
317+ "url" : "https://example.sharepoint.com/sites/Docs/Q1%231%20Plan.pptx"
318+ } ,
319+ "position" : 6 ,
320+ "@type" : "Claim" ,
321+ "@id" : "CLAIM_TEST_106"
322+ }
323+ ]
324+ } ,
325+ { "type" : "https://schema.org/Claim" , "@type" : "Claim" , "@context" : "https://schema.org" , "@id" : "CLAIM_TEST_106" , "text" : "" , "name" : "Q1#1 Plan.pptx" }
326+ ]
327+ } ) ;
328+
329+ expect ( Array . from ( document . querySelectorAll ( '.webchat__render-markdown a' ) ) . map ( a => a . href ) ) . toEqual ( [
330+ 'https://example.sharepoint.com/sites/Docs/2025%20Product%20Area%20Review%20%5BTemplate%5D.pptx' ,
331+ 'https://example.sharepoint.com/sites/Docs/2025%20Product%20Area%20Review%20%5BTemplate%5D.pptx' ,
332+ 'https://files.example.com/search?tags%5B%5D=a&tags%5B%5D=a%2Fb&redirect=https%3A%2F%2Fexample.com%2Fx%3Fy%3Dz' ,
333+ 'https://docs.example.com/reports/%D0%9E%D1%82%D1%87%D1%91%D1%82%20%E2%80%94%20%D0%BF%D0%BB%D0%B0%D0%BD%20%F0%9F%93%84.pdf' ,
334+ 'mailto:support+roadmap@example.com?subject=Roadmap%20Review%20%5BTemplate%5D&body=Please%20review%20slide%203.%0AThanks%21' ,
335+ 'https://example.sharepoint.com/sites/Docs/Q1%231%20Plan.pptx'
336+ ] ) ;
337+
338+ await host . snapshot ( 'local' ) ;
339+ } ) ;
340+ </ script >
341+ </ body >
342+
343+ </ html >
0 commit comments