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