1import { screen } from '@testing-library/react';
2
3import AppConfigSchemaPropertiesTable, {
4  formatSchema,
5  createDescription,
6  _getType,
7  Property,
8} from './AppConfigSchemaPropertiesTable';
9
10import { renderWithHeadings } from '~/common/test-utilities';
11
12const testSchema: Record<string, Property> = {
13  name: {
14    description: 'Name of your app.',
15    type: 'string',
16    meta: {
17      bareWorkflow: "Edit the 'Display Name' field in Xcode",
18    },
19  },
20  androidNavigationBar: {
21    description: 'Configuration for the bottom navigation bar on Android.',
22    type: 'object',
23    properties: {
24      visible: {
25        description: 'Determines how and when the navigation bar is shown.',
26        type: 'string',
27        properties: {
28          always: {
29            description: 'Test sub-sub-property',
30            type: 'boolean',
31          },
32        },
33        meta: {
34          expoKit: 'Set this property using Xcode.',
35        },
36        enum: ['leanback', 'immersive', 'sticky-immersive'],
37      },
38      backgroundColor: {
39        description: 'Specifies the background color of the navigation bar. ',
40        type: 'string',
41        pattern: '^#|(&#x23;)\\d{6}$',
42        meta: {
43          regexHuman: "6 character long hex color string, eg: `'#000000'`",
44        },
45      },
46    },
47    meta: {
48      expoKit: 'Set this property using AppConstants.java.',
49      bareWorkflow: 'Set this property using just Xcode',
50    },
51  },
52  intentFilters: {
53    description: 'Configuration for setting an array of custom intent filters in Android manifest.',
54    example: [
55      {
56        autoVerify: true,
57        data: {
58          host: '*.example.com',
59        },
60      },
61    ],
62    exampleString: '\n [{ \n "autoVerify": true, \n "data": {"host": "*.example.com" \n } \n }]',
63    type: 'array',
64    uniqueItems: true,
65    items: {
66      type: 'object',
67      properties: {
68        autoVerify: {
69          description:
70            'You may also use an intent filter to set your app as the default handler for links',
71          type: 'boolean',
72        },
73        data: {
74          type: ['array', 'object'],
75          items: {
76            type: 'object',
77            properties: {
78              host: { description: 'the host, e.g. `example.com`', type: 'string' },
79            },
80            additionalProperties: false,
81          },
82          properties: {
83            host: { type: 'string' },
84          },
85          additionalProperties: false,
86        },
87      },
88      additionalProperties: false,
89      required: ['action'],
90    },
91    meta: {
92      bareWorkflow: 'This is set in AndroidManifest.xml directly.',
93    },
94  },
95};
96
97describe('AppConfigSchemaPropertiesTable', () => {
98  test('correctly matches snapshot', () => {
99    const { container } = renderWithHeadings(
100      <AppConfigSchemaPropertiesTable schema={testSchema} />
101    );
102    expect(container).toMatchSnapshot();
103  });
104
105  test('description includes all required components', () => {
106    renderWithHeadings(
107      <AppConfigSchemaPropertiesTable schema={{ entry: testSchema.androidNavigationBar }} />
108    );
109
110    expect(screen.getByText('- Specifies the background color of the navigation bar.'));
111    expect(screen.getByText('6 character long hex color string, eg:'));
112    expect(screen.getByText('Set this property using just Xcode'));
113    expect(screen.getByText('Set this property using AppConstants.java.'));
114  });
115});
116
117describe('formatSchema', () => {
118  const formattedSchema = formatSchema(Object.entries(testSchema));
119  test('name is property nestingLevel 0', () => {
120    expect(formattedSchema[0].nestingLevel).toBe(0);
121  });
122  test('androidNavigationBar is property nestingLevel 0', () => {
123    expect(formattedSchema[1].nestingLevel).toBe(0);
124  });
125  test('visible is subproperty nestingLevel 1', () => {
126    expect(formattedSchema[2].nestingLevel).toBe(1);
127  });
128  test('always is subproperty nestingLevel 2', () => {
129    expect(formattedSchema[3].nestingLevel).toBe(2);
130  });
131  test('backgroundColor is subproperty nestingLevel 1', () => {
132    expect(formattedSchema[4].nestingLevel).toBe(1);
133  });
134  test('intentFilters is property nestingLevel 0', () => {
135    expect(formattedSchema[5].nestingLevel).toBe(0);
136  });
137  test('autoVerify is subproperty nestingLevel 1', () => {
138    expect(formattedSchema[6].nestingLevel).toBe(1);
139  });
140  test('data is subproperty nestingLevel 1', () => {
141    expect(formattedSchema[7].nestingLevel).toBe(1);
142  });
143  test('host is subproperty nestingLevel 2', () => {
144    expect(formattedSchema[8].nestingLevel).toBe(2);
145  });
146});
147
148describe('createDescription', () => {
149  test('type and description are rendered correctly', () => {
150    const intentFiltersObject = Object.entries(testSchema)[2];
151    const intentFiltersObjectValue = intentFiltersObject[1] as any;
152    const result = createDescription(intentFiltersObject);
153
154    expect(result).toBe(
155      `**(${_getType(intentFiltersObjectValue)})** - ${intentFiltersObjectValue.description}`
156    );
157  });
158
159  test('regexHuman is added correctly', () => {
160    //Note: to access this subproperty is tedious without a call to formatSchema
161    const backgroundColorObject = Object.entries(Object.values(testSchema)[1].properties!)[1];
162    const backgroundColorObjectValue = backgroundColorObject[1];
163    const result = createDescription(backgroundColorObject);
164
165    expect(result).toBe(
166      `**(${_getType(backgroundColorObjectValue)})** - ${
167        backgroundColorObjectValue.description
168      }\n\n${backgroundColorObjectValue.meta!.regexHuman}`
169    );
170  });
171});
172