@testforgejs/vue-test-core 1.0.0-beta.1 → 1.0.0-beta.2

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 CHANGED
@@ -60,6 +60,58 @@ A preset controls:
60
60
 
61
61
  The preset system keeps the TestForge core independent from specific Vue ecosystem integrations. The core runtime does not need built-in knowledge of Pinia, Vue Router, Vue I18n, Vuetify, PrimeVue, or other integrations.
62
62
 
63
+ ### Single and Multiple Presets
64
+
65
+ `createTestFramework()` supports two mutually exclusive ways to configure presets.
66
+
67
+ Use `preset` when the framework needs a single runtime environment:
68
+
69
+ ```typescript
70
+ createTestFramework({
71
+ preset: projectPreset,
72
+ });
73
+ ```
74
+
75
+ Use `presets` when the framework should provide multiple named runtime environments:
76
+
77
+ ```typescript
78
+ createTestFramework({
79
+ presets: {
80
+ default: projectPreset,
81
+ i18n: i18nPreset,
82
+ router: routerPreset,
83
+ },
84
+ });
85
+ ```
86
+
87
+ These options cannot be used together.
88
+
89
+ A single `preset` is treated as the framework's `default` preset internally. A `presets` registry allows individual factory invocations to select a named preset through `extraOptions.preset`.
90
+
91
+ For example:
92
+
93
+ ```typescript
94
+ const { testComponentFactory } = createTestFramework({
95
+ presets: {
96
+ default: defaultPreset,
97
+ i18n: i18nPreset,
98
+ },
99
+ });
100
+
101
+ const factory = testComponentFactory(MyComponent);
102
+
103
+ factory(
104
+ {},
105
+ {},
106
+ {},
107
+ {
108
+ preset: "i18n",
109
+ },
110
+ );
111
+ ```
112
+
113
+ This distinction allows a project to start with a single custom runtime environment and introduce named runtime profiles later without changing the preset definition itself.
114
+
63
115
  ### Official preset packages
64
116
 
65
117
  TestForge provides a layered preset architecture:
@@ -100,7 +152,11 @@ The recommended presets include configurations for commonly used managed integra
100
152
  - Vue I18n;
101
153
  - Vue Router.
102
154
 
103
- The recommended preset packages are optional. You can also use the base presets directly or create and compose your own presets.
155
+ The recommended preset is a convenient starting point for exploring TestForge and its approach to reusable component test environments.
156
+
157
+ However, recommended presets are intentionally generic. Real applications usually have application-specific routes, managed plugins, and plugin defaults. Most projects will therefore eventually benefit from a project-specific preset that extends or adapts an existing preset to the application's runtime environment.
158
+
159
+ The recommended preset packages are optional. You can also use the base preset directly or create your own project-specific preset.
104
160
 
105
161
  > [!TIP]
106
162
  > If you are getting started with TestForge, use the recommended preset that matches your test runner.
@@ -111,7 +167,7 @@ See the [Getting Started Guide](https://github.com/testforgejs/testforge/blob/ma
111
167
 
112
168
  ## Quick Usage
113
169
 
114
- The following example uses Vitest and the recommended Vitest preset.
170
+ The following example uses Vitest and the recommended Vitest preset registry.
115
171
 
116
172
  ```typescript
117
173
  // tests/setup.ts
@@ -126,6 +182,8 @@ const { testComponentFactory } = createTestFramework({
126
182
  export { testComponentFactory };
127
183
  ```
128
184
 
185
+ This setup is a good starting point for exploring TestForge. As the application-specific testing environment grows, the project can define its own preset while continuing to reuse the official preset as a base.
186
+
129
187
  The resulting `testComponentFactory` can then be imported and reused throughout your component tests.
130
188
 
131
189
  ```typescript
@@ -151,6 +209,30 @@ For Jest projects, use `@testforgejs/vue-test-preset-recommended-jest` instead.
151
209
 
152
210
  👉 For a complete walkthrough, continue with the [Getting Started Guide](https://github.com/testforgejs/testforge/blob/main/docs/getting-started.md).
153
211
 
212
+ ---
213
+
214
+ ## Project-Specific Presets
215
+
216
+ Most applications will eventually benefit from some application-specific preset configuration.
217
+
218
+ For example, a project can extend the recommended preset with its own locale configuration:
219
+
220
+ ```typescript
221
+ import { extendPreset } from "@testforgejs/vue-test-core";
222
+ import { presets as recommendedPresets } from "@testforgejs/vue-test-preset-recommended";
223
+
224
+ const projectPreset = extendPreset(recommendedPresets.default, {
225
+ defaults: {
226
+ i18n: () => ({
227
+ ...recommendedPresets.default.defaults.i18n(),
228
+ locale: "uk",
229
+ }),
230
+ },
231
+ });
232
+ ```
233
+
234
+ ---
235
+
154
236
  ## Documentation
155
237
 
156
238
  - [Getting Started Guide](https://github.com/testforgejs/testforge/blob/main/docs/getting-started.md) — Set up TestForge in a project and create reusable component test factories.
package/dist/index.cjs CHANGED
@@ -56,16 +56,29 @@ var FRAMEWORK_NAME = "TestForge";
56
56
  var ERROR_PREFIX = `[${FRAMEWORK_NAME}]`;
57
57
  var DEFAULT_PRESET_NAME = "default";
58
58
 
59
+ // src/guards/isPlainObject.ts
60
+ function isPlainObject(item) {
61
+ if (item === null || typeof item !== "object" || Array.isArray(item)) {
62
+ return false;
63
+ }
64
+ const prototype = Object.getPrototypeOf(item);
65
+ return prototype === Object.prototype || prototype === null;
66
+ }
67
+
59
68
  // src/presets/validators/validatePreset.ts
60
69
  function validatePreset(name, preset) {
61
70
  if (!preset) {
62
71
  throw new Error(`${ERROR_PREFIX} Preset "${name}" is null or undefined.`);
63
72
  }
64
- if (!Array.isArray(preset.manifest)) {
73
+ if (!isPlainObject(preset)) {
74
+ throw new Error(`${ERROR_PREFIX} Preset "${name}" must be a plain object.`);
75
+ }
76
+ const manifest = preset.manifest;
77
+ if (!Array.isArray(manifest)) {
65
78
  throw new Error(`${ERROR_PREFIX} Preset "${name}" must have a "manifest" array.`);
66
79
  }
67
80
  const manifestPluginNames = /* @__PURE__ */ new Set();
68
- preset.manifest.forEach((entry, index) => {
81
+ manifest.forEach((entry, index) => {
69
82
  const { module: module2, enabled } = entry;
70
83
  if (!module2 || typeof module2.getName !== "function") {
71
84
  throw new Error(`${ERROR_PREFIX} Invalid module at manifest[${index}] in preset "${name}".`);
@@ -83,22 +96,24 @@ function validatePreset(name, preset) {
83
96
  }
84
97
  manifestPluginNames.add(pluginName);
85
98
  });
86
- if (preset.defaults) {
87
- const defaultKeys = Object.keys(preset.defaults);
88
- defaultKeys.forEach((key) => {
89
- if (!manifestPluginNames.has(key)) {
90
- throw new Error(
91
- `${ERROR_PREFIX} Preset "${name}" contains defaults for unknown plugin "${key}". This plugin is not present in the manifest.`
92
- );
93
- }
94
- const value = preset.defaults[key];
95
- if (typeof value !== "function") {
96
- throw new Error(
97
- `${ERROR_PREFIX} Invalid default configuration for plugin "${key}" in preset "${name}". Expected a plugin options factory function, but received ${typeof value}.`
98
- );
99
- }
100
- });
99
+ const defaults = preset.defaults;
100
+ if (!isPlainObject(defaults)) {
101
+ throw new Error(`${ERROR_PREFIX} Preset "${name}" must have a "defaults" plain object.`);
101
102
  }
103
+ const defaultKeys = Object.keys(defaults);
104
+ defaultKeys.forEach((key) => {
105
+ if (!manifestPluginNames.has(key)) {
106
+ throw new Error(
107
+ `${ERROR_PREFIX} Preset "${name}" contains defaults for unknown plugin "${key}". This plugin is not present in the manifest.`
108
+ );
109
+ }
110
+ const value = defaults[key];
111
+ if (typeof value !== "function") {
112
+ throw new Error(
113
+ `${ERROR_PREFIX} Invalid default configuration for plugin "${key}" in preset "${name}". Expected a plugin options factory function, but received ${typeof value}.`
114
+ );
115
+ }
116
+ });
102
117
  }
103
118
 
104
119
  // src/presets/getActivePreset.ts
@@ -331,15 +346,6 @@ var withBaseMountOptions = (ctx) => {
331
346
  });
332
347
  };
333
348
 
334
- // src/guards/isPlainObject.ts
335
- function isPlainObject(item) {
336
- if (item === null || typeof item !== "object" || Array.isArray(item)) {
337
- return false;
338
- }
339
- const prototype = Object.getPrototypeOf(item);
340
- return prototype === Object.prototype || prototype === null;
341
- }
342
-
343
349
  // src/utils/mergeConfigs.ts
344
350
  function mergeConfigs(target, source) {
345
351
  const arrays = Array.isArray(target) && Array.isArray(source);
@@ -643,7 +649,7 @@ function mountWithPlugins(component, ctx, overrides = {}, runtimeOptions = {
643
649
  }
644
650
 
645
651
  // src/presets/validators/validatePresets.ts
646
- function validatePresets(presets = {}) {
652
+ function validatePresets(presets) {
647
653
  if (!isPlainObject(presets)) {
648
654
  throw new Error(`${ERROR_PREFIX} Presets must be a plain object.`);
649
655
  }
@@ -652,8 +658,8 @@ function validatePresets(presets = {}) {
652
658
  });
653
659
  }
654
660
 
655
- // src/assertions/assertIsPlainObject.ts
656
- function assertIsPlainObject(value, name = "value") {
661
+ // src/assertions/assertIsPlainObjectValue.ts
662
+ function assertIsPlainObjectValue(value, name = "value") {
657
663
  if (!isPlainObject(value)) {
658
664
  throw new Error(`${name} must be a plain object.`);
659
665
  }
@@ -661,8 +667,14 @@ function assertIsPlainObject(value, name = "value") {
661
667
 
662
668
  // src/validators/validateCreateTestFrameworkOptions.ts
663
669
  function validateCreateTestFrameworkOptions(options = {}) {
664
- assertIsPlainObject(options, "createTestFramework options");
665
- const { shallowByDefault, presets } = options;
670
+ assertIsPlainObjectValue(options, "createTestFramework options");
671
+ const { preset, presets, shallowByDefault } = options;
672
+ if (preset !== void 0 && presets !== void 0) {
673
+ throw new Error(`${ERROR_PREFIX} "preset" and "presets" cannot be used together.`);
674
+ }
675
+ if (preset !== void 0) {
676
+ validatePreset("default", preset);
677
+ }
666
678
  if (presets !== void 0) {
667
679
  validatePresets(presets);
668
680
  }
@@ -765,10 +777,21 @@ function validateComponentFactoryArguments(props, mountOptions, slots, extraOpti
765
777
  validateComponentFactoryExtraOptions(extraOptions, presets);
766
778
  }
767
779
 
780
+ // src/core/utils/resolvePresets.ts
781
+ function resolvePresets(options) {
782
+ if (options.preset !== void 0) {
783
+ return {
784
+ default: options.preset
785
+ };
786
+ }
787
+ return options.presets ?? {};
788
+ }
789
+
768
790
  // src/core/createTestFramework.ts
769
791
  function createTestFramework(options = {}) {
770
792
  validateCreateTestFrameworkOptions(options);
771
- const { presets = {}, shallowByDefault = false } = options;
793
+ const { shallowByDefault = false } = options;
794
+ const presets = resolvePresets(options);
772
795
  const testComponentFactory = (component, defaultProps = {}, defaultMountOptions = {}, defaultSlots = {}) => {
773
796
  validateTestComponentFactoryArguments(
774
797
  component,
package/dist/index.d.cts CHANGED
@@ -29,6 +29,12 @@ type SupportedPluginsMap = Record<PluginName, SupportedPluginState>;
29
29
  type RuntimePluginConfig = Record<string, any>;
30
30
  type RuntimePluginOption = RuntimePluginConfig | false;
31
31
  type ResolvedPluginOptions = Record<PluginName, RuntimePluginOption>;
32
+ /**
33
+ * Default plugin configuration factories.
34
+ *
35
+ * Only plugins that require preset-level default configuration
36
+ * need to be included.
37
+ */
32
38
  type PluginConfigDefaults = Record<PluginName, PluginOptionsFactory<RuntimePluginConfig>>;
33
39
  type ResolvedPluginDefaults = Record<PluginName, RuntimePluginConfig>;
34
40
  interface PluginRuntimeMeta<TInstance> {
@@ -98,7 +104,15 @@ type ComponentFactoryExtraOptions = {
98
104
  * `plugin.getName()` for plugins declared in `manifest`.
99
105
  */
100
106
  interface PresetDefinition {
107
+ /** Plugins available to the preset and their enabled state. */
101
108
  manifest: PluginManifestEntry<any, any>[];
109
+ /**
110
+ * Default plugin configurations.
111
+ *
112
+ * A plugin declared in `manifest` does not have to be present here.
113
+ * Missing defaults mean that the preset provides no default configuration
114
+ * for that plugin.
115
+ */
102
116
  defaults: PluginConfigDefaults;
103
117
  }
104
118
  type TestFrameworkPresets = Record<string, PresetDefinition>;
@@ -160,9 +174,7 @@ type ComponentDataInput<T extends Component> = Partial<ComponentData<T>>;
160
174
  * instead of maintaining a parallel wrapper type hierarchy.
161
175
  */
162
176
  type ComponentFactory<T extends Component> = (props?: ComponentPropsInput<T>, mountOptions?: ComponentFactoryOptions<ComponentPropsInput<T>, ComponentSlotsInput<T>, ComponentDataInput<T>>, slots?: ComponentSlotsInput<T>, extraOptions?: ComponentFactoryExtraOptions) => ReturnType<typeof mount<T>>;
163
- interface CreateTestFrameworkOptions {
164
- /** Preset configurations for plugins */
165
- presets?: TestFrameworkPresets;
177
+ interface CommonCreateTestFrameworkOptions {
166
178
  /**
167
179
  * Default value for Vue Test Utils `shallow` mounting.
168
180
  *
@@ -173,6 +185,17 @@ interface CreateTestFrameworkOptions {
173
185
  */
174
186
  shallowByDefault?: boolean;
175
187
  }
188
+ interface SinglePresetOptions extends CommonCreateTestFrameworkOptions {
189
+ /** Single preset used by the framework. */
190
+ preset: PresetDefinition;
191
+ presets?: never;
192
+ }
193
+ interface MultiplePresetsOptions extends CommonCreateTestFrameworkOptions {
194
+ /** Named preset configurations for plugins. */
195
+ preset?: never;
196
+ presets?: TestFrameworkPresets;
197
+ }
198
+ type CreateTestFrameworkOptions = SinglePresetOptions | MultiplePresetsOptions;
176
199
  interface ComponentFactoryCreator {
177
200
  <T extends Component>(component: T, defaultProps?: ComponentPropsInput<T>, defaultMountOptions?: ComponentFactoryOptions<ComponentPropsInput<T>, ComponentSlotsInput<T>, ComponentDataInput<T>>, defaultSlots?: ComponentSlotsInput<T>): ComponentFactory<T>;
178
201
  }
@@ -193,10 +216,10 @@ declare function captureInstance<T = unknown>(): InstanceCapture<T>;
193
216
 
194
217
  declare function extendPreset(basePreset: PresetDefinition, extension: PresetExtension): PresetDefinition;
195
218
 
196
- declare function validatePreset(name: PluginName, preset: PresetDefinition): void;
219
+ declare function validatePreset(name: string, preset: unknown): asserts preset is PresetDefinition;
197
220
 
198
- declare function validatePresets(presets?: TestFrameworkPresets): void;
221
+ declare function validatePresets(presets: unknown): asserts presets is TestFrameworkPresets;
199
222
 
200
223
  declare const Types: {};
201
224
 
202
- export { type ComponentFactory, type ComponentFactoryCreator, type ComponentFactoryExtraOptions, type ComponentFactoryOptions, type MountPlugin, type PluginControlOptions, type PluginModule, type PluginOptionsFactory, type PluginOptionsInput, type PluginOptionsMap, type PluginOverridesInput, type PresetDefinition, type TestFramework, type TestFrameworkPresets, Types, captureInstance, createPluginInstance, createTestFramework, createVuePlugin, extendPreset, validatePreset, validatePresets };
225
+ export { type ComponentFactory, type ComponentFactoryCreator, type ComponentFactoryExtraOptions, type ComponentFactoryOptions, type CreateTestFrameworkOptions, type MountPlugin, type PluginControlOptions, type PluginManifestEntry, type PluginModule, type PluginOptionsFactory, type PluginOptionsInput, type PluginOptionsMap, type PluginOverridesInput, type PresetDefinition, type PresetExtension, type TestFramework, type TestFrameworkPresets, Types, captureInstance, createPluginInstance, createTestFramework, createVuePlugin, extendPreset, validatePreset, validatePresets };
package/dist/index.d.ts CHANGED
@@ -29,6 +29,12 @@ type SupportedPluginsMap = Record<PluginName, SupportedPluginState>;
29
29
  type RuntimePluginConfig = Record<string, any>;
30
30
  type RuntimePluginOption = RuntimePluginConfig | false;
31
31
  type ResolvedPluginOptions = Record<PluginName, RuntimePluginOption>;
32
+ /**
33
+ * Default plugin configuration factories.
34
+ *
35
+ * Only plugins that require preset-level default configuration
36
+ * need to be included.
37
+ */
32
38
  type PluginConfigDefaults = Record<PluginName, PluginOptionsFactory<RuntimePluginConfig>>;
33
39
  type ResolvedPluginDefaults = Record<PluginName, RuntimePluginConfig>;
34
40
  interface PluginRuntimeMeta<TInstance> {
@@ -98,7 +104,15 @@ type ComponentFactoryExtraOptions = {
98
104
  * `plugin.getName()` for plugins declared in `manifest`.
99
105
  */
100
106
  interface PresetDefinition {
107
+ /** Plugins available to the preset and their enabled state. */
101
108
  manifest: PluginManifestEntry<any, any>[];
109
+ /**
110
+ * Default plugin configurations.
111
+ *
112
+ * A plugin declared in `manifest` does not have to be present here.
113
+ * Missing defaults mean that the preset provides no default configuration
114
+ * for that plugin.
115
+ */
102
116
  defaults: PluginConfigDefaults;
103
117
  }
104
118
  type TestFrameworkPresets = Record<string, PresetDefinition>;
@@ -160,9 +174,7 @@ type ComponentDataInput<T extends Component> = Partial<ComponentData<T>>;
160
174
  * instead of maintaining a parallel wrapper type hierarchy.
161
175
  */
162
176
  type ComponentFactory<T extends Component> = (props?: ComponentPropsInput<T>, mountOptions?: ComponentFactoryOptions<ComponentPropsInput<T>, ComponentSlotsInput<T>, ComponentDataInput<T>>, slots?: ComponentSlotsInput<T>, extraOptions?: ComponentFactoryExtraOptions) => ReturnType<typeof mount<T>>;
163
- interface CreateTestFrameworkOptions {
164
- /** Preset configurations for plugins */
165
- presets?: TestFrameworkPresets;
177
+ interface CommonCreateTestFrameworkOptions {
166
178
  /**
167
179
  * Default value for Vue Test Utils `shallow` mounting.
168
180
  *
@@ -173,6 +185,17 @@ interface CreateTestFrameworkOptions {
173
185
  */
174
186
  shallowByDefault?: boolean;
175
187
  }
188
+ interface SinglePresetOptions extends CommonCreateTestFrameworkOptions {
189
+ /** Single preset used by the framework. */
190
+ preset: PresetDefinition;
191
+ presets?: never;
192
+ }
193
+ interface MultiplePresetsOptions extends CommonCreateTestFrameworkOptions {
194
+ /** Named preset configurations for plugins. */
195
+ preset?: never;
196
+ presets?: TestFrameworkPresets;
197
+ }
198
+ type CreateTestFrameworkOptions = SinglePresetOptions | MultiplePresetsOptions;
176
199
  interface ComponentFactoryCreator {
177
200
  <T extends Component>(component: T, defaultProps?: ComponentPropsInput<T>, defaultMountOptions?: ComponentFactoryOptions<ComponentPropsInput<T>, ComponentSlotsInput<T>, ComponentDataInput<T>>, defaultSlots?: ComponentSlotsInput<T>): ComponentFactory<T>;
178
201
  }
@@ -193,10 +216,10 @@ declare function captureInstance<T = unknown>(): InstanceCapture<T>;
193
216
 
194
217
  declare function extendPreset(basePreset: PresetDefinition, extension: PresetExtension): PresetDefinition;
195
218
 
196
- declare function validatePreset(name: PluginName, preset: PresetDefinition): void;
219
+ declare function validatePreset(name: string, preset: unknown): asserts preset is PresetDefinition;
197
220
 
198
- declare function validatePresets(presets?: TestFrameworkPresets): void;
221
+ declare function validatePresets(presets: unknown): asserts presets is TestFrameworkPresets;
199
222
 
200
223
  declare const Types: {};
201
224
 
202
- export { type ComponentFactory, type ComponentFactoryCreator, type ComponentFactoryExtraOptions, type ComponentFactoryOptions, type MountPlugin, type PluginControlOptions, type PluginModule, type PluginOptionsFactory, type PluginOptionsInput, type PluginOptionsMap, type PluginOverridesInput, type PresetDefinition, type TestFramework, type TestFrameworkPresets, Types, captureInstance, createPluginInstance, createTestFramework, createVuePlugin, extendPreset, validatePreset, validatePresets };
225
+ export { type ComponentFactory, type ComponentFactoryCreator, type ComponentFactoryExtraOptions, type ComponentFactoryOptions, type CreateTestFrameworkOptions, type MountPlugin, type PluginControlOptions, type PluginManifestEntry, type PluginModule, type PluginOptionsFactory, type PluginOptionsInput, type PluginOptionsMap, type PluginOverridesInput, type PresetDefinition, type PresetExtension, type TestFramework, type TestFrameworkPresets, Types, captureInstance, createPluginInstance, createTestFramework, createVuePlugin, extendPreset, validatePreset, validatePresets };
package/dist/index.js CHANGED
@@ -23,16 +23,29 @@ var FRAMEWORK_NAME = "TestForge";
23
23
  var ERROR_PREFIX = `[${FRAMEWORK_NAME}]`;
24
24
  var DEFAULT_PRESET_NAME = "default";
25
25
 
26
+ // src/guards/isPlainObject.ts
27
+ function isPlainObject(item) {
28
+ if (item === null || typeof item !== "object" || Array.isArray(item)) {
29
+ return false;
30
+ }
31
+ const prototype = Object.getPrototypeOf(item);
32
+ return prototype === Object.prototype || prototype === null;
33
+ }
34
+
26
35
  // src/presets/validators/validatePreset.ts
27
36
  function validatePreset(name, preset) {
28
37
  if (!preset) {
29
38
  throw new Error(`${ERROR_PREFIX} Preset "${name}" is null or undefined.`);
30
39
  }
31
- if (!Array.isArray(preset.manifest)) {
40
+ if (!isPlainObject(preset)) {
41
+ throw new Error(`${ERROR_PREFIX} Preset "${name}" must be a plain object.`);
42
+ }
43
+ const manifest = preset.manifest;
44
+ if (!Array.isArray(manifest)) {
32
45
  throw new Error(`${ERROR_PREFIX} Preset "${name}" must have a "manifest" array.`);
33
46
  }
34
47
  const manifestPluginNames = /* @__PURE__ */ new Set();
35
- preset.manifest.forEach((entry, index) => {
48
+ manifest.forEach((entry, index) => {
36
49
  const { module, enabled } = entry;
37
50
  if (!module || typeof module.getName !== "function") {
38
51
  throw new Error(`${ERROR_PREFIX} Invalid module at manifest[${index}] in preset "${name}".`);
@@ -50,22 +63,24 @@ function validatePreset(name, preset) {
50
63
  }
51
64
  manifestPluginNames.add(pluginName);
52
65
  });
53
- if (preset.defaults) {
54
- const defaultKeys = Object.keys(preset.defaults);
55
- defaultKeys.forEach((key) => {
56
- if (!manifestPluginNames.has(key)) {
57
- throw new Error(
58
- `${ERROR_PREFIX} Preset "${name}" contains defaults for unknown plugin "${key}". This plugin is not present in the manifest.`
59
- );
60
- }
61
- const value = preset.defaults[key];
62
- if (typeof value !== "function") {
63
- throw new Error(
64
- `${ERROR_PREFIX} Invalid default configuration for plugin "${key}" in preset "${name}". Expected a plugin options factory function, but received ${typeof value}.`
65
- );
66
- }
67
- });
66
+ const defaults = preset.defaults;
67
+ if (!isPlainObject(defaults)) {
68
+ throw new Error(`${ERROR_PREFIX} Preset "${name}" must have a "defaults" plain object.`);
68
69
  }
70
+ const defaultKeys = Object.keys(defaults);
71
+ defaultKeys.forEach((key) => {
72
+ if (!manifestPluginNames.has(key)) {
73
+ throw new Error(
74
+ `${ERROR_PREFIX} Preset "${name}" contains defaults for unknown plugin "${key}". This plugin is not present in the manifest.`
75
+ );
76
+ }
77
+ const value = defaults[key];
78
+ if (typeof value !== "function") {
79
+ throw new Error(
80
+ `${ERROR_PREFIX} Invalid default configuration for plugin "${key}" in preset "${name}". Expected a plugin options factory function, but received ${typeof value}.`
81
+ );
82
+ }
83
+ });
69
84
  }
70
85
 
71
86
  // src/presets/getActivePreset.ts
@@ -298,15 +313,6 @@ var withBaseMountOptions = (ctx) => {
298
313
  });
299
314
  };
300
315
 
301
- // src/guards/isPlainObject.ts
302
- function isPlainObject(item) {
303
- if (item === null || typeof item !== "object" || Array.isArray(item)) {
304
- return false;
305
- }
306
- const prototype = Object.getPrototypeOf(item);
307
- return prototype === Object.prototype || prototype === null;
308
- }
309
-
310
316
  // src/utils/mergeConfigs.ts
311
317
  function mergeConfigs(target, source) {
312
318
  const arrays = Array.isArray(target) && Array.isArray(source);
@@ -610,7 +616,7 @@ function mountWithPlugins(component, ctx, overrides = {}, runtimeOptions = {
610
616
  }
611
617
 
612
618
  // src/presets/validators/validatePresets.ts
613
- function validatePresets(presets = {}) {
619
+ function validatePresets(presets) {
614
620
  if (!isPlainObject(presets)) {
615
621
  throw new Error(`${ERROR_PREFIX} Presets must be a plain object.`);
616
622
  }
@@ -619,8 +625,8 @@ function validatePresets(presets = {}) {
619
625
  });
620
626
  }
621
627
 
622
- // src/assertions/assertIsPlainObject.ts
623
- function assertIsPlainObject(value, name = "value") {
628
+ // src/assertions/assertIsPlainObjectValue.ts
629
+ function assertIsPlainObjectValue(value, name = "value") {
624
630
  if (!isPlainObject(value)) {
625
631
  throw new Error(`${name} must be a plain object.`);
626
632
  }
@@ -628,8 +634,14 @@ function assertIsPlainObject(value, name = "value") {
628
634
 
629
635
  // src/validators/validateCreateTestFrameworkOptions.ts
630
636
  function validateCreateTestFrameworkOptions(options = {}) {
631
- assertIsPlainObject(options, "createTestFramework options");
632
- const { shallowByDefault, presets } = options;
637
+ assertIsPlainObjectValue(options, "createTestFramework options");
638
+ const { preset, presets, shallowByDefault } = options;
639
+ if (preset !== void 0 && presets !== void 0) {
640
+ throw new Error(`${ERROR_PREFIX} "preset" and "presets" cannot be used together.`);
641
+ }
642
+ if (preset !== void 0) {
643
+ validatePreset("default", preset);
644
+ }
633
645
  if (presets !== void 0) {
634
646
  validatePresets(presets);
635
647
  }
@@ -732,10 +744,21 @@ function validateComponentFactoryArguments(props, mountOptions, slots, extraOpti
732
744
  validateComponentFactoryExtraOptions(extraOptions, presets);
733
745
  }
734
746
 
747
+ // src/core/utils/resolvePresets.ts
748
+ function resolvePresets(options) {
749
+ if (options.preset !== void 0) {
750
+ return {
751
+ default: options.preset
752
+ };
753
+ }
754
+ return options.presets ?? {};
755
+ }
756
+
735
757
  // src/core/createTestFramework.ts
736
758
  function createTestFramework(options = {}) {
737
759
  validateCreateTestFrameworkOptions(options);
738
- const { presets = {}, shallowByDefault = false } = options;
760
+ const { shallowByDefault = false } = options;
761
+ const presets = resolvePresets(options);
739
762
  const testComponentFactory = (component, defaultProps = {}, defaultMountOptions = {}, defaultSlots = {}) => {
740
763
  validateTestComponentFactoryArguments(
741
764
  component,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testforgejs/vue-test-core",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.2",
4
4
  "type": "module",
5
5
  "description": "Core testing utilities and pipeline orchestration for the TestForge component testing framework",
6
6
  "homepage": "https://github.com/testforgejs/testforge#readme",
@@ -52,11 +52,7 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@vue/test-utils": "^2.0.0",
55
- "vue": "^3.3.0",
56
- "vue-router": "^5.0.0",
57
- "@testforgejs/vue-test-plugin-i18n": "1.0.0-beta.1",
58
- "@testforgejs/vue-test-plugin-router": "1.0.0-beta.1",
59
- "@testforgejs/vue-test-plugin-pinia": "1.0.0-beta.1"
55
+ "vue": "^3.3.0"
60
56
  },
61
57
  "tsd": {
62
58
  "directory": "test-d"