@form-eng/core 1.2.1 → 1.4.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/dist/adapter-utils.d.mts +107 -0
- package/dist/adapter-utils.d.ts +107 -0
- package/dist/adapter-utils.js +146 -0
- package/dist/adapter-utils.js.map +1 -0
- package/dist/adapter-utils.mjs +33 -0
- package/dist/adapter-utils.mjs.map +1 -0
- package/dist/chunk-F57MYSS6.mjs +133 -0
- package/dist/chunk-F57MYSS6.mjs.map +1 -0
- package/dist/chunk-YMUYHDWI.mjs +57 -0
- package/dist/chunk-YMUYHDWI.mjs.map +1 -0
- package/dist/index-BrfbmVFA.d.mts +24 -0
- package/dist/index-BrfbmVFA.d.ts +24 -0
- package/dist/index.d.mts +4 -127
- package/dist/index.d.ts +4 -127
- package/dist/index.mjs +27 -162
- package/dist/index.mjs.map +1 -1
- package/dist/testing.d.mts +30 -0
- package/dist/testing.d.ts +30 -0
- package/dist/testing.js +231 -0
- package/dist/testing.js.map +1 -0
- package/dist/testing.mjs +157 -0
- package/dist/testing.mjs.map +1 -0
- package/package.json +24 -2
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { D as Dictionary } from './index-BrfbmVFA.mjs';
|
|
3
|
+
|
|
4
|
+
/** Tier 1 field types that every adapter should implement */
|
|
5
|
+
declare const TIER_1_FIELDS: readonly ["Textbox", "Number", "Toggle", "Dropdown", "SimpleDropdown", "Multiselect", "DateControl", "Slider", "RadioGroup", "CheckboxGroup", "Textarea", "ReadOnly", "DynamicFragment"];
|
|
6
|
+
/** All standard field types (Tier 1 + 2 + 3) */
|
|
7
|
+
declare const ALL_FIELD_TYPES: ("Textbox" | "Dropdown" | "Toggle" | "Number" | "Multiselect" | "DateControl" | "Slider" | "DynamicFragment" | "SimpleDropdown" | "MultiSelectSearch" | "PopOutEditor" | "RichText" | "Textarea" | "DocumentLinks" | "StatusDropdown" | "ReadOnly" | "ReadOnlyArray" | "ReadOnlyDateTime" | "ReadOnlyCumulativeNumber" | "ReadOnlyRichText" | "ReadOnlyWithButton" | "ChoiceSet" | "FieldArray" | "RadioGroup" | "CheckboxGroup" | "Rating" | "ColorPicker" | "Autocomplete" | "FileUpload" | "DateRange" | "DateTime" | "PhoneInput")[];
|
|
8
|
+
/** Default test values by field type */
|
|
9
|
+
declare const VALUE_BY_TYPE: Record<string, unknown>;
|
|
10
|
+
interface IContractTestOptions {
|
|
11
|
+
/** Field types to exclude from registry presence check */
|
|
12
|
+
excludeTypes?: string[];
|
|
13
|
+
/** If set, only test these types instead of ALL_FIELD_TYPES */
|
|
14
|
+
onlyTypes?: string[];
|
|
15
|
+
/** Description prefix for the test suite */
|
|
16
|
+
suiteName: string;
|
|
17
|
+
/** Optional wrapper component for providers (e.g., StyletronProvider for base-web) */
|
|
18
|
+
wrapper?: React.ComponentType<{
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Runs the adapter contract test suite against a field registry.
|
|
24
|
+
*
|
|
25
|
+
* @param registryFactory - Function that creates the field registry
|
|
26
|
+
* @param options - Test configuration
|
|
27
|
+
*/
|
|
28
|
+
declare function runAdapterContractTests(registryFactory: () => Dictionary<React.JSX.Element>, options: IContractTestOptions): void;
|
|
29
|
+
|
|
30
|
+
export { ALL_FIELD_TYPES, type IContractTestOptions, TIER_1_FIELDS, VALUE_BY_TYPE, runAdapterContractTests };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { D as Dictionary } from './index-BrfbmVFA.js';
|
|
3
|
+
|
|
4
|
+
/** Tier 1 field types that every adapter should implement */
|
|
5
|
+
declare const TIER_1_FIELDS: readonly ["Textbox", "Number", "Toggle", "Dropdown", "SimpleDropdown", "Multiselect", "DateControl", "Slider", "RadioGroup", "CheckboxGroup", "Textarea", "ReadOnly", "DynamicFragment"];
|
|
6
|
+
/** All standard field types (Tier 1 + 2 + 3) */
|
|
7
|
+
declare const ALL_FIELD_TYPES: ("Textbox" | "Dropdown" | "Toggle" | "Number" | "Multiselect" | "DateControl" | "Slider" | "DynamicFragment" | "SimpleDropdown" | "MultiSelectSearch" | "PopOutEditor" | "RichText" | "Textarea" | "DocumentLinks" | "StatusDropdown" | "ReadOnly" | "ReadOnlyArray" | "ReadOnlyDateTime" | "ReadOnlyCumulativeNumber" | "ReadOnlyRichText" | "ReadOnlyWithButton" | "ChoiceSet" | "FieldArray" | "RadioGroup" | "CheckboxGroup" | "Rating" | "ColorPicker" | "Autocomplete" | "FileUpload" | "DateRange" | "DateTime" | "PhoneInput")[];
|
|
8
|
+
/** Default test values by field type */
|
|
9
|
+
declare const VALUE_BY_TYPE: Record<string, unknown>;
|
|
10
|
+
interface IContractTestOptions {
|
|
11
|
+
/** Field types to exclude from registry presence check */
|
|
12
|
+
excludeTypes?: string[];
|
|
13
|
+
/** If set, only test these types instead of ALL_FIELD_TYPES */
|
|
14
|
+
onlyTypes?: string[];
|
|
15
|
+
/** Description prefix for the test suite */
|
|
16
|
+
suiteName: string;
|
|
17
|
+
/** Optional wrapper component for providers (e.g., StyletronProvider for base-web) */
|
|
18
|
+
wrapper?: React.ComponentType<{
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Runs the adapter contract test suite against a field registry.
|
|
24
|
+
*
|
|
25
|
+
* @param registryFactory - Function that creates the field registry
|
|
26
|
+
* @param options - Test configuration
|
|
27
|
+
*/
|
|
28
|
+
declare function runAdapterContractTests(registryFactory: () => Dictionary<React.JSX.Element>, options: IContractTestOptions): void;
|
|
29
|
+
|
|
30
|
+
export { ALL_FIELD_TYPES, type IContractTestOptions, TIER_1_FIELDS, VALUE_BY_TYPE, runAdapterContractTests };
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/testing.ts
|
|
31
|
+
var testing_exports = {};
|
|
32
|
+
__export(testing_exports, {
|
|
33
|
+
ALL_FIELD_TYPES: () => ALL_FIELD_TYPES,
|
|
34
|
+
TIER_1_FIELDS: () => TIER_1_FIELDS,
|
|
35
|
+
VALUE_BY_TYPE: () => VALUE_BY_TYPE,
|
|
36
|
+
runAdapterContractTests: () => runAdapterContractTests
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(testing_exports);
|
|
39
|
+
|
|
40
|
+
// src/testing/fieldContractTests.tsx
|
|
41
|
+
var import_vitest = require("vitest");
|
|
42
|
+
var import_react = require("@testing-library/react");
|
|
43
|
+
var import_react2 = __toESM(require("react"));
|
|
44
|
+
|
|
45
|
+
// src/constants.ts
|
|
46
|
+
var ComponentTypes = {
|
|
47
|
+
Textbox: "Textbox",
|
|
48
|
+
Dropdown: "Dropdown",
|
|
49
|
+
Toggle: "Toggle",
|
|
50
|
+
Number: "Number",
|
|
51
|
+
MultiSelect: "Multiselect",
|
|
52
|
+
DateControl: "DateControl",
|
|
53
|
+
Slider: "Slider",
|
|
54
|
+
Fragment: "DynamicFragment",
|
|
55
|
+
SimpleDropdown: "SimpleDropdown",
|
|
56
|
+
MultiSelectSearch: "MultiSelectSearch",
|
|
57
|
+
PopOutEditor: "PopOutEditor",
|
|
58
|
+
RichText: "RichText",
|
|
59
|
+
Textarea: "Textarea",
|
|
60
|
+
DocumentLinks: "DocumentLinks",
|
|
61
|
+
StatusDropdown: "StatusDropdown",
|
|
62
|
+
ReadOnly: "ReadOnly",
|
|
63
|
+
ReadOnlyArray: "ReadOnlyArray",
|
|
64
|
+
ReadOnlyDateTime: "ReadOnlyDateTime",
|
|
65
|
+
ReadOnlyCumulativeNumber: "ReadOnlyCumulativeNumber",
|
|
66
|
+
ReadOnlyRichText: "ReadOnlyRichText",
|
|
67
|
+
ReadOnlyWithButton: "ReadOnlyWithButton",
|
|
68
|
+
ChoiceSet: "ChoiceSet",
|
|
69
|
+
FieldArray: "FieldArray",
|
|
70
|
+
RadioGroup: "RadioGroup",
|
|
71
|
+
CheckboxGroup: "CheckboxGroup",
|
|
72
|
+
Rating: "Rating",
|
|
73
|
+
ColorPicker: "ColorPicker",
|
|
74
|
+
Autocomplete: "Autocomplete",
|
|
75
|
+
FileUpload: "FileUpload",
|
|
76
|
+
DateRange: "DateRange",
|
|
77
|
+
DateTime: "DateTime",
|
|
78
|
+
PhoneInput: "PhoneInput"
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// src/testing/fieldContractTests.tsx
|
|
82
|
+
var TIER_1_FIELDS = [
|
|
83
|
+
ComponentTypes.Textbox,
|
|
84
|
+
ComponentTypes.Number,
|
|
85
|
+
ComponentTypes.Toggle,
|
|
86
|
+
ComponentTypes.Dropdown,
|
|
87
|
+
ComponentTypes.SimpleDropdown,
|
|
88
|
+
ComponentTypes.MultiSelect,
|
|
89
|
+
ComponentTypes.DateControl,
|
|
90
|
+
ComponentTypes.Slider,
|
|
91
|
+
ComponentTypes.RadioGroup,
|
|
92
|
+
ComponentTypes.CheckboxGroup,
|
|
93
|
+
ComponentTypes.Textarea,
|
|
94
|
+
ComponentTypes.ReadOnly,
|
|
95
|
+
ComponentTypes.Fragment
|
|
96
|
+
];
|
|
97
|
+
var ALL_FIELD_TYPES = Object.values(ComponentTypes);
|
|
98
|
+
var VALUE_BY_TYPE = {
|
|
99
|
+
[ComponentTypes.Textbox]: "hello",
|
|
100
|
+
[ComponentTypes.Number]: 42,
|
|
101
|
+
[ComponentTypes.Toggle]: true,
|
|
102
|
+
[ComponentTypes.Dropdown]: "opt1",
|
|
103
|
+
[ComponentTypes.SimpleDropdown]: "opt1",
|
|
104
|
+
[ComponentTypes.MultiSelect]: ["opt1"],
|
|
105
|
+
[ComponentTypes.DateControl]: "2024-01-15",
|
|
106
|
+
[ComponentTypes.Slider]: 50,
|
|
107
|
+
[ComponentTypes.RadioGroup]: "opt1",
|
|
108
|
+
[ComponentTypes.CheckboxGroup]: ["opt1"],
|
|
109
|
+
[ComponentTypes.Textarea]: "some text",
|
|
110
|
+
[ComponentTypes.ReadOnly]: "read only text",
|
|
111
|
+
[ComponentTypes.Fragment]: "hidden",
|
|
112
|
+
// Tier 2+ types
|
|
113
|
+
[ComponentTypes.MultiSelectSearch]: ["opt1"],
|
|
114
|
+
[ComponentTypes.ReadOnlyArray]: ["item1", "item2"],
|
|
115
|
+
[ComponentTypes.ReadOnlyDateTime]: "2024-01-15T10:30:00Z",
|
|
116
|
+
[ComponentTypes.ReadOnlyRichText]: "<p>rich text</p>",
|
|
117
|
+
[ComponentTypes.ReadOnlyWithButton]: "value",
|
|
118
|
+
[ComponentTypes.Rating]: 3,
|
|
119
|
+
[ComponentTypes.ColorPicker]: "#ff0000",
|
|
120
|
+
[ComponentTypes.Autocomplete]: "opt1",
|
|
121
|
+
[ComponentTypes.FileUpload]: null,
|
|
122
|
+
[ComponentTypes.DateRange]: { start: "2024-01-01", end: "2024-01-31" },
|
|
123
|
+
[ComponentTypes.DateTime]: "2024-01-15T10:30:00Z",
|
|
124
|
+
[ComponentTypes.PhoneInput]: "5551234567"
|
|
125
|
+
};
|
|
126
|
+
var TEST_OPTIONS = [
|
|
127
|
+
{ value: "opt1", label: "Option 1" },
|
|
128
|
+
{ value: "opt2", label: "Option 2" }
|
|
129
|
+
];
|
|
130
|
+
var OPTION_FIELDS = /* @__PURE__ */ new Set([
|
|
131
|
+
ComponentTypes.Dropdown,
|
|
132
|
+
ComponentTypes.SimpleDropdown,
|
|
133
|
+
ComponentTypes.MultiSelect,
|
|
134
|
+
ComponentTypes.MultiSelectSearch,
|
|
135
|
+
ComponentTypes.RadioGroup,
|
|
136
|
+
ComponentTypes.CheckboxGroup,
|
|
137
|
+
ComponentTypes.Autocomplete
|
|
138
|
+
]);
|
|
139
|
+
function runAdapterContractTests(registryFactory, options) {
|
|
140
|
+
const { excludeTypes = [], suiteName, onlyTypes, wrapper } = options;
|
|
141
|
+
(0, import_vitest.describe)(`${suiteName} adapter contract`, () => {
|
|
142
|
+
let registry;
|
|
143
|
+
(0, import_vitest.beforeEach)(() => {
|
|
144
|
+
registry = registryFactory();
|
|
145
|
+
});
|
|
146
|
+
const typesToTest = onlyTypes ?? ALL_FIELD_TYPES.filter((t) => !excludeTypes.includes(t));
|
|
147
|
+
const renderWithWrapper = (element) => {
|
|
148
|
+
return (0, import_react.render)(element, wrapper ? { wrapper } : void 0);
|
|
149
|
+
};
|
|
150
|
+
(0, import_vitest.describe)("registry coverage", () => {
|
|
151
|
+
(0, import_vitest.it)("registry is a non-empty object", () => {
|
|
152
|
+
(0, import_vitest.expect)(typeof registry).toBe("object");
|
|
153
|
+
(0, import_vitest.expect)(Object.keys(registry).length).toBeGreaterThan(0);
|
|
154
|
+
});
|
|
155
|
+
for (const type of typesToTest) {
|
|
156
|
+
(0, import_vitest.it)(`has entry for "${type}"`, () => {
|
|
157
|
+
(0, import_vitest.expect)(registry[type]).toBeDefined();
|
|
158
|
+
(0, import_vitest.expect)(import_react2.default.isValidElement(registry[type])).toBe(true);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
(0, import_vitest.describe)("field rendering", () => {
|
|
163
|
+
const minimalProps = {
|
|
164
|
+
fieldName: "testField",
|
|
165
|
+
programName: "testProg",
|
|
166
|
+
entityType: "testEntity",
|
|
167
|
+
entityId: "123",
|
|
168
|
+
value: void 0,
|
|
169
|
+
readOnly: false,
|
|
170
|
+
required: false,
|
|
171
|
+
setFieldValue: import_vitest.vi.fn()
|
|
172
|
+
};
|
|
173
|
+
for (const type of typesToTest) {
|
|
174
|
+
(0, import_vitest.it)(`"${type}" renders without error with minimal props`, () => {
|
|
175
|
+
const element = registry[type];
|
|
176
|
+
if (!element) return;
|
|
177
|
+
const props = OPTION_FIELDS.has(type) ? { ...minimalProps, options: TEST_OPTIONS } : minimalProps;
|
|
178
|
+
const { container } = renderWithWrapper(import_react2.default.cloneElement(element, props));
|
|
179
|
+
(0, import_vitest.expect)(container).toBeTruthy();
|
|
180
|
+
});
|
|
181
|
+
(0, import_vitest.it)(`"${type}" renders in readOnly mode`, () => {
|
|
182
|
+
const element = registry[type];
|
|
183
|
+
if (!element) return;
|
|
184
|
+
const readOnlyValue = VALUE_BY_TYPE[type] ?? "Test";
|
|
185
|
+
const props = OPTION_FIELDS.has(type) ? { ...minimalProps, readOnly: true, value: readOnlyValue, options: TEST_OPTIONS } : { ...minimalProps, readOnly: true, value: readOnlyValue };
|
|
186
|
+
const { container } = renderWithWrapper(
|
|
187
|
+
import_react2.default.cloneElement(element, props)
|
|
188
|
+
);
|
|
189
|
+
(0, import_vitest.expect)(container).toBeTruthy();
|
|
190
|
+
});
|
|
191
|
+
(0, import_vitest.it)(`"${type}" renders in disabled state`, () => {
|
|
192
|
+
const element = registry[type];
|
|
193
|
+
if (!element) return;
|
|
194
|
+
const props = OPTION_FIELDS.has(type) ? { ...minimalProps, disabled: true, options: TEST_OPTIONS } : { ...minimalProps, disabled: true };
|
|
195
|
+
const { container } = renderWithWrapper(import_react2.default.cloneElement(element, props));
|
|
196
|
+
(0, import_vitest.expect)(container).toBeTruthy();
|
|
197
|
+
});
|
|
198
|
+
(0, import_vitest.it)(`"${type}" renders in required state`, () => {
|
|
199
|
+
const element = registry[type];
|
|
200
|
+
if (!element) return;
|
|
201
|
+
const props = OPTION_FIELDS.has(type) ? { ...minimalProps, required: true, options: TEST_OPTIONS } : { ...minimalProps, required: true };
|
|
202
|
+
const { container } = renderWithWrapper(import_react2.default.cloneElement(element, props));
|
|
203
|
+
(0, import_vitest.expect)(container).toBeTruthy();
|
|
204
|
+
});
|
|
205
|
+
(0, import_vitest.it)(`"${type}" renders with a value`, () => {
|
|
206
|
+
const element = registry[type];
|
|
207
|
+
if (!element) return;
|
|
208
|
+
const testValue = VALUE_BY_TYPE[type];
|
|
209
|
+
const props = OPTION_FIELDS.has(type) ? { ...minimalProps, value: testValue, options: TEST_OPTIONS } : { ...minimalProps, value: testValue };
|
|
210
|
+
const { container } = renderWithWrapper(import_react2.default.cloneElement(element, props));
|
|
211
|
+
(0, import_vitest.expect)(container).toBeTruthy();
|
|
212
|
+
});
|
|
213
|
+
(0, import_vitest.it)(`"${type}" renders safely with undefined value`, () => {
|
|
214
|
+
const element = registry[type];
|
|
215
|
+
if (!element) return;
|
|
216
|
+
const props = OPTION_FIELDS.has(type) ? { ...minimalProps, value: void 0, options: TEST_OPTIONS } : { ...minimalProps, value: void 0 };
|
|
217
|
+
const { container } = renderWithWrapper(import_react2.default.cloneElement(element, props));
|
|
218
|
+
(0, import_vitest.expect)(container).toBeTruthy();
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
225
|
+
0 && (module.exports = {
|
|
226
|
+
ALL_FIELD_TYPES,
|
|
227
|
+
TIER_1_FIELDS,
|
|
228
|
+
VALUE_BY_TYPE,
|
|
229
|
+
runAdapterContractTests
|
|
230
|
+
});
|
|
231
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/testing.ts","../src/testing/fieldContractTests.tsx","../src/constants.ts"],"sourcesContent":["/**\n * Testing utilities subpath export.\n *\n * Import as: import { ... } from \"@form-eng/core/testing\"\n *\n * Provides contract test infrastructure for adapter packages to validate\n * their field registries conform to the adapter contract.\n *\n * NOTE: This module imports from vitest and @testing-library/react.\n * It should only be imported in test files where these dependencies are available.\n */\n\n/// <reference types=\"vitest\" />\n\nexport {\n runAdapterContractTests,\n TIER_1_FIELDS,\n ALL_FIELD_TYPES,\n VALUE_BY_TYPE,\n} from \"./testing/index\";\nexport type { IContractTestOptions } from \"./testing/index\";\n","/**\n * Shared adapter contract test suite.\n *\n * Generates a set of vitest tests that validate a field registry\n * conforms to the adapter contract. Each adapter package should\n * import this function and call it with their registry factory.\n */\nimport { describe, it, expect, vi, beforeEach } from \"vitest\";\nimport { render } from \"@testing-library/react\";\nimport React from \"react\";\nimport { ComponentTypes } from \"../constants\";\nimport type { Dictionary } from \"../utils\";\nimport type { IOption } from \"../types/IOption\";\n\n/** Tier 1 field types that every adapter should implement */\nexport const TIER_1_FIELDS = [\n ComponentTypes.Textbox,\n ComponentTypes.Number,\n ComponentTypes.Toggle,\n ComponentTypes.Dropdown,\n ComponentTypes.SimpleDropdown,\n ComponentTypes.MultiSelect,\n ComponentTypes.DateControl,\n ComponentTypes.Slider,\n ComponentTypes.RadioGroup,\n ComponentTypes.CheckboxGroup,\n ComponentTypes.Textarea,\n ComponentTypes.ReadOnly,\n ComponentTypes.Fragment,\n] as const;\n\n/** All standard field types (Tier 1 + 2 + 3) */\nexport const ALL_FIELD_TYPES = Object.values(ComponentTypes);\n\n/** Default test values by field type */\nexport const VALUE_BY_TYPE: Record<string, unknown> = {\n [ComponentTypes.Textbox]: \"hello\",\n [ComponentTypes.Number]: 42,\n [ComponentTypes.Toggle]: true,\n [ComponentTypes.Dropdown]: \"opt1\",\n [ComponentTypes.SimpleDropdown]: \"opt1\",\n [ComponentTypes.MultiSelect]: [\"opt1\"],\n [ComponentTypes.DateControl]: \"2024-01-15\",\n [ComponentTypes.Slider]: 50,\n [ComponentTypes.RadioGroup]: \"opt1\",\n [ComponentTypes.CheckboxGroup]: [\"opt1\"],\n [ComponentTypes.Textarea]: \"some text\",\n [ComponentTypes.ReadOnly]: \"read only text\",\n [ComponentTypes.Fragment]: \"hidden\",\n // Tier 2+ types\n [ComponentTypes.MultiSelectSearch]: [\"opt1\"],\n [ComponentTypes.ReadOnlyArray]: [\"item1\", \"item2\"],\n [ComponentTypes.ReadOnlyDateTime]: \"2024-01-15T10:30:00Z\",\n [ComponentTypes.ReadOnlyRichText]: \"<p>rich text</p>\",\n [ComponentTypes.ReadOnlyWithButton]: \"value\",\n [ComponentTypes.Rating]: 3,\n [ComponentTypes.ColorPicker]: \"#ff0000\",\n [ComponentTypes.Autocomplete]: \"opt1\",\n [ComponentTypes.FileUpload]: null,\n [ComponentTypes.DateRange]: { start: \"2024-01-01\", end: \"2024-01-31\" },\n [ComponentTypes.DateTime]: \"2024-01-15T10:30:00Z\",\n [ComponentTypes.PhoneInput]: \"5551234567\",\n};\n\n/** Default test options for select-like fields */\nconst TEST_OPTIONS: IOption[] = [\n { value: \"opt1\", label: \"Option 1\" },\n { value: \"opt2\", label: \"Option 2\" },\n];\n\n/** Fields that use options */\nconst OPTION_FIELDS: Set<string> = new Set([\n ComponentTypes.Dropdown,\n ComponentTypes.SimpleDropdown,\n ComponentTypes.MultiSelect,\n ComponentTypes.MultiSelectSearch,\n ComponentTypes.RadioGroup,\n ComponentTypes.CheckboxGroup,\n ComponentTypes.Autocomplete,\n]);\n\nexport interface IContractTestOptions {\n /** Field types to exclude from registry presence check */\n excludeTypes?: string[];\n /** If set, only test these types instead of ALL_FIELD_TYPES */\n onlyTypes?: string[];\n /** Description prefix for the test suite */\n suiteName: string;\n /** Optional wrapper component for providers (e.g., StyletronProvider for base-web) */\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n}\n\n/**\n * Runs the adapter contract test suite against a field registry.\n *\n * @param registryFactory - Function that creates the field registry\n * @param options - Test configuration\n */\nexport function runAdapterContractTests(\n registryFactory: () => Dictionary<React.JSX.Element>,\n options: IContractTestOptions\n) {\n const { excludeTypes = [], suiteName, onlyTypes, wrapper } = options;\n\n describe(`${suiteName} adapter contract`, () => {\n let registry: Dictionary<React.JSX.Element>;\n\n beforeEach(() => {\n registry = registryFactory();\n });\n\n const typesToTest = onlyTypes ?? ALL_FIELD_TYPES.filter(t => !excludeTypes.includes(t));\n\n const renderWithWrapper = (element: React.ReactElement) => {\n return render(element, wrapper ? { wrapper } : undefined);\n };\n\n describe(\"registry coverage\", () => {\n it(\"registry is a non-empty object\", () => {\n expect(typeof registry).toBe(\"object\");\n expect(Object.keys(registry).length).toBeGreaterThan(0);\n });\n\n for (const type of typesToTest) {\n it(`has entry for \"${type}\"`, () => {\n expect(registry[type]).toBeDefined();\n expect(React.isValidElement(registry[type])).toBe(true);\n });\n }\n });\n\n describe(\"field rendering\", () => {\n const minimalProps = {\n fieldName: \"testField\",\n programName: \"testProg\",\n entityType: \"testEntity\",\n entityId: \"123\",\n value: undefined,\n readOnly: false,\n required: false,\n setFieldValue: vi.fn(),\n };\n\n for (const type of typesToTest) {\n it(`\"${type}\" renders without error with minimal props`, () => {\n const element = registry[type];\n if (!element) return;\n const props = OPTION_FIELDS.has(type)\n ? { ...minimalProps, options: TEST_OPTIONS }\n : minimalProps;\n const { container } = renderWithWrapper(React.cloneElement(element, props));\n expect(container).toBeTruthy();\n });\n\n it(`\"${type}\" renders in readOnly mode`, () => {\n const element = registry[type];\n if (!element) return;\n const readOnlyValue = VALUE_BY_TYPE[type] ?? \"Test\";\n const props = OPTION_FIELDS.has(type)\n ? { ...minimalProps, readOnly: true, value: readOnlyValue, options: TEST_OPTIONS }\n : { ...minimalProps, readOnly: true, value: readOnlyValue };\n const { container } = renderWithWrapper(\n React.cloneElement(element, props)\n );\n expect(container).toBeTruthy();\n });\n\n it(`\"${type}\" renders in disabled state`, () => {\n const element = registry[type];\n if (!element) return;\n const props = OPTION_FIELDS.has(type)\n ? { ...minimalProps, disabled: true, options: TEST_OPTIONS }\n : { ...minimalProps, disabled: true };\n const { container } = renderWithWrapper(React.cloneElement(element, props));\n expect(container).toBeTruthy();\n });\n\n it(`\"${type}\" renders in required state`, () => {\n const element = registry[type];\n if (!element) return;\n const props = OPTION_FIELDS.has(type)\n ? { ...minimalProps, required: true, options: TEST_OPTIONS }\n : { ...minimalProps, required: true };\n const { container } = renderWithWrapper(React.cloneElement(element, props));\n expect(container).toBeTruthy();\n });\n\n it(`\"${type}\" renders with a value`, () => {\n const element = registry[type];\n if (!element) return;\n const testValue = VALUE_BY_TYPE[type];\n const props = OPTION_FIELDS.has(type)\n ? { ...minimalProps, value: testValue, options: TEST_OPTIONS }\n : { ...minimalProps, value: testValue };\n const { container } = renderWithWrapper(React.cloneElement(element, props));\n expect(container).toBeTruthy();\n });\n\n it(`\"${type}\" renders safely with undefined value`, () => {\n const element = registry[type];\n if (!element) return;\n const props = OPTION_FIELDS.has(type)\n ? { ...minimalProps, value: undefined, options: TEST_OPTIONS }\n : { ...minimalProps, value: undefined };\n const { container } = renderWithWrapper(React.cloneElement(element, props));\n expect(container).toBeTruthy();\n });\n }\n });\n });\n}\n","export const FIELD_PARENT_PREFIX = \"Parent.\";\n\n/** Component type constants */\nexport const ComponentTypes = {\n Textbox: \"Textbox\",\n Dropdown: \"Dropdown\",\n Toggle: \"Toggle\",\n Number: \"Number\",\n MultiSelect: \"Multiselect\",\n DateControl: \"DateControl\",\n Slider: \"Slider\",\n Fragment: \"DynamicFragment\",\n SimpleDropdown: \"SimpleDropdown\",\n MultiSelectSearch: \"MultiSelectSearch\",\n PopOutEditor: \"PopOutEditor\",\n RichText: \"RichText\",\n Textarea: \"Textarea\",\n DocumentLinks: \"DocumentLinks\",\n StatusDropdown: \"StatusDropdown\",\n ReadOnly: \"ReadOnly\",\n ReadOnlyArray: \"ReadOnlyArray\",\n ReadOnlyDateTime: \"ReadOnlyDateTime\",\n ReadOnlyCumulativeNumber: \"ReadOnlyCumulativeNumber\",\n ReadOnlyRichText: \"ReadOnlyRichText\",\n ReadOnlyWithButton: \"ReadOnlyWithButton\",\n ChoiceSet: \"ChoiceSet\",\n FieldArray: \"FieldArray\",\n RadioGroup: \"RadioGroup\",\n CheckboxGroup: \"CheckboxGroup\",\n Rating: \"Rating\",\n ColorPicker: \"ColorPicker\",\n Autocomplete: \"Autocomplete\",\n FileUpload: \"FileUpload\",\n DateRange: \"DateRange\",\n DateTime: \"DateTime\",\n PhoneInput: \"PhoneInput\",\n} as const;\n\n/** Form-level constants */\nexport const FormConstants = {\n defaultExpandCutoffCount: 12,\n loadingShimmerCount: 12,\n loadingFieldShimmerHeight: 32,\n na: \"n/a\",\n panelActionKeys: {\n cancel: \"Cancel\",\n close: \"Close\",\n create: \"Create\",\n update: \"Update\",\n },\n urlRegex: /(http(s?)):\\/\\//i,\n errorColor: \"#a4262c\",\n} as const;\n\n"],"mappings":"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","names":["import_react","React"]}
|
package/dist/testing.mjs
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ComponentTypes
|
|
3
|
+
} from "./chunk-YMUYHDWI.mjs";
|
|
4
|
+
|
|
5
|
+
// src/testing/fieldContractTests.tsx
|
|
6
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
7
|
+
import { render } from "@testing-library/react";
|
|
8
|
+
import React from "react";
|
|
9
|
+
var TIER_1_FIELDS = [
|
|
10
|
+
ComponentTypes.Textbox,
|
|
11
|
+
ComponentTypes.Number,
|
|
12
|
+
ComponentTypes.Toggle,
|
|
13
|
+
ComponentTypes.Dropdown,
|
|
14
|
+
ComponentTypes.SimpleDropdown,
|
|
15
|
+
ComponentTypes.MultiSelect,
|
|
16
|
+
ComponentTypes.DateControl,
|
|
17
|
+
ComponentTypes.Slider,
|
|
18
|
+
ComponentTypes.RadioGroup,
|
|
19
|
+
ComponentTypes.CheckboxGroup,
|
|
20
|
+
ComponentTypes.Textarea,
|
|
21
|
+
ComponentTypes.ReadOnly,
|
|
22
|
+
ComponentTypes.Fragment
|
|
23
|
+
];
|
|
24
|
+
var ALL_FIELD_TYPES = Object.values(ComponentTypes);
|
|
25
|
+
var VALUE_BY_TYPE = {
|
|
26
|
+
[ComponentTypes.Textbox]: "hello",
|
|
27
|
+
[ComponentTypes.Number]: 42,
|
|
28
|
+
[ComponentTypes.Toggle]: true,
|
|
29
|
+
[ComponentTypes.Dropdown]: "opt1",
|
|
30
|
+
[ComponentTypes.SimpleDropdown]: "opt1",
|
|
31
|
+
[ComponentTypes.MultiSelect]: ["opt1"],
|
|
32
|
+
[ComponentTypes.DateControl]: "2024-01-15",
|
|
33
|
+
[ComponentTypes.Slider]: 50,
|
|
34
|
+
[ComponentTypes.RadioGroup]: "opt1",
|
|
35
|
+
[ComponentTypes.CheckboxGroup]: ["opt1"],
|
|
36
|
+
[ComponentTypes.Textarea]: "some text",
|
|
37
|
+
[ComponentTypes.ReadOnly]: "read only text",
|
|
38
|
+
[ComponentTypes.Fragment]: "hidden",
|
|
39
|
+
// Tier 2+ types
|
|
40
|
+
[ComponentTypes.MultiSelectSearch]: ["opt1"],
|
|
41
|
+
[ComponentTypes.ReadOnlyArray]: ["item1", "item2"],
|
|
42
|
+
[ComponentTypes.ReadOnlyDateTime]: "2024-01-15T10:30:00Z",
|
|
43
|
+
[ComponentTypes.ReadOnlyRichText]: "<p>rich text</p>",
|
|
44
|
+
[ComponentTypes.ReadOnlyWithButton]: "value",
|
|
45
|
+
[ComponentTypes.Rating]: 3,
|
|
46
|
+
[ComponentTypes.ColorPicker]: "#ff0000",
|
|
47
|
+
[ComponentTypes.Autocomplete]: "opt1",
|
|
48
|
+
[ComponentTypes.FileUpload]: null,
|
|
49
|
+
[ComponentTypes.DateRange]: { start: "2024-01-01", end: "2024-01-31" },
|
|
50
|
+
[ComponentTypes.DateTime]: "2024-01-15T10:30:00Z",
|
|
51
|
+
[ComponentTypes.PhoneInput]: "5551234567"
|
|
52
|
+
};
|
|
53
|
+
var TEST_OPTIONS = [
|
|
54
|
+
{ value: "opt1", label: "Option 1" },
|
|
55
|
+
{ value: "opt2", label: "Option 2" }
|
|
56
|
+
];
|
|
57
|
+
var OPTION_FIELDS = /* @__PURE__ */ new Set([
|
|
58
|
+
ComponentTypes.Dropdown,
|
|
59
|
+
ComponentTypes.SimpleDropdown,
|
|
60
|
+
ComponentTypes.MultiSelect,
|
|
61
|
+
ComponentTypes.MultiSelectSearch,
|
|
62
|
+
ComponentTypes.RadioGroup,
|
|
63
|
+
ComponentTypes.CheckboxGroup,
|
|
64
|
+
ComponentTypes.Autocomplete
|
|
65
|
+
]);
|
|
66
|
+
function runAdapterContractTests(registryFactory, options) {
|
|
67
|
+
const { excludeTypes = [], suiteName, onlyTypes, wrapper } = options;
|
|
68
|
+
describe(`${suiteName} adapter contract`, () => {
|
|
69
|
+
let registry;
|
|
70
|
+
beforeEach(() => {
|
|
71
|
+
registry = registryFactory();
|
|
72
|
+
});
|
|
73
|
+
const typesToTest = onlyTypes ?? ALL_FIELD_TYPES.filter((t) => !excludeTypes.includes(t));
|
|
74
|
+
const renderWithWrapper = (element) => {
|
|
75
|
+
return render(element, wrapper ? { wrapper } : void 0);
|
|
76
|
+
};
|
|
77
|
+
describe("registry coverage", () => {
|
|
78
|
+
it("registry is a non-empty object", () => {
|
|
79
|
+
expect(typeof registry).toBe("object");
|
|
80
|
+
expect(Object.keys(registry).length).toBeGreaterThan(0);
|
|
81
|
+
});
|
|
82
|
+
for (const type of typesToTest) {
|
|
83
|
+
it(`has entry for "${type}"`, () => {
|
|
84
|
+
expect(registry[type]).toBeDefined();
|
|
85
|
+
expect(React.isValidElement(registry[type])).toBe(true);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
describe("field rendering", () => {
|
|
90
|
+
const minimalProps = {
|
|
91
|
+
fieldName: "testField",
|
|
92
|
+
programName: "testProg",
|
|
93
|
+
entityType: "testEntity",
|
|
94
|
+
entityId: "123",
|
|
95
|
+
value: void 0,
|
|
96
|
+
readOnly: false,
|
|
97
|
+
required: false,
|
|
98
|
+
setFieldValue: vi.fn()
|
|
99
|
+
};
|
|
100
|
+
for (const type of typesToTest) {
|
|
101
|
+
it(`"${type}" renders without error with minimal props`, () => {
|
|
102
|
+
const element = registry[type];
|
|
103
|
+
if (!element) return;
|
|
104
|
+
const props = OPTION_FIELDS.has(type) ? { ...minimalProps, options: TEST_OPTIONS } : minimalProps;
|
|
105
|
+
const { container } = renderWithWrapper(React.cloneElement(element, props));
|
|
106
|
+
expect(container).toBeTruthy();
|
|
107
|
+
});
|
|
108
|
+
it(`"${type}" renders in readOnly mode`, () => {
|
|
109
|
+
const element = registry[type];
|
|
110
|
+
if (!element) return;
|
|
111
|
+
const readOnlyValue = VALUE_BY_TYPE[type] ?? "Test";
|
|
112
|
+
const props = OPTION_FIELDS.has(type) ? { ...minimalProps, readOnly: true, value: readOnlyValue, options: TEST_OPTIONS } : { ...minimalProps, readOnly: true, value: readOnlyValue };
|
|
113
|
+
const { container } = renderWithWrapper(
|
|
114
|
+
React.cloneElement(element, props)
|
|
115
|
+
);
|
|
116
|
+
expect(container).toBeTruthy();
|
|
117
|
+
});
|
|
118
|
+
it(`"${type}" renders in disabled state`, () => {
|
|
119
|
+
const element = registry[type];
|
|
120
|
+
if (!element) return;
|
|
121
|
+
const props = OPTION_FIELDS.has(type) ? { ...minimalProps, disabled: true, options: TEST_OPTIONS } : { ...minimalProps, disabled: true };
|
|
122
|
+
const { container } = renderWithWrapper(React.cloneElement(element, props));
|
|
123
|
+
expect(container).toBeTruthy();
|
|
124
|
+
});
|
|
125
|
+
it(`"${type}" renders in required state`, () => {
|
|
126
|
+
const element = registry[type];
|
|
127
|
+
if (!element) return;
|
|
128
|
+
const props = OPTION_FIELDS.has(type) ? { ...minimalProps, required: true, options: TEST_OPTIONS } : { ...minimalProps, required: true };
|
|
129
|
+
const { container } = renderWithWrapper(React.cloneElement(element, props));
|
|
130
|
+
expect(container).toBeTruthy();
|
|
131
|
+
});
|
|
132
|
+
it(`"${type}" renders with a value`, () => {
|
|
133
|
+
const element = registry[type];
|
|
134
|
+
if (!element) return;
|
|
135
|
+
const testValue = VALUE_BY_TYPE[type];
|
|
136
|
+
const props = OPTION_FIELDS.has(type) ? { ...minimalProps, value: testValue, options: TEST_OPTIONS } : { ...minimalProps, value: testValue };
|
|
137
|
+
const { container } = renderWithWrapper(React.cloneElement(element, props));
|
|
138
|
+
expect(container).toBeTruthy();
|
|
139
|
+
});
|
|
140
|
+
it(`"${type}" renders safely with undefined value`, () => {
|
|
141
|
+
const element = registry[type];
|
|
142
|
+
if (!element) return;
|
|
143
|
+
const props = OPTION_FIELDS.has(type) ? { ...minimalProps, value: void 0, options: TEST_OPTIONS } : { ...minimalProps, value: void 0 };
|
|
144
|
+
const { container } = renderWithWrapper(React.cloneElement(element, props));
|
|
145
|
+
expect(container).toBeTruthy();
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
export {
|
|
152
|
+
ALL_FIELD_TYPES,
|
|
153
|
+
TIER_1_FIELDS,
|
|
154
|
+
VALUE_BY_TYPE,
|
|
155
|
+
runAdapterContractTests
|
|
156
|
+
};
|
|
157
|
+
//# sourceMappingURL=testing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/testing/fieldContractTests.tsx"],"sourcesContent":["/**\n * Shared adapter contract test suite.\n *\n * Generates a set of vitest tests that validate a field registry\n * conforms to the adapter contract. Each adapter package should\n * import this function and call it with their registry factory.\n */\nimport { describe, it, expect, vi, beforeEach } from \"vitest\";\nimport { render } from \"@testing-library/react\";\nimport React from \"react\";\nimport { ComponentTypes } from \"../constants\";\nimport type { Dictionary } from \"../utils\";\nimport type { IOption } from \"../types/IOption\";\n\n/** Tier 1 field types that every adapter should implement */\nexport const TIER_1_FIELDS = [\n ComponentTypes.Textbox,\n ComponentTypes.Number,\n ComponentTypes.Toggle,\n ComponentTypes.Dropdown,\n ComponentTypes.SimpleDropdown,\n ComponentTypes.MultiSelect,\n ComponentTypes.DateControl,\n ComponentTypes.Slider,\n ComponentTypes.RadioGroup,\n ComponentTypes.CheckboxGroup,\n ComponentTypes.Textarea,\n ComponentTypes.ReadOnly,\n ComponentTypes.Fragment,\n] as const;\n\n/** All standard field types (Tier 1 + 2 + 3) */\nexport const ALL_FIELD_TYPES = Object.values(ComponentTypes);\n\n/** Default test values by field type */\nexport const VALUE_BY_TYPE: Record<string, unknown> = {\n [ComponentTypes.Textbox]: \"hello\",\n [ComponentTypes.Number]: 42,\n [ComponentTypes.Toggle]: true,\n [ComponentTypes.Dropdown]: \"opt1\",\n [ComponentTypes.SimpleDropdown]: \"opt1\",\n [ComponentTypes.MultiSelect]: [\"opt1\"],\n [ComponentTypes.DateControl]: \"2024-01-15\",\n [ComponentTypes.Slider]: 50,\n [ComponentTypes.RadioGroup]: \"opt1\",\n [ComponentTypes.CheckboxGroup]: [\"opt1\"],\n [ComponentTypes.Textarea]: \"some text\",\n [ComponentTypes.ReadOnly]: \"read only text\",\n [ComponentTypes.Fragment]: \"hidden\",\n // Tier 2+ types\n [ComponentTypes.MultiSelectSearch]: [\"opt1\"],\n [ComponentTypes.ReadOnlyArray]: [\"item1\", \"item2\"],\n [ComponentTypes.ReadOnlyDateTime]: \"2024-01-15T10:30:00Z\",\n [ComponentTypes.ReadOnlyRichText]: \"<p>rich text</p>\",\n [ComponentTypes.ReadOnlyWithButton]: \"value\",\n [ComponentTypes.Rating]: 3,\n [ComponentTypes.ColorPicker]: \"#ff0000\",\n [ComponentTypes.Autocomplete]: \"opt1\",\n [ComponentTypes.FileUpload]: null,\n [ComponentTypes.DateRange]: { start: \"2024-01-01\", end: \"2024-01-31\" },\n [ComponentTypes.DateTime]: \"2024-01-15T10:30:00Z\",\n [ComponentTypes.PhoneInput]: \"5551234567\",\n};\n\n/** Default test options for select-like fields */\nconst TEST_OPTIONS: IOption[] = [\n { value: \"opt1\", label: \"Option 1\" },\n { value: \"opt2\", label: \"Option 2\" },\n];\n\n/** Fields that use options */\nconst OPTION_FIELDS: Set<string> = new Set([\n ComponentTypes.Dropdown,\n ComponentTypes.SimpleDropdown,\n ComponentTypes.MultiSelect,\n ComponentTypes.MultiSelectSearch,\n ComponentTypes.RadioGroup,\n ComponentTypes.CheckboxGroup,\n ComponentTypes.Autocomplete,\n]);\n\nexport interface IContractTestOptions {\n /** Field types to exclude from registry presence check */\n excludeTypes?: string[];\n /** If set, only test these types instead of ALL_FIELD_TYPES */\n onlyTypes?: string[];\n /** Description prefix for the test suite */\n suiteName: string;\n /** Optional wrapper component for providers (e.g., StyletronProvider for base-web) */\n wrapper?: React.ComponentType<{ children: React.ReactNode }>;\n}\n\n/**\n * Runs the adapter contract test suite against a field registry.\n *\n * @param registryFactory - Function that creates the field registry\n * @param options - Test configuration\n */\nexport function runAdapterContractTests(\n registryFactory: () => Dictionary<React.JSX.Element>,\n options: IContractTestOptions\n) {\n const { excludeTypes = [], suiteName, onlyTypes, wrapper } = options;\n\n describe(`${suiteName} adapter contract`, () => {\n let registry: Dictionary<React.JSX.Element>;\n\n beforeEach(() => {\n registry = registryFactory();\n });\n\n const typesToTest = onlyTypes ?? ALL_FIELD_TYPES.filter(t => !excludeTypes.includes(t));\n\n const renderWithWrapper = (element: React.ReactElement) => {\n return render(element, wrapper ? { wrapper } : undefined);\n };\n\n describe(\"registry coverage\", () => {\n it(\"registry is a non-empty object\", () => {\n expect(typeof registry).toBe(\"object\");\n expect(Object.keys(registry).length).toBeGreaterThan(0);\n });\n\n for (const type of typesToTest) {\n it(`has entry for \"${type}\"`, () => {\n expect(registry[type]).toBeDefined();\n expect(React.isValidElement(registry[type])).toBe(true);\n });\n }\n });\n\n describe(\"field rendering\", () => {\n const minimalProps = {\n fieldName: \"testField\",\n programName: \"testProg\",\n entityType: \"testEntity\",\n entityId: \"123\",\n value: undefined,\n readOnly: false,\n required: false,\n setFieldValue: vi.fn(),\n };\n\n for (const type of typesToTest) {\n it(`\"${type}\" renders without error with minimal props`, () => {\n const element = registry[type];\n if (!element) return;\n const props = OPTION_FIELDS.has(type)\n ? { ...minimalProps, options: TEST_OPTIONS }\n : minimalProps;\n const { container } = renderWithWrapper(React.cloneElement(element, props));\n expect(container).toBeTruthy();\n });\n\n it(`\"${type}\" renders in readOnly mode`, () => {\n const element = registry[type];\n if (!element) return;\n const readOnlyValue = VALUE_BY_TYPE[type] ?? \"Test\";\n const props = OPTION_FIELDS.has(type)\n ? { ...minimalProps, readOnly: true, value: readOnlyValue, options: TEST_OPTIONS }\n : { ...minimalProps, readOnly: true, value: readOnlyValue };\n const { container } = renderWithWrapper(\n React.cloneElement(element, props)\n );\n expect(container).toBeTruthy();\n });\n\n it(`\"${type}\" renders in disabled state`, () => {\n const element = registry[type];\n if (!element) return;\n const props = OPTION_FIELDS.has(type)\n ? { ...minimalProps, disabled: true, options: TEST_OPTIONS }\n : { ...minimalProps, disabled: true };\n const { container } = renderWithWrapper(React.cloneElement(element, props));\n expect(container).toBeTruthy();\n });\n\n it(`\"${type}\" renders in required state`, () => {\n const element = registry[type];\n if (!element) return;\n const props = OPTION_FIELDS.has(type)\n ? { ...minimalProps, required: true, options: TEST_OPTIONS }\n : { ...minimalProps, required: true };\n const { container } = renderWithWrapper(React.cloneElement(element, props));\n expect(container).toBeTruthy();\n });\n\n it(`\"${type}\" renders with a value`, () => {\n const element = registry[type];\n if (!element) return;\n const testValue = VALUE_BY_TYPE[type];\n const props = OPTION_FIELDS.has(type)\n ? { ...minimalProps, value: testValue, options: TEST_OPTIONS }\n : { ...minimalProps, value: testValue };\n const { container } = renderWithWrapper(React.cloneElement(element, props));\n expect(container).toBeTruthy();\n });\n\n it(`\"${type}\" renders safely with undefined value`, () => {\n const element = registry[type];\n if (!element) return;\n const props = OPTION_FIELDS.has(type)\n ? { ...minimalProps, value: undefined, options: TEST_OPTIONS }\n : { ...minimalProps, value: undefined };\n const { container } = renderWithWrapper(React.cloneElement(element, props));\n expect(container).toBeTruthy();\n });\n }\n });\n });\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@form-eng/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Core business rules engine and form orchestration for dynamic React forms",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -42,6 +42,16 @@
|
|
|
42
42
|
"types": "./dist/index.d.ts",
|
|
43
43
|
"import": "./dist/index.mjs",
|
|
44
44
|
"require": "./dist/index.js"
|
|
45
|
+
},
|
|
46
|
+
"./adapter-utils": {
|
|
47
|
+
"types": "./dist/adapter-utils.d.ts",
|
|
48
|
+
"import": "./dist/adapter-utils.mjs",
|
|
49
|
+
"require": "./dist/adapter-utils.js"
|
|
50
|
+
},
|
|
51
|
+
"./testing": {
|
|
52
|
+
"types": "./dist/testing.d.ts",
|
|
53
|
+
"import": "./dist/testing.mjs",
|
|
54
|
+
"require": "./dist/testing.js"
|
|
45
55
|
}
|
|
46
56
|
},
|
|
47
57
|
"files": [
|
|
@@ -61,12 +71,24 @@
|
|
|
61
71
|
"react-hook-form": "^7.0.0"
|
|
62
72
|
},
|
|
63
73
|
"devDependencies": {
|
|
74
|
+
"@form-eng/antd": "*",
|
|
75
|
+
"@form-eng/atlaskit": "*",
|
|
76
|
+
"@form-eng/base-web": "*",
|
|
77
|
+
"@form-eng/chakra": "*",
|
|
78
|
+
"@form-eng/fluent": "*",
|
|
79
|
+
"@form-eng/headless": "*",
|
|
80
|
+
"@form-eng/heroui": "*",
|
|
81
|
+
"@form-eng/mantine": "*",
|
|
82
|
+
"@form-eng/mui": "*",
|
|
83
|
+
"@testing-library/react": "^16.3.2",
|
|
64
84
|
"@types/expr-eval": "^1.0.2",
|
|
65
85
|
"@types/react": "^19.2.14",
|
|
66
86
|
"react": "^19.2.4",
|
|
87
|
+
"react-dom": "^19.2.4",
|
|
67
88
|
"react-hook-form": "^7.71.2",
|
|
68
89
|
"tsup": "^8.5.1",
|
|
69
|
-
"typescript": "^5.9.3"
|
|
90
|
+
"typescript": "^5.9.3",
|
|
91
|
+
"vitest": "^4.0.18"
|
|
70
92
|
},
|
|
71
93
|
"dependencies": {
|
|
72
94
|
"expr-eval": "^2.0.2"
|