1import { render } from '@testing-library/react';
2import * as React from 'react';
3
4import type { CommentData } from './APIDataTypes';
5import { CommentTextBlock, mdInlineComponents, resolveTypeName } from './APISectionUtils';
6
7describe('APISectionUtils.resolveTypeName', () => {
8  test('void', () => {
9    const { container } = render(<>{resolveTypeName({ type: 'intrinsic', name: 'void' })}</>);
10    expect(container).toMatchSnapshot();
11  });
12
13  test('generic type', () => {
14    const { container } = render(<>{resolveTypeName({ type: 'intrinsic', name: 'string' })}</>);
15    expect(container).toMatchSnapshot();
16  });
17
18  test('custom type', () => {
19    const { container } = render(
20      <>{resolveTypeName({ type: 'reference', name: 'SpeechSynthesisEvent' })}</>
21    );
22    expect(container).toMatchSnapshot();
23  });
24
25  test('custom type array', () => {
26    const { container } = render(
27      <>
28        {resolveTypeName({
29          type: 'array',
30          elementType: { type: 'reference', name: 'AppleAuthenticationScope' },
31        })}
32      </>
33    );
34    expect(container).toMatchSnapshot();
35  });
36
37  test('custom type non-linkable array', () => {
38    const { container } = render(
39      <>
40        {resolveTypeName({
41          type: 'array',
42          elementType: { type: 'reference', name: 'T' },
43        })}
44      </>
45    );
46    expect(container).toMatchSnapshot();
47  });
48
49  test('query type', () => {
50    const { container } = render(
51      <>
52        {resolveTypeName({
53          type: 'reference',
54          typeArguments: [{ queryType: { type: 'reference', name: 'View' }, type: 'query' }],
55          name: 'React.ComponentProps',
56        })}
57      </>
58    );
59    expect(container).toMatchSnapshot();
60  });
61
62  test('Promise', () => {
63    const { container } = render(
64      <>
65        {resolveTypeName({
66          type: 'reference',
67          typeArguments: [{ type: 'intrinsic', name: 'void' }],
68          name: 'Promise',
69        })}
70      </>
71    );
72    expect(container).toMatchSnapshot();
73  });
74
75  test('Promise with custom type', () => {
76    const { container } = render(
77      <>
78        {resolveTypeName({
79          type: 'reference',
80          typeArguments: [{ type: 'reference', name: 'AppleAuthenticationCredential' }],
81          name: 'Promise',
82        })}
83      </>
84    );
85    expect(container).toMatchSnapshot();
86  });
87
88  test('Record', () => {
89    const { container } = render(
90      <>
91        {resolveTypeName({
92          type: 'reference',
93          typeArguments: [
94            { type: 'intrinsic', name: 'string' },
95            { type: 'intrinsic', name: 'any' },
96          ],
97          name: 'Record',
98        })}
99      </>
100    );
101    expect(container).toMatchSnapshot();
102  });
103
104  test('alternative generic object notation', () => {
105    const { container } = render(
106      <>
107        {resolveTypeName({
108          type: 'array',
109          elementType: {
110            type: 'reflection',
111            declaration: {
112              name: '__type',
113              indexSignature: {
114                name: '__index',
115                parameters: [{ name: 'column', type: { type: 'intrinsic', name: 'string' } }],
116                type: { type: 'intrinsic', name: 'any' },
117              },
118            },
119          },
120        })}
121      </>
122    );
123    expect(container).toMatchSnapshot();
124  });
125
126  test('Record with union', () => {
127    const { container } = render(
128      <>
129        {resolveTypeName({
130          type: 'reference',
131          typeArguments: [
132            { type: 'intrinsic', name: 'string' },
133            {
134              type: 'union',
135              types: [
136                { type: 'intrinsic', name: 'number' },
137                { type: 'intrinsic', name: 'boolean' },
138                { type: 'intrinsic', name: 'string' },
139              ],
140            },
141          ],
142          name: 'Record',
143        })}
144      </>
145    );
146    expect(container).toMatchSnapshot();
147  });
148
149  test('union', () => {
150    const { container } = render(
151      <>
152        {resolveTypeName({
153          type: 'union',
154          types: [
155            { type: 'reference', name: 'SpeechEventCallback' },
156            { type: 'literal', value: null },
157          ],
158        })}
159      </>
160    );
161    expect(container).toMatchSnapshot();
162  });
163
164  test('union with array', () => {
165    const { container } = render(
166      <>
167        {resolveTypeName({
168          type: 'union',
169          types: [
170            { type: 'array', elementType: { type: 'intrinsic', name: 'number' } },
171            { type: 'literal', value: null },
172          ],
173        })}
174      </>
175    );
176    expect(container).toMatchSnapshot();
177  });
178
179  test('union with custom type and array', () => {
180    const { container } = render(
181      <>
182        {resolveTypeName({
183          type: 'union',
184          types: [
185            { type: 'array', elementType: { type: 'reference', name: 'AssetRef' } },
186            { type: 'reference', name: 'AssetRef' },
187          ],
188        })}
189      </>
190    );
191    expect(container).toMatchSnapshot();
192  });
193
194  test('union of array values', () => {
195    const { container } = render(
196      <>
197        {resolveTypeName({
198          type: 'array',
199          elementType: {
200            type: 'union',
201            types: [
202              { type: 'reference', name: 'ResultSetError' },
203              { type: 'reference', name: 'ResultSet' },
204            ],
205          },
206        })}
207      </>
208    );
209    expect(container).toMatchSnapshot();
210  });
211
212  test('generic type', () => {
213    const { container } = render(
214      <>
215        {resolveTypeName({
216          type: 'reference',
217          typeArguments: [{ type: 'reference', name: 'Asset' }],
218          name: 'PagedInfo',
219        })}
220      </>
221    );
222    expect(container).toMatchSnapshot();
223  });
224
225  test('tuple type', () => {
226    const { container } = render(
227      <>
228        {resolveTypeName({
229          type: 'tuple',
230          elements: [
231            { type: 'reference', name: 'SortByKey' },
232            { type: 'intrinsic', name: 'boolean' },
233          ],
234        })}
235      </>
236    );
237    expect(container).toMatchSnapshot();
238  });
239
240  test('generic type in Promise', () => {
241    const { container } = render(
242      <>
243        {resolveTypeName({
244          type: 'reference',
245          typeArguments: [
246            {
247              type: 'reference',
248              typeArguments: [{ type: 'reference', name: 'Asset' }],
249              name: 'PagedInfo',
250            },
251          ],
252          name: 'Promise',
253        })}
254      </>
255    );
256    expect(container).toMatchSnapshot();
257  });
258
259  test('function', () => {
260    const { container } = render(
261      <>
262        {resolveTypeName({
263          type: 'reflection',
264          declaration: {
265            signatures: [
266              {
267                type: {
268                  type: 'union',
269                  types: [
270                    { type: 'intrinsic', name: 'void' },
271                    {
272                      type: 'reference',
273                      name: 'SpeechEventCallback',
274                    },
275                  ],
276                },
277              },
278            ],
279          },
280        })}
281      </>
282    );
283    expect(container).toMatchSnapshot();
284  });
285
286  test('function with arguments', () => {
287    const { container } = render(
288      <>
289        {resolveTypeName({
290          type: 'reflection',
291          declaration: {
292            signatures: [
293              {
294                parameters: [
295                  {
296                    name: 'error',
297                    type: { type: 'reference', name: 'Error' },
298                  },
299                ],
300                type: {
301                  type: 'union',
302                  types: [
303                    { type: 'intrinsic', name: 'void' },
304                    { type: 'reference', name: 'SpeechEventCallback' },
305                  ],
306                },
307              },
308            ],
309          },
310        })}
311      </>
312    );
313    expect(container).toMatchSnapshot();
314  });
315
316  test('function with non-linkable custom type', () => {
317    const { container } = render(
318      <>
319        {resolveTypeName({
320          type: 'reflection',
321          declaration: {
322            signatures: [
323              {
324                parameters: [
325                  {
326                    name: 'error',
327                    type: { type: 'reference', name: 'Error' },
328                  },
329                ],
330                type: { type: 'intrinsic', name: 'void' },
331              },
332            ],
333          },
334        })}
335      </>
336    );
337    expect(container).toMatchSnapshot();
338  });
339
340  test('object reflection', () => {
341    const { container } = render(
342      <>
343        {resolveTypeName({
344          type: 'reflection',
345          declaration: {
346            children: [
347              {
348                name: 'target',
349                type: { type: 'intrinsic', name: 'number' },
350              },
351              {
352                name: 'value',
353                type: { type: 'intrinsic', name: 'boolean' },
354              },
355            ],
356          },
357        })}
358      </>
359    );
360    expect(container).toMatchSnapshot();
361  });
362
363  test('custom type with single pick', () => {
364    const { container } = render(
365      <>
366        {resolveTypeName({
367          type: 'reference',
368          typeArguments: [
369            { type: 'reference', name: 'FontResource' },
370            { type: 'literal', value: 'display' },
371          ],
372          name: 'Pick',
373        })}
374      </>
375    );
376    expect(container).toMatchSnapshot();
377  });
378
379  test('props with multiple omits', () => {
380    const { container } = render(
381      <>
382        {resolveTypeName({
383          type: 'reference',
384          typeArguments: [
385            {
386              type: 'reference',
387              typeArguments: [
388                { type: 'reference', name: 'ViewStyle' },
389                {
390                  type: 'union',
391                  types: [
392                    { type: 'literal', value: 'backgroundColor' },
393                    {
394                      type: 'literal',
395                      value: 'borderRadius',
396                    },
397                  ],
398                },
399              ],
400              name: 'Omit',
401            },
402          ],
403          name: 'StyleProp',
404        })}
405      </>
406    );
407    expect(container).toMatchSnapshot();
408  });
409});
410
411describe('APISectionUtils.CommentTextBlock component', () => {
412  test('no comment', () => {
413    const { container } = render(<CommentTextBlock comment={undefined} />);
414    expect(container).toMatchSnapshot();
415  });
416
417  test('basic comment', () => {
418    const comment: CommentData = {
419      summary: [{ kind: 'text', text: 'This is the basic comment.' }],
420    };
421
422    const { container } = render(<CommentTextBlock comment={comment} />);
423    expect(container).toMatchSnapshot();
424  });
425
426  test('basic inline comment', () => {
427    const comment: CommentData = {
428      summary: [{ kind: 'text', text: 'This is the basic comment.' }],
429    };
430
431    const { container } = render(
432      <CommentTextBlock comment={comment} components={mdInlineComponents} withDash />
433    );
434    expect(container).toMatchSnapshot();
435  });
436
437  test('comment with example', () => {
438    const comment: CommentData = {
439      summary: [
440        {
441          kind: 'text',
442          text: 'Gets the referrer URL of the installed app with the [',
443        },
444        {
445          kind: 'code',
446          text: '`Install Referrer API`',
447        },
448        {
449          kind: 'text',
450          text: '](https://developer.android.com/google/play/installreferrer)\nfrom the Google Play Store. In practice, the referrer URL may not be a complete, absolute URL.',
451        },
452      ],
453      blockTags: [
454        {
455          tag: '@returns',
456          content: [
457            {
458              kind: 'text',
459              text: 'A ',
460            },
461            {
462              kind: 'code',
463              text: '`Promise`',
464            },
465            {
466              kind: 'text',
467              text: ' that fulfills with a ',
468            },
469            {
470              kind: 'code',
471              text: '`string`',
472            },
473            {
474              kind: 'text',
475              text: ' of the referrer URL of the installed app.',
476            },
477          ],
478        },
479        {
480          tag: '@example',
481          content: [
482            {
483              kind: 'code',
484              text: '```ts\nawait Application.getInstallReferrerAsync();\n// "utm_source=google-play&utm_medium=organic"\n```',
485            },
486          ],
487        },
488        {
489          tag: '@platform',
490          content: [
491            {
492              kind: 'text',
493              text: 'android',
494            },
495          ],
496        },
497      ],
498    };
499
500    const { container } = render(<CommentTextBlock comment={comment} />);
501    expect(container).toMatchSnapshot();
502  });
503});
504