@vobs/test-utils 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 +57 -0
- package/dist/index.js +146 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 vobsjs
|
|
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,57 @@
|
|
|
1
|
+
/** @license MIT
|
|
2
|
+
* Copyright (c) 2026 vobsjs
|
|
3
|
+
* @vobs/test-utils
|
|
4
|
+
*/
|
|
5
|
+
import { type I18nInstance, type I18nOptions } from '@vobs/i18n';
|
|
6
|
+
import { type IconDefinition, type IconRegistry } from '@vobs/icons';
|
|
7
|
+
import type { PageEnvironment, PageInstance, TemplateEnvironment } from '@vobs/runtime-core';
|
|
8
|
+
import { type PageDefinition } from '@vobs/runtime-dom';
|
|
9
|
+
import { type RenderPageOptions, type RenderPageResult } from '@vobs/server-renderer';
|
|
10
|
+
import { type ThemeController, type ThemeControllerOptions, type ThemeTarget } from '@vobs/ui';
|
|
11
|
+
import { type UiEnvironment } from '@vobs/ui/icons';
|
|
12
|
+
export interface TestEnvironmentOptions extends Partial<PageEnvironment> {
|
|
13
|
+
readonly baseUrl?: string;
|
|
14
|
+
readonly errors?: unknown[];
|
|
15
|
+
}
|
|
16
|
+
export interface TestContainer extends Element {
|
|
17
|
+
readonly items: Element[];
|
|
18
|
+
}
|
|
19
|
+
export interface TestPageHarness {
|
|
20
|
+
readonly container: TestContainer;
|
|
21
|
+
readonly environment: PageEnvironment;
|
|
22
|
+
readonly instance: PageInstance;
|
|
23
|
+
cleanup(): void;
|
|
24
|
+
}
|
|
25
|
+
export interface UiTestContextOptions {
|
|
26
|
+
readonly i18n?: I18nOptions;
|
|
27
|
+
readonly icons?: Readonly<Record<string, IconDefinition>>;
|
|
28
|
+
readonly theme?: Omit<ThemeControllerOptions, 'target'>;
|
|
29
|
+
}
|
|
30
|
+
export interface UiTestContext {
|
|
31
|
+
readonly i18n: I18nInstance;
|
|
32
|
+
readonly icons: IconRegistry;
|
|
33
|
+
readonly ui: UiEnvironment;
|
|
34
|
+
readonly themeTarget: TestThemeTarget;
|
|
35
|
+
readonly theme: ThemeController;
|
|
36
|
+
cleanup(): void;
|
|
37
|
+
}
|
|
38
|
+
export interface TestThemeTarget extends ThemeTarget {
|
|
39
|
+
readonly attributes: Readonly<Record<string, string>>;
|
|
40
|
+
readonly variables: ReadonlyMap<string, string>;
|
|
41
|
+
}
|
|
42
|
+
export declare function createTestEnvironment(options?: TestEnvironmentOptions): PageEnvironment;
|
|
43
|
+
export declare function createTestContainer(initialRoot?: Element): TestContainer;
|
|
44
|
+
export declare function mountTestPage(page: PageDefinition, options?: {
|
|
45
|
+
readonly container?: TestContainer;
|
|
46
|
+
readonly environment?: TestEnvironmentOptions;
|
|
47
|
+
}): Promise<TestPageHarness>;
|
|
48
|
+
export declare function hydrateTestPage(page: PageDefinition, options: {
|
|
49
|
+
readonly container: TestContainer;
|
|
50
|
+
readonly environment?: TestEnvironmentOptions;
|
|
51
|
+
}): Promise<TestPageHarness>;
|
|
52
|
+
export declare function renderTestPage<Scope extends object, InitialState = unknown>(options: Omit<RenderPageOptions<Scope, InitialState>, 'environment'> & {
|
|
53
|
+
readonly environment?: TemplateEnvironment;
|
|
54
|
+
}): RenderPageResult;
|
|
55
|
+
export declare function createUiTestContext(options?: UiTestContextOptions): UiTestContext;
|
|
56
|
+
export declare function createThemeTestTarget(): TestThemeTarget;
|
|
57
|
+
export declare function cleanup(): void;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/** @license MIT
|
|
2
|
+
* Copyright (c) 2026 vobsjs
|
|
3
|
+
* @vobs/test-utils
|
|
4
|
+
*/
|
|
5
|
+
import { createI18n } from '@vobs/i18n';
|
|
6
|
+
import { createIconRegistry } from '@vobs/icons';
|
|
7
|
+
import { Scheduler } from '@vobs/reactivity';
|
|
8
|
+
import { createDefaultUrlPolicy } from '@vobs/runtime-dom';
|
|
9
|
+
import { renderPage } from '@vobs/server-renderer';
|
|
10
|
+
import { createThemeController, } from '@vobs/ui';
|
|
11
|
+
import { createUiEnvironment } from '@vobs/ui/icons';
|
|
12
|
+
const cleanups = new Set();
|
|
13
|
+
export function createTestEnvironment(options = {}) {
|
|
14
|
+
const errors = options.errors;
|
|
15
|
+
const environment = {
|
|
16
|
+
scheduler: options.scheduler ?? new Scheduler(),
|
|
17
|
+
security: options.security ?? {
|
|
18
|
+
urlPolicy: createDefaultUrlPolicy(options.baseUrl ?? 'https://example.test/'),
|
|
19
|
+
},
|
|
20
|
+
onError: options.onError ??
|
|
21
|
+
((error) => {
|
|
22
|
+
errors?.push(error);
|
|
23
|
+
if (errors === undefined)
|
|
24
|
+
throw error;
|
|
25
|
+
}),
|
|
26
|
+
...(options.components === undefined ? {} : { components: options.components }),
|
|
27
|
+
...(options.slots === undefined ? {} : { slots: options.slots }),
|
|
28
|
+
...(options.route === undefined ? {} : { route: options.route }),
|
|
29
|
+
...(options.initialState === undefined ? {} : { initialState: options.initialState }),
|
|
30
|
+
};
|
|
31
|
+
return environment;
|
|
32
|
+
}
|
|
33
|
+
export function createTestContainer(initialRoot) {
|
|
34
|
+
const items = initialRoot === undefined ? [] : [initialRoot];
|
|
35
|
+
const appendNodes = (nodes) => {
|
|
36
|
+
for (const node of nodes) {
|
|
37
|
+
if (typeof node !== 'string')
|
|
38
|
+
items.push(node);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
items,
|
|
43
|
+
get firstElementChild() {
|
|
44
|
+
return items[0] ?? null;
|
|
45
|
+
},
|
|
46
|
+
append(...nodes) {
|
|
47
|
+
appendNodes(nodes);
|
|
48
|
+
},
|
|
49
|
+
replaceChildren(...nodes) {
|
|
50
|
+
items.length = 0;
|
|
51
|
+
appendNodes(nodes);
|
|
52
|
+
},
|
|
53
|
+
querySelectorAll() {
|
|
54
|
+
return [];
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export async function mountTestPage(page, options = {}) {
|
|
59
|
+
const container = options.container ?? createTestContainer();
|
|
60
|
+
const environment = createTestEnvironment(options.environment);
|
|
61
|
+
const instance = await page.mount(environment);
|
|
62
|
+
container.append(instance.root);
|
|
63
|
+
return createPageHarness(container, environment, instance);
|
|
64
|
+
}
|
|
65
|
+
export async function hydrateTestPage(page, options) {
|
|
66
|
+
const environment = createTestEnvironment(options.environment);
|
|
67
|
+
const instance = await page.hydrate(options.container, environment);
|
|
68
|
+
return createPageHarness(options.container, environment, instance);
|
|
69
|
+
}
|
|
70
|
+
export function renderTestPage(options) {
|
|
71
|
+
return renderPage({
|
|
72
|
+
...options,
|
|
73
|
+
environment: options.environment ?? createTestEnvironment(),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
export function createUiTestContext(options = {}) {
|
|
77
|
+
const i18n = createI18n(options.i18n ?? { locale: 'en-US', messages: {} });
|
|
78
|
+
const icons = createIconRegistry(options.icons ?? {});
|
|
79
|
+
const ui = createUiEnvironment({ icons });
|
|
80
|
+
const themeTarget = createThemeTestTarget();
|
|
81
|
+
const theme = createThemeController({
|
|
82
|
+
target: themeTarget,
|
|
83
|
+
...(options.theme ?? {}),
|
|
84
|
+
});
|
|
85
|
+
const cleanup = trackCleanup(() => {
|
|
86
|
+
theme.destroy();
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
i18n,
|
|
90
|
+
icons,
|
|
91
|
+
ui,
|
|
92
|
+
themeTarget,
|
|
93
|
+
theme,
|
|
94
|
+
cleanup,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
export function createThemeTestTarget() {
|
|
98
|
+
const attributes = {};
|
|
99
|
+
const variables = new Map();
|
|
100
|
+
return {
|
|
101
|
+
attributes,
|
|
102
|
+
variables,
|
|
103
|
+
setAttribute(name, value) {
|
|
104
|
+
attributes[name] = value;
|
|
105
|
+
},
|
|
106
|
+
style: {
|
|
107
|
+
setProperty(name, value) {
|
|
108
|
+
variables.set(name, value);
|
|
109
|
+
},
|
|
110
|
+
removeProperty(name) {
|
|
111
|
+
const current = variables.get(name) ?? '';
|
|
112
|
+
variables.delete(name);
|
|
113
|
+
return current;
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export function cleanup() {
|
|
119
|
+
const pending = Array.from(cleanups).reverse();
|
|
120
|
+
cleanups.clear();
|
|
121
|
+
for (const dispose of pending)
|
|
122
|
+
dispose();
|
|
123
|
+
}
|
|
124
|
+
function createPageHarness(container, environment, instance) {
|
|
125
|
+
const cleanupHarness = trackCleanup(() => {
|
|
126
|
+
instance.destroy();
|
|
127
|
+
});
|
|
128
|
+
return {
|
|
129
|
+
container,
|
|
130
|
+
environment,
|
|
131
|
+
instance,
|
|
132
|
+
cleanup: cleanupHarness,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function trackCleanup(dispose) {
|
|
136
|
+
let active = true;
|
|
137
|
+
const cleanupOnce = () => {
|
|
138
|
+
if (!active)
|
|
139
|
+
return;
|
|
140
|
+
active = false;
|
|
141
|
+
cleanups.delete(cleanupOnce);
|
|
142
|
+
dispose();
|
|
143
|
+
};
|
|
144
|
+
cleanups.add(cleanupOnce);
|
|
145
|
+
return cleanupOnce;
|
|
146
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vobs/test-utils",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Mount, hydrate and cleanup test harnesses for vobs applications and components.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"author": "vobsjs",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/vobsjs/vobs.git",
|
|
14
|
+
"directory": "packages/tools/test-utils"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/vobsjs/vobs/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/vobsjs/vobs#readme",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@vobs/icons": "0.1.0",
|
|
22
|
+
"@vobs/i18n": "0.1.0",
|
|
23
|
+
"@vobs/reactivity": "0.1.0",
|
|
24
|
+
"@vobs/runtime-core": "0.1.0",
|
|
25
|
+
"@vobs/runtime-dom": "0.1.0",
|
|
26
|
+
"@vobs/server-renderer": "0.1.0",
|
|
27
|
+
"@vobs/ui": "0.1.0"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"import": "./dist/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./package.json": "./package.json"
|
|
38
|
+
},
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"module": "./dist/index.js",
|
|
41
|
+
"main": "./dist/index.js",
|
|
42
|
+
"sideEffects": false,
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=20.19.0"
|
|
45
|
+
}
|
|
46
|
+
}
|