@modular-frontend/testing 0.1.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/LICENSE +21 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Igor Savin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ModuleDescriptor, ModuleEntry, SlotMap, SlotMapOf, Store } from "@modular-frontend/core";
|
|
2
|
+
|
|
3
|
+
//#region src/mock-store.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Creates a store pre-populated with the given state.
|
|
6
|
+
* Convenience alias for `createStore(initialState)` with a
|
|
7
|
+
* test-oriented name.
|
|
8
|
+
*
|
|
9
|
+
* Works as a drop-in replacement for zustand's `createStore` in tests.
|
|
10
|
+
* The returned `Store<T>` is compatible with `resolveModule()` and with
|
|
11
|
+
* whichever UI-framework binding's shared-state factory and render helper
|
|
12
|
+
* the test uses (`createSharedHooks`/`createSharedComposables`, etc.).
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const authStore = createMockStore<AuthStore>({
|
|
16
|
+
* user: { id: '1', name: 'Test User' },
|
|
17
|
+
* token: 'mock-token',
|
|
18
|
+
* isAuthenticated: true,
|
|
19
|
+
* login: async () => {},
|
|
20
|
+
* logout: () => {},
|
|
21
|
+
* })
|
|
22
|
+
*/
|
|
23
|
+
declare function createMockStore<T>(initialState: T): Store<T>;
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/resolve-module.d.ts
|
|
26
|
+
interface ResolveModuleOptions<TSharedDependencies extends Record<string, any>, TSlots extends SlotMapOf<TSlots>> {
|
|
27
|
+
/** Dependencies snapshot passed to onRegister lifecycle hook and dynamicSlots evaluation */
|
|
28
|
+
deps?: Partial<TSharedDependencies>;
|
|
29
|
+
/** Default slot values (same as registry slot defaults) */
|
|
30
|
+
defaults?: Partial<{ [K in keyof TSlots]: TSlots[K] }>;
|
|
31
|
+
}
|
|
32
|
+
interface ResolveModuleResult<TSlots> {
|
|
33
|
+
/** The module's resolved slot contributions (merged with defaults, including dynamic slots) */
|
|
34
|
+
slots: TSlots;
|
|
35
|
+
/** The ModuleEntry as it would appear in useModules() */
|
|
36
|
+
entry: ModuleEntry;
|
|
37
|
+
/** Whether onRegister was called */
|
|
38
|
+
onRegisterCalled: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Resolves a module without rendering — runs it through slot merging
|
|
42
|
+
* (static + dynamic) and lifecycle hooks, returning the resolved contributions.
|
|
43
|
+
*
|
|
44
|
+
* Use this for headless modules (no component, no routes) that can't
|
|
45
|
+
* be tested by rendering with a UI-framework binding.
|
|
46
|
+
*
|
|
47
|
+
* When the module has `dynamicSlots`, they are evaluated with the
|
|
48
|
+
* provided `deps` snapshot and merged with static slot contributions.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const { slots, entry } = resolveModule(externalSystemsModule, {
|
|
52
|
+
* defaults: { systems: [], commands: [] },
|
|
53
|
+
* deps: { auth: { user: { isAdmin: true } } },
|
|
54
|
+
* })
|
|
55
|
+
* expect(slots.systems).toHaveLength(1)
|
|
56
|
+
* expect(entry.id).toBe('external-systems')
|
|
57
|
+
*/
|
|
58
|
+
declare function resolveModule<TSharedDependencies extends Record<string, any>, TSlots extends SlotMapOf<TSlots> = SlotMap>(module: ModuleDescriptor<TSharedDependencies, TSlots>, options?: ResolveModuleOptions<TSharedDependencies, TSlots>): ResolveModuleResult<TSlots>;
|
|
59
|
+
//#endregion
|
|
60
|
+
export { type ResolveModuleOptions, type ResolveModuleResult, createMockStore, resolveModule };
|
|
61
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/mock-store.ts","../src/resolve-module.ts"],"mappings":";;;;;AAsBA;;;;;;;;;;;;;;AAA4D;;;iBAA5C,eAAA,IAAmB,YAAA,EAAc,CAAA,GAAI,KAAA,CAAM,CAAA;;;UCnB1C,oBAAA,6BACa,MAAA,8BACb,SAAA,CAAU,MAAA;;EAGzB,IAAA,GAAO,OAAA,CAAQ,mBAAA;EDcc;ECZ7B,QAAA,GAAW,OAAA,eAAsB,MAAA,GAAS,MAAA,CAAO,CAAA;AAAA;AAAA,UAGlC,mBAAA;EDSyC;ECPxD,KAAA,EAAO,MAAA;EDOwC;ECL/C,KAAA,EAAO,WAAW;EDKiC;ECHnD,gBAAA;AAAA;ADG0D;;;;ACnB5D;;;;;;;;;;;;;;ADmB4D,iBCkB5C,aAAA,6BACc,MAAA,8BACb,SAAA,CAAU,MAAA,IAAU,OAAA,EAEnC,MAAA,EAAQ,gBAAA,CAAiB,mBAAA,EAAqB,MAAA,GAC9C,OAAA,GAAU,oBAAA,CAAqB,mBAAA,EAAqB,MAAA,IACnD,mBAAA,CAAoB,MAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { buildSlotsManifest as e, createStore as t, evaluateDynamicSlots as n } from "@modular-frontend/core";
|
|
2
|
+
//#region src/mock-store.ts
|
|
3
|
+
function r(e) {
|
|
4
|
+
return t(e);
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/resolve-module.ts
|
|
8
|
+
function i(t, r) {
|
|
9
|
+
let i = e([t], r?.defaults);
|
|
10
|
+
if (t.dynamicSlots) {
|
|
11
|
+
let e = r?.deps ?? {};
|
|
12
|
+
i = n(i, [t.dynamicSlots], e);
|
|
13
|
+
}
|
|
14
|
+
let a = {
|
|
15
|
+
id: t.id,
|
|
16
|
+
version: t.version,
|
|
17
|
+
meta: t.meta,
|
|
18
|
+
component: t.component,
|
|
19
|
+
zones: t.zones
|
|
20
|
+
}, o = !1;
|
|
21
|
+
return t.lifecycle?.onRegister && (t.lifecycle.onRegister(r?.deps ?? {}), o = !0), {
|
|
22
|
+
slots: i,
|
|
23
|
+
entry: a,
|
|
24
|
+
onRegisterCalled: o
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { r as createMockStore, i as resolveModule };
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/mock-store.ts","../src/resolve-module.ts"],"sourcesContent":["import { createStore } from \"@modular-frontend/core\";\nimport type { Store } from \"@modular-frontend/core\";\n\n/**\n * Creates a store pre-populated with the given state.\n * Convenience alias for `createStore(initialState)` with a\n * test-oriented name.\n *\n * Works as a drop-in replacement for zustand's `createStore` in tests.\n * The returned `Store<T>` is compatible with `resolveModule()` and with\n * whichever UI-framework binding's shared-state factory and render helper\n * the test uses (`createSharedHooks`/`createSharedComposables`, etc.).\n *\n * @example\n * const authStore = createMockStore<AuthStore>({\n * user: { id: '1', name: 'Test User' },\n * token: 'mock-token',\n * isAuthenticated: true,\n * login: async () => {},\n * logout: () => {},\n * })\n */\nexport function createMockStore<T>(initialState: T): Store<T> {\n return createStore<T>(initialState);\n}\n","import type { ModuleDescriptor, SlotMap, SlotMapOf, ModuleEntry } from \"@modular-frontend/core\";\nimport { buildSlotsManifest, evaluateDynamicSlots } from \"@modular-frontend/core\";\n\nexport interface ResolveModuleOptions<\n TSharedDependencies extends Record<string, any>,\n TSlots extends SlotMapOf<TSlots>,\n> {\n /** Dependencies snapshot passed to onRegister lifecycle hook and dynamicSlots evaluation */\n deps?: Partial<TSharedDependencies>;\n /** Default slot values (same as registry slot defaults) */\n defaults?: Partial<{ [K in keyof TSlots]: TSlots[K] }>;\n}\n\nexport interface ResolveModuleResult<TSlots> {\n /** The module's resolved slot contributions (merged with defaults, including dynamic slots) */\n slots: TSlots;\n /** The ModuleEntry as it would appear in useModules() */\n entry: ModuleEntry;\n /** Whether onRegister was called */\n onRegisterCalled: boolean;\n}\n\n/**\n * Resolves a module without rendering — runs it through slot merging\n * (static + dynamic) and lifecycle hooks, returning the resolved contributions.\n *\n * Use this for headless modules (no component, no routes) that can't\n * be tested by rendering with a UI-framework binding.\n *\n * When the module has `dynamicSlots`, they are evaluated with the\n * provided `deps` snapshot and merged with static slot contributions.\n *\n * @example\n * const { slots, entry } = resolveModule(externalSystemsModule, {\n * defaults: { systems: [], commands: [] },\n * deps: { auth: { user: { isAdmin: true } } },\n * })\n * expect(slots.systems).toHaveLength(1)\n * expect(entry.id).toBe('external-systems')\n */\nexport function resolveModule<\n TSharedDependencies extends Record<string, any>,\n TSlots extends SlotMapOf<TSlots> = SlotMap,\n>(\n module: ModuleDescriptor<TSharedDependencies, TSlots>,\n options?: ResolveModuleOptions<TSharedDependencies, TSlots>,\n): ResolveModuleResult<TSlots> {\n let slots = buildSlotsManifest<TSlots>([module], options?.defaults);\n\n // Evaluate dynamic slots if the module has them\n if (module.dynamicSlots) {\n const deps = (options?.deps ?? {}) as Record<string, unknown>;\n slots = evaluateDynamicSlots(\n slots,\n [\n module.dynamicSlots as (\n deps: Record<string, unknown>,\n ) => Record<string, readonly unknown[]>,\n ],\n deps,\n );\n }\n\n const entry: ModuleEntry = {\n id: module.id,\n version: module.version,\n meta: module.meta,\n component: module.component,\n zones: module.zones,\n };\n\n let onRegisterCalled = false;\n if (module.lifecycle?.onRegister) {\n module.lifecycle.onRegister((options?.deps ?? {}) as TSharedDependencies);\n onRegisterCalled = true;\n }\n\n return { slots, entry, onRegisterCalled };\n}\n"],"mappings":";;AAsBA,SAAgB,EAAmB,GAA2B;CAC5D,OAAO,EAAe,CAAY;AACpC;;;ACgBA,SAAgB,EAId,GACA,GAC6B;CAC7B,IAAI,IAAQ,EAA2B,CAAC,CAAM,GAAG,GAAS,QAAQ;CAGlE,IAAI,EAAO,cAAc;EACvB,IAAM,IAAQ,GAAS,QAAQ,CAAC;EAChC,IAAQ,EACN,GACA,CACE,EAAO,YAGT,GACA,CACF;CACF;CAEA,IAAM,IAAqB;EACzB,IAAI,EAAO;EACX,SAAS,EAAO;EAChB,MAAM,EAAO;EACb,WAAW,EAAO;EAClB,OAAO,EAAO;CAChB,GAEI,IAAmB;CAMvB,OALI,EAAO,WAAW,eACpB,EAAO,UAAU,WAAY,GAAS,QAAQ,CAAC,CAAyB,GACxE,IAAmB,KAGd;EAAE;EAAO;EAAO;CAAiB;AAC1C"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@modular-frontend/testing",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Framework-neutral testing utilities for modular frontend modules: mock stores and headless module resolution over @modular-frontend/core.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git://github.com/kibertoad/modular-react.git",
|
|
8
|
+
"directory": "packages/frontend-testing"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"oxfmt": "^0.51.0",
|
|
27
|
+
"oxlint": "^1.66.0",
|
|
28
|
+
"rolldown-plugin-dts": "^0.26.0",
|
|
29
|
+
"typescript": "^6.0.3",
|
|
30
|
+
"vite": "^8.1.3",
|
|
31
|
+
"vitest": "^4.1.10",
|
|
32
|
+
"@modular-frontend/core": "0.4.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@modular-frontend/core": ">=0.1.0 <2.0.0"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "vite build",
|
|
39
|
+
"dev": "vite build --watch",
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"typecheck": "tsc --noEmit"
|
|
42
|
+
}
|
|
43
|
+
}
|