@untestutils/nuxt 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/dist/config/index.d.mts +58 -0
  3. package/dist/config/index.d.ts +59 -0
  4. package/dist/config/index.d.ts.map +1 -0
  5. package/dist/config/index.mjs +323 -0
  6. package/dist/config/utils.d.mts +12 -0
  7. package/dist/config/utils.d.ts +13 -0
  8. package/dist/config/utils.d.ts.map +1 -0
  9. package/dist/config/utils.mjs +79 -0
  10. package/dist/environment/index.d.mts +22 -0
  11. package/dist/environment/index.d.ts +23 -0
  12. package/dist/environment/index.d.ts.map +1 -0
  13. package/dist/environment/index.mjs +129 -0
  14. package/dist/index.d.mts +36 -0
  15. package/dist/index.d.ts +65 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.mjs +355 -0
  18. package/dist/module/index.d.mts +3 -0
  19. package/dist/module/index.d.ts +4 -0
  20. package/dist/module/index.d.ts.map +1 -0
  21. package/dist/module/index.mjs +294 -0
  22. package/dist/runtime/browser-entry.d.mts +5 -0
  23. package/dist/runtime/browser-entry.d.ts +6 -0
  24. package/dist/runtime/browser-entry.d.ts.map +1 -0
  25. package/dist/runtime/browser-entry.mjs +2 -0
  26. package/dist/runtime/entry.d.mts +1 -0
  27. package/dist/runtime/entry.d.ts +2 -0
  28. package/dist/runtime/entry.d.ts.map +1 -0
  29. package/dist/runtime/entry.mjs +9 -0
  30. package/dist/runtime/index.d.mts +81 -0
  31. package/dist/runtime/index.d.ts +82 -0
  32. package/dist/runtime/index.d.ts.map +1 -0
  33. package/dist/runtime/index.mjs +156 -0
  34. package/dist/runtime/mocks/vue-devtools.d.mts +12 -0
  35. package/dist/runtime/mocks/vue-devtools.d.ts +13 -0
  36. package/dist/runtime/mocks/vue-devtools.d.ts.map +1 -0
  37. package/dist/runtime/mocks/vue-devtools.mjs +12 -0
  38. package/dist/runtime/nuxt-root.d.mts +3 -0
  39. package/dist/runtime/nuxt-root.d.ts +4 -0
  40. package/dist/runtime/nuxt-root.d.ts.map +1 -0
  41. package/dist/runtime/nuxt-root.mjs +29 -0
  42. package/dist/runtime/shared/environment.d.mts +52 -0
  43. package/dist/runtime/shared/environment.d.ts +53 -0
  44. package/dist/runtime/shared/environment.d.ts.map +1 -0
  45. package/dist/runtime/shared/environment.mjs +79 -0
  46. package/dist/runtime/shared/h3-v1.d.mts +7 -0
  47. package/dist/runtime/shared/h3-v1.d.ts +8 -0
  48. package/dist/runtime/shared/h3-v1.d.ts.map +1 -0
  49. package/dist/runtime/shared/h3-v1.mjs +50 -0
  50. package/dist/runtime/shared/h3-v2.d.mts +7 -0
  51. package/dist/runtime/shared/h3-v2.d.ts +8 -0
  52. package/dist/runtime/shared/h3-v2.d.ts.map +1 -0
  53. package/dist/runtime/shared/h3-v2.mjs +32 -0
  54. package/dist/runtime/shared/h3.d.mts +4 -0
  55. package/dist/runtime/shared/h3.d.ts +5 -0
  56. package/dist/runtime/shared/h3.d.ts.map +1 -0
  57. package/dist/runtime/shared/h3.mjs +3 -0
  58. package/dist/runtime/shared/nuxt.d.mts +2 -0
  59. package/dist/runtime/shared/nuxt.d.ts +3 -0
  60. package/dist/runtime/shared/nuxt.d.ts.map +1 -0
  61. package/dist/runtime/shared/nuxt.mjs +17 -0
  62. package/dist/runtime/shared/vue-wrapper-plugin.d.mts +12 -0
  63. package/dist/runtime/shared/vue-wrapper-plugin.d.ts +13 -0
  64. package/dist/runtime/shared/vue-wrapper-plugin.d.ts.map +1 -0
  65. package/dist/runtime/shared/vue-wrapper-plugin.mjs +42 -0
  66. package/dist/runtime/suspended.d.mts +45 -0
  67. package/dist/runtime/suspended.d.ts +46 -0
  68. package/dist/runtime/suspended.d.ts.map +1 -0
  69. package/dist/runtime/suspended.mjs +259 -0
  70. package/package.json +150 -0
@@ -0,0 +1,259 @@
1
+
2
+ import { Suspense, effectScope, getCurrentInstance, h, nextTick, onErrorCaptured, reactive } from "vue";
3
+ import { vi } from "vitest";
4
+ import { defineComponent, tryUseNuxtApp, useNuxtApp, useRouter } from "#imports";
5
+ import NuxtRoot from "#build/root-component.mjs";
6
+ //#region src/runtime-utils/components/RouterLink.ts
7
+ function getUseLink(nuxtApp) {
8
+ const linkComponent = nuxtApp.vueApp._context.components.RouterLink;
9
+ if (!linkComponent || typeof linkComponent !== "object") return void 0;
10
+ if (typeof linkComponent.useLink !== "function") return void 0;
11
+ return linkComponent.useLink.bind(linkComponent);
12
+ }
13
+ const RouterLink = defineComponent({
14
+ functional: true,
15
+ props: {
16
+ to: {
17
+ type: [String, Object],
18
+ required: true
19
+ },
20
+ custom: Boolean,
21
+ replace: Boolean,
22
+ activeClass: String,
23
+ exactActiveClass: String,
24
+ ariaCurrentValue: String
25
+ },
26
+ setup: (props, { slots }) => {
27
+ const useLink = getUseLink(useNuxtApp());
28
+ if (!useLink) {
29
+ const navigate = () => {};
30
+ const router = useRouter();
31
+ return () => {
32
+ const route = router.resolve(props.to);
33
+ return props.custom ? slots.default?.({
34
+ href: route.href,
35
+ navigate,
36
+ route
37
+ }) : h("a", {
38
+ href: route.href,
39
+ onClick: (e) => {
40
+ e.preventDefault();
41
+ }
42
+ }, slots);
43
+ };
44
+ }
45
+ const link = useLink(props);
46
+ return () => {
47
+ const route = link.route.value;
48
+ const href = link.href.value;
49
+ const isActive = link.isActive.value;
50
+ const isExactActive = link.isExactActive.value;
51
+ return props.custom ? slots.default?.({
52
+ href,
53
+ navigate: link.navigate,
54
+ route,
55
+ isActive,
56
+ isExactActive
57
+ }) : h("a", {
58
+ href,
59
+ onClick: (e) => {
60
+ e.preventDefault();
61
+ return link.navigate(e);
62
+ }
63
+ }, slots);
64
+ };
65
+ }
66
+ });
67
+ //#endregion
68
+ //#region src/runtime-utils/utils/suspended.ts
69
+ function resolveVueApp() {
70
+ return tryUseNuxtApp()?.vueApp || globalThis.__unctx__.get("nuxt-app").tryUse().vueApp;
71
+ }
72
+
73
+ function patchWrapperSetProps(wrapper, setProps) {
74
+ Object.assign(wrapper, { __setProps: setProps });
75
+ }
76
+ function cleanupAll() {
77
+ for (const fn of (window.__cleanup || []).splice(0)) fn();
78
+ }
79
+ function addCleanup(fn) {
80
+ window.__cleanup ||= [];
81
+ window.__cleanup.push(fn);
82
+ }
83
+ function removeCleanup(fn) {
84
+ const index = window.__cleanup?.indexOf(fn) ?? -1;
85
+ if (index !== -1) window.__cleanup?.splice(index, 1);
86
+ }
87
+ function runEffectScope(fn, register) {
88
+ const scope = effectScope();
89
+ register(() => scope.stop());
90
+ return scope.run(fn);
91
+ }
92
+ function wrapperSuspended(component, options = {}, { wrapperFn, wrappedRender = (fn) => fn, suspendedHelperName, clonedComponentName, stubRouterLink = true }) {
93
+ const vueApp = resolveVueApp();
94
+ const globalProperties = makeAllPropertiesEnumerable(vueApp.config.globalProperties);
95
+ const resolvedOptions = options ?? {};
96
+ const ownCleanups = [];
97
+ function registerCleanup(fn) {
98
+ ownCleanups.push(fn);
99
+ addCleanup(fn);
100
+ }
101
+ function cleanup() {
102
+ for (const fn of ownCleanups.splice(0)) {
103
+ removeCleanup(fn);
104
+ fn();
105
+ }
106
+ }
107
+ const { props = {}, attrs = {} } = resolvedOptions;
108
+ const { route = "/", scoped = false, spy = false, ...wrapperFnOptions } = resolvedOptions;
109
+ const componentOptions = component;
110
+ const { setup: componentSetup, ...componentRest } = componentOptions;
111
+ let wrappedInstance = null;
112
+ let setupContext;
113
+ let setupState = {};
114
+ const setProps = reactive({});
115
+ function patchInstanceAppContext() {
116
+ const app = getCurrentInstance()?.appContext.app;
117
+ if (!app) return;
118
+ for (const [key, value] of Object.entries(vueApp)) {
119
+ if (key in app) continue;
120
+ app[key] = value;
121
+ }
122
+ }
123
+ const ClonedComponent = {
124
+ components: {},
125
+ ...component,
126
+ name: clonedComponentName,
127
+ async setup(props, instanceContext) {
128
+ const currentInstance = getCurrentInstance();
129
+ if (currentInstance) currentInstance.emit = (event, ...args) => {
130
+ setupContext?.emit(event, ...args);
131
+ };
132
+ if (!componentSetup) return;
133
+ let result = scoped ? await runEffectScope(() => componentSetup(props, setupContext), registerCleanup) : await componentSetup(props, setupContext);
134
+ if (wrappedInstance?.exposed) instanceContext.expose(wrappedInstance.exposed);
135
+ if (result && typeof result === "object") {
136
+ if (spy) result = vi.mockObject(result, { spy: true });
137
+ setupState = result;
138
+ } else setupState = {};
139
+ return result;
140
+ }
141
+ };
142
+ const SuspendedHelper = {
143
+ name: suspendedHelperName,
144
+ render: () => "",
145
+ async setup() {
146
+ if (route) await useRouter().replace(route);
147
+ return () => h(ClonedComponent, {
148
+ ...props,
149
+ ...setProps,
150
+ ...attrs
151
+ }, setupContext?.slots);
152
+ }
153
+ };
154
+ return new Promise((resolve, reject) => {
155
+ let isMountSettled = false;
156
+ const wrapper = wrapperFn({
157
+ inheritAttrs: false,
158
+ __cssModules: componentRest.__cssModules,
159
+ setup: (props, ctx) => {
160
+ patchInstanceAppContext();
161
+ wrappedInstance = getCurrentInstance();
162
+ setupContext = ctx;
163
+ const nuxtRootSetupResult = runEffectScope(() => typeof NuxtRoot === "object" && "setup" in NuxtRoot && typeof NuxtRoot.setup === "function" ? NuxtRoot.setup(props, {
164
+ ...ctx,
165
+ expose: () => {}
166
+ }) : undefined, registerCleanup);
167
+ onErrorCaptured((error, ...args) => {
168
+ if (isMountSettled) return;
169
+ isMountSettled = true;
170
+ try {
171
+ wrappedInstance?.appContext.config.errorHandler?.(error, ...args);
172
+ reject(error);
173
+ } catch (error) {
174
+ reject(error);
175
+ }
176
+ return false;
177
+ });
178
+ return nuxtRootSetupResult;
179
+ },
180
+ render: wrappedRender(() => h(Suspense, { onResolve: () => nextTick().then(() => {
181
+ if (isMountSettled) return;
182
+ isMountSettled = true;
183
+ const typedWrapper = wrapper;
184
+ typedWrapper.setupState = setupState;
185
+ resolve({
186
+ wrapper: typedWrapper,
187
+ setProps: (props) => {
188
+ Object.assign(setProps, props);
189
+ },
190
+ cleanup
191
+ });
192
+ }) }, { default: () => h(SuspendedHelper) }))
193
+ }, {
194
+ ...wrapperFnOptions,
195
+ global: mergeComponentMountingGlobalOptions(wrapperFnOptions.global, {
196
+ config: { globalProperties },
197
+ directives: vueApp._context.directives,
198
+ provide: vueApp._context.provides,
199
+ stubs: {
200
+ Suspense: false,
201
+ [SuspendedHelper.name]: false,
202
+ [ClonedComponent.name]: false
203
+ },
204
+ components: {
205
+ ...vueApp._context.components,
206
+ ...stubRouterLink ? { RouterLink } : {}
207
+ }
208
+ })
209
+ });
210
+ });
211
+ }
212
+ function mergeComponentMountingGlobalOptions(options = {}, defaults = {}) {
213
+ const compilerOptions = {
214
+ ...defaults.config?.compilerOptions,
215
+ ...options.config?.compilerOptions
216
+ };
217
+ return {
218
+ ...options,
219
+ mixins: [...defaults.mixins || [], ...options.mixins || []],
220
+ stubs: {
221
+ ...defaults.stubs,
222
+ ...Array.isArray(options.stubs) ? Object.fromEntries(options.stubs.map((n) => [n, true])) : options.stubs
223
+ },
224
+ plugins: [...defaults.plugins || [], ...options.plugins || []],
225
+ components: {
226
+ ...defaults.components,
227
+ ...options.components
228
+ },
229
+ provide: {
230
+ ...defaults.provide,
231
+ ...options.provide
232
+ },
233
+ mocks: {
234
+ ...defaults.mocks,
235
+ ...options.mocks
236
+ },
237
+ config: {
238
+ ...defaults.config,
239
+ ...options.config,
240
+ ...Object.keys(compilerOptions).length ? { compilerOptions } : void 0,
241
+ globalProperties: {
242
+ ...defaults.config?.globalProperties,
243
+ ...options.config?.globalProperties
244
+ }
245
+ },
246
+ directives: {
247
+ ...defaults.directives,
248
+ ...options.directives
249
+ }
250
+ };
251
+ }
252
+ function makeAllPropertiesEnumerable(target) {
253
+ return {
254
+ ...target,
255
+ ...Object.fromEntries(Object.getOwnPropertyNames(target).map((key) => [key, target[key]]))
256
+ };
257
+ }
258
+ //#endregion
259
+ export { cleanupAll, patchWrapperSetProps, wrapperSuspended };
package/package.json ADDED
@@ -0,0 +1,150 @@
1
+ {
2
+ "name": "@untestutils/nuxt",
3
+ "version": "0.5.0",
4
+ "description": "Nuxt recipes + in-process unit runtime, config, module, and Vitest environment",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "type": "module",
9
+ "sideEffects": false,
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.mjs",
14
+ "default": "./dist/index.mjs"
15
+ },
16
+ "./runtime": {
17
+ "types": "./dist/runtime/index.d.ts",
18
+ "import": "./dist/runtime/index.mjs",
19
+ "default": "./dist/runtime/index.mjs"
20
+ },
21
+ "./runtime/entry": {
22
+ "types": "./dist/runtime/entry.d.ts",
23
+ "import": "./dist/runtime/entry.mjs",
24
+ "default": "./dist/runtime/entry.mjs"
25
+ },
26
+ "./runtime/nuxt-root": {
27
+ "types": "./dist/runtime/nuxt-root.d.ts",
28
+ "import": "./dist/runtime/nuxt-root.mjs",
29
+ "default": "./dist/runtime/nuxt-root.mjs"
30
+ },
31
+ "./runtime/mocks/vue-devtools": {
32
+ "types": "./dist/runtime/mocks/vue-devtools.d.ts",
33
+ "import": "./dist/runtime/mocks/vue-devtools.mjs",
34
+ "default": "./dist/runtime/mocks/vue-devtools.mjs"
35
+ },
36
+ "./runtime/browser-entry": {
37
+ "types": "./dist/runtime/browser-entry.d.ts",
38
+ "import": "./dist/runtime/browser-entry.mjs",
39
+ "default": "./dist/runtime/browser-entry.mjs"
40
+ },
41
+ "./config": {
42
+ "types": "./dist/config/index.d.ts",
43
+ "import": "./dist/config/index.mjs",
44
+ "default": "./dist/config/index.mjs"
45
+ },
46
+ "./module": {
47
+ "types": "./dist/module/index.d.ts",
48
+ "import": "./dist/module/index.mjs",
49
+ "default": "./dist/module/index.mjs"
50
+ },
51
+ "./environment": {
52
+ "types": "./dist/environment/index.d.ts",
53
+ "import": "./dist/environment/index.mjs",
54
+ "default": "./dist/environment/index.mjs"
55
+ },
56
+ "./vitest-environment": {
57
+ "types": "./dist/environment/index.d.ts",
58
+ "import": "./dist/environment/index.mjs",
59
+ "default": "./dist/environment/index.mjs"
60
+ },
61
+ "./package.json": "./package.json"
62
+ },
63
+ "dependencies": {
64
+ "@nuxt/kit": "^4.5.2",
65
+ "@nuxt/schema": "^4.5.2",
66
+ "c12": "^3.0.0",
67
+ "defu": "^6.1.7",
68
+ "destr": "^2.0.5",
69
+ "estree-walker": "^3.0.3",
70
+ "exsolve": "^1.1.1",
71
+ "fake-indexeddb": "^6.2.5",
72
+ "local-pkg": "^1.2.1",
73
+ "magic-string": "^0.30.0",
74
+ "node-fetch-native": "^1.6.7",
75
+ "node-mock-http": "^1.0.5",
76
+ "ofetch": "^1.5.1",
77
+ "pathe": "^2.0.3",
78
+ "radix3": "^1.1.2",
79
+ "scule": "^1.3.0",
80
+ "ufo": "^1.6.4",
81
+ "unimport": "^6.5.0",
82
+ "unplugin": "^3.3.0",
83
+ "@untestutils/core": "0.5.0"
84
+ },
85
+ "devDependencies": {
86
+ "@types/estree": "^1.0.8",
87
+ "@types/jsdom": "^27.0.0",
88
+ "@types/node": "^26.6.1",
89
+ "@vue/test-utils": "^2.5.1",
90
+ "obuild": "^0.4.40",
91
+ "publint": "^0.3.24",
92
+ "rollup": "^4.63.3",
93
+ "typescript": "^6.0.3",
94
+ "vue": "^3.5.0",
95
+ "vue-router": "^4.6.3"
96
+ },
97
+ "peerDependencies": {
98
+ "@nuxt/kit": "^4.5.2",
99
+ "@testing-library/vue": "^8.0.0",
100
+ "@vue/test-utils": "^2.4.0",
101
+ "h3": ">=1.15.0",
102
+ "happy-dom": ">=20.0.0",
103
+ "jsdom": ">=27.0.0",
104
+ "nuxt": "^3.0.0 || ^4.0.0",
105
+ "vitest": "^4.0.0 || ^5.0.0",
106
+ "vue": "^3.5.0"
107
+ },
108
+ "peerDependenciesMeta": {
109
+ "@nuxt/kit": {
110
+ "optional": true
111
+ },
112
+ "@testing-library/vue": {
113
+ "optional": true
114
+ },
115
+ "h3": {
116
+ "optional": true
117
+ },
118
+ "happy-dom": {
119
+ "optional": true
120
+ },
121
+ "jsdom": {
122
+ "optional": true
123
+ },
124
+ "nuxt": {
125
+ "optional": true
126
+ },
127
+ "vitest": {
128
+ "optional": true
129
+ }
130
+ },
131
+ "engines": {
132
+ "node": ">=20"
133
+ },
134
+ "license": "MIT",
135
+ "homepage": "https://s00d.github.io/untestutils/",
136
+ "repository": {
137
+ "type": "git",
138
+ "url": "git+https://github.com/s00d/untestutils.git",
139
+ "directory": "packages/nuxt"
140
+ },
141
+ "main": "./dist/index.mjs",
142
+ "types": "./dist/index.d.ts",
143
+ "publishConfig": {
144
+ "access": "public"
145
+ },
146
+ "scripts": {
147
+ "build": "obuild && tsc -p tsconfig.build.json",
148
+ "publint": "publint --strict"
149
+ }
150
+ }