docusaurus-plugin-generate-schema-docs 1.6.0 → 1.7.1
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/README.md +17 -0
- package/__tests__/__fixtures__/static/schemas/battle-test-event.json +771 -0
- package/__tests__/__fixtures__/static/schemas/conditional-event.json +52 -0
- package/__tests__/__fixtures__/static/schemas/nested-conditional-event.json +50 -0
- package/__tests__/components/ConditionalRows.test.js +150 -0
- package/__tests__/components/ConnectorLines.visualRegression.test.js +93 -0
- package/__tests__/components/FoldableRows.test.js +7 -4
- package/__tests__/components/SchemaRows.test.js +31 -0
- package/__tests__/components/__snapshots__/ConnectorLines.visualRegression.test.js.snap +7 -0
- package/__tests__/generateEventDocs.partials.test.js +134 -0
- package/__tests__/helpers/buildExampleFromSchema.test.js +49 -0
- package/__tests__/helpers/schemaToExamples.test.js +75 -0
- package/__tests__/helpers/schemaToTableData.battleTest.test.js +704 -0
- package/__tests__/helpers/schemaToTableData.hierarchicalLines.test.js +190 -7
- package/__tests__/helpers/schemaToTableData.test.js +263 -2
- package/__tests__/helpers/validator.test.js +6 -6
- package/__tests__/syncGtm.test.js +346 -0
- package/components/ConditionalRows.js +156 -0
- package/components/FoldableRows.js +88 -61
- package/components/PropertiesTable.js +1 -1
- package/components/PropertyRow.js +24 -8
- package/components/SchemaRows.css +115 -0
- package/components/SchemaRows.js +31 -4
- package/generateEventDocs.js +41 -34
- package/helpers/buildExampleFromSchema.js +11 -0
- package/helpers/continuingLinesStyle.js +169 -0
- package/helpers/schema-doc-template.js +2 -5
- package/helpers/schemaToExamples.js +75 -2
- package/helpers/schemaToTableData.js +252 -26
- package/helpers/update-schema-ids.js +3 -3
- package/helpers/validator.js +7 -19
- package/index.js +34 -0
- package/package.json +1 -1
- package/scripts/sync-gtm.js +397 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://tracking-docs-demo.buchert.digital/schemas/events/conditional-event.json",
|
|
4
|
+
"title": "Conditional Event",
|
|
5
|
+
"description": "An event with conditional properties based on country.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"event": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"const": "form_submit"
|
|
11
|
+
},
|
|
12
|
+
"country": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "The user's country.",
|
|
15
|
+
"enum": ["US", "CA"],
|
|
16
|
+
"examples": ["US"]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"required": ["event", "country"],
|
|
20
|
+
"if": {
|
|
21
|
+
"properties": {
|
|
22
|
+
"country": { "const": "US" }
|
|
23
|
+
},
|
|
24
|
+
"required": ["country"]
|
|
25
|
+
},
|
|
26
|
+
"then": {
|
|
27
|
+
"properties": {
|
|
28
|
+
"postal_code": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"description": "US ZIP code format.",
|
|
31
|
+
"pattern": "[0-9]{5}",
|
|
32
|
+
"examples": ["90210"]
|
|
33
|
+
},
|
|
34
|
+
"state": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"description": "US state abbreviation.",
|
|
37
|
+
"examples": ["CA"]
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"required": ["postal_code"]
|
|
41
|
+
},
|
|
42
|
+
"else": {
|
|
43
|
+
"properties": {
|
|
44
|
+
"postal_code": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "Canadian postal code format.",
|
|
47
|
+
"pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]",
|
|
48
|
+
"examples": ["K1A 0B1"]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://tracking-docs-demo.buchert.digital/schemas/events/nested-conditional-event.json",
|
|
4
|
+
"title": "Nested Conditional Event",
|
|
5
|
+
"description": "An event with conditional properties nested inside a property.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"event": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"const": "order_placed"
|
|
11
|
+
},
|
|
12
|
+
"shipping": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"description": "Shipping details.",
|
|
15
|
+
"properties": {
|
|
16
|
+
"method": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "The shipping method.",
|
|
19
|
+
"examples": ["express"]
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"required": ["method"],
|
|
23
|
+
"if": {
|
|
24
|
+
"properties": {
|
|
25
|
+
"method": { "const": "express" }
|
|
26
|
+
},
|
|
27
|
+
"required": ["method"]
|
|
28
|
+
},
|
|
29
|
+
"then": {
|
|
30
|
+
"properties": {
|
|
31
|
+
"priority_level": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "Express priority level.",
|
|
34
|
+
"examples": ["high"]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"else": {
|
|
39
|
+
"properties": {
|
|
40
|
+
"estimated_days": {
|
|
41
|
+
"type": "integer",
|
|
42
|
+
"description": "Estimated delivery days.",
|
|
43
|
+
"examples": [5]
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"required": ["event", "shipping"]
|
|
50
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
4
|
+
import ConditionalRows from '../../components/ConditionalRows';
|
|
5
|
+
|
|
6
|
+
jest.mock('../../components/SchemaRows', () => {
|
|
7
|
+
const MockSchemaRows = (props) => (
|
|
8
|
+
<tr data-testid="schema-rows">
|
|
9
|
+
<td>{JSON.stringify(props.tableData)}</td>
|
|
10
|
+
</tr>
|
|
11
|
+
);
|
|
12
|
+
MockSchemaRows.displayName = 'MockSchemaRows';
|
|
13
|
+
return MockSchemaRows;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('ConditionalRows', () => {
|
|
17
|
+
const conditionalRow = {
|
|
18
|
+
type: 'conditional',
|
|
19
|
+
path: ['if/then/else'],
|
|
20
|
+
level: 0,
|
|
21
|
+
continuingLevels: [],
|
|
22
|
+
condition: {
|
|
23
|
+
title: 'If',
|
|
24
|
+
description: 'When country is US',
|
|
25
|
+
rows: [{ name: 'country', isCondition: true }],
|
|
26
|
+
},
|
|
27
|
+
branches: [
|
|
28
|
+
{
|
|
29
|
+
title: 'Then',
|
|
30
|
+
description: 'US-specific fields',
|
|
31
|
+
rows: [{ name: 'postal_code' }],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
title: 'Else',
|
|
35
|
+
description: 'Non-US fields',
|
|
36
|
+
rows: [{ name: 'province' }],
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
it('renders condition (if) rows always visible', () => {
|
|
42
|
+
render(
|
|
43
|
+
<table>
|
|
44
|
+
<tbody>
|
|
45
|
+
<ConditionalRows row={conditionalRow} />
|
|
46
|
+
</tbody>
|
|
47
|
+
</table>,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
expect(screen.getByText('If')).toBeInTheDocument();
|
|
51
|
+
expect(
|
|
52
|
+
screen.getByText(
|
|
53
|
+
JSON.stringify([{ name: 'country', isCondition: true }]),
|
|
54
|
+
),
|
|
55
|
+
).toBeInTheDocument();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('shows Then branch by default', () => {
|
|
59
|
+
render(
|
|
60
|
+
<table>
|
|
61
|
+
<tbody>
|
|
62
|
+
<ConditionalRows row={conditionalRow} />
|
|
63
|
+
</tbody>
|
|
64
|
+
</table>,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
expect(
|
|
68
|
+
screen.getByText(JSON.stringify([{ name: 'postal_code' }])),
|
|
69
|
+
).toBeInTheDocument();
|
|
70
|
+
expect(
|
|
71
|
+
screen.queryByText(JSON.stringify([{ name: 'province' }])),
|
|
72
|
+
).not.toBeInTheDocument();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('switches to Else branch when clicked', () => {
|
|
76
|
+
render(
|
|
77
|
+
<table>
|
|
78
|
+
<tbody>
|
|
79
|
+
<ConditionalRows row={conditionalRow} />
|
|
80
|
+
</tbody>
|
|
81
|
+
</table>,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
// Click the Else toggle
|
|
85
|
+
fireEvent.click(screen.getByText('Else'));
|
|
86
|
+
|
|
87
|
+
// Now Else should be visible and Then should be hidden
|
|
88
|
+
expect(
|
|
89
|
+
screen.queryByText(JSON.stringify([{ name: 'postal_code' }])),
|
|
90
|
+
).not.toBeInTheDocument();
|
|
91
|
+
expect(
|
|
92
|
+
screen.getByText(JSON.stringify([{ name: 'province' }])),
|
|
93
|
+
).toBeInTheDocument();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('renders condition description when present', () => {
|
|
97
|
+
render(
|
|
98
|
+
<table>
|
|
99
|
+
<tbody>
|
|
100
|
+
<ConditionalRows row={conditionalRow} />
|
|
101
|
+
</tbody>
|
|
102
|
+
</table>,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
expect(screen.getByText('When country is US')).toBeInTheDocument();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('applies correct indentation for nested levels', () => {
|
|
109
|
+
const nestedRow = {
|
|
110
|
+
...conditionalRow,
|
|
111
|
+
level: 2,
|
|
112
|
+
continuingLevels: [0],
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const { container } = render(
|
|
116
|
+
<table>
|
|
117
|
+
<tbody>
|
|
118
|
+
<ConditionalRows row={nestedRow} />
|
|
119
|
+
</tbody>
|
|
120
|
+
</table>,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
124
|
+
// level 2: 2 * 1.25 + 0.5 = 3rem
|
|
125
|
+
cells.forEach((cell) => {
|
|
126
|
+
expect(cell.style.paddingLeft).toBe('3rem');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('handles conditional with only Then branch (no Else)', () => {
|
|
131
|
+
const rowWithoutElse = {
|
|
132
|
+
...conditionalRow,
|
|
133
|
+
branches: [conditionalRow.branches[0]],
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
render(
|
|
137
|
+
<table>
|
|
138
|
+
<tbody>
|
|
139
|
+
<ConditionalRows row={rowWithoutElse} />
|
|
140
|
+
</tbody>
|
|
141
|
+
</table>,
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
expect(screen.getByText('Then')).toBeInTheDocument();
|
|
145
|
+
expect(screen.queryByText('Else')).not.toBeInTheDocument();
|
|
146
|
+
expect(
|
|
147
|
+
screen.getByText(JSON.stringify([{ name: 'postal_code' }])),
|
|
148
|
+
).toBeInTheDocument();
|
|
149
|
+
});
|
|
150
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
+
import FoldableRows from '../../components/FoldableRows';
|
|
5
|
+
import ConditionalRows from '../../components/ConditionalRows';
|
|
6
|
+
import { schemaToTableData } from '../../helpers/schemaToTableData';
|
|
7
|
+
import battleTestSchema from '../__fixtures__/static/schemas/battle-test-event.json';
|
|
8
|
+
|
|
9
|
+
const renderInTable = (ui) =>
|
|
10
|
+
render(
|
|
11
|
+
<table>
|
|
12
|
+
<tbody>{ui}</tbody>
|
|
13
|
+
</table>,
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const getPropertyCellByName = (container, name) => {
|
|
17
|
+
const strongEls = Array.from(
|
|
18
|
+
container.querySelectorAll('span.property-name > strong'),
|
|
19
|
+
);
|
|
20
|
+
const strong = strongEls.find((el) => el.textContent === name);
|
|
21
|
+
return strong?.closest('td');
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
describe('connector lines visual regressions', () => {
|
|
25
|
+
const rows = schemaToTableData(battleTestSchema);
|
|
26
|
+
|
|
27
|
+
it('keeps user_id option row open when user conditional follows', () => {
|
|
28
|
+
const userIdChoice = rows.find(
|
|
29
|
+
(row) => row.type === 'choice' && row.name === 'user_id',
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const { container } = renderInTable(<FoldableRows row={userIdChoice} />);
|
|
33
|
+
fireEvent.click(screen.getByText('Integer ID'));
|
|
34
|
+
|
|
35
|
+
const userIdCell = getPropertyCellByName(container, 'user_id');
|
|
36
|
+
expect(userIdCell).toBeInTheDocument();
|
|
37
|
+
expect(userIdCell).not.toHaveClass('is-last');
|
|
38
|
+
expect(userIdCell.outerHTML).toMatchSnapshot();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('keeps wallet_provider option row open when wallet_email follows', () => {
|
|
42
|
+
const paymentChoice = rows.find(
|
|
43
|
+
(row) =>
|
|
44
|
+
row.type === 'choice' &&
|
|
45
|
+
row.path[0] === 'payment' &&
|
|
46
|
+
row.choiceType === 'anyOf',
|
|
47
|
+
);
|
|
48
|
+
const digitalWallet = paymentChoice.options.find(
|
|
49
|
+
(option) => option.title === 'Digital Wallet',
|
|
50
|
+
);
|
|
51
|
+
const walletProviderChoice = digitalWallet.rows.find(
|
|
52
|
+
(row) => row.type === 'choice' && row.name === 'wallet_provider',
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const { container } = renderInTable(
|
|
56
|
+
<FoldableRows row={walletProviderChoice} />,
|
|
57
|
+
);
|
|
58
|
+
fireEvent.click(screen.getByText('Custom Provider'));
|
|
59
|
+
|
|
60
|
+
const walletProviderCell = getPropertyCellByName(
|
|
61
|
+
container,
|
|
62
|
+
'wallet_provider',
|
|
63
|
+
);
|
|
64
|
+
expect(walletProviderCell).toBeInTheDocument();
|
|
65
|
+
expect(walletProviderCell).not.toHaveClass('is-last');
|
|
66
|
+
expect(walletProviderCell.outerHTML).toMatchSnapshot();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('keeps cvv row open when payment choice has following options', () => {
|
|
70
|
+
const paymentChoice = rows.find(
|
|
71
|
+
(row) =>
|
|
72
|
+
row.type === 'choice' &&
|
|
73
|
+
row.path[0] === 'payment' &&
|
|
74
|
+
row.choiceType === 'anyOf',
|
|
75
|
+
);
|
|
76
|
+
const creditCard = paymentChoice.options.find(
|
|
77
|
+
(option) => option.title === 'Credit Card',
|
|
78
|
+
);
|
|
79
|
+
const cardConditional = creditCard.rows.find(
|
|
80
|
+
(row) => row.type === 'conditional',
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const { container } = renderInTable(
|
|
84
|
+
<ConditionalRows row={cardConditional} />,
|
|
85
|
+
);
|
|
86
|
+
fireEvent.click(screen.getByText('Else'));
|
|
87
|
+
|
|
88
|
+
const cvvCell = getPropertyCellByName(container, 'cvv');
|
|
89
|
+
expect(cvvCell).toBeInTheDocument();
|
|
90
|
+
expect(cvvCell).not.toHaveClass('is-last');
|
|
91
|
+
expect(cvvCell.outerHTML).toMatchSnapshot();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -233,7 +233,7 @@ describe('FoldableRows', () => {
|
|
|
233
233
|
});
|
|
234
234
|
});
|
|
235
235
|
|
|
236
|
-
it('has
|
|
236
|
+
it('has a bracket gradient for root level choices with no continuing levels', () => {
|
|
237
237
|
const rootLevelRow = {
|
|
238
238
|
type: 'choice',
|
|
239
239
|
choiceType: 'oneOf',
|
|
@@ -241,6 +241,7 @@ describe('FoldableRows', () => {
|
|
|
241
241
|
level: 0,
|
|
242
242
|
description: 'Root level choice',
|
|
243
243
|
continuingLevels: [],
|
|
244
|
+
groupBrackets: [],
|
|
244
245
|
options: [
|
|
245
246
|
{
|
|
246
247
|
title: 'Option A',
|
|
@@ -257,9 +258,10 @@ describe('FoldableRows', () => {
|
|
|
257
258
|
</table>,
|
|
258
259
|
);
|
|
259
260
|
|
|
261
|
+
// Root-level choice rows get a bracket gradient even without tree-line continuing levels
|
|
260
262
|
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
261
263
|
cells.forEach((cell) => {
|
|
262
|
-
expect(cell.style.backgroundImage).
|
|
264
|
+
expect(cell.style.backgroundImage).toContain('linear-gradient');
|
|
263
265
|
});
|
|
264
266
|
});
|
|
265
267
|
|
|
@@ -290,9 +292,10 @@ describe('FoldableRows', () => {
|
|
|
290
292
|
const cells = container.querySelectorAll('td[colspan="5"]');
|
|
291
293
|
cells.forEach((cell) => {
|
|
292
294
|
const bgImage = cell.style.backgroundImage;
|
|
293
|
-
//
|
|
295
|
+
// colSpan=5 rows only have bracket lines (right side), not tree lines (left side).
|
|
296
|
+
// Should have exactly 1 bracket gradient.
|
|
294
297
|
const gradientCount = (bgImage.match(/linear-gradient/g) || []).length;
|
|
295
|
-
expect(gradientCount).toBeGreaterThanOrEqual(
|
|
298
|
+
expect(gradientCount).toBeGreaterThanOrEqual(1);
|
|
296
299
|
});
|
|
297
300
|
});
|
|
298
301
|
|
|
@@ -24,6 +24,16 @@ jest.mock('../../components/FoldableRows', () => {
|
|
|
24
24
|
return MockFoldableRows;
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
+
jest.mock('../../components/ConditionalRows', () => {
|
|
28
|
+
const MockConditionalRows = (props) => (
|
|
29
|
+
<tr>
|
|
30
|
+
<td>Mocked ConditionalRows: {props.row.condition.title}</td>
|
|
31
|
+
</tr>
|
|
32
|
+
);
|
|
33
|
+
MockConditionalRows.displayName = 'MockConditionalRows';
|
|
34
|
+
return MockConditionalRows;
|
|
35
|
+
});
|
|
36
|
+
|
|
27
37
|
describe('SchemaRows', () => {
|
|
28
38
|
it('renders a PropertyRow for each property type item in tableData', () => {
|
|
29
39
|
const tableData = [
|
|
@@ -107,4 +117,25 @@ describe('SchemaRows', () => {
|
|
|
107
117
|
expect(getByText('Mocked FoldableRows: anyOf')).toBeInTheDocument();
|
|
108
118
|
expect(getByText('Mocked PropertyRow: prop2')).toBeInTheDocument();
|
|
109
119
|
});
|
|
120
|
+
|
|
121
|
+
it('renders a ConditionalRows for conditional type items in tableData', () => {
|
|
122
|
+
const tableData = [
|
|
123
|
+
{
|
|
124
|
+
type: 'conditional',
|
|
125
|
+
path: ['if/then/else'],
|
|
126
|
+
condition: { title: 'If', rows: [] },
|
|
127
|
+
branches: [],
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
const { getByText } = render(
|
|
132
|
+
<table>
|
|
133
|
+
<tbody>
|
|
134
|
+
<SchemaRows tableData={tableData} />
|
|
135
|
+
</tbody>
|
|
136
|
+
</table>,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
expect(getByText('Mocked ConditionalRows: If')).toBeInTheDocument();
|
|
140
|
+
});
|
|
110
141
|
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
|
2
|
+
|
|
3
|
+
exports[`connector lines visual regressions keeps cvv row open when payment choice has following options 1`] = `"<td rowspan="1" style="padding-left: 1.75rem;" class="level-1"><span class="property-name"><strong>cvv</strong></span></td>"`;
|
|
4
|
+
|
|
5
|
+
exports[`connector lines visual regressions keeps user_id option row open when user conditional follows 1`] = `"<td rowspan="1" style="padding-left: 1.75rem;" class="level-1"><span class="property-name"><strong>user_id</strong></span></td>"`;
|
|
6
|
+
|
|
7
|
+
exports[`connector lines visual regressions keeps wallet_provider option row open when wallet_email follows 1`] = `"<td rowspan="2" style="padding-left: 1.75rem;" class="level-1"><span class="property-name"><strong>wallet_provider</strong></span></td>"`;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment node
|
|
3
|
+
*
|
|
4
|
+
* Tests that top and bottom partials are correctly injected into generated MDX
|
|
5
|
+
* when matching partial files exist in the partials directory, and that the
|
|
6
|
+
* generated import paths use the event name (not the component prefix).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import generateEventDocs from '../generateEventDocs';
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
|
|
13
|
+
jest.mock('fs', () => {
|
|
14
|
+
const memfs = require('memfs');
|
|
15
|
+
return memfs;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('generateEventDocs (partials)', () => {
|
|
19
|
+
const fixturesDir = path.resolve(__dirname, '__fixtures__');
|
|
20
|
+
const options = {
|
|
21
|
+
organizationName: 'test-org',
|
|
22
|
+
projectName: 'test-project',
|
|
23
|
+
siteDir: fixturesDir,
|
|
24
|
+
url: 'https://tracking-docs-demo.buchert.digital',
|
|
25
|
+
};
|
|
26
|
+
const outputDir = path.join(fixturesDir, 'docs');
|
|
27
|
+
const partialsDir = path.join(outputDir, 'partials');
|
|
28
|
+
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
fs.vol.reset();
|
|
31
|
+
const realFs = jest.requireActual('fs');
|
|
32
|
+
|
|
33
|
+
function readDirRecursive(dir) {
|
|
34
|
+
const files = realFs.readdirSync(dir, { withFileTypes: true });
|
|
35
|
+
for (const file of files) {
|
|
36
|
+
const filePath = path.join(dir, file.name);
|
|
37
|
+
if (file.isDirectory()) {
|
|
38
|
+
fs.vol.mkdirSync(filePath, { recursive: true });
|
|
39
|
+
readDirRecursive(filePath);
|
|
40
|
+
} else {
|
|
41
|
+
fs.vol.writeFileSync(filePath, realFs.readFileSync(filePath));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
readDirRecursive(fixturesDir);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('injects top partial when _<eventName>.mdx exists in partials dir', async () => {
|
|
49
|
+
console.log = jest.fn();
|
|
50
|
+
fs.vol.mkdirSync(partialsDir, { recursive: true });
|
|
51
|
+
fs.vol.writeFileSync(
|
|
52
|
+
path.join(partialsDir, '_add-to-cart-event.mdx'),
|
|
53
|
+
'## Top content',
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
await generateEventDocs(options);
|
|
57
|
+
|
|
58
|
+
const output = fs.readFileSync(
|
|
59
|
+
path.join(outputDir, 'add-to-cart-event.mdx'),
|
|
60
|
+
'utf-8',
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
expect(output).toContain(
|
|
64
|
+
"import TopPartial from '@site/docs/partials/_add-to-cart-event.mdx'",
|
|
65
|
+
);
|
|
66
|
+
expect(output).toContain('<TopPartial />');
|
|
67
|
+
expect(output).not.toContain('_Top.mdx');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('injects bottom partial when _<eventName>_bottom.mdx exists in partials dir', async () => {
|
|
71
|
+
console.log = jest.fn();
|
|
72
|
+
fs.vol.mkdirSync(partialsDir, { recursive: true });
|
|
73
|
+
fs.vol.writeFileSync(
|
|
74
|
+
path.join(partialsDir, '_add-to-cart-event_bottom.mdx'),
|
|
75
|
+
'## Bottom content',
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
await generateEventDocs(options);
|
|
79
|
+
|
|
80
|
+
const output = fs.readFileSync(
|
|
81
|
+
path.join(outputDir, 'add-to-cart-event.mdx'),
|
|
82
|
+
'utf-8',
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(output).toContain(
|
|
86
|
+
"import BottomPartial from '@site/docs/partials/_add-to-cart-event_bottom.mdx'",
|
|
87
|
+
);
|
|
88
|
+
expect(output).toContain('<BottomPartial />');
|
|
89
|
+
expect(output).not.toContain('_Bottom.mdx');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('injects both top and bottom partials when both exist', async () => {
|
|
93
|
+
console.log = jest.fn();
|
|
94
|
+
fs.vol.mkdirSync(partialsDir, { recursive: true });
|
|
95
|
+
fs.vol.writeFileSync(
|
|
96
|
+
path.join(partialsDir, '_add-to-cart-event.mdx'),
|
|
97
|
+
'## Top content',
|
|
98
|
+
);
|
|
99
|
+
fs.vol.writeFileSync(
|
|
100
|
+
path.join(partialsDir, '_add-to-cart-event_bottom.mdx'),
|
|
101
|
+
'## Bottom content',
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
await generateEventDocs(options);
|
|
105
|
+
|
|
106
|
+
const output = fs.readFileSync(
|
|
107
|
+
path.join(outputDir, 'add-to-cart-event.mdx'),
|
|
108
|
+
'utf-8',
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
expect(output).toContain(
|
|
112
|
+
"import TopPartial from '@site/docs/partials/_add-to-cart-event.mdx'",
|
|
113
|
+
);
|
|
114
|
+
expect(output).toContain('<TopPartial />');
|
|
115
|
+
expect(output).toContain(
|
|
116
|
+
"import BottomPartial from '@site/docs/partials/_add-to-cart-event_bottom.mdx'",
|
|
117
|
+
);
|
|
118
|
+
expect(output).toContain('<BottomPartial />');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('omits partial imports when no partial files exist', async () => {
|
|
122
|
+
console.log = jest.fn();
|
|
123
|
+
|
|
124
|
+
await generateEventDocs(options);
|
|
125
|
+
|
|
126
|
+
const output = fs.readFileSync(
|
|
127
|
+
path.join(outputDir, 'add-to-cart-event.mdx'),
|
|
128
|
+
'utf-8',
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
expect(output).not.toContain('TopPartial');
|
|
132
|
+
expect(output).not.toContain('BottomPartial');
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -185,4 +185,53 @@ describe('buildExampleFromSchema', () => {
|
|
|
185
185
|
},
|
|
186
186
|
});
|
|
187
187
|
});
|
|
188
|
+
|
|
189
|
+
it('should handle if/then/else by defaulting to then branch', () => {
|
|
190
|
+
const schema = {
|
|
191
|
+
type: 'object',
|
|
192
|
+
properties: {
|
|
193
|
+
event: { type: 'string', examples: ['form_submit'] },
|
|
194
|
+
},
|
|
195
|
+
if: { properties: { event: { const: 'form_submit' } } },
|
|
196
|
+
then: {
|
|
197
|
+
properties: {
|
|
198
|
+
form_name: { type: 'string', examples: ['contact'] },
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
else: {
|
|
202
|
+
properties: {
|
|
203
|
+
error_code: { type: 'integer', examples: [404] },
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const example = buildExampleFromSchema(schema);
|
|
209
|
+
expect(example).toHaveProperty('event', 'form_submit');
|
|
210
|
+
expect(example).toHaveProperty('form_name', 'contact');
|
|
211
|
+
expect(example).not.toHaveProperty('error_code');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should handle nested if/then/else inside a property', () => {
|
|
215
|
+
const schema = {
|
|
216
|
+
type: 'object',
|
|
217
|
+
properties: {
|
|
218
|
+
shipping: {
|
|
219
|
+
type: 'object',
|
|
220
|
+
properties: {
|
|
221
|
+
method: { type: 'string', examples: ['express'] },
|
|
222
|
+
},
|
|
223
|
+
if: { properties: { method: { const: 'express' } } },
|
|
224
|
+
then: {
|
|
225
|
+
properties: {
|
|
226
|
+
priority: { type: 'string', examples: ['high'] },
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const example = buildExampleFromSchema(schema);
|
|
234
|
+
expect(example.shipping).toHaveProperty('method', 'express');
|
|
235
|
+
expect(example.shipping).toHaveProperty('priority', 'high');
|
|
236
|
+
});
|
|
188
237
|
});
|