docusaurus-plugin-generate-schema-docs 1.8.2 → 1.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/__snapshots__/generateEventDocs.anchor.test.js.snap +15 -3
- package/__tests__/__snapshots__/generateEventDocs.nested.test.js.snap +20 -4
- package/__tests__/__snapshots__/generateEventDocs.test.js.snap +30 -6
- package/__tests__/__snapshots__/generateEventDocs.versioned.test.js.snap +10 -2
- package/__tests__/components/ConditionalRows.test.js +28 -0
- package/__tests__/components/FoldableRows.test.js +31 -290
- package/__tests__/components/PropertyRow.test.js +216 -0
- package/__tests__/components/SchemaJsonViewer.test.js +76 -10
- package/__tests__/components/SchemaRows.test.js +62 -12
- package/__tests__/components/__snapshots__/ConnectorLines.visualRegression.test.js.snap +3 -3
- package/__tests__/generateEventDocs.test.js +3 -0
- package/__tests__/helpers/schemaToTableData.test.js +112 -0
- package/components/ConditionalRows.js +6 -3
- package/components/FoldableRows.js +9 -3
- package/components/PropertiesTable.js +2 -1
- package/components/PropertyRow.js +90 -5
- package/components/SchemaJsonViewer.js +221 -4
- package/components/SchemaRows.css +98 -7
- package/components/SchemaRows.js +11 -1
- package/generateEventDocs.js +87 -1
- package/helpers/choice-index-template.js +6 -2
- package/helpers/file-system.js +28 -0
- package/helpers/schema-doc-template.js +7 -1
- package/helpers/schemaToTableData.js +68 -7
- package/package.json +1 -1
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import '@testing-library/jest-dom';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { render, screen
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
4
|
import FoldableRows from '../../components/FoldableRows';
|
|
5
5
|
|
|
6
6
|
jest.mock('../../components/SchemaRows', () => {
|
|
7
7
|
const MockSchemaRows = (props) => (
|
|
8
|
-
// The mock needs to return a valid element to be a child of a tbody
|
|
9
|
-
// We'll use a data-testid to check for its presence.
|
|
10
8
|
<tr data-testid="schema-rows">
|
|
11
9
|
<td>{JSON.stringify(props.tableData)}</td>
|
|
12
10
|
</tr>
|
|
@@ -16,318 +14,61 @@ jest.mock('../../components/SchemaRows', () => {
|
|
|
16
14
|
});
|
|
17
15
|
|
|
18
16
|
jest.mock('@theme/Heading', () => {
|
|
19
|
-
const MockHeading = ({ as:
|
|
20
|
-
<
|
|
17
|
+
const MockHeading = ({ as: Tag = 'h4', children, className }) => (
|
|
18
|
+
<Tag className={className}>{children}</Tag>
|
|
21
19
|
);
|
|
22
20
|
MockHeading.displayName = 'MockHeading';
|
|
23
21
|
return MockHeading;
|
|
24
22
|
});
|
|
25
23
|
|
|
26
24
|
describe('FoldableRows', () => {
|
|
27
|
-
const
|
|
25
|
+
const choiceRow = {
|
|
28
26
|
type: 'choice',
|
|
29
27
|
choiceType: 'oneOf',
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
description: 'Choose one payment type.',
|
|
29
|
+
name: 'payment',
|
|
30
|
+
level: 0,
|
|
31
|
+
continuingLevels: [],
|
|
33
32
|
options: [
|
|
34
33
|
{
|
|
35
34
|
title: 'Credit Card',
|
|
36
|
-
description: '
|
|
37
|
-
rows: [{ name: '
|
|
35
|
+
description: 'Card payment.',
|
|
36
|
+
rows: [{ name: 'card_number' }],
|
|
38
37
|
},
|
|
39
38
|
{
|
|
40
39
|
title: 'PayPal',
|
|
41
|
-
description: '
|
|
40
|
+
description: 'PayPal payment.',
|
|
42
41
|
rows: [{ name: 'email' }],
|
|
43
42
|
},
|
|
44
43
|
],
|
|
45
44
|
};
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
type: 'choice',
|
|
49
|
-
choiceType: 'anyOf',
|
|
50
|
-
path: ['contact'],
|
|
51
|
-
level: 1,
|
|
52
|
-
description: 'Select any contact method:',
|
|
53
|
-
options: [
|
|
54
|
-
{
|
|
55
|
-
title: 'Email',
|
|
56
|
-
description: 'Contact via email',
|
|
57
|
-
rows: [{ name: 'email_address' }],
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
title: 'Phone',
|
|
61
|
-
description: 'Contact via phone',
|
|
62
|
-
rows: [{ name: 'phone_number' }],
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
it('renders oneOf as a radio-style accordion', () => {
|
|
68
|
-
render(
|
|
69
|
-
<table>
|
|
70
|
-
<tbody>
|
|
71
|
-
<FoldableRows row={oneOfRow} />
|
|
72
|
-
</tbody>
|
|
73
|
-
</table>,
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
const creditCardToggle = screen.getByText('Credit Card');
|
|
77
|
-
const paypalToggle = screen.getByText('PayPal');
|
|
78
|
-
|
|
79
|
-
// Initially, first option is open
|
|
80
|
-
expect(
|
|
81
|
-
screen.getByText(JSON.stringify([{ name: 'cardNumber' }])),
|
|
82
|
-
).toBeInTheDocument();
|
|
83
|
-
expect(
|
|
84
|
-
screen.queryByText(JSON.stringify([{ name: 'email' }])),
|
|
85
|
-
).not.toBeInTheDocument();
|
|
86
|
-
|
|
87
|
-
// Click the second option
|
|
88
|
-
fireEvent.click(paypalToggle);
|
|
89
|
-
|
|
90
|
-
// Now, second option should be open and first should be closed
|
|
91
|
-
expect(
|
|
92
|
-
screen.queryByText(JSON.stringify([{ name: 'cardNumber' }])),
|
|
93
|
-
).not.toBeInTheDocument();
|
|
94
|
-
expect(
|
|
95
|
-
screen.getByText(JSON.stringify([{ name: 'email' }])),
|
|
96
|
-
).toBeInTheDocument();
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('renders anyOf as a checkbox-style accordion', () => {
|
|
46
|
+
it('keeps choice headers and toggles neutral instead of zebra-striped', () => {
|
|
100
47
|
render(
|
|
101
48
|
<table>
|
|
102
49
|
<tbody>
|
|
103
|
-
<FoldableRows
|
|
50
|
+
<FoldableRows
|
|
51
|
+
row={choiceRow}
|
|
52
|
+
stripeIndex={1}
|
|
53
|
+
stripeState={{ current: 2 }}
|
|
54
|
+
/>
|
|
104
55
|
</tbody>
|
|
105
56
|
</table>,
|
|
106
57
|
);
|
|
107
58
|
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
expect(
|
|
117
|
-
|
|
118
|
-
).
|
|
119
|
-
expect(
|
|
120
|
-
|
|
121
|
-
).not.
|
|
122
|
-
|
|
123
|
-
// Click the second option
|
|
124
|
-
fireEvent.click(phoneToggle);
|
|
125
|
-
expect(
|
|
126
|
-
screen.getByText(JSON.stringify([{ name: 'email_address' }])),
|
|
127
|
-
).toBeInTheDocument();
|
|
128
|
-
expect(
|
|
129
|
-
screen.getByText(JSON.stringify([{ name: 'phone_number' }])),
|
|
130
|
-
).toBeInTheDocument();
|
|
131
|
-
|
|
132
|
-
// Click the first option again to close it
|
|
133
|
-
fireEvent.click(emailToggle);
|
|
134
|
-
expect(
|
|
135
|
-
screen.queryByText(JSON.stringify([{ name: 'email_address' }])),
|
|
136
|
-
).not.toBeInTheDocument();
|
|
137
|
-
expect(
|
|
138
|
-
screen.getByText(JSON.stringify([{ name: 'phone_number' }])),
|
|
139
|
-
).toBeInTheDocument();
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
describe('hierarchical lines feature', () => {
|
|
143
|
-
it('applies padding-left based on level using rem units', () => {
|
|
144
|
-
const rowWithLevel = {
|
|
145
|
-
type: 'choice',
|
|
146
|
-
choiceType: 'oneOf',
|
|
147
|
-
path: ['nested', 'payment'],
|
|
148
|
-
level: 2,
|
|
149
|
-
description: 'Nested choice',
|
|
150
|
-
continuingLevels: [],
|
|
151
|
-
options: [
|
|
152
|
-
{
|
|
153
|
-
title: 'Option A',
|
|
154
|
-
description: 'First option',
|
|
155
|
-
rows: [{ name: 'fieldA' }],
|
|
156
|
-
},
|
|
157
|
-
],
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const { container } = render(
|
|
161
|
-
<table>
|
|
162
|
-
<tbody>
|
|
163
|
-
<FoldableRows row={rowWithLevel} />
|
|
164
|
-
</tbody>
|
|
165
|
-
</table>,
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
169
|
-
// level 2: 2 * 1.25 + 0.5 = 3rem
|
|
170
|
-
cells.forEach((cell) => {
|
|
171
|
-
expect(cell.style.paddingLeft).toBe('3rem');
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('applies background-image for continuing ancestor lines', () => {
|
|
176
|
-
const rowWithContinuingLevels = {
|
|
177
|
-
type: 'choice',
|
|
178
|
-
choiceType: 'anyOf',
|
|
179
|
-
path: ['deeply', 'nested', 'choice'],
|
|
180
|
-
level: 2,
|
|
181
|
-
description: 'Choice with continuing lines',
|
|
182
|
-
continuingLevels: [0], // Ancestor at level 0 has more siblings
|
|
183
|
-
options: [
|
|
184
|
-
{
|
|
185
|
-
title: 'Option A',
|
|
186
|
-
rows: [{ name: 'fieldA' }],
|
|
187
|
-
},
|
|
188
|
-
],
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
const { container } = render(
|
|
192
|
-
<table>
|
|
193
|
-
<tbody>
|
|
194
|
-
<FoldableRows row={rowWithContinuingLevels} />
|
|
195
|
-
</tbody>
|
|
196
|
-
</table>,
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
200
|
-
cells.forEach((cell) => {
|
|
201
|
-
expect(cell.style.backgroundImage).toContain('linear-gradient');
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it('applies background-image for immediate parent level connection', () => {
|
|
206
|
-
const rowWithParentLevel = {
|
|
207
|
-
type: 'choice',
|
|
208
|
-
choiceType: 'oneOf',
|
|
209
|
-
path: ['parent', 'choice'],
|
|
210
|
-
level: 1,
|
|
211
|
-
description: 'Choice at level 1',
|
|
212
|
-
continuingLevels: [],
|
|
213
|
-
options: [
|
|
214
|
-
{
|
|
215
|
-
title: 'Option A',
|
|
216
|
-
rows: [{ name: 'fieldA' }],
|
|
217
|
-
},
|
|
218
|
-
],
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
const { container } = render(
|
|
222
|
-
<table>
|
|
223
|
-
<tbody>
|
|
224
|
-
<FoldableRows row={rowWithParentLevel} />
|
|
225
|
-
</tbody>
|
|
226
|
-
</table>,
|
|
227
|
-
);
|
|
228
|
-
|
|
229
|
-
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
230
|
-
// Should have a line at parent level (level 0) position
|
|
231
|
-
cells.forEach((cell) => {
|
|
232
|
-
expect(cell.style.backgroundImage).toContain('linear-gradient');
|
|
233
|
-
});
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
it('has a bracket gradient for root level choices with no continuing levels', () => {
|
|
237
|
-
const rootLevelRow = {
|
|
238
|
-
type: 'choice',
|
|
239
|
-
choiceType: 'oneOf',
|
|
240
|
-
path: ['user_id'],
|
|
241
|
-
level: 0,
|
|
242
|
-
description: 'Root level choice',
|
|
243
|
-
continuingLevels: [],
|
|
244
|
-
groupBrackets: [],
|
|
245
|
-
options: [
|
|
246
|
-
{
|
|
247
|
-
title: 'Option A',
|
|
248
|
-
rows: [{ name: 'fieldA' }],
|
|
249
|
-
},
|
|
250
|
-
],
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
const { container } = render(
|
|
254
|
-
<table>
|
|
255
|
-
<tbody>
|
|
256
|
-
<FoldableRows row={rootLevelRow} />
|
|
257
|
-
</tbody>
|
|
258
|
-
</table>,
|
|
259
|
-
);
|
|
260
|
-
|
|
261
|
-
// Root-level choice rows get a bracket gradient even without tree-line continuing levels
|
|
262
|
-
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
263
|
-
cells.forEach((cell) => {
|
|
264
|
-
expect(cell.style.backgroundImage).toContain('linear-gradient');
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it('combines multiple continuing levels in background-image', () => {
|
|
269
|
-
const rowWithMultipleLevels = {
|
|
270
|
-
type: 'choice',
|
|
271
|
-
choiceType: 'anyOf',
|
|
272
|
-
path: ['a', 'b', 'c', 'choice'],
|
|
273
|
-
level: 3,
|
|
274
|
-
description: 'Deeply nested choice',
|
|
275
|
-
continuingLevels: [0, 1], // Multiple ancestors have siblings
|
|
276
|
-
options: [
|
|
277
|
-
{
|
|
278
|
-
title: 'Option A',
|
|
279
|
-
rows: [{ name: 'fieldA' }],
|
|
280
|
-
},
|
|
281
|
-
],
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
const { container } = render(
|
|
285
|
-
<table>
|
|
286
|
-
<tbody>
|
|
287
|
-
<FoldableRows row={rowWithMultipleLevels} />
|
|
288
|
-
</tbody>
|
|
289
|
-
</table>,
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
293
|
-
cells.forEach((cell) => {
|
|
294
|
-
const bgImage = cell.style.backgroundImage;
|
|
295
|
-
// colSpan=5 rows only have bracket lines (right side), not tree lines (left side).
|
|
296
|
-
// Should have exactly 1 bracket gradient.
|
|
297
|
-
const gradientCount = (bgImage.match(/linear-gradient/g) || []).length;
|
|
298
|
-
expect(gradientCount).toBeGreaterThanOrEqual(1);
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
it('applies correct indentation for level 0', () => {
|
|
303
|
-
const levelZeroRow = {
|
|
304
|
-
type: 'choice',
|
|
305
|
-
choiceType: 'oneOf',
|
|
306
|
-
path: ['user_id'],
|
|
307
|
-
level: 0,
|
|
308
|
-
description: 'Level 0 choice',
|
|
309
|
-
continuingLevels: [],
|
|
310
|
-
options: [
|
|
311
|
-
{
|
|
312
|
-
title: 'Option A',
|
|
313
|
-
rows: [{ name: 'fieldA' }],
|
|
314
|
-
},
|
|
315
|
-
],
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
const { container } = render(
|
|
319
|
-
<table>
|
|
320
|
-
<tbody>
|
|
321
|
-
<FoldableRows row={levelZeroRow} />
|
|
322
|
-
</tbody>
|
|
323
|
-
</table>,
|
|
324
|
-
);
|
|
325
|
-
|
|
326
|
-
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
327
|
-
// level 0: 0 * 1.25 + 0.5 = 0.5rem
|
|
328
|
-
cells.forEach((cell) => {
|
|
329
|
-
expect(cell.style.paddingLeft).toBe('0.5rem');
|
|
330
|
-
});
|
|
331
|
-
});
|
|
59
|
+
const headerRow = screen
|
|
60
|
+
.getByText((content) =>
|
|
61
|
+
content.includes('Select one of the following options:'),
|
|
62
|
+
)
|
|
63
|
+
.closest('tr');
|
|
64
|
+
const firstToggleRow = screen.getByText('Credit Card').closest('tr');
|
|
65
|
+
const secondToggleRow = screen.getByText('PayPal').closest('tr');
|
|
66
|
+
|
|
67
|
+
expect(headerRow).toHaveClass('schema-row--control');
|
|
68
|
+
expect(firstToggleRow).toHaveClass('schema-row--control');
|
|
69
|
+
expect(secondToggleRow).toHaveClass('schema-row--control');
|
|
70
|
+
expect(headerRow).not.toHaveClass('schema-row--zebra-even');
|
|
71
|
+
expect(firstToggleRow).not.toHaveClass('schema-row--zebra-even');
|
|
72
|
+
expect(secondToggleRow).not.toHaveClass('schema-row--zebra-even');
|
|
332
73
|
});
|
|
333
74
|
});
|
|
@@ -1,9 +1,35 @@
|
|
|
1
1
|
import '@testing-library/jest-dom';
|
|
2
|
+
import fs from 'fs';
|
|
2
3
|
import React from 'react';
|
|
4
|
+
import path from 'path';
|
|
3
5
|
import { render } from '@testing-library/react';
|
|
4
6
|
import PropertyRow from '../../components/PropertyRow';
|
|
5
7
|
|
|
6
8
|
describe('PropertyRow', () => {
|
|
9
|
+
it('does not suppress first-column separators for nested tree cells in CSS', () => {
|
|
10
|
+
const cssPath = path.join(__dirname, '../../components/SchemaRows.css');
|
|
11
|
+
const css = fs.readFileSync(cssPath, 'utf8');
|
|
12
|
+
|
|
13
|
+
expect(css).not.toContain(
|
|
14
|
+
'.schema-table tbody tr + tr td.property-cell--tree',
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('removes the extra left border from full-width schema rows in CSS', () => {
|
|
19
|
+
const cssPath = path.join(__dirname, '../../components/SchemaRows.css');
|
|
20
|
+
const css = fs.readFileSync(cssPath, 'utf8');
|
|
21
|
+
|
|
22
|
+
expect(css).toContain(".schema-table td[colspan='5']");
|
|
23
|
+
expect(css).toContain('border-left: none;');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('defines an explicit neutral class for control rows in CSS', () => {
|
|
27
|
+
const cssPath = path.join(__dirname, '../../components/SchemaRows.css');
|
|
28
|
+
const css = fs.readFileSync(cssPath, 'utf8');
|
|
29
|
+
|
|
30
|
+
expect(css).toContain('.schema-row--control');
|
|
31
|
+
expect(css).toContain('background-color: transparent');
|
|
32
|
+
});
|
|
7
33
|
it('renders a basic property', () => {
|
|
8
34
|
const row = {
|
|
9
35
|
name: 'name',
|
|
@@ -51,10 +77,40 @@ describe('PropertyRow', () => {
|
|
|
51
77
|
);
|
|
52
78
|
|
|
53
79
|
expect(container.querySelector('.required-row')).toBeInTheDocument();
|
|
80
|
+
expect(
|
|
81
|
+
container.querySelector('.property-cell--required'),
|
|
82
|
+
).toBeInTheDocument();
|
|
54
83
|
expect(container.querySelector('.required')).toBeInTheDocument();
|
|
55
84
|
expect(getByText('required')).toBeInTheDocument();
|
|
56
85
|
});
|
|
57
86
|
|
|
87
|
+
it('applies the same zebra class to the main row and continuation rows', () => {
|
|
88
|
+
const row = {
|
|
89
|
+
name: 'event',
|
|
90
|
+
level: 0,
|
|
91
|
+
required: true,
|
|
92
|
+
propertyType: 'string',
|
|
93
|
+
description: 'Event name.',
|
|
94
|
+
examples: ['purchase'],
|
|
95
|
+
constraints: ['required', 'const: "purchase"'],
|
|
96
|
+
path: ['event'],
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const { container } = render(
|
|
100
|
+
<table>
|
|
101
|
+
<tbody>
|
|
102
|
+
<PropertyRow row={row} stripeIndex={1} />
|
|
103
|
+
</tbody>
|
|
104
|
+
</table>,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const rows = container.querySelectorAll('tbody tr');
|
|
108
|
+
expect(rows).toHaveLength(2);
|
|
109
|
+
expect(rows[0]).toHaveClass('schema-row--zebra-odd');
|
|
110
|
+
expect(rows[1]).toHaveClass('schema-row--zebra-odd');
|
|
111
|
+
expect(rows[0]).not.toHaveClass('schema-row--zebra-even');
|
|
112
|
+
});
|
|
113
|
+
|
|
58
114
|
it('renders multiple constraints', () => {
|
|
59
115
|
const row = {
|
|
60
116
|
name: 'name',
|
|
@@ -156,6 +212,107 @@ describe('PropertyRow', () => {
|
|
|
156
212
|
expect(cells[2].innerHTML).toBe('');
|
|
157
213
|
});
|
|
158
214
|
|
|
215
|
+
it('renders additionalProperties as a schema keyword row and keeps its connector open', () => {
|
|
216
|
+
const row = {
|
|
217
|
+
name: 'additionalProperties',
|
|
218
|
+
level: 1,
|
|
219
|
+
required: false,
|
|
220
|
+
propertyType: 'string',
|
|
221
|
+
description: 'Catch-all values.',
|
|
222
|
+
examples: ['beta_tester'],
|
|
223
|
+
constraints: [],
|
|
224
|
+
path: ['user_properties', 'additionalProperties'],
|
|
225
|
+
hasChildren: false,
|
|
226
|
+
containerType: null,
|
|
227
|
+
continuingLevels: [],
|
|
228
|
+
isSchemaKeywordRow: true,
|
|
229
|
+
keepConnectorOpen: false,
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const { container, getByText } = render(
|
|
233
|
+
<table>
|
|
234
|
+
<tbody>
|
|
235
|
+
<PropertyRow row={row} isLastInGroup={true} />
|
|
236
|
+
</tbody>
|
|
237
|
+
</table>,
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
const keyword = getByText('additionalProperties');
|
|
241
|
+
expect(keyword).toBeInTheDocument();
|
|
242
|
+
expect(container.querySelector('.property-keyword')).toBeInTheDocument();
|
|
243
|
+
expect(
|
|
244
|
+
container.querySelector('.property-cell--keyword'),
|
|
245
|
+
).toBeInTheDocument();
|
|
246
|
+
expect(container.querySelector('.property-cell--tree')).toBeInTheDocument();
|
|
247
|
+
expect(
|
|
248
|
+
container.querySelector('.property-name--keyword'),
|
|
249
|
+
).toBeInTheDocument();
|
|
250
|
+
expect(keyword).not.toHaveAttribute('title');
|
|
251
|
+
expect(keyword).toHaveAttribute(
|
|
252
|
+
'aria-describedby',
|
|
253
|
+
'schema-keyword-help-additionalProperties',
|
|
254
|
+
);
|
|
255
|
+
expect(
|
|
256
|
+
container.querySelector('.property-keyword-tooltip'),
|
|
257
|
+
).toBeInTheDocument();
|
|
258
|
+
expect(
|
|
259
|
+
container.querySelector('#schema-keyword-help-additionalProperties'),
|
|
260
|
+
).toBeInTheDocument();
|
|
261
|
+
expect(
|
|
262
|
+
getByText(
|
|
263
|
+
'Controls properties not listed in properties and not matched by patternProperties.',
|
|
264
|
+
),
|
|
265
|
+
).toBeInTheDocument();
|
|
266
|
+
expect(container.querySelector('.is-last')).toBeInTheDocument();
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('renders patternProperties rows as schema keywords with tooltip help', () => {
|
|
270
|
+
const row = {
|
|
271
|
+
name: 'patternProperties /^custom_/',
|
|
272
|
+
level: 1,
|
|
273
|
+
required: false,
|
|
274
|
+
propertyType: 'number',
|
|
275
|
+
description: 'Numeric custom attribute values.',
|
|
276
|
+
examples: [5],
|
|
277
|
+
constraints: ['minimum: 0'],
|
|
278
|
+
path: ['attributes', 'patternProperties /^custom_/'],
|
|
279
|
+
hasChildren: false,
|
|
280
|
+
containerType: null,
|
|
281
|
+
continuingLevels: [],
|
|
282
|
+
isSchemaKeywordRow: true,
|
|
283
|
+
keepConnectorOpen: false,
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const { container, getByText } = render(
|
|
287
|
+
<table>
|
|
288
|
+
<tbody>
|
|
289
|
+
<PropertyRow row={row} isLastInGroup={true} />
|
|
290
|
+
</tbody>
|
|
291
|
+
</table>,
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
const keyword = getByText('patternProperties');
|
|
295
|
+
expect(getByText('/^custom_/')).toBeInTheDocument();
|
|
296
|
+
expect(
|
|
297
|
+
container.querySelector('.property-keyword-pattern'),
|
|
298
|
+
).toBeInTheDocument();
|
|
299
|
+
expect(keyword).toHaveAttribute(
|
|
300
|
+
'aria-describedby',
|
|
301
|
+
'schema-keyword-help-patternProperties /^custom_/',
|
|
302
|
+
);
|
|
303
|
+
expect(
|
|
304
|
+
container.ownerDocument.getElementById(
|
|
305
|
+
'schema-keyword-help-patternProperties /^custom_/',
|
|
306
|
+
),
|
|
307
|
+
).toBeInTheDocument();
|
|
308
|
+
expect(
|
|
309
|
+
getByText(
|
|
310
|
+
'Applies the subschema to property names that match the given regular expression.',
|
|
311
|
+
),
|
|
312
|
+
).toBeInTheDocument();
|
|
313
|
+
expect(container.querySelector('.is-last')).toBeInTheDocument();
|
|
314
|
+
});
|
|
315
|
+
|
|
159
316
|
describe('hierarchical lines feature', () => {
|
|
160
317
|
it('renders {} symbol for object containers', () => {
|
|
161
318
|
const row = {
|
|
@@ -368,6 +525,65 @@ describe('PropertyRow', () => {
|
|
|
368
525
|
);
|
|
369
526
|
|
|
370
527
|
expect(container.querySelector('.level-2')).toBeInTheDocument();
|
|
528
|
+
expect(
|
|
529
|
+
container.querySelector('.property-cell--tree'),
|
|
530
|
+
).toBeInTheDocument();
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
it('does not add a separator-suppression class to nested tree cells', () => {
|
|
534
|
+
const row = {
|
|
535
|
+
name: 'nested_item',
|
|
536
|
+
level: 2,
|
|
537
|
+
required: false,
|
|
538
|
+
propertyType: 'string',
|
|
539
|
+
description: '',
|
|
540
|
+
example: '',
|
|
541
|
+
constraints: [],
|
|
542
|
+
path: ['parent', 'nested_item'],
|
|
543
|
+
hasChildren: false,
|
|
544
|
+
containerType: null,
|
|
545
|
+
continuingLevels: [],
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
const { container } = render(
|
|
549
|
+
<table>
|
|
550
|
+
<tbody>
|
|
551
|
+
<PropertyRow row={row} />
|
|
552
|
+
</tbody>
|
|
553
|
+
</table>,
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
expect(
|
|
557
|
+
container.querySelector('.property-cell--tree-no-separator'),
|
|
558
|
+
).not.toBeInTheDocument();
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
it('does not mark root-level cells as tree cells', () => {
|
|
562
|
+
const row = {
|
|
563
|
+
name: 'root_item',
|
|
564
|
+
level: 0,
|
|
565
|
+
required: false,
|
|
566
|
+
propertyType: 'string',
|
|
567
|
+
description: '',
|
|
568
|
+
example: '',
|
|
569
|
+
constraints: [],
|
|
570
|
+
path: ['root_item'],
|
|
571
|
+
hasChildren: false,
|
|
572
|
+
containerType: null,
|
|
573
|
+
continuingLevels: [],
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
const { container } = render(
|
|
577
|
+
<table>
|
|
578
|
+
<tbody>
|
|
579
|
+
<PropertyRow row={row} />
|
|
580
|
+
</tbody>
|
|
581
|
+
</table>,
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
expect(
|
|
585
|
+
container.querySelector('.property-cell--tree'),
|
|
586
|
+
).not.toBeInTheDocument();
|
|
371
587
|
});
|
|
372
588
|
|
|
373
589
|
it('applies padding-left based on level using rem units', () => {
|