ux4g-components-web 1.4.0 → 1.5.0
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 +76 -0
- package/dist/__tests__/css-bundle.integration.test.d.ts +11 -0
- package/dist/__tests__/css-bundle.integration.test.js +1102 -0
- package/dist/__tests__/css-bundle.phase10.property.test.d.ts +9 -0
- package/dist/__tests__/css-bundle.phase10.property.test.js +64 -0
- package/dist/__tests__/css-bundle.phase5.property.test.d.ts +9 -0
- package/dist/__tests__/css-bundle.phase5.property.test.js +126 -0
- package/dist/__tests__/css-bundle.phase6.property.test.d.ts +9 -0
- package/dist/__tests__/css-bundle.phase6.property.test.js +73 -0
- package/dist/__tests__/css-bundle.phase7.property.test.d.ts +9 -0
- package/dist/__tests__/css-bundle.phase7.property.test.js +76 -0
- package/dist/__tests__/css-bundle.phase8.property.test.d.ts +9 -0
- package/dist/__tests__/css-bundle.phase8.property.test.js +67 -0
- package/dist/__tests__/css-bundle.phase9.property.test.d.ts +9 -0
- package/dist/__tests__/css-bundle.phase9.property.test.js +93 -0
- package/dist/__tests__/css-bundle.property.test.d.ts +14 -0
- package/dist/__tests__/css-bundle.property.test.js +393 -0
- package/dist/__tests__/dom-generators.determinism.property.test.d.ts +1 -0
- package/dist/__tests__/dom-generators.determinism.property.test.js +71 -0
- package/dist/__tests__/dom-generators.id.property.test.d.ts +1 -0
- package/dist/__tests__/dom-generators.id.property.test.js +99 -0
- package/dist/__tests__/dom-generators.otp.property.test.d.ts +1 -0
- package/dist/__tests__/dom-generators.property.test.d.ts +1 -0
- package/dist/__tests__/dom-generators.property.test.js +205 -0
- package/dist/__tests__/dom-generators.states.property.test.d.ts +1 -0
- package/dist/__tests__/dom-generators.table.property.test.d.ts +1 -0
- package/dist/__tests__/dom-generators.tier1.property.test.d.ts +1 -0
- package/dist/__tests__/dom-generators.tier1.property.test.js +403 -0
- package/dist/__tests__/dom-generators.validation.property.test.d.ts +1 -0
- package/dist/__tests__/dom-generators.validation.property.test.js +327 -0
- package/dist/__tests__/megamenu.classbuilder.property.test.d.ts +1 -0
- package/dist/__tests__/megamenu.classbuilder.property.test.js +88 -0
- package/dist/__tests__/smoke.test.d.ts +1 -0
- package/dist/__tests__/smoke.test.js +65 -0
- package/dist/__tests__/types.phase10.property.test.d.ts +1 -0
- package/dist/__tests__/types.phase10.property.test.js +166 -0
- package/dist/__tests__/types.phase10.test.d.ts +1 -0
- package/dist/__tests__/types.phase10.test.js +76 -0
- package/dist/__tests__/types.phase3.property.test.d.ts +1 -0
- package/dist/__tests__/types.phase3.property.test.js +83 -0
- package/dist/__tests__/types.phase3.test.d.ts +1 -0
- package/dist/__tests__/types.phase3.test.js +76 -0
- package/dist/__tests__/types.phase4.property.test.d.ts +1 -0
- package/dist/__tests__/types.phase4.property.test.js +119 -0
- package/dist/__tests__/types.phase4.test.d.ts +1 -0
- package/dist/__tests__/types.phase4.test.js +70 -0
- package/dist/__tests__/types.phase5.property.test.d.ts +1 -0
- package/dist/__tests__/types.phase5.property.test.js +120 -0
- package/dist/__tests__/types.phase5.test.d.ts +1 -0
- package/dist/__tests__/types.phase5.test.js +64 -0
- package/dist/__tests__/types.phase6.property.test.d.ts +1 -0
- package/dist/__tests__/types.phase6.property.test.js +189 -0
- package/dist/__tests__/types.phase6.test.d.ts +1 -0
- package/dist/__tests__/types.phase6.test.js +121 -0
- package/dist/__tests__/types.phase7.property.test.d.ts +1 -0
- package/dist/__tests__/types.phase7.property.test.js +217 -0
- package/dist/__tests__/types.phase7.test.d.ts +1 -0
- package/dist/__tests__/types.phase7.test.js +106 -0
- package/dist/__tests__/types.phase8.property.test.d.ts +1 -0
- package/dist/__tests__/types.phase8.property.test.js +224 -0
- package/dist/__tests__/types.phase8.test.d.ts +1 -0
- package/dist/__tests__/types.phase8.test.js +114 -0
- package/dist/__tests__/types.phase9.property.test.d.ts +1 -0
- package/dist/__tests__/types.phase9.property.test.js +347 -0
- package/dist/__tests__/types.phase9.test.d.ts +1 -0
- package/dist/__tests__/types.phase9.test.js +226 -0
- package/dist/__tests__/types.restructure.property.test.d.ts +1 -0
- package/dist/__tests__/types.restructure.property.test.js +76 -0
- package/dist/__tests__/types.test.d.ts +1 -0
- package/dist/__tests__/types.test.js +175 -0
- package/dist/dom-generators/accordion.d.ts +23 -0
- package/dist/dom-generators/avatar.d.ts +19 -0
- package/dist/dom-generators/carousel.d.ts +20 -0
- package/dist/dom-generators/chip.d.ts +18 -0
- package/dist/dom-generators/combobox.d.ts +28 -0
- package/dist/dom-generators/date-picker.d.ts +19 -0
- package/dist/dom-generators/dom-generators/accordion.d.ts +21 -0
- package/dist/dom-generators/dom-generators/avatar.d.ts +17 -0
- package/dist/dom-generators/dom-generators/carousel.d.ts +19 -0
- package/dist/dom-generators/dom-generators/chip.d.ts +16 -0
- package/dist/dom-generators/dom-generators/combobox.d.ts +26 -0
- package/dist/dom-generators/dom-generators/date-picker.d.ts +18 -0
- package/dist/dom-generators/dom-generators/drawer.d.ts +17 -0
- package/dist/dom-generators/dom-generators/dropdown.d.ts +26 -0
- package/dist/dom-generators/dom-generators/file-upload.d.ts +20 -0
- package/dist/dom-generators/dom-generators/id-generator.d.ts +9 -0
- package/dist/dom-generators/dom-generators/index.d.ts +27 -0
- package/dist/dom-generators/dom-generators/modal.d.ts +19 -0
- package/dist/dom-generators/dom-generators/otp.d.ts +16 -0
- package/dist/dom-generators/dom-generators/popover.d.ts +17 -0
- package/dist/dom-generators/dom-generators/progress.d.ts +16 -0
- package/dist/dom-generators/dom-generators/search.d.ts +20 -0
- package/dist/dom-generators/dom-generators/stepper.d.ts +21 -0
- package/dist/dom-generators/dom-generators/table.d.ts +23 -0
- package/dist/dom-generators/dom-generators/tabs.d.ts +21 -0
- package/dist/dom-generators/dom-generators/time-picker.d.ts +18 -0
- package/dist/dom-generators/dom-generators/tooltip.d.ts +17 -0
- package/dist/dom-generators/dom-generators/types.d.ts +27 -0
- package/dist/dom-generators/dom-generators/validate.d.ts +20 -0
- package/dist/dom-generators/drawer.d.ts +19 -0
- package/dist/dom-generators/dropdown.d.ts +28 -0
- package/dist/dom-generators/file-upload.d.ts +22 -0
- package/dist/dom-generators/id-generator.d.ts +9 -0
- package/dist/dom-generators/index.bundled.d.ts +654 -0
- package/dist/dom-generators/index.cjs +2029 -0
- package/dist/dom-generators/index.d.ts +27 -0
- package/dist/dom-generators/index.mjs +2001 -0
- package/dist/dom-generators/modal.d.ts +21 -0
- package/dist/dom-generators/otp.d.ts +18 -0
- package/dist/dom-generators/popover.d.ts +19 -0
- package/dist/dom-generators/progress.d.ts +18 -0
- package/dist/dom-generators/search.d.ts +22 -0
- package/dist/dom-generators/stepper.d.ts +23 -0
- package/dist/dom-generators/table.d.ts +25 -0
- package/dist/dom-generators/tabs.d.ts +23 -0
- package/dist/dom-generators/time-picker.d.ts +19 -0
- package/dist/dom-generators/tooltip.d.ts +19 -0
- package/dist/dom-generators/types.d.ts +155 -0
- package/dist/dom-generators/validate.d.ts +20 -0
- package/dist/runtime/bootstrap.js +59 -0
- package/dist/runtime/index.js +55 -0
- package/dist/types.d.ts +155 -0
- package/dist/types.js +552 -0
- package/package.json +12 -2
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Property-based tests for Phase 6 build functions
|
|
3
|
+
*
|
|
4
|
+
* Property 1: List class string contains all required tokens and has no duplicates
|
|
5
|
+
* Property 2: Dropdown class string contains all required tokens and correctly toggles is-open
|
|
6
|
+
* Property 3: Combobox class string contains all required tokens and correctly toggles is-open
|
|
7
|
+
* Property 4: Modal backdrop class string contains required tokens and correctly toggles blur and is-open
|
|
8
|
+
* Property 5: Modal box class string contains required tokens and correctly toggles center-content
|
|
9
|
+
* Property 6: Inline alert class string contains required tokens and applies mutually exclusive layout modifiers
|
|
10
|
+
* Property 7: Context-alert class string uses ux4g-context-alert as base and does not include standalone ux4g-alert
|
|
11
|
+
* Property 8: Alert container class string contains required tokens for all positions
|
|
12
|
+
* Property 9: Search container class string contains required tokens for all sizes, and extra param is always appended
|
|
13
|
+
*/
|
|
14
|
+
import * as fc from 'fast-check';
|
|
15
|
+
import { buildListClasses, buildDropdownClasses, buildComboboxClasses, buildModalBackdropClasses, buildModalBoxClasses, buildAlertClasses, buildContextAlertClasses, buildAlertContainerClasses, buildSearchContainerClasses, } from '../../src/types';
|
|
16
|
+
/**
|
|
17
|
+
* Property 1: List class string contains all required tokens and has no duplicates
|
|
18
|
+
* Tag: Feature: ux4g-phase6-components, Property 1
|
|
19
|
+
* Validates: Requirements 12.1, 12.2
|
|
20
|
+
*/
|
|
21
|
+
describe('Property 1: List class string contains all required tokens and has no duplicates', () => {
|
|
22
|
+
it('Feature: ux4g-phase6-components, Property 1', () => {
|
|
23
|
+
fc.assert(fc.property(fc.constantFrom('default', 'error', 'success', 'warning'), fc.constantFrom('s', 'm', 'l', 'xl'), (variant, size) => {
|
|
24
|
+
const result = buildListClasses(variant, size);
|
|
25
|
+
const tokens = result.split(' ');
|
|
26
|
+
const hasBase = tokens.includes('ux4g-list');
|
|
27
|
+
const hasVariant = tokens.includes(`ux4g-list-${variant}`);
|
|
28
|
+
const hasSize = tokens.includes(`ux4g-list-${size}`);
|
|
29
|
+
const noDuplicates = tokens.length === new Set(tokens).size;
|
|
30
|
+
return hasBase && hasVariant && hasSize && noDuplicates;
|
|
31
|
+
}), { numRuns: 100 });
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* Property 2: Dropdown class string contains all required tokens and correctly toggles is-open
|
|
36
|
+
* Tag: Feature: ux4g-phase6-components, Property 2
|
|
37
|
+
* Validates: Requirements 12.4, 12.5
|
|
38
|
+
*/
|
|
39
|
+
describe('Property 2: Dropdown class string contains all required tokens and correctly toggles is-open', () => {
|
|
40
|
+
it('Feature: ux4g-phase6-components, Property 2', () => {
|
|
41
|
+
fc.assert(fc.property(fc.constantFrom('selection', 'button', 'overflow'), fc.constantFrom('single', 'multi'), fc.constantFrom('sm', 'md', 'lg'), fc.constantFrom('default', 'error', 'success', 'warning'), fc.boolean(), (type, mode, size, state, open) => {
|
|
42
|
+
const result = buildDropdownClasses(type, mode, size, state, open);
|
|
43
|
+
const tokens = result.split(' ');
|
|
44
|
+
const hasBase = tokens.includes('ux4g-dropdown');
|
|
45
|
+
const hasType = tokens.includes(`ux4g-dropdown-${type}`);
|
|
46
|
+
const hasMode = tokens.includes(`ux4g-dropdown-${mode}`);
|
|
47
|
+
const hasSize = tokens.includes(`ux4g-dropdown-${size}`);
|
|
48
|
+
const hasState = tokens.includes(`ux4g-dropdown-${state}`);
|
|
49
|
+
const openCorrect = open ? tokens.includes('is-open') : !tokens.includes('is-open');
|
|
50
|
+
return hasBase && hasType && hasMode && hasSize && hasState && openCorrect;
|
|
51
|
+
}), { numRuns: 100 });
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* Property 3: Combobox class string contains all required tokens and correctly toggles is-open
|
|
56
|
+
* Tag: Feature: ux4g-phase6-components, Property 3
|
|
57
|
+
* Validates: Requirements 12.6, 12.7
|
|
58
|
+
*/
|
|
59
|
+
describe('Property 3: Combobox class string contains all required tokens and correctly toggles is-open', () => {
|
|
60
|
+
it('Feature: ux4g-phase6-components, Property 3', () => {
|
|
61
|
+
fc.assert(fc.property(fc.constantFrom('single', 'multi'), fc.constantFrom('sm', 'md', 'lg'), fc.constantFrom('default', 'error', 'success', 'warning'), fc.boolean(), (type, size, state, open) => {
|
|
62
|
+
const result = buildComboboxClasses(type, size, state, open);
|
|
63
|
+
const tokens = result.split(' ');
|
|
64
|
+
const hasBase = tokens.includes('ux4g-combobox');
|
|
65
|
+
const hasType = tokens.includes(`ux4g-combobox-${type}`);
|
|
66
|
+
const hasSize = tokens.includes(`ux4g-combobox-${size}`);
|
|
67
|
+
const hasState = tokens.includes(`ux4g-combobox-${state}`);
|
|
68
|
+
const openCorrect = open ? tokens.includes('is-open') : !tokens.includes('is-open');
|
|
69
|
+
return hasBase && hasType && hasSize && hasState && openCorrect;
|
|
70
|
+
}), { numRuns: 100 });
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* Property 4: Modal backdrop class string contains required tokens and correctly toggles blur and is-open
|
|
75
|
+
* Tag: Feature: ux4g-phase6-components, Property 4
|
|
76
|
+
* Validates: Requirements 12.8, 12.9, 12.10
|
|
77
|
+
*/
|
|
78
|
+
describe('Property 4: Modal backdrop class string contains required tokens and correctly toggles blur and is-open', () => {
|
|
79
|
+
it('Feature: ux4g-phase6-components, Property 4', () => {
|
|
80
|
+
fc.assert(fc.property(fc.constantFrom('25', '50', '75'), fc.boolean(), fc.boolean(), (opacity, blur, open) => {
|
|
81
|
+
const result = buildModalBackdropClasses(opacity, blur, open);
|
|
82
|
+
const tokens = result.split(' ');
|
|
83
|
+
const hasBase = tokens.includes('ux4g-modal-backdrop');
|
|
84
|
+
const hasOpacity = tokens.includes(`ux4g-modal-backdrop-${opacity}`);
|
|
85
|
+
const blurCorrect = blur ? tokens.includes('ux4g-modal-backdrop-blur') : !tokens.includes('ux4g-modal-backdrop-blur');
|
|
86
|
+
const openCorrect = open ? tokens.includes('is-open') : !tokens.includes('is-open');
|
|
87
|
+
return hasBase && hasOpacity && blurCorrect && openCorrect;
|
|
88
|
+
}), { numRuns: 100 });
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
/**
|
|
92
|
+
* Property 5: Modal box class string contains required tokens and correctly toggles center-content
|
|
93
|
+
* Tag: Feature: ux4g-phase6-components, Property 5
|
|
94
|
+
* Validates: Requirements 12.11, 12.12
|
|
95
|
+
*/
|
|
96
|
+
describe('Property 5: Modal box class string contains required tokens and correctly toggles center-content', () => {
|
|
97
|
+
it('Feature: ux4g-phase6-components, Property 5', () => {
|
|
98
|
+
fc.assert(fc.property(fc.constantFrom('s', 'm', 'l'), fc.boolean(), (size, centerContent) => {
|
|
99
|
+
const result = buildModalBoxClasses(size, centerContent);
|
|
100
|
+
const tokens = result.split(' ');
|
|
101
|
+
const hasBase = tokens.includes('ux4g-modal-box');
|
|
102
|
+
const hasSize = tokens.includes(`ux4g-modal-${size}`);
|
|
103
|
+
const centerCorrect = centerContent
|
|
104
|
+
? tokens.includes('ux4g-modal-center-content')
|
|
105
|
+
: !tokens.includes('ux4g-modal-center-content');
|
|
106
|
+
return hasBase && hasSize && centerCorrect;
|
|
107
|
+
}), { numRuns: 100 });
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
/**
|
|
111
|
+
* Property 6: Inline alert class string contains required tokens and applies mutually exclusive layout modifiers
|
|
112
|
+
* Tag: Feature: ux4g-phase6-components, Property 6
|
|
113
|
+
* Validates: Requirements 12.13, 12.14
|
|
114
|
+
*/
|
|
115
|
+
describe('Property 6: Inline alert class string contains required tokens and applies mutually exclusive layout modifiers', () => {
|
|
116
|
+
it('Feature: ux4g-phase6-components, Property 6', () => {
|
|
117
|
+
fc.assert(fc.property(fc.constantFrom('info', 'success', 'warning', 'error'), fc.constantFrom('fluid', 'center', 'wide'), (variant, layout) => {
|
|
118
|
+
const result = buildAlertClasses(variant, layout);
|
|
119
|
+
const tokens = result.split(' ');
|
|
120
|
+
const hasBase = tokens.includes('ux4g-alert');
|
|
121
|
+
const hasVariant = tokens.includes(`ux4g-alert-${variant}`);
|
|
122
|
+
let layoutCorrect;
|
|
123
|
+
if (layout === 'center') {
|
|
124
|
+
layoutCorrect = tokens.includes('ux4g-alert-center') && !tokens.includes('ux4g-alert-wide');
|
|
125
|
+
}
|
|
126
|
+
else if (layout === 'wide') {
|
|
127
|
+
layoutCorrect = tokens.includes('ux4g-alert-wide') && !tokens.includes('ux4g-alert-center');
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// fluid — neither modifier present
|
|
131
|
+
layoutCorrect = !tokens.includes('ux4g-alert-center') && !tokens.includes('ux4g-alert-wide');
|
|
132
|
+
}
|
|
133
|
+
return hasBase && hasVariant && layoutCorrect;
|
|
134
|
+
}), { numRuns: 100 });
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
/**
|
|
138
|
+
* Property 7: Context-alert class string uses ux4g-context-alert as base and does not include standalone ux4g-alert
|
|
139
|
+
* Tag: Feature: ux4g-phase6-components, Property 7
|
|
140
|
+
* Validates: Requirements 12.15
|
|
141
|
+
*/
|
|
142
|
+
describe('Property 7: Context-alert class string uses ux4g-context-alert as base and does not include standalone ux4g-alert', () => {
|
|
143
|
+
it('Feature: ux4g-phase6-components, Property 7', () => {
|
|
144
|
+
fc.assert(fc.property(fc.constantFrom('info', 'success', 'warning', 'error'), (variant) => {
|
|
145
|
+
const result = buildContextAlertClasses(variant);
|
|
146
|
+
const tokens = result.split(' ');
|
|
147
|
+
const hasContextBase = tokens.includes('ux4g-context-alert');
|
|
148
|
+
const hasVariant = tokens.includes(`ux4g-alert-${variant}`);
|
|
149
|
+
// 'ux4g-alert' must NOT appear as a standalone token (exact match)
|
|
150
|
+
const noStandaloneAlert = !tokens.includes('ux4g-alert');
|
|
151
|
+
return hasContextBase && hasVariant && noStandaloneAlert;
|
|
152
|
+
}), { numRuns: 100 });
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
/**
|
|
156
|
+
* Property 8: Alert container class string contains required tokens for all positions
|
|
157
|
+
* Tag: Feature: ux4g-phase6-components, Property 8
|
|
158
|
+
* Validates: Requirements 12.16
|
|
159
|
+
*/
|
|
160
|
+
describe('Property 8: Alert container class string contains required tokens for all positions', () => {
|
|
161
|
+
it('Feature: ux4g-phase6-components, Property 8', () => {
|
|
162
|
+
fc.assert(fc.property(fc.constantFrom('top-left', 'top-right', 'bottom-left', 'bottom-right'), (position) => {
|
|
163
|
+
const result = buildAlertContainerClasses(position);
|
|
164
|
+
const tokens = result.split(' ');
|
|
165
|
+
const hasBase = tokens.includes('ux4g-alert-container');
|
|
166
|
+
const hasPosition = tokens.includes(`ux4g-alert-${position}`);
|
|
167
|
+
return hasBase && hasPosition;
|
|
168
|
+
}), { numRuns: 100 });
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
/**
|
|
172
|
+
* Property 9: Search container class string contains required tokens for all sizes, and extra param is always appended
|
|
173
|
+
* Tag: Feature: ux4g-phase6-components, Property 9
|
|
174
|
+
* Validates: Requirements 12.17, 12.18
|
|
175
|
+
*/
|
|
176
|
+
describe('Property 9: Search container class string contains required tokens for all sizes, and extra param is always appended', () => {
|
|
177
|
+
it('Feature: ux4g-phase6-components, Property 9', () => {
|
|
178
|
+
fc.assert(fc.property(fc.constantFrom('s', 'm', 'lg'), fc.option(fc.stringMatching(/^[a-z][a-z0-9-]*$/), { nil: undefined }), (size, extra) => {
|
|
179
|
+
const result = buildSearchContainerClasses(size, extra);
|
|
180
|
+
const tokens = result.split(' ');
|
|
181
|
+
const hasBase = tokens.includes('ux4g-search-container');
|
|
182
|
+
const hasSize = tokens.includes(`ux4g-search-${size}`);
|
|
183
|
+
const extraCorrect = extra !== undefined
|
|
184
|
+
? tokens.includes(extra) && tokens.length === new Set(tokens).size
|
|
185
|
+
: true;
|
|
186
|
+
return hasBase && hasSize && extraCorrect;
|
|
187
|
+
}), { numRuns: 100 });
|
|
188
|
+
});
|
|
189
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { buildListClasses, buildDropdownClasses, buildComboboxClasses, buildModalBackdropClasses, buildModalBoxClasses, buildAlertClasses, buildContextAlertClasses, buildAlertContainerClasses, buildSearchContainerClasses, } from '../../src/types';
|
|
2
|
+
// ── buildListClasses ──────────────────────────────────────────────────────────
|
|
3
|
+
// Requirements: 4.3
|
|
4
|
+
describe('buildListClasses', () => {
|
|
5
|
+
it("variant='default' size='m' → base + variant + size", () => {
|
|
6
|
+
expect(buildListClasses('default', 'm')).toBe('ux4g-list ux4g-list-default ux4g-list-m');
|
|
7
|
+
});
|
|
8
|
+
it("variant='error' size='s' → base + variant + size", () => {
|
|
9
|
+
expect(buildListClasses('error', 's')).toBe('ux4g-list ux4g-list-error ux4g-list-s');
|
|
10
|
+
});
|
|
11
|
+
it("variant='success' size='xl' with extra → appends extra class", () => {
|
|
12
|
+
expect(buildListClasses('success', 'xl', 'my-list')).toBe('ux4g-list ux4g-list-success ux4g-list-xl my-list');
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
// ── buildDropdownClasses ──────────────────────────────────────────────────────
|
|
16
|
+
// Requirements: 4.8
|
|
17
|
+
describe('buildDropdownClasses', () => {
|
|
18
|
+
it("type='selection' mode='single' size='md' state='default' → all five tokens", () => {
|
|
19
|
+
expect(buildDropdownClasses('selection', 'single', 'md', 'default')).toBe('ux4g-dropdown ux4g-dropdown-selection ux4g-dropdown-single ux4g-dropdown-md ux4g-dropdown-default');
|
|
20
|
+
});
|
|
21
|
+
it("type='button' mode='multi' size='lg' state='error' open=true → includes is-open", () => {
|
|
22
|
+
expect(buildDropdownClasses('button', 'multi', 'lg', 'error', true)).toBe('ux4g-dropdown ux4g-dropdown-button ux4g-dropdown-multi ux4g-dropdown-lg ux4g-dropdown-error is-open');
|
|
23
|
+
});
|
|
24
|
+
it("type='overflow' mode='single' size='sm' state='default' open=false → no is-open", () => {
|
|
25
|
+
const result = buildDropdownClasses('overflow', 'single', 'sm', 'default', false);
|
|
26
|
+
expect(result).not.toContain('is-open');
|
|
27
|
+
expect(result).toBe('ux4g-dropdown ux4g-dropdown-overflow ux4g-dropdown-single ux4g-dropdown-sm ux4g-dropdown-default');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
// ── buildComboboxClasses ──────────────────────────────────────────────────────
|
|
31
|
+
// Requirements: 4.12
|
|
32
|
+
describe('buildComboboxClasses', () => {
|
|
33
|
+
it("type='single' size='md' state='default' → all four tokens", () => {
|
|
34
|
+
expect(buildComboboxClasses('single', 'md', 'default')).toBe('ux4g-combobox ux4g-combobox-single ux4g-combobox-md ux4g-combobox-default');
|
|
35
|
+
});
|
|
36
|
+
it("type='multi' size='lg' state='error' open=true → includes is-open", () => {
|
|
37
|
+
expect(buildComboboxClasses('multi', 'lg', 'error', true)).toBe('ux4g-combobox ux4g-combobox-multi ux4g-combobox-lg ux4g-combobox-error is-open');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
// ── buildModalBackdropClasses ─────────────────────────────────────────────────
|
|
41
|
+
// Requirements: 4.15
|
|
42
|
+
describe('buildModalBackdropClasses', () => {
|
|
43
|
+
it("opacity='50' → base + opacity only", () => {
|
|
44
|
+
expect(buildModalBackdropClasses('50')).toBe('ux4g-modal-backdrop ux4g-modal-backdrop-50');
|
|
45
|
+
});
|
|
46
|
+
it("opacity='75' blur=true open=true → includes blur and is-open", () => {
|
|
47
|
+
expect(buildModalBackdropClasses('75', true, true)).toBe('ux4g-modal-backdrop ux4g-modal-backdrop-75 ux4g-modal-backdrop-blur is-open');
|
|
48
|
+
});
|
|
49
|
+
it("opacity='25' blur=false open=false → no blur, no is-open", () => {
|
|
50
|
+
const result = buildModalBackdropClasses('25', false, false);
|
|
51
|
+
expect(result).not.toContain('ux4g-modal-backdrop-blur');
|
|
52
|
+
expect(result).not.toContain('is-open');
|
|
53
|
+
expect(result).toBe('ux4g-modal-backdrop ux4g-modal-backdrop-25');
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
// ── buildModalBoxClasses ──────────────────────────────────────────────────────
|
|
57
|
+
// Requirements: 4.16
|
|
58
|
+
describe('buildModalBoxClasses', () => {
|
|
59
|
+
it("size='m' → base + size", () => {
|
|
60
|
+
expect(buildModalBoxClasses('m')).toBe('ux4g-modal-box ux4g-modal-m');
|
|
61
|
+
});
|
|
62
|
+
it("size='l' centerContent=true → includes center-content", () => {
|
|
63
|
+
expect(buildModalBoxClasses('l', true)).toBe('ux4g-modal-box ux4g-modal-l ux4g-modal-center-content');
|
|
64
|
+
});
|
|
65
|
+
it("size='s' centerContent=false → no center-content", () => {
|
|
66
|
+
const result = buildModalBoxClasses('s', false);
|
|
67
|
+
expect(result).not.toContain('ux4g-modal-center-content');
|
|
68
|
+
expect(result).toBe('ux4g-modal-box ux4g-modal-s');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
// ── buildAlertClasses ─────────────────────────────────────────────────────────
|
|
72
|
+
// Requirements: 4.19
|
|
73
|
+
describe('buildAlertClasses', () => {
|
|
74
|
+
it("variant='info' → base + variant only", () => {
|
|
75
|
+
expect(buildAlertClasses('info')).toBe('ux4g-alert ux4g-alert-info');
|
|
76
|
+
});
|
|
77
|
+
it("variant='warning' layout='center' → includes center modifier", () => {
|
|
78
|
+
expect(buildAlertClasses('warning', 'center')).toBe('ux4g-alert ux4g-alert-warning ux4g-alert-center');
|
|
79
|
+
});
|
|
80
|
+
it("variant='error' layout='wide' → includes wide modifier", () => {
|
|
81
|
+
expect(buildAlertClasses('error', 'wide')).toBe('ux4g-alert ux4g-alert-error ux4g-alert-wide');
|
|
82
|
+
});
|
|
83
|
+
it("variant='success' layout='fluid' → no layout modifier", () => {
|
|
84
|
+
const result = buildAlertClasses('success', 'fluid');
|
|
85
|
+
expect(result).not.toContain('ux4g-alert-fluid');
|
|
86
|
+
expect(result).toBe('ux4g-alert ux4g-alert-success');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
// ── buildContextAlertClasses ──────────────────────────────────────────────────
|
|
90
|
+
// Requirements: 4.20
|
|
91
|
+
describe('buildContextAlertClasses', () => {
|
|
92
|
+
it("variant='info' → ux4g-context-alert + variant modifier", () => {
|
|
93
|
+
expect(buildContextAlertClasses('info')).toBe('ux4g-context-alert ux4g-alert-info');
|
|
94
|
+
});
|
|
95
|
+
it("variant='error' → ux4g-context-alert + variant modifier", () => {
|
|
96
|
+
expect(buildContextAlertClasses('error')).toBe('ux4g-context-alert ux4g-alert-error');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
// ── buildAlertContainerClasses ────────────────────────────────────────────────
|
|
100
|
+
// Requirements: 4.22
|
|
101
|
+
describe('buildAlertContainerClasses', () => {
|
|
102
|
+
it("position='top-right' → base + position", () => {
|
|
103
|
+
expect(buildAlertContainerClasses('top-right')).toBe('ux4g-alert-container ux4g-alert-top-right');
|
|
104
|
+
});
|
|
105
|
+
it("position='bottom-left' → base + position", () => {
|
|
106
|
+
expect(buildAlertContainerClasses('bottom-left')).toBe('ux4g-alert-container ux4g-alert-bottom-left');
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
// ── buildSearchContainerClasses ───────────────────────────────────────────────
|
|
110
|
+
// Requirements: 4.24
|
|
111
|
+
describe('buildSearchContainerClasses', () => {
|
|
112
|
+
it("size='m' → base + size", () => {
|
|
113
|
+
expect(buildSearchContainerClasses('m')).toBe('ux4g-search-container ux4g-search-m');
|
|
114
|
+
});
|
|
115
|
+
it("size='s' → base + size", () => {
|
|
116
|
+
expect(buildSearchContainerClasses('s')).toBe('ux4g-search-container ux4g-search-s');
|
|
117
|
+
});
|
|
118
|
+
it("size='lg' → base + size", () => {
|
|
119
|
+
expect(buildSearchContainerClasses('lg')).toBe('ux4g-search-container ux4g-search-lg');
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Property-based tests for Phase 7 build functions
|
|
3
|
+
*
|
|
4
|
+
* Property 1: Pagination class correctly toggles dotted variant and style modifiers
|
|
5
|
+
* Property 2: Table class contains all required tokens and correctly toggles divider, zebra, and boolean flags
|
|
6
|
+
* Property 3: Popover class contains required tokens and correctly toggles show
|
|
7
|
+
* Property 4: Tooltip class contains all required tokens for all placement and size combinations
|
|
8
|
+
* Property 5: Tab class contains all required tokens and correctly toggles vertical
|
|
9
|
+
* Property 6: Icon button class contains all required tokens and correctly toggles pill
|
|
10
|
+
* Property 7: Extra param is always appended and never duplicated across all build functions
|
|
11
|
+
*/
|
|
12
|
+
import * as fc from 'fast-check';
|
|
13
|
+
import { buildPaginationClasses, buildTableClasses, buildPopoverClasses, buildTooltipClasses, buildTabClasses, buildIconButtonClasses, } from '../../src/types';
|
|
14
|
+
/**
|
|
15
|
+
* Property 1: Pagination class string contains required tokens and correctly applies dotted variant and style modifiers
|
|
16
|
+
* Tag: Feature: ux4g-phase7-components, Property 1
|
|
17
|
+
* Validates: Requirements 12.1, 12.2, 12.3, 12.4, 12.5
|
|
18
|
+
*/
|
|
19
|
+
describe('Property 1: Pagination class correctly toggles dotted variant and style modifiers', () => {
|
|
20
|
+
it('Feature: ux4g-phase7-components, Property 1', () => {
|
|
21
|
+
fc.assert(fc.property(fc.constantFrom('default', 'dotted'), fc.constantFrom('default', 'solid', 'translucent'), (variant, paginationStyle) => {
|
|
22
|
+
const result = buildPaginationClasses(variant, paginationStyle);
|
|
23
|
+
const tokens = result.split(' ');
|
|
24
|
+
// Always contains base class
|
|
25
|
+
const hasBase = tokens.includes('ux4g-pagination');
|
|
26
|
+
// Dotted variant toggles correctly
|
|
27
|
+
const dottedCorrect = variant === 'dotted'
|
|
28
|
+
? tokens.includes('ux4g-pagination-dotted')
|
|
29
|
+
: !tokens.includes('ux4g-pagination-dotted');
|
|
30
|
+
// Style modifiers only apply when dotted; mutually exclusive
|
|
31
|
+
let styleCorrect;
|
|
32
|
+
if (variant === 'dotted' && paginationStyle === 'solid') {
|
|
33
|
+
styleCorrect = tokens.includes('ux4g-pagination-solid') && !tokens.includes('ux4g-pagination-translucent');
|
|
34
|
+
}
|
|
35
|
+
else if (variant === 'dotted' && paginationStyle === 'translucent') {
|
|
36
|
+
styleCorrect = tokens.includes('ux4g-pagination-translucent') && !tokens.includes('ux4g-pagination-solid');
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// variant='default' (any style) or variant='dotted' paginationStyle='default' — no style modifier
|
|
40
|
+
styleCorrect = !tokens.includes('ux4g-pagination-solid') && !tokens.includes('ux4g-pagination-translucent');
|
|
41
|
+
}
|
|
42
|
+
// No duplicates
|
|
43
|
+
const noDuplicates = tokens.length === new Set(tokens).size;
|
|
44
|
+
return hasBase && dottedCorrect && styleCorrect && noDuplicates;
|
|
45
|
+
}), { numRuns: 25 });
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* Property 2: Table class string contains all required tokens and correctly toggles divider, zebra, and boolean modifier flags
|
|
50
|
+
* Tag: Feature: ux4g-phase7-components, Property 2
|
|
51
|
+
* Validates: Requirements 12.6, 12.7, 12.8, 12.9, 12.10, 12.11, 12.12, 12.13
|
|
52
|
+
*/
|
|
53
|
+
describe('Property 2: Table class contains all required tokens and correctly toggles divider, zebra, and boolean flags', () => {
|
|
54
|
+
it('Feature: ux4g-phase7-components, Property 2', () => {
|
|
55
|
+
fc.assert(fc.property(fc.constantFrom('s', 'm', 'lg'), fc.constantFrom('row', 'column', 'none'), fc.constantFrom('none', 'rows', 'cols'), fc.boolean(), fc.boolean(), fc.boolean(), fc.boolean(), (size, divider, zebra, interactive, sortable, resizable, headerBrand) => {
|
|
56
|
+
const result = buildTableClasses(size, divider, zebra, interactive, sortable, resizable, headerBrand);
|
|
57
|
+
const tokens = result.split(' ');
|
|
58
|
+
// Always contains base and size
|
|
59
|
+
const hasBase = tokens.includes('ux4g-table');
|
|
60
|
+
const hasSize = tokens.includes(`ux4g-table-${size}`);
|
|
61
|
+
// Divider modifiers are mutually exclusive
|
|
62
|
+
let dividerCorrect;
|
|
63
|
+
if (divider === 'column') {
|
|
64
|
+
dividerCorrect = tokens.includes('ux4g-table-column-dividers') && !tokens.includes('ux4g-table-no-row-dividers');
|
|
65
|
+
}
|
|
66
|
+
else if (divider === 'none') {
|
|
67
|
+
dividerCorrect = tokens.includes('ux4g-table-no-row-dividers') && !tokens.includes('ux4g-table-column-dividers');
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// divider === 'row' — no modifier
|
|
71
|
+
dividerCorrect = !tokens.includes('ux4g-table-column-dividers') && !tokens.includes('ux4g-table-no-row-dividers');
|
|
72
|
+
}
|
|
73
|
+
// Zebra modifiers are mutually exclusive
|
|
74
|
+
let zebraCorrect;
|
|
75
|
+
if (zebra === 'rows') {
|
|
76
|
+
zebraCorrect = tokens.includes('ux4g-table-zebra-rows') && !tokens.includes('ux4g-table-zebra-cols');
|
|
77
|
+
}
|
|
78
|
+
else if (zebra === 'cols') {
|
|
79
|
+
zebraCorrect = tokens.includes('ux4g-table-zebra-cols') && !tokens.includes('ux4g-table-zebra-rows');
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// zebra === 'none' — no modifier
|
|
83
|
+
zebraCorrect = !tokens.includes('ux4g-table-zebra-rows') && !tokens.includes('ux4g-table-zebra-cols');
|
|
84
|
+
}
|
|
85
|
+
// Boolean flags toggle independently
|
|
86
|
+
const interactiveCorrect = interactive ? tokens.includes('ux4g-table-interactive') : !tokens.includes('ux4g-table-interactive');
|
|
87
|
+
const sortableCorrect = sortable ? tokens.includes('ux4g-table-sortable') : !tokens.includes('ux4g-table-sortable');
|
|
88
|
+
const resizableCorrect = resizable ? tokens.includes('ux4g-table-resizable') : !tokens.includes('ux4g-table-resizable');
|
|
89
|
+
const headerBrandCorrect = headerBrand ? tokens.includes('ux4g-table-header-brand') : !tokens.includes('ux4g-table-header-brand');
|
|
90
|
+
// No duplicates
|
|
91
|
+
const noDuplicates = tokens.length === new Set(tokens).size;
|
|
92
|
+
return hasBase && hasSize && dividerCorrect && zebraCorrect
|
|
93
|
+
&& interactiveCorrect && sortableCorrect && resizableCorrect && headerBrandCorrect
|
|
94
|
+
&& noDuplicates;
|
|
95
|
+
}), { numRuns: 25 });
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
/**
|
|
99
|
+
* Property 3: Popover class string contains required tokens and correctly toggles show
|
|
100
|
+
* Tag: Feature: ux4g-phase7-components, Property 3
|
|
101
|
+
* Validates: Requirements 12.14, 12.15, 12.16
|
|
102
|
+
*/
|
|
103
|
+
describe('Property 3: Popover class contains required tokens and correctly toggles show', () => {
|
|
104
|
+
it('Feature: ux4g-phase7-components, Property 3', () => {
|
|
105
|
+
fc.assert(fc.property(fc.constantFrom('top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end', 'right', 'right-start', 'right-end'), fc.boolean(), (placement, show) => {
|
|
106
|
+
const result = buildPopoverClasses(placement, show);
|
|
107
|
+
const tokens = result.split(' ');
|
|
108
|
+
// Always contains base and placement
|
|
109
|
+
const hasBase = tokens.includes('ux4g-popover');
|
|
110
|
+
const hasPlacement = tokens.includes(`ux4g-popover-${placement}`);
|
|
111
|
+
// show toggles correctly
|
|
112
|
+
const showCorrect = show ? tokens.includes('show') : !tokens.includes('show');
|
|
113
|
+
// No duplicates
|
|
114
|
+
const noDuplicates = tokens.length === new Set(tokens).size;
|
|
115
|
+
return hasBase && hasPlacement && showCorrect && noDuplicates;
|
|
116
|
+
}), { numRuns: 25 });
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
/**
|
|
120
|
+
* Property 4: Tooltip class string contains all required tokens for all valid placement and size combinations
|
|
121
|
+
* Tag: Feature: ux4g-phase7-components, Property 4
|
|
122
|
+
* Validates: Requirements 12.17, 12.18
|
|
123
|
+
*/
|
|
124
|
+
describe('Property 4: Tooltip class contains all required tokens for all placement and size combinations', () => {
|
|
125
|
+
it('Feature: ux4g-phase7-components, Property 4', () => {
|
|
126
|
+
fc.assert(fc.property(fc.constantFrom('top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right', 'left-center', 'right-center'), fc.constantFrom('s', 'xs'), (placement, size) => {
|
|
127
|
+
const result = buildTooltipClasses(placement, size);
|
|
128
|
+
const tokens = result.split(' ');
|
|
129
|
+
// Always contains base, placement, and size
|
|
130
|
+
const hasBase = tokens.includes('ux4g-tooltip');
|
|
131
|
+
const hasPlacement = tokens.includes(`ux4g-tooltip-${placement}`);
|
|
132
|
+
const hasSize = tokens.includes(`ux4g-tooltip-${size}`);
|
|
133
|
+
// No duplicates
|
|
134
|
+
const noDuplicates = tokens.length === new Set(tokens).size;
|
|
135
|
+
return hasBase && hasPlacement && hasSize && noDuplicates;
|
|
136
|
+
}), { numRuns: 25 });
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
/**
|
|
140
|
+
* Property 5: Tab class string contains all required tokens and correctly toggles vertical modifier
|
|
141
|
+
* Tag: Feature: ux4g-phase7-components, Property 5
|
|
142
|
+
* Validates: Requirements 12.19, 12.20, 12.21
|
|
143
|
+
*/
|
|
144
|
+
describe('Property 5: Tab class contains all required tokens and correctly toggles vertical', () => {
|
|
145
|
+
it('Feature: ux4g-phase7-components, Property 5', () => {
|
|
146
|
+
fc.assert(fc.property(fc.constantFrom('underline', 'pill'), fc.constantFrom('sm', 'md', 'lg'), fc.boolean(), (variant, size, vertical) => {
|
|
147
|
+
const result = buildTabClasses(variant, size, vertical);
|
|
148
|
+
const tokens = result.split(' ');
|
|
149
|
+
// Always contains base, variant, and size
|
|
150
|
+
const hasBase = tokens.includes('ux4g-tab');
|
|
151
|
+
const hasVariant = tokens.includes(`ux4g-tab-${variant}`);
|
|
152
|
+
const hasSize = tokens.includes(`ux4g-tab-${size}`);
|
|
153
|
+
// vertical toggles correctly
|
|
154
|
+
const verticalCorrect = vertical
|
|
155
|
+
? tokens.includes('ux4g-tab-vertical')
|
|
156
|
+
: !tokens.includes('ux4g-tab-vertical');
|
|
157
|
+
// No duplicates
|
|
158
|
+
const noDuplicates = tokens.length === new Set(tokens).size;
|
|
159
|
+
return hasBase && hasVariant && hasSize && verticalCorrect && noDuplicates;
|
|
160
|
+
}), { numRuns: 25 });
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
/**
|
|
164
|
+
* Property 6: Icon button class string contains all required tokens and correctly toggles pill modifier
|
|
165
|
+
* Tag: Feature: ux4g-phase7-components, Property 6
|
|
166
|
+
* Validates: Requirements 12.22, 12.23, 12.24
|
|
167
|
+
*/
|
|
168
|
+
describe('Property 6: Icon button class contains all required tokens and correctly toggles pill', () => {
|
|
169
|
+
it('Feature: ux4g-phase7-components, Property 6', () => {
|
|
170
|
+
fc.assert(fc.property(fc.constantFrom('primary', 'outline-primary', 'tonal-primary', 'text-primary'), fc.constantFrom('xl', 'lg', 'md', 'sm', 'xs'), fc.boolean(), (variant, size, pill) => {
|
|
171
|
+
const result = buildIconButtonClasses(variant, size, pill);
|
|
172
|
+
const tokens = result.split(' ');
|
|
173
|
+
// Always contains base, variant, and size
|
|
174
|
+
const hasBase = tokens.includes('ux4g-icon-btn');
|
|
175
|
+
const hasVariant = tokens.includes(`ux4g-icon-btn-${variant}`);
|
|
176
|
+
const hasSize = tokens.includes(`ux4g-icon-btn-${size}`);
|
|
177
|
+
// pill toggles correctly
|
|
178
|
+
const pillCorrect = pill
|
|
179
|
+
? tokens.includes('ux4g-icon-btn-pill')
|
|
180
|
+
: !tokens.includes('ux4g-icon-btn-pill');
|
|
181
|
+
// No duplicates
|
|
182
|
+
const noDuplicates = tokens.length === new Set(tokens).size;
|
|
183
|
+
return hasBase && hasVariant && hasSize && pillCorrect && noDuplicates;
|
|
184
|
+
}), { numRuns: 25 });
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
/**
|
|
188
|
+
* Property 7: Extra param is always appended as a space-separated token and never duplicates existing tokens
|
|
189
|
+
* Tag: Feature: ux4g-phase7-components, Property 7
|
|
190
|
+
* Validates: Requirements 12.25
|
|
191
|
+
*/
|
|
192
|
+
describe('Property 7: Extra param is always appended and never duplicated across all build functions', () => {
|
|
193
|
+
it('Feature: ux4g-phase7-components, Property 7', () => {
|
|
194
|
+
// Generator for a non-empty extra token with no spaces (valid CSS class name)
|
|
195
|
+
const extraArb = fc.stringMatching(/^[a-z][a-z0-9-]*$/);
|
|
196
|
+
fc.assert(fc.property(extraArb, (extra) => {
|
|
197
|
+
const results = [
|
|
198
|
+
buildPaginationClasses('dotted', 'solid', extra),
|
|
199
|
+
buildTableClasses('m', 'column', 'cols', true, true, true, true, extra),
|
|
200
|
+
buildPopoverClasses('bottom', true, extra),
|
|
201
|
+
buildTooltipClasses('top-center', 's', extra),
|
|
202
|
+
buildTabClasses('underline', 'md', true, extra),
|
|
203
|
+
buildIconButtonClasses('primary', 'md', true, extra),
|
|
204
|
+
];
|
|
205
|
+
return results.every((result) => {
|
|
206
|
+
const tokens = result.split(' ');
|
|
207
|
+
// Extra token appears in result
|
|
208
|
+
const hasExtra = tokens.includes(extra);
|
|
209
|
+
// No duplicates
|
|
210
|
+
const noDuplicates = tokens.length === new Set(tokens).size;
|
|
211
|
+
// Extra token appears exactly once
|
|
212
|
+
const exactlyOnce = tokens.filter((t) => t === extra).length === 1;
|
|
213
|
+
return hasExtra && noDuplicates && exactlyOnce;
|
|
214
|
+
});
|
|
215
|
+
}), { numRuns: 25 });
|
|
216
|
+
});
|
|
217
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|