@testforgejs/vue-test-preset-recommended-jest 1.0.0-beta.2 → 1.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,9 +2,42 @@
2
2
 
3
3
  Recommended **Jest** presets for the [TestForge](https://github.com/testforgejs/testforge) Vue 3 component testing framework.
4
4
 
5
- This package builds on [`@testforgejs/vue-test-preset-base`](https://www.npmjs.com/package/@testforgejs/vue-test-preset-base) and provides recommended defaults for projects using **Jest**.
5
+ This package builds on [`@testforgejs/vue-test-preset-base`](https://www.npmjs.com/package/@testforgejs/vue-test-preset-base) and adds Jest-specific configuration where required.
6
6
 
7
- The main difference from the base presets is the Pinia configuration: the recommended presets configure Pinia to use Jest's `jest.fn` as its `createSpy` implementation.
7
+ The primary difference from the base presets is the Pinia configuration:
8
+
9
+ ```typescript
10
+ piniaPlugin.getDefaultOptions(jest);
11
+ ```
12
+
13
+ This allows the Pinia plugin to use Jest's `jest.fn` as the `createSpy` implementation required by `@pinia/testing` when an explicit runner is provided.
14
+
15
+ Vue I18n and Vue Router do not require Jest-specific configuration, so their presets are inherited directly from the base package.
16
+
17
+ Conceptually:
18
+
19
+ ```text
20
+ plugin
21
+ → owns reusable integration knowledge
22
+
23
+ base preset
24
+ → consumes runner-independent plugin defaults
25
+ → composes plugins without choosing a test runner
26
+
27
+ recommended-jest preset
28
+ → consumes runner-aware plugin defaults
29
+ → adds Jest-specific runner integration
30
+
31
+ project-owned preset
32
+ → materializes concrete plugin configuration
33
+ → owns application-specific policy
34
+ ```
35
+
36
+ The distinction between the recommended Jest preset and a project-owned preset is intentional.
37
+
38
+ The TestForge-maintained recommended preset may use `getDefaultOptions()` because it deliberately follows the integration baseline exported by the installed plugin version.
39
+
40
+ A project-owned preset should normally materialize the concrete configuration it wants to preserve in its own source code.
8
41
 
9
42
  ## Installation
10
43
 
@@ -32,7 +65,7 @@ yarn add -D @testforgejs/vue-test-preset-recommended-jest@beta
32
65
 
33
66
  ## Quick Usage
34
67
 
35
- Import the `presets` object and pass it to `createTestFramework()`:
68
+ For a single runtime environment, pass the recommended default preset through `preset`:
36
69
 
37
70
  ```typescript
38
71
  // tests/setup.ts
@@ -41,16 +74,17 @@ import { createTestFramework } from "@testforgejs/vue-test-core";
41
74
  import { presets } from "@testforgejs/vue-test-preset-recommended-jest";
42
75
 
43
76
  const { testComponentFactory } = createTestFramework({
44
- presets,
77
+ preset: presets.default,
45
78
  });
46
79
 
47
80
  export { testComponentFactory };
48
81
  ```
49
82
 
50
- You can then use `testComponentFactory` in your component tests:
83
+ You can then use `testComponentFactory` in component tests:
51
84
 
52
85
  ```typescript
53
86
  import { describe, expect, it } from "@jest/globals";
87
+
54
88
  import { testComponentFactory } from "./setup";
55
89
  import MyComponent from "./MyComponent.vue";
56
90
 
@@ -64,6 +98,50 @@ describe("MyComponent", () => {
64
98
  });
65
99
  ```
66
100
 
101
+ ## Single vs. Multiple Presets
102
+
103
+ `createTestFramework()` supports two mutually exclusive preset configuration forms.
104
+
105
+ Use `preset` when the framework needs a single runtime environment:
106
+
107
+ ```typescript
108
+ const { testComponentFactory } = createTestFramework({
109
+ preset: presets.default,
110
+ });
111
+ ```
112
+
113
+ A single preset is treated as the framework's default runtime environment.
114
+
115
+ Use `presets` when the framework should expose multiple named runtime environments:
116
+
117
+ ```typescript
118
+ const { testComponentFactory } = createTestFramework({
119
+ presets,
120
+ });
121
+ ```
122
+
123
+ The exported registry contains:
124
+
125
+ ```text
126
+ default
127
+ piniaPreset
128
+ i18nPreset
129
+ routerPreset
130
+ ```
131
+
132
+ Named presets registered through `presets` can be selected for individual component factory invocations through `extraOptions.preset`.
133
+
134
+ In general:
135
+
136
+ ```text
137
+ preset
138
+ → one runtime environment
139
+
140
+ presets
141
+ → multiple named runtime environments
142
+ → runtime selection through extraOptions.preset
143
+ ```
144
+
67
145
  ## Available Presets
68
146
 
69
147
  The package exports four presets:
@@ -73,136 +151,271 @@ The package exports four presets:
73
151
  - `presets.i18nPreset`
74
152
  - `presets.routerPreset`
75
153
 
76
- The presets are based on the corresponding presets from `@testforgejs/vue-test-preset-base`.
154
+ They are built from the corresponding presets exported by `@testforgejs/vue-test-preset-base`.
155
+
156
+ The current composition is equivalent to:
157
+
158
+ ```typescript
159
+ import { jest } from "@jest/globals";
160
+
161
+ import { extendPreset } from "@testforgejs/vue-test-core";
162
+ import { presets as basePresets } from "@testforgejs/vue-test-preset-base";
163
+ import { piniaPlugin, PLUGIN_NAME as PINIA_PLUGIN_NAME } from "@testforgejs/vue-test-plugin-pinia";
164
+
165
+ export const presets = {
166
+ default: extendPreset(basePresets.default, {
167
+ defaults: {
168
+ [PINIA_PLUGIN_NAME]: piniaPlugin.getDefaultOptions(jest),
169
+ },
170
+ }),
171
+
172
+ piniaPreset: extendPreset(basePresets.piniaPreset, {
173
+ defaults: {
174
+ [PINIA_PLUGIN_NAME]: piniaPlugin.getDefaultOptions(jest),
175
+ },
176
+ }),
177
+
178
+ i18nPreset: basePresets.i18nPreset,
179
+ routerPreset: basePresets.routerPreset,
180
+ };
181
+ ```
182
+
183
+ Preset definitions use the standardized `PLUGIN_NAME` export as the configuration key instead of repeating plugin name literals.
184
+
185
+ This keeps the identifier exported by the plugin package as the single source of truth.
186
+
187
+ Because this package is a TestForge-maintained reusable preset, it intentionally obtains its runner-aware Pinia baseline through `getDefaultOptions(jest)`.
188
+
189
+ When only one of these environments is needed, use it directly through `createTestFramework({ preset })`.
77
190
 
78
191
  ### `presets.default`
79
192
 
80
- The default recommended Jest preset enables:
193
+ The default recommended Jest preset contains:
194
+
195
+ - Pinia — enabled;
196
+ - Vue I18n — enabled;
197
+ - Vue Router — declared but disabled.
198
+
199
+ It inherits the plugin composition from `presets.default` in the base package.
200
+
201
+ The Pinia defaults are replaced with the runner-aware defaults provided by the Pinia plugin:
202
+
203
+ ```typescript
204
+ piniaPlugin.getDefaultOptions(jest);
205
+ ```
206
+
207
+ The resulting Pinia options are currently equivalent to:
208
+
209
+ ```typescript
210
+ {
211
+ createSpy: jest.fn,
212
+ }
213
+ ```
214
+
215
+ TestForge does not override other `@pinia/testing` behavior.
81
216
 
82
- - Pinia;
83
- - Vue I18n;
84
- - Vue Router — disabled by default.
217
+ In particular, actions follow the upstream `createTestingPinia()` behavior and are stubbed by default unless a project explicitly configures:
85
218
 
86
- It also provides default option factories for these managed plugins.
219
+ ```typescript
220
+ stubActions: false;
221
+ ```
87
222
 
88
- For Pinia, the recommended preset additionally configures Jest's `jest.fn` as the `createSpy` implementation.
223
+ Vue I18n and Vue Router continue to use the defaults selected by the base preset.
89
224
 
90
225
  ```typescript
91
226
  const { testComponentFactory } = createTestFramework({
92
- presets: {
93
- default: presets.default,
94
- },
227
+ preset: presets.default,
95
228
  });
96
229
  ```
97
230
 
98
- This is the preset intended for most Jest-based TestForge projects.
231
+ This is the general-purpose preset intended for Jest-based TestForge projects.
99
232
 
100
233
  ### `presets.piniaPreset`
101
234
 
102
- A minimal preset for tests that require Pinia.
103
-
104
- It enables Pinia and configures its spy factory to use Jest:
235
+ A minimal preset containing only Pinia.
105
236
 
106
237
  ```typescript
107
238
  const { testComponentFactory } = createTestFramework({
108
- presets: {
109
- default: presets.piniaPreset,
110
- },
239
+ preset: presets.piniaPreset,
111
240
  });
112
241
  ```
113
242
 
114
- The Pinia option factory is based on the base preset and adds Jest's `jest.fn`:
243
+ The preset is based on `basePresets.piniaPreset`, but replaces its runner-neutral Pinia defaults with:
115
244
 
116
245
  ```typescript
117
- pinia: () => ({
118
- ...basePiniaOptions,
119
- createSpy: jest.fn,
120
- });
246
+ piniaPlugin.getDefaultOptions(jest);
121
247
  ```
122
248
 
123
- This makes the Pinia preset immediately usable in Jest-based TestForge projects.
249
+ This provides the Jest spy implementation explicitly rather than relying on test-runner globals.
124
250
 
125
- ### `presets.i18nPreset`
251
+ The current Pinia defaults are equivalent to:
126
252
 
127
- A minimal preset for tests that require Vue I18n.
253
+ ```typescript
254
+ {
255
+ createSpy: jest.fn,
256
+ }
257
+ ```
128
258
 
129
- It enables Vue I18n using the base preset's default configuration:
259
+ Other Pinia testing behavior remains controlled by `@pinia/testing` unless the project overrides it.
130
260
 
131
- - Composition API mode (`legacy: false`);
132
- - English locale;
133
- - English fallback locale;
134
- - empty messages;
135
- - disabled missing-translation warnings.
261
+ ### `presets.i18nPreset`
136
262
 
137
- The plugin defaults are provided through a plugin options factory, so each pipeline context receives fresh plugin options.
263
+ A minimal preset containing only Vue I18n.
138
264
 
139
265
  ```typescript
140
266
  const { testComponentFactory } = createTestFramework({
141
- presets: {
142
- default: presets.i18nPreset,
143
- },
267
+ preset: presets.i18nPreset,
144
268
  });
145
269
  ```
146
270
 
147
- ### `presets.routerPreset`
271
+ This preset is inherited directly from `@testforgejs/vue-test-preset-base` because Vue I18n does not require Jest-specific configuration.
272
+
273
+ The plugin defaults selected by the base preset are currently equivalent to:
274
+
275
+ ```typescript
276
+ {
277
+ legacy: false,
278
+ globalInjection: true,
279
+ }
280
+ ```
281
+
282
+ These options provide a project-independent Vue 3 integration baseline.
148
283
 
149
- A minimal preset for tests that require Vue Router.
284
+ The preset intentionally does not choose:
150
285
 
151
- It enables the managed Vue Router integration using the base preset's default router configuration.
286
+ - an application locale;
287
+ - a fallback locale;
288
+ - translation messages;
289
+ - formatting configuration;
290
+ - missing-translation or fallback warning policy.
291
+
292
+ Those settings belong in project-specific configuration.
293
+
294
+ ### `presets.routerPreset`
295
+
296
+ A minimal preset containing only Vue Router.
152
297
 
153
298
  ```typescript
154
299
  const { testComponentFactory } = createTestFramework({
155
- presets: {
156
- default: presets.routerPreset,
157
- },
300
+ preset: presets.routerPreset,
158
301
  });
159
302
  ```
160
303
 
161
- The router preset provides a test-oriented router configuration suitable for isolated component tests.
304
+ This preset is inherited directly from `@testforgejs/vue-test-preset-base`.
305
+
306
+ The Router defaults selected by the base preset are currently equivalent to:
307
+
308
+ ```typescript
309
+ {
310
+ history: createMemoryHistory(),
311
+ routes: [],
312
+ }
313
+ ```
314
+
315
+ The in-memory history keeps routing isolated from browser URL state.
162
316
 
163
- Its plugin defaults are provided through a plugin options factory, which produces fresh options for each pipeline context.
317
+ The empty route table ensures that TestForge does not invent application-specific routes.
164
318
 
165
- ## Recommended vs Base Presets
319
+ Projects that need actual routes or another history implementation should provide them explicitly in a project-owned preset.
166
320
 
167
- `@testforgejs/vue-test-preset-base` provides runner-neutral preset definitions.
321
+ ## Recommended Jest vs Base Presets
168
322
 
169
- `@testforgejs/vue-test-preset-recommended-jest` builds on those presets and adds Jest-specific configuration where necessary.
323
+ `@testforgejs/vue-test-preset-base` provides runner-independent preset definitions.
170
324
 
171
- In particular:
325
+ `@testforgejs/vue-test-preset-recommended-jest` adds Jest-specific configuration only where it is required.
172
326
 
173
327
  ```text
174
328
  @testforgejs/vue-test-preset-base
175
- │
176
- ├── default
177
- ├── piniaPreset
178
- ├── i18nPreset
179
- └── routerPreset
180
- │
181
- ▼
329
+ │
330
+ ├── default
331
+ │ └── Pinia defaults without a runner
332
+ │
333
+ ├── piniaPreset
334
+ │ └── Pinia defaults without a runner
335
+ │
336
+ ├── i18nPreset
337
+ │
338
+ └── routerPreset
339
+ │
340
+ ▼
182
341
  @testforgejs/vue-test-preset-recommended-jest
183
- │
184
- ├── default → adds Jest jest.fn to Pinia
185
- ├── piniaPreset → adds Jest jest.fn to Pinia
186
- ├── i18nPreset → inherited from base
187
- └── routerPreset → inherited from base
342
+ │
343
+ ├── default
344
+ │ └── piniaPlugin.getDefaultOptions(jest)
345
+ │
346
+ ├── piniaPreset
347
+ │ └── piniaPlugin.getDefaultOptions(jest)
348
+ │
349
+ ├── i18nPreset
350
+ │ └── inherited unchanged
351
+ │
352
+ └── routerPreset
353
+ └── inherited unchanged
188
354
  ```
189
355
 
190
- This separation keeps the base preset independent from a particular test runner while allowing the recommended Jest preset to provide runner-specific defaults.
356
+ This separation keeps runner knowledge out of the base preset.
191
357
 
192
- The Jest-specific Pinia defaults are implemented as a **plugin options factory**. The factory invokes the base Pinia options factory and adds `createSpy`:
358
+ It also keeps knowledge about how Jest integrates with Pinia inside the Pinia plugin rather than duplicating that configuration in the TestForge-maintained preset package.
359
+
360
+ In other words:
361
+
362
+ ```text
363
+ recommended-jest preset
364
+ → knows that the runner is Jest
365
+
366
+ Pinia plugin
367
+ → knows how Jest runner support maps to Pinia configuration
368
+ ```
369
+
370
+ ## Plugin Defaults Are Explicit
371
+
372
+ Plugin defaults are not automatically applied simply because a plugin appears in a preset manifest.
373
+
374
+ For example:
193
375
 
194
376
  ```typescript
195
- const defaultJestPinia = (() => ({
196
- ...defaultPinia(),
197
- createSpy: jest.fn,
198
- })) satisfies PluginOptionsFactory<VueTestPiniaOptions>;
377
+ manifest: [
378
+ {
379
+ module: piniaPlugin,
380
+ enabled: true,
381
+ },
382
+ ];
383
+ ```
384
+
385
+ does not implicitly call:
386
+
387
+ ```typescript
388
+ piniaPlugin.getDefaultOptions(jest);
199
389
  ```
200
390
 
201
- The resulting factory can be reused by both the `default` and `piniaPreset` profiles.
391
+ The recommended Jest preset explicitly selects the runner-aware Pinia defaults using the identifier exported by the plugin package:
392
+
393
+ ```typescript
394
+ defaults: {
395
+ [PINIA_PLUGIN_NAME]: piniaPlugin.getDefaultOptions(jest),
396
+ }
397
+ ```
398
+
399
+ The `PLUGIN_NAME` export identifies the plugin consistently across its module and preset configuration, while `getDefaultOptions()` provides the configuration factory selected by this TestForge-maintained preset.
400
+
401
+ Because the recommended Jest preset deliberately references `getDefaultOptions(jest)`, it intentionally follows the runner-aware integration baseline provided by the installed Pinia plugin version.
402
+
403
+ Project-owned presets that need their concrete configuration to remain visible and stable across plugin baseline changes should materialize that configuration explicitly instead.
202
404
 
203
405
  ## Switching Presets at Runtime
204
406
 
205
- A **component factory invocation** can select a different registered preset using the fourth `extraOptions` argument:
407
+ Use the preset registry when the same TestForge framework instance should expose multiple named runtime environments:
408
+
409
+ ```typescript
410
+ import { createTestFramework } from "@testforgejs/vue-test-core";
411
+ import { presets } from "@testforgejs/vue-test-preset-recommended-jest";
412
+
413
+ const { testComponentFactory } = createTestFramework({
414
+ presets,
415
+ });
416
+ ```
417
+
418
+ A component factory invocation can then select another registered preset using the fourth `extraOptions` argument:
206
419
 
207
420
  ```typescript
208
421
  const factory = testComponentFactory(MyComponent);
@@ -217,9 +430,7 @@ factory(
217
430
  );
218
431
  ```
219
432
 
220
- The selected preset defines the complete managed plugin runtime for that component factory invocation.
221
-
222
- This allows the same TestForge framework instance to use different runtime environments without creating a separate framework instance.
433
+ The selected preset defines the complete managed-plugin runtime for that invocation.
223
434
 
224
435
  For example:
225
436
 
@@ -234,63 +445,378 @@ factory(
234
445
  );
235
446
  ```
236
447
 
237
- selects the Pinia-only runtime environment for that invocation.
448
+ selects the Pinia-only runtime environment.
449
+
450
+ This allows a single TestForge framework instance to expose several predefined runtime profiles.
451
+
452
+ The similarly named options operate at different levels:
453
+
454
+ ```text
455
+ createTestFramework({ preset })
456
+ → configures one framework-wide runtime environment
457
+
458
+ createTestFramework({ presets })
459
+ → registers multiple named runtime environments
460
+
461
+ extraOptions.preset
462
+ → selects one registered runtime environment for a factory invocation
463
+ ```
464
+
465
+ Runtime selection through `extraOptions.preset` applies to named presets registered through `presets`.
238
466
 
239
467
  ## Customizing Presets
240
468
 
241
- The recommended presets are ordinary TestForge preset definitions and can be composed with [`extendPreset()`](https://github.com/testforgejs/testforge).
469
+ The recommended Jest presets are ordinary TestForge preset definitions and can be composed with `extendPreset()`.
470
+
471
+ Application-specific behavior should normally be added in a project-owned preset rather than in TestForge plugin defaults.
472
+
473
+ When a project replaces a plugin factory, it should normally materialize the concrete configuration it wants to own rather than call `getDefaultOptions()` again.
474
+
475
+ This keeps the project's effective test environment visible in source and prevents future changes to a plugin baseline from silently changing that materialized configuration.
476
+
477
+ ### Customizing Pinia
478
+
479
+ For example, a project may want real Pinia actions to execute instead of using the upstream testing default that stubs them.
242
480
 
243
- For example, a project can create its own preset from the recommended default:
481
+ A project-owned preset can materialize both the required Jest integration and the project-specific action policy:
244
482
 
245
483
  ```typescript
484
+ import { jest } from "@jest/globals";
246
485
  import { extendPreset } from "@testforgejs/vue-test-core";
486
+ import { PLUGIN_NAME as PINIA_PLUGIN_NAME } from "@testforgejs/vue-test-plugin-pinia";
247
487
  import { presets as recommendedPresets } from "@testforgejs/vue-test-preset-recommended-jest";
248
488
 
249
- const projectPresets = {
250
- default: extendPreset(recommendedPresets.default, {
251
- defaults: {
252
- pinia: () => ({
253
- ...recommendedPresets.default.defaults.pinia(),
254
- // project-specific options
255
- }),
256
- },
257
- }),
258
- };
489
+ const projectPreset = extendPreset(recommendedPresets.default, {
490
+ defaults: {
491
+ [PINIA_PLUGIN_NAME]: () => ({
492
+ createSpy: jest.fn,
493
+ stubActions: false,
494
+ }),
495
+ },
496
+ });
259
497
  ```
260
498
 
261
- Because `defaults.pinia` is a plugin options factory, the base Pinia options are obtained by invoking the factory.
499
+ This produces:
262
500
 
263
- When extending a preset, explicitly preserve any base plugin options that should remain enabled. Managed plugin configuration is intentionally replaced when an extension provides configuration for that plugin.
501
+ ```typescript
502
+ {
503
+ createSpy: jest.fn,
504
+ stubActions: false,
505
+ }
506
+ ```
264
507
 
265
- For details about preset composition and configuration layering, see the [TestForge core documentation](https://github.com/testforgejs/testforge/blob/main/packages/vue-test-core/README.md).
508
+ The recommended Jest preset obtains `createSpy: jest.fn` through the Pinia plugin's runner-aware defaults.
266
509
 
267
- ## Using a Preset with Other Framework Configuration
510
+ The project-owned preset materializes that value in its own source together with its `stubActions: false` policy.
268
511
 
269
- The exported presets can be combined with other TestForge configuration options:
512
+ Conceptually:
513
+
514
+ ```text
515
+ recommended-jest preset
516
+ → follows runner-aware plugin baseline
517
+
518
+ project-owned preset
519
+ → materializes createSpy: jest.fn
520
+ → adds stubActions: false
521
+ → owns the resulting configuration
522
+ ```
523
+
524
+ A project using this single runtime environment can pass it directly to TestForge:
270
525
 
271
526
  ```typescript
272
527
  const { testComponentFactory } = createTestFramework({
273
- presets,
274
- shallowByDefault: true,
528
+ preset: projectPreset,
529
+ });
530
+ ```
531
+
532
+ ### Customizing Vue I18n
533
+
534
+ Application locale and translation messages should be configured explicitly.
535
+
536
+ A project-owned preset should also materialize the integration values it intends to preserve:
537
+
538
+ ```typescript
539
+ import { extendPreset } from "@testforgejs/vue-test-core";
540
+ import { PLUGIN_NAME as I18N_PLUGIN_NAME } from "@testforgejs/vue-test-plugin-i18n";
541
+ import { presets as recommendedPresets } from "@testforgejs/vue-test-preset-recommended-jest";
542
+
543
+ const projectPreset = extendPreset(recommendedPresets.default, {
544
+ defaults: {
545
+ [I18N_PLUGIN_NAME]: () => ({
546
+ legacy: false,
547
+ globalInjection: true,
548
+
549
+ locale: "en",
550
+ messages: {
551
+ en: {
552
+ hello: "Hello",
553
+ },
554
+ },
555
+ }),
556
+ },
557
+ });
558
+ ```
559
+
560
+ Here:
561
+
562
+ ```text
563
+ legacy / globalInjection
564
+ → materialized integration baseline
565
+
566
+ locale / messages
567
+ → project-specific policy
568
+ ```
569
+
570
+ All of these values are now visible and owned by the project preset.
571
+
572
+ Use it directly when no runtime preset switching is needed:
573
+
574
+ ```typescript
575
+ const { testComponentFactory } = createTestFramework({
576
+ preset: projectPreset,
577
+ });
578
+ ```
579
+
580
+ ### Customizing Vue Router
581
+
582
+ Application routes should also be configured explicitly.
583
+
584
+ The recommended default preset declares Router but keeps it disabled, so a project that wants Router as part of its default runtime should explicitly enable it and materialize its Router configuration:
585
+
586
+ ```typescript
587
+ import { createMemoryHistory } from "vue-router";
588
+ import { extendPreset } from "@testforgejs/vue-test-core";
589
+ import {
590
+ routerPlugin,
591
+ PLUGIN_NAME as ROUTER_PLUGIN_NAME,
592
+ } from "@testforgejs/vue-test-plugin-router";
593
+ import { presets as recommendedPresets } from "@testforgejs/vue-test-preset-recommended-jest";
594
+
595
+ const projectPreset = extendPreset(recommendedPresets.default, {
596
+ manifest: [
597
+ {
598
+ module: routerPlugin,
599
+ enabled: true,
600
+ },
601
+ ],
602
+
603
+ defaults: {
604
+ [ROUTER_PLUGIN_NAME]: () => ({
605
+ history: createMemoryHistory(),
606
+
607
+ routes: [
608
+ {
609
+ path: "/",
610
+ component: HomeView,
611
+ },
612
+ ],
613
+ }),
614
+ },
615
+ });
616
+ ```
617
+
618
+ The project now owns both decisions:
619
+
620
+ ```text
621
+ manifest
622
+ → Router is enabled
623
+
624
+ defaults
625
+ → createMemoryHistory()
626
+ → application routes
627
+ ```
628
+
629
+ The in-memory history is explicit project-owned configuration rather than an indirect dependency on `routerPlugin.getDefaultOptions()`.
630
+
631
+ If the application requires another history implementation, replace it directly:
632
+
633
+ ```typescript
634
+ import { createWebHistory } from "vue-router";
635
+
636
+ const projectPreset = extendPreset(recommendedPresets.default, {
637
+ manifest: [
638
+ {
639
+ module: routerPlugin,
640
+ enabled: true,
641
+ },
642
+ ],
643
+
644
+ defaults: {
645
+ [ROUTER_PLUGIN_NAME]: () => ({
646
+ history: createWebHistory(),
647
+ routes,
648
+ }),
649
+ },
650
+ });
651
+ ```
652
+
653
+ ## Replacing Preset Defaults
654
+
655
+ When an extension provides a plugin options factory, that factory replaces the corresponding factory from the source preset.
656
+
657
+ For example:
658
+
659
+ ```typescript
660
+ extendPreset(recommendedPresets.default, {
661
+ defaults: {
662
+ [PINIA_PLUGIN_NAME]: () => ({
663
+ createSpy: jest.fn,
664
+ stubActions: false,
665
+ }),
666
+ },
275
667
  });
276
668
  ```
277
669
 
278
- The preset provides the runtime plugin baseline, while individual component factory invocations and tests can override configuration when needed.
670
+ TestForge does not implicitly merge this factory with:
671
+
672
+ ```typescript
673
+ piniaPlugin.getDefaultOptions(jest);
674
+ ```
675
+
676
+ or with the factory already present in `recommendedPresets.default`.
677
+
678
+ For a project-owned preset, explicit replacement is normally preferable because the effective configuration is visible in project source:
679
+
680
+ ```typescript
681
+ [PINIA_PLUGIN_NAME]: () => ({
682
+ createSpy: jest.fn,
683
+ stubActions: false,
684
+ })
685
+ ```
686
+
687
+ A project can instead deliberately preserve and spread the source preset factory:
688
+
689
+ ```typescript
690
+ const sourcePinia = recommendedPresets.default.defaults.pinia;
691
+
692
+ const projectPreset = extendPreset(recommendedPresets.default, {
693
+ defaults: {
694
+ [PINIA_PLUGIN_NAME]: () => ({
695
+ ...sourcePinia(),
696
+ stubActions: false,
697
+ }),
698
+ },
699
+ });
700
+ ```
701
+
702
+ This has different semantics.
703
+
704
+ The project now intentionally continues to depend on the Pinia factory provided by `recommendedPresets.default`.
705
+
706
+ If that source factory changes after a dependency update, the effective project configuration can change as well.
707
+
708
+ Conceptually:
709
+
710
+ ```text
711
+ spread source preset factory
712
+ → continue following source preset behavior
713
+
714
+ explicit replacement factory
715
+ → project owns the resulting configuration
716
+ ```
717
+
718
+ For a stable project-owned preset, prefer explicit materialization:
719
+
720
+ ```typescript
721
+ const projectPreset = extendPreset(recommendedPresets.default, {
722
+ defaults: {
723
+ [PINIA_PLUGIN_NAME]: () => ({
724
+ createSpy: jest.fn,
725
+ stubActions: false,
726
+ }),
727
+ },
728
+ });
729
+ ```
279
730
 
280
731
  ## Plugin Options Factory Isolation
281
732
 
282
- The `defaults` values in the presets are **plugin options factories**, not shared plugin configuration objects.
733
+ Preset `defaults` values are plugin options factories rather than shared configuration objects.
734
+
735
+ The recommended Jest preset stores its Pinia options factory under the exported plugin identifier:
736
+
737
+ ```typescript
738
+ defaults: {
739
+ [PINIA_PLUGIN_NAME]: piniaPlugin.getDefaultOptions(jest),
740
+ }
741
+ ```
742
+
743
+ Because `PINIA_PLUGIN_NAME` resolves to `"pinia"`, the resolved preset can still be consumed through its normal property key.
744
+
745
+ Each invocation produces a fresh options object for the current pipeline context:
746
+
747
+ ```typescript
748
+ const first = presets.default.defaults.pinia();
749
+ const second = presets.default.defaults.pinia();
283
750
 
284
- When a plugin options factory is invoked, it produces fresh plugin options for the current pipeline context.
751
+ first !== second; // true
752
+ ```
753
+
754
+ Runner-independent presets preserve the same factory-based isolation.
755
+
756
+ For Router, the options factory also creates a fresh in-memory history instance for each invocation:
757
+
758
+ ```typescript
759
+ const first = presets.routerPreset.defaults.router();
760
+ const second = presets.routerPreset.defaults.router();
761
+
762
+ first.history !== second.history; // true
763
+ ```
764
+
765
+ This avoids unintentionally sharing mutable plugin configuration or runtime state between independent pipeline contexts.
766
+
767
+ A plugin options factory and a component factory operate at different levels:
768
+
769
+ ```text
770
+ plugin options factory
771
+ → creates plugin configuration
772
+
773
+ testComponentFactory()
774
+ → creates a reusable component mounting factory
775
+
776
+ component factory invocation
777
+ → creates an individual component test runtime
778
+ ```
779
+
780
+ The `getDefaultOptions(jest)` example in this section describes the implementation of the TestForge-maintained recommended Jest preset.
781
+
782
+ A project-owned preset can preserve the same factory isolation while materializing its configuration explicitly:
783
+
784
+ ```typescript
785
+ defaults: {
786
+ [PINIA_PLUGIN_NAME]: () => ({
787
+ createSpy: jest.fn,
788
+ }),
789
+ }
790
+ ```
791
+
792
+ ## Using a Preset with Other Framework Configuration
793
+
794
+ When using a single runtime environment, combine it with other framework options through `preset`:
795
+
796
+ ```typescript
797
+ const { testComponentFactory } = createTestFramework({
798
+ preset: presets.default,
799
+ shallowByDefault: true,
800
+ });
801
+ ```
802
+
803
+ When multiple named environments are required, use the registry form instead:
804
+
805
+ ```typescript
806
+ const { testComponentFactory } = createTestFramework({
807
+ presets,
808
+ shallowByDefault: true,
809
+ });
810
+ ```
285
811
 
286
- This keeps mutable configuration isolated between independent pipeline contexts.
812
+ The selected preset provides the managed-plugin runtime baseline.
287
813
 
288
- This is separate from component factory isolation: `testComponentFactory()` creates a reusable function for mounting a component, while each invocation of that component factory establishes its own runtime environment.
814
+ A project-owned preset can materialize and replace that configuration explicitly, while individual component tests can apply local overrides where needed.
289
815
 
290
816
  ## Related Packages
291
817
 
292
818
  - [`@testforgejs/vue-test-core`](https://www.npmjs.com/package/@testforgejs/vue-test-core) — TestForge core framework
293
- - [`@testforgejs/vue-test-preset-base`](https://www.npmjs.com/package/@testforgejs/vue-test-preset-base) — base, runner-neutral presets
819
+ - [`@testforgejs/vue-test-preset-base`](https://www.npmjs.com/package/@testforgejs/vue-test-preset-base) — base runner-independent presets
294
820
  - [`@testforgejs/vue-test-preset-recommended`](https://www.npmjs.com/package/@testforgejs/vue-test-preset-recommended) — recommended Vitest presets
295
821
  - [`@testforgejs/vue-test-plugin-pinia`](https://www.npmjs.com/package/@testforgejs/vue-test-plugin-pinia) — Pinia integration
296
822
  - [`@testforgejs/vue-test-plugin-i18n`](https://www.npmjs.com/package/@testforgejs/vue-test-plugin-i18n) — Vue I18n integration
package/dist/index.cjs CHANGED
@@ -27,20 +27,17 @@ module.exports = __toCommonJS(index_exports);
27
27
  // src/presets.ts
28
28
  var import_vue_test_core = require("@testforgejs/vue-test-core");
29
29
  var import_vue_test_preset_base = require("@testforgejs/vue-test-preset-base");
30
+ var import_vue_test_plugin_pinia = require("@testforgejs/vue-test-plugin-pinia");
30
31
  var import_globals = require("@jest/globals");
31
- var defaultJestPinia = (() => ({
32
- ...(0, import_vue_test_preset_base.defaultPinia)(),
33
- createSpy: import_globals.jest.fn
34
- }));
35
32
  var presets = {
36
33
  default: (0, import_vue_test_core.extendPreset)(import_vue_test_preset_base.presets.default, {
37
34
  defaults: {
38
- pinia: defaultJestPinia
35
+ [import_vue_test_plugin_pinia.PLUGIN_NAME]: import_vue_test_plugin_pinia.piniaPlugin.getDefaultOptions(import_globals.jest)
39
36
  }
40
37
  }),
41
38
  piniaPreset: (0, import_vue_test_core.extendPreset)(import_vue_test_preset_base.presets.piniaPreset, {
42
39
  defaults: {
43
- pinia: defaultJestPinia
40
+ [import_vue_test_plugin_pinia.PLUGIN_NAME]: import_vue_test_plugin_pinia.piniaPlugin.getDefaultOptions(import_globals.jest)
44
41
  }
45
42
  }),
46
43
  i18nPreset: import_vue_test_preset_base.presets.i18nPreset,
package/dist/index.d.cts CHANGED
@@ -3,27 +3,26 @@ import * as vue_router from 'vue-router';
3
3
  import * as _testforgejs_vue_test_plugin_i18n from '@testforgejs/vue-test-plugin-i18n';
4
4
  import * as vue_i18n from 'vue-i18n';
5
5
  import * as _testforgejs_vue_test_core from '@testforgejs/vue-test-core';
6
- import { PluginOptionsFactory } from '@testforgejs/vue-test-core';
7
6
 
8
7
  declare const presets: {
9
8
  default: _testforgejs_vue_test_core.PresetDefinition;
10
9
  piniaPreset: _testforgejs_vue_test_core.PresetDefinition;
11
10
  i18nPreset: {
12
11
  manifest: {
13
- module: _testforgejs_vue_test_core.PluginModule<vue_i18n.I18n<{}, {}, {}, string, boolean>, _testforgejs_vue_test_plugin_i18n.VueTestI18nOptions>;
12
+ module: _testforgejs_vue_test_core.PluginModuleWithDefaults<vue_i18n.I18n<{}, {}, {}, string, boolean>, _testforgejs_vue_test_plugin_i18n.VueTestI18nOptions>;
14
13
  enabled: true;
15
14
  }[];
16
15
  defaults: {
17
- i18n: PluginOptionsFactory<_testforgejs_vue_test_plugin_i18n.VueTestI18nOptions>;
16
+ i18n: _testforgejs_vue_test_core.PluginOptionsFactory<_testforgejs_vue_test_plugin_i18n.VueTestI18nOptions>;
18
17
  };
19
18
  };
20
19
  routerPreset: {
21
20
  manifest: {
22
- module: _testforgejs_vue_test_core.PluginModule<vue_router._RouterClassic, _testforgejs_vue_test_plugin_router.VueTestRouterOptions>;
21
+ module: _testforgejs_vue_test_core.PluginModuleWithDefaults<vue_router._RouterClassic, _testforgejs_vue_test_plugin_router.VueTestRouterOptions>;
23
22
  enabled: true;
24
23
  }[];
25
24
  defaults: {
26
- router: PluginOptionsFactory<_testforgejs_vue_test_plugin_router.VueTestRouterOptions>;
25
+ router: _testforgejs_vue_test_core.PluginOptionsFactory<_testforgejs_vue_test_plugin_router.VueTestRouterOptions>;
27
26
  };
28
27
  };
29
28
  };
package/dist/index.d.ts CHANGED
@@ -3,27 +3,26 @@ import * as vue_router from 'vue-router';
3
3
  import * as _testforgejs_vue_test_plugin_i18n from '@testforgejs/vue-test-plugin-i18n';
4
4
  import * as vue_i18n from 'vue-i18n';
5
5
  import * as _testforgejs_vue_test_core from '@testforgejs/vue-test-core';
6
- import { PluginOptionsFactory } from '@testforgejs/vue-test-core';
7
6
 
8
7
  declare const presets: {
9
8
  default: _testforgejs_vue_test_core.PresetDefinition;
10
9
  piniaPreset: _testforgejs_vue_test_core.PresetDefinition;
11
10
  i18nPreset: {
12
11
  manifest: {
13
- module: _testforgejs_vue_test_core.PluginModule<vue_i18n.I18n<{}, {}, {}, string, boolean>, _testforgejs_vue_test_plugin_i18n.VueTestI18nOptions>;
12
+ module: _testforgejs_vue_test_core.PluginModuleWithDefaults<vue_i18n.I18n<{}, {}, {}, string, boolean>, _testforgejs_vue_test_plugin_i18n.VueTestI18nOptions>;
14
13
  enabled: true;
15
14
  }[];
16
15
  defaults: {
17
- i18n: PluginOptionsFactory<_testforgejs_vue_test_plugin_i18n.VueTestI18nOptions>;
16
+ i18n: _testforgejs_vue_test_core.PluginOptionsFactory<_testforgejs_vue_test_plugin_i18n.VueTestI18nOptions>;
18
17
  };
19
18
  };
20
19
  routerPreset: {
21
20
  manifest: {
22
- module: _testforgejs_vue_test_core.PluginModule<vue_router._RouterClassic, _testforgejs_vue_test_plugin_router.VueTestRouterOptions>;
21
+ module: _testforgejs_vue_test_core.PluginModuleWithDefaults<vue_router._RouterClassic, _testforgejs_vue_test_plugin_router.VueTestRouterOptions>;
23
22
  enabled: true;
24
23
  }[];
25
24
  defaults: {
26
- router: PluginOptionsFactory<_testforgejs_vue_test_plugin_router.VueTestRouterOptions>;
25
+ router: _testforgejs_vue_test_core.PluginOptionsFactory<_testforgejs_vue_test_plugin_router.VueTestRouterOptions>;
27
26
  };
28
27
  };
29
28
  };
package/dist/index.js CHANGED
@@ -1,20 +1,17 @@
1
1
  // src/presets.ts
2
2
  import { extendPreset } from "@testforgejs/vue-test-core";
3
- import { defaultPinia, presets as basePresets } from "@testforgejs/vue-test-preset-base";
3
+ import { presets as basePresets } from "@testforgejs/vue-test-preset-base";
4
+ import { piniaPlugin, PLUGIN_NAME as PINIA_PLUGIN_NAME } from "@testforgejs/vue-test-plugin-pinia";
4
5
  import { jest } from "@jest/globals";
5
- var defaultJestPinia = (() => ({
6
- ...defaultPinia(),
7
- createSpy: jest.fn
8
- }));
9
6
  var presets = {
10
7
  default: extendPreset(basePresets.default, {
11
8
  defaults: {
12
- pinia: defaultJestPinia
9
+ [PINIA_PLUGIN_NAME]: piniaPlugin.getDefaultOptions(jest)
13
10
  }
14
11
  }),
15
12
  piniaPreset: extendPreset(basePresets.piniaPreset, {
16
13
  defaults: {
17
- pinia: defaultJestPinia
14
+ [PINIA_PLUGIN_NAME]: piniaPlugin.getDefaultOptions(jest)
18
15
  }
19
16
  }),
20
17
  i18nPreset: basePresets.i18nPreset,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testforgejs/vue-test-preset-recommended-jest",
3
- "version": "1.0.0-beta.2",
3
+ "version": "1.0.0-beta.3",
4
4
  "type": "module",
5
5
  "description": "Official recommended preset for projects using Jest with the TestForge framework",
6
6
  "homepage": "https://github.com/testforgejs/testforge#readme",
@@ -43,21 +43,21 @@
43
43
  "license": "MIT",
44
44
  "author": "Roman Levchenko",
45
45
  "dependencies": {
46
- "@testforgejs/vue-test-plugin-i18n": "1.0.0-beta.2",
47
- "@testforgejs/vue-test-plugin-router": "1.0.0-beta.2",
48
- "@testforgejs/vue-test-plugin-pinia": "1.0.0-beta.2"
46
+ "@testforgejs/vue-test-plugin-i18n": "1.0.0-beta.3",
47
+ "@testforgejs/vue-test-plugin-pinia": "1.0.0-beta.3",
48
+ "@testforgejs/vue-test-plugin-router": "1.0.0-beta.3"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@jest/globals": "^30.0.0",
52
52
  "jest": "^30.0.0",
53
- "@testforgejs/vue-test-core": "1.0.0-beta.2",
54
- "@testforgejs/vue-test-preset-base": "1.0.0-beta.2"
53
+ "@testforgejs/vue-test-core": "1.0.0-beta.3",
54
+ "@testforgejs/vue-test-preset-base": "1.0.0-beta.3"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@jest/globals": "^30.0.0",
58
58
  "jest": "^30.0.0",
59
- "@testforgejs/vue-test-core": "1.0.0-beta.2",
60
- "@testforgejs/vue-test-preset-base": "1.0.0-beta.2"
59
+ "@testforgejs/vue-test-preset-base": "1.0.0-beta.3",
60
+ "@testforgejs/vue-test-core": "1.0.0-beta.3"
61
61
  },
62
62
  "scripts": {
63
63
  "build": "tsup",