@atomic-testing/vue-3 0.71.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/README.md +9 -0
- package/dist/index.d.mts +36 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +145 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +120 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +44 -0
- package/src/VueInteractor.ts +142 -0
- package/src/createTestEngine.ts +79 -0
- package/src/index.ts +3 -0
- package/src/types.ts +5 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Tianzhen Lin (Tangent)
|
|
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/README.md
ADDED
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ClickOption, EnterTextOption, FocusOption, HoverOption, IComponentDriverOption, Interactor, MouseDownOption, MouseEnterOption, MouseLeaveOption, MouseMoveOption, MouseOutOption, MouseUpOption, PartLocator, ScenePart, TestEngine, WaitForOption, WaitUntilOption } from "@atomic-testing/core";
|
|
2
|
+
import { Component } from "vue";
|
|
3
|
+
import { DOMInteractor } from "@atomic-testing/dom-core";
|
|
4
|
+
|
|
5
|
+
//#region src/types.d.ts
|
|
6
|
+
interface IVueTestEngineOption extends IComponentDriverOption {
|
|
7
|
+
rootElement?: Element;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/createTestEngine.d.ts
|
|
11
|
+
declare function createTestEngine<T extends ScenePart>(component: Component, partDefinitions: T, option?: Readonly<Partial<IVueTestEngineOption>>): TestEngine<T>;
|
|
12
|
+
declare function createRenderedTestEngine<T extends ScenePart>(rootElement: HTMLElement, partDefinitions: T, _option?: Readonly<Partial<IVueTestEngineOption>>): TestEngine<T>;
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/VueInteractor.d.ts
|
|
15
|
+
declare class VueInteractor extends DOMInteractor {
|
|
16
|
+
private flush;
|
|
17
|
+
enterText(locator: PartLocator, text: string, option?: Partial<EnterTextOption>): Promise<void>;
|
|
18
|
+
click(locator: PartLocator, option?: Partial<ClickOption>): Promise<void>;
|
|
19
|
+
hover(locator: PartLocator, option?: Partial<HoverOption>): Promise<void>;
|
|
20
|
+
mouseMove(locator: PartLocator, option?: Partial<MouseMoveOption>): Promise<void>;
|
|
21
|
+
mouseDown(locator: PartLocator, option?: Partial<MouseDownOption>): Promise<void>;
|
|
22
|
+
mouseUp(locator: PartLocator, option?: Partial<MouseUpOption>): Promise<void>;
|
|
23
|
+
mouseOver(locator: PartLocator, option?: Partial<HoverOption>): Promise<void>;
|
|
24
|
+
mouseOut(locator: PartLocator, option?: Partial<MouseOutOption>): Promise<void>;
|
|
25
|
+
mouseEnter(locator: PartLocator, option?: Partial<MouseEnterOption>): Promise<void>;
|
|
26
|
+
mouseLeave(locator: PartLocator, option?: Partial<MouseLeaveOption>): Promise<void>;
|
|
27
|
+
focus(locator: PartLocator, option?: Partial<FocusOption>): Promise<void>;
|
|
28
|
+
selectOptionValue(locator: PartLocator, values: string[]): Promise<void>;
|
|
29
|
+
wait(ms: number): Promise<void>;
|
|
30
|
+
waitUntilComponentState(locator: PartLocator, option?: Partial<Readonly<WaitForOption>>): Promise<void>;
|
|
31
|
+
waitUntil<T>(option: WaitUntilOption<T>): Promise<T>;
|
|
32
|
+
clone(): Interactor;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { IVueTestEngineOption, VueInteractor, createRenderedTestEngine, createTestEngine };
|
|
36
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ClickOption, EnterTextOption, FocusOption, HoverOption, IComponentDriverOption, Interactor, MouseDownOption, MouseEnterOption, MouseLeaveOption, MouseMoveOption, MouseOutOption, MouseUpOption, PartLocator, ScenePart, TestEngine, WaitForOption, WaitUntilOption } from "@atomic-testing/core";
|
|
2
|
+
import { Component } from "vue";
|
|
3
|
+
import { DOMInteractor } from "@atomic-testing/dom-core";
|
|
4
|
+
|
|
5
|
+
//#region src/types.d.ts
|
|
6
|
+
interface IVueTestEngineOption extends IComponentDriverOption {
|
|
7
|
+
rootElement?: Element;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/createTestEngine.d.ts
|
|
11
|
+
declare function createTestEngine<T extends ScenePart>(component: Component, partDefinitions: T, option?: Readonly<Partial<IVueTestEngineOption>>): TestEngine<T>;
|
|
12
|
+
declare function createRenderedTestEngine<T extends ScenePart>(rootElement: HTMLElement, partDefinitions: T, _option?: Readonly<Partial<IVueTestEngineOption>>): TestEngine<T>;
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/VueInteractor.d.ts
|
|
15
|
+
declare class VueInteractor extends DOMInteractor {
|
|
16
|
+
private flush;
|
|
17
|
+
enterText(locator: PartLocator, text: string, option?: Partial<EnterTextOption>): Promise<void>;
|
|
18
|
+
click(locator: PartLocator, option?: Partial<ClickOption>): Promise<void>;
|
|
19
|
+
hover(locator: PartLocator, option?: Partial<HoverOption>): Promise<void>;
|
|
20
|
+
mouseMove(locator: PartLocator, option?: Partial<MouseMoveOption>): Promise<void>;
|
|
21
|
+
mouseDown(locator: PartLocator, option?: Partial<MouseDownOption>): Promise<void>;
|
|
22
|
+
mouseUp(locator: PartLocator, option?: Partial<MouseUpOption>): Promise<void>;
|
|
23
|
+
mouseOver(locator: PartLocator, option?: Partial<HoverOption>): Promise<void>;
|
|
24
|
+
mouseOut(locator: PartLocator, option?: Partial<MouseOutOption>): Promise<void>;
|
|
25
|
+
mouseEnter(locator: PartLocator, option?: Partial<MouseEnterOption>): Promise<void>;
|
|
26
|
+
mouseLeave(locator: PartLocator, option?: Partial<MouseLeaveOption>): Promise<void>;
|
|
27
|
+
focus(locator: PartLocator, option?: Partial<FocusOption>): Promise<void>;
|
|
28
|
+
selectOptionValue(locator: PartLocator, values: string[]): Promise<void>;
|
|
29
|
+
wait(ms: number): Promise<void>;
|
|
30
|
+
waitUntilComponentState(locator: PartLocator, option?: Partial<Readonly<WaitForOption>>): Promise<void>;
|
|
31
|
+
waitUntil<T>(option: WaitUntilOption<T>): Promise<T>;
|
|
32
|
+
clone(): Interactor;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { IVueTestEngineOption, VueInteractor, createRenderedTestEngine, createTestEngine };
|
|
36
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
const __atomic_testing_core = __toESM(require("@atomic-testing/core"));
|
|
25
|
+
const __testing_library_vue = __toESM(require("@testing-library/vue"));
|
|
26
|
+
const vue = __toESM(require("vue"));
|
|
27
|
+
const __atomic_testing_dom_core = __toESM(require("@atomic-testing/dom-core"));
|
|
28
|
+
|
|
29
|
+
//#region src/VueInteractor.ts
|
|
30
|
+
var VueInteractor = class VueInteractor extends __atomic_testing_dom_core.DOMInteractor {
|
|
31
|
+
async flush() {
|
|
32
|
+
await (0, vue.nextTick)();
|
|
33
|
+
}
|
|
34
|
+
async enterText(locator, text, option) {
|
|
35
|
+
await super.enterText(locator, text, option);
|
|
36
|
+
await this.flush();
|
|
37
|
+
}
|
|
38
|
+
async click(locator, option) {
|
|
39
|
+
await super.click(locator, option);
|
|
40
|
+
await this.flush();
|
|
41
|
+
}
|
|
42
|
+
async hover(locator, option) {
|
|
43
|
+
await super.hover(locator, option);
|
|
44
|
+
await this.flush();
|
|
45
|
+
}
|
|
46
|
+
async mouseMove(locator, option) {
|
|
47
|
+
await super.mouseMove(locator, option);
|
|
48
|
+
await this.flush();
|
|
49
|
+
}
|
|
50
|
+
async mouseDown(locator, option) {
|
|
51
|
+
await super.mouseDown(locator, option);
|
|
52
|
+
await this.flush();
|
|
53
|
+
}
|
|
54
|
+
async mouseUp(locator, option) {
|
|
55
|
+
await super.mouseUp(locator, option);
|
|
56
|
+
await this.flush();
|
|
57
|
+
}
|
|
58
|
+
async mouseOver(locator, option) {
|
|
59
|
+
await super.mouseOver(locator, option);
|
|
60
|
+
await this.flush();
|
|
61
|
+
}
|
|
62
|
+
async mouseOut(locator, option) {
|
|
63
|
+
await super.mouseOut(locator, option);
|
|
64
|
+
await this.flush();
|
|
65
|
+
}
|
|
66
|
+
async mouseEnter(locator, option) {
|
|
67
|
+
await super.mouseEnter(locator, option);
|
|
68
|
+
await this.flush();
|
|
69
|
+
}
|
|
70
|
+
async mouseLeave(locator, option) {
|
|
71
|
+
await super.mouseLeave(locator, option);
|
|
72
|
+
await this.flush();
|
|
73
|
+
}
|
|
74
|
+
async focus(locator, option) {
|
|
75
|
+
await super.focus(locator, option);
|
|
76
|
+
await this.flush();
|
|
77
|
+
}
|
|
78
|
+
async selectOptionValue(locator, values) {
|
|
79
|
+
await super.selectOptionValue(locator, values);
|
|
80
|
+
await this.flush();
|
|
81
|
+
}
|
|
82
|
+
async wait(ms) {
|
|
83
|
+
await super.wait(ms);
|
|
84
|
+
await this.flush();
|
|
85
|
+
}
|
|
86
|
+
async waitUntilComponentState(locator, option = __atomic_testing_core.defaultWaitForOption) {
|
|
87
|
+
await super.waitUntilComponentState(locator, option);
|
|
88
|
+
await this.flush();
|
|
89
|
+
}
|
|
90
|
+
async waitUntil(option) {
|
|
91
|
+
const result = await super.waitUntil(option);
|
|
92
|
+
await this.flush();
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
clone() {
|
|
96
|
+
return new VueInteractor();
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/createTestEngine.ts
|
|
102
|
+
let _rootId = 0;
|
|
103
|
+
function getNextRootElementId() {
|
|
104
|
+
return `${_rootId++}`;
|
|
105
|
+
}
|
|
106
|
+
const rootElementAttributeName = "data-atomic-testing-vue";
|
|
107
|
+
function createTestEngine(component, partDefinitions, option) {
|
|
108
|
+
const rootEl = option?.rootElement ?? document.body;
|
|
109
|
+
const container = rootEl.appendChild(document.createElement("div"));
|
|
110
|
+
const rootId = getNextRootElementId();
|
|
111
|
+
container.setAttribute(rootElementAttributeName, rootId);
|
|
112
|
+
let unmount;
|
|
113
|
+
let app;
|
|
114
|
+
try {
|
|
115
|
+
const renderResult = (0, __testing_library_vue.render)(component, { container });
|
|
116
|
+
unmount = renderResult.unmount;
|
|
117
|
+
} catch (_error) {
|
|
118
|
+
app = (0, vue.createApp)(component);
|
|
119
|
+
app.mount(container);
|
|
120
|
+
unmount = () => {
|
|
121
|
+
if (app) app.unmount();
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
const cleanup = () => {
|
|
125
|
+
unmount();
|
|
126
|
+
rootEl.removeChild(container);
|
|
127
|
+
return Promise.resolve();
|
|
128
|
+
};
|
|
129
|
+
return new __atomic_testing_core.TestEngine((0, __atomic_testing_core.byAttribute)(rootElementAttributeName, rootId), new VueInteractor(), { parts: partDefinitions }, cleanup);
|
|
130
|
+
}
|
|
131
|
+
function createRenderedTestEngine(rootElement, partDefinitions, _option) {
|
|
132
|
+
const rootId = getNextRootElementId();
|
|
133
|
+
rootElement.setAttribute(rootElementAttributeName, rootId);
|
|
134
|
+
const cleanup = () => {
|
|
135
|
+
rootElement.removeAttribute(rootElementAttributeName);
|
|
136
|
+
return Promise.resolve();
|
|
137
|
+
};
|
|
138
|
+
return new __atomic_testing_core.TestEngine((0, __atomic_testing_core.byAttribute)(rootElementAttributeName, rootId), new VueInteractor(), { parts: partDefinitions }, cleanup);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
//#endregion
|
|
142
|
+
exports.VueInteractor = VueInteractor;
|
|
143
|
+
exports.createRenderedTestEngine = createRenderedTestEngine;
|
|
144
|
+
exports.createTestEngine = createTestEngine;
|
|
145
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["DOMInteractor","locator: PartLocator","text: string","option?: Partial<EnterTextOption>","option?: Partial<ClickOption>","option?: Partial<HoverOption>","option?: Partial<MouseMoveOption>","option?: Partial<MouseDownOption>","option?: Partial<MouseUpOption>","option?: Partial<MouseOutOption>","option?: Partial<MouseEnterOption>","option?: Partial<MouseLeaveOption>","option?: Partial<FocusOption>","values: string[]","ms: number","option: Partial<Readonly<WaitForOption>>","defaultWaitForOption","option: WaitUntilOption<T>","component: Component","partDefinitions: T","option?: Readonly<Partial<IVueTestEngineOption>>","unmount: () => void","app: App","TestEngine","rootElement: HTMLElement","_option?: Readonly<Partial<IVueTestEngineOption>>"],"sources":["../src/VueInteractor.ts","../src/createTestEngine.ts"],"sourcesContent":["import {\n ClickOption,\n defaultWaitForOption,\n EnterTextOption,\n FocusOption,\n HoverOption,\n Interactor,\n MouseDownOption,\n MouseEnterOption,\n MouseLeaveOption,\n MouseMoveOption,\n MouseOutOption,\n MouseUpOption,\n PartLocator,\n WaitForOption,\n WaitUntilOption,\n} from '@atomic-testing/core';\nimport { DOMInteractor } from '@atomic-testing/dom-core';\nimport { nextTick } from 'vue';\n\nexport class VueInteractor extends DOMInteractor {\n private async flush() {\n await nextTick();\n }\n\n override async enterText(\n locator: PartLocator,\n text: string,\n option?: Partial<EnterTextOption>,\n ): Promise<void> {\n await super.enterText(locator, text, option);\n await this.flush();\n }\n\n override async click(\n locator: PartLocator,\n option?: Partial<ClickOption>,\n ): Promise<void> {\n await super.click(locator, option);\n await this.flush();\n }\n\n override async hover(\n locator: PartLocator,\n option?: Partial<HoverOption>,\n ): Promise<void> {\n await super.hover(locator, option);\n await this.flush();\n }\n\n async mouseMove(\n locator: PartLocator,\n option?: Partial<MouseMoveOption>,\n ): Promise<void> {\n await super.mouseMove(locator, option);\n await this.flush();\n }\n\n async mouseDown(\n locator: PartLocator,\n option?: Partial<MouseDownOption>,\n ): Promise<void> {\n await super.mouseDown(locator, option);\n await this.flush();\n }\n\n async mouseUp(\n locator: PartLocator,\n option?: Partial<MouseUpOption>,\n ): Promise<void> {\n await super.mouseUp(locator, option);\n await this.flush();\n }\n\n async mouseOver(\n locator: PartLocator,\n option?: Partial<HoverOption>,\n ): Promise<void> {\n await super.mouseOver(locator, option);\n await this.flush();\n }\n\n async mouseOut(\n locator: PartLocator,\n option?: Partial<MouseOutOption>,\n ): Promise<void> {\n await super.mouseOut(locator, option);\n await this.flush();\n }\n\n async mouseEnter(\n locator: PartLocator,\n option?: Partial<MouseEnterOption>,\n ): Promise<void> {\n await super.mouseEnter(locator, option);\n await this.flush();\n }\n\n async mouseLeave(\n locator: PartLocator,\n option?: Partial<MouseLeaveOption>,\n ): Promise<void> {\n await super.mouseLeave(locator, option);\n await this.flush();\n }\n\n async focus(locator: PartLocator, option?: Partial<FocusOption>): Promise<void> {\n await super.focus(locator, option);\n await this.flush();\n }\n\n override async selectOptionValue(\n locator: PartLocator,\n values: string[],\n ): Promise<void> {\n await super.selectOptionValue(locator, values);\n await this.flush();\n }\n\n override async wait(ms: number): Promise<void> {\n await super.wait(ms);\n await this.flush();\n }\n\n override async waitUntilComponentState(\n locator: PartLocator,\n option: Partial<Readonly<WaitForOption>> = defaultWaitForOption,\n ): Promise<void> {\n await super.waitUntilComponentState(locator, option);\n await this.flush();\n }\n\n override async waitUntil<T>(option: WaitUntilOption<T>): Promise<T> {\n const result = await super.waitUntil(option);\n await this.flush();\n return result;\n }\n\n override clone(): Interactor {\n return new VueInteractor();\n }\n}\n","import { byAttribute, ScenePart, TestEngine } from '@atomic-testing/core';\nimport { render } from '@testing-library/vue';\nimport { App, Component, createApp } from 'vue';\n\nimport { VueInteractor } from './VueInteractor';\nimport { IVueTestEngineOption } from './types';\n\nlet _rootId = 0;\nfunction getNextRootElementId() {\n return `${_rootId++}`;\n}\n\nconst rootElementAttributeName = 'data-atomic-testing-vue';\n\nexport function createTestEngine<T extends ScenePart>(\n component: Component,\n partDefinitions: T,\n option?: Readonly<Partial<IVueTestEngineOption>>\n): TestEngine<T> {\n const rootEl = option?.rootElement ?? document.body;\n const container = rootEl.appendChild(document.createElement('div'));\n const rootId = getNextRootElementId();\n container.setAttribute(rootElementAttributeName, rootId);\n \n let unmount: () => void;\n let app: App;\n \n try {\n const renderResult = render(component, { container });\n unmount = renderResult.unmount;\n } catch (_error) {\n // Fallback to manual Vue app creation if render fails\n app = createApp(component);\n app.mount(container);\n unmount = () => {\n if (app) {\n app.unmount();\n }\n };\n }\n\n const cleanup = () => {\n unmount();\n rootEl.removeChild(container);\n return Promise.resolve();\n };\n\n return new TestEngine(\n byAttribute(rootElementAttributeName, rootId),\n new VueInteractor(),\n {\n parts: partDefinitions,\n },\n cleanup\n );\n}\n\nexport function createRenderedTestEngine<T extends ScenePart>(\n rootElement: HTMLElement,\n partDefinitions: T,\n _option?: Readonly<Partial<IVueTestEngineOption>>\n): TestEngine<T> {\n const rootId = getNextRootElementId();\n rootElement.setAttribute(rootElementAttributeName, rootId);\n\n const cleanup = () => {\n rootElement.removeAttribute(rootElementAttributeName);\n return Promise.resolve();\n };\n\n return new TestEngine(\n byAttribute(rootElementAttributeName, rootId),\n new VueInteractor(),\n {\n parts: partDefinitions,\n },\n cleanup\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,IAAa,gBAAb,MAAa,sBAAsBA,wCAAc;CAC/C,MAAc,QAAQ;AACpB,QAAM,mBAAU;CACjB;CAED,MAAe,UACbC,SACAC,MACAC,QACe;AACf,QAAM,MAAM,UAAU,SAAS,MAAM,OAAO;AAC5C,QAAM,KAAK,OAAO;CACnB;CAED,MAAe,MACbF,SACAG,QACe;AACf,QAAM,MAAM,MAAM,SAAS,OAAO;AAClC,QAAM,KAAK,OAAO;CACnB;CAED,MAAe,MACbH,SACAI,QACe;AACf,QAAM,MAAM,MAAM,SAAS,OAAO;AAClC,QAAM,KAAK,OAAO;CACnB;CAED,MAAM,UACJJ,SACAK,QACe;AACf,QAAM,MAAM,UAAU,SAAS,OAAO;AACtC,QAAM,KAAK,OAAO;CACnB;CAED,MAAM,UACJL,SACAM,QACe;AACf,QAAM,MAAM,UAAU,SAAS,OAAO;AACtC,QAAM,KAAK,OAAO;CACnB;CAED,MAAM,QACJN,SACAO,QACe;AACf,QAAM,MAAM,QAAQ,SAAS,OAAO;AACpC,QAAM,KAAK,OAAO;CACnB;CAED,MAAM,UACJP,SACAI,QACe;AACf,QAAM,MAAM,UAAU,SAAS,OAAO;AACtC,QAAM,KAAK,OAAO;CACnB;CAED,MAAM,SACJJ,SACAQ,QACe;AACf,QAAM,MAAM,SAAS,SAAS,OAAO;AACrC,QAAM,KAAK,OAAO;CACnB;CAED,MAAM,WACJR,SACAS,QACe;AACf,QAAM,MAAM,WAAW,SAAS,OAAO;AACvC,QAAM,KAAK,OAAO;CACnB;CAED,MAAM,WACJT,SACAU,QACe;AACf,QAAM,MAAM,WAAW,SAAS,OAAO;AACvC,QAAM,KAAK,OAAO;CACnB;CAED,MAAM,MAAMV,SAAsBW,QAA8C;AAC9E,QAAM,MAAM,MAAM,SAAS,OAAO;AAClC,QAAM,KAAK,OAAO;CACnB;CAED,MAAe,kBACbX,SACAY,QACe;AACf,QAAM,MAAM,kBAAkB,SAAS,OAAO;AAC9C,QAAM,KAAK,OAAO;CACnB;CAED,MAAe,KAAKC,IAA2B;AAC7C,QAAM,MAAM,KAAK,GAAG;AACpB,QAAM,KAAK,OAAO;CACnB;CAED,MAAe,wBACbb,SACAc,SAA2CC,4CAC5B;AACf,QAAM,MAAM,wBAAwB,SAAS,OAAO;AACpD,QAAM,KAAK,OAAO;CACnB;CAED,MAAe,UAAaC,QAAwC;EAClE,MAAM,SAAS,MAAM,MAAM,UAAU,OAAO;AAC5C,QAAM,KAAK,OAAO;AAClB,SAAO;CACR;CAED,AAAS,QAAoB;AAC3B,SAAO,IAAI;CACZ;AACF;;;;ACtID,IAAI,UAAU;AACd,SAAS,uBAAuB;AAC9B,SAAQ,EAAE,UAAU;AACrB;AAED,MAAM,2BAA2B;AAEjC,SAAgB,iBACdC,WACAC,iBACAC,QACe;CACf,MAAM,SAAS,QAAQ,eAAe,SAAS;CAC/C,MAAM,YAAY,OAAO,YAAY,SAAS,cAAc,MAAM,CAAC;CACnE,MAAM,SAAS,sBAAsB;AACrC,WAAU,aAAa,0BAA0B,OAAO;CAExD,IAAIC;CACJ,IAAIC;AAEJ,KAAI;EACF,MAAM,eAAe,kCAAO,WAAW,EAAE,UAAW,EAAC;AACrD,YAAU,aAAa;CACxB,SAAQ,QAAQ;AAEf,QAAM,mBAAU,UAAU;AAC1B,MAAI,MAAM,UAAU;AACpB,YAAU,MAAM;AACd,OAAI,IACF,KAAI,SAAS;EAEhB;CACF;CAED,MAAM,UAAU,MAAM;AACpB,WAAS;AACT,SAAO,YAAY,UAAU;AAC7B,SAAO,QAAQ,SAAS;CACzB;AAED,QAAO,IAAIC,iCACT,uCAAY,0BAA0B,OAAO,EAC7C,IAAI,iBACJ,EACE,OAAO,gBACR,GACD;AAEH;AAED,SAAgB,yBACdC,aACAL,iBACAM,SACe;CACf,MAAM,SAAS,sBAAsB;AACrC,aAAY,aAAa,0BAA0B,OAAO;CAE1D,MAAM,UAAU,MAAM;AACpB,cAAY,gBAAgB,yBAAyB;AACrD,SAAO,QAAQ,SAAS;CACzB;AAED,QAAO,IAAIF,iCACT,uCAAY,0BAA0B,OAAO,EAC7C,IAAI,iBACJ,EACE,OAAO,gBACR,GACD;AAEH"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { TestEngine, byAttribute, defaultWaitForOption } from "@atomic-testing/core";
|
|
2
|
+
import { render } from "@testing-library/vue";
|
|
3
|
+
import { createApp, nextTick } from "vue";
|
|
4
|
+
import { DOMInteractor } from "@atomic-testing/dom-core";
|
|
5
|
+
|
|
6
|
+
//#region src/VueInteractor.ts
|
|
7
|
+
var VueInteractor = class VueInteractor extends DOMInteractor {
|
|
8
|
+
async flush() {
|
|
9
|
+
await nextTick();
|
|
10
|
+
}
|
|
11
|
+
async enterText(locator, text, option) {
|
|
12
|
+
await super.enterText(locator, text, option);
|
|
13
|
+
await this.flush();
|
|
14
|
+
}
|
|
15
|
+
async click(locator, option) {
|
|
16
|
+
await super.click(locator, option);
|
|
17
|
+
await this.flush();
|
|
18
|
+
}
|
|
19
|
+
async hover(locator, option) {
|
|
20
|
+
await super.hover(locator, option);
|
|
21
|
+
await this.flush();
|
|
22
|
+
}
|
|
23
|
+
async mouseMove(locator, option) {
|
|
24
|
+
await super.mouseMove(locator, option);
|
|
25
|
+
await this.flush();
|
|
26
|
+
}
|
|
27
|
+
async mouseDown(locator, option) {
|
|
28
|
+
await super.mouseDown(locator, option);
|
|
29
|
+
await this.flush();
|
|
30
|
+
}
|
|
31
|
+
async mouseUp(locator, option) {
|
|
32
|
+
await super.mouseUp(locator, option);
|
|
33
|
+
await this.flush();
|
|
34
|
+
}
|
|
35
|
+
async mouseOver(locator, option) {
|
|
36
|
+
await super.mouseOver(locator, option);
|
|
37
|
+
await this.flush();
|
|
38
|
+
}
|
|
39
|
+
async mouseOut(locator, option) {
|
|
40
|
+
await super.mouseOut(locator, option);
|
|
41
|
+
await this.flush();
|
|
42
|
+
}
|
|
43
|
+
async mouseEnter(locator, option) {
|
|
44
|
+
await super.mouseEnter(locator, option);
|
|
45
|
+
await this.flush();
|
|
46
|
+
}
|
|
47
|
+
async mouseLeave(locator, option) {
|
|
48
|
+
await super.mouseLeave(locator, option);
|
|
49
|
+
await this.flush();
|
|
50
|
+
}
|
|
51
|
+
async focus(locator, option) {
|
|
52
|
+
await super.focus(locator, option);
|
|
53
|
+
await this.flush();
|
|
54
|
+
}
|
|
55
|
+
async selectOptionValue(locator, values) {
|
|
56
|
+
await super.selectOptionValue(locator, values);
|
|
57
|
+
await this.flush();
|
|
58
|
+
}
|
|
59
|
+
async wait(ms) {
|
|
60
|
+
await super.wait(ms);
|
|
61
|
+
await this.flush();
|
|
62
|
+
}
|
|
63
|
+
async waitUntilComponentState(locator, option = defaultWaitForOption) {
|
|
64
|
+
await super.waitUntilComponentState(locator, option);
|
|
65
|
+
await this.flush();
|
|
66
|
+
}
|
|
67
|
+
async waitUntil(option) {
|
|
68
|
+
const result = await super.waitUntil(option);
|
|
69
|
+
await this.flush();
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
clone() {
|
|
73
|
+
return new VueInteractor();
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/createTestEngine.ts
|
|
79
|
+
let _rootId = 0;
|
|
80
|
+
function getNextRootElementId() {
|
|
81
|
+
return `${_rootId++}`;
|
|
82
|
+
}
|
|
83
|
+
const rootElementAttributeName = "data-atomic-testing-vue";
|
|
84
|
+
function createTestEngine(component, partDefinitions, option) {
|
|
85
|
+
const rootEl = option?.rootElement ?? document.body;
|
|
86
|
+
const container = rootEl.appendChild(document.createElement("div"));
|
|
87
|
+
const rootId = getNextRootElementId();
|
|
88
|
+
container.setAttribute(rootElementAttributeName, rootId);
|
|
89
|
+
let unmount;
|
|
90
|
+
let app;
|
|
91
|
+
try {
|
|
92
|
+
const renderResult = render(component, { container });
|
|
93
|
+
unmount = renderResult.unmount;
|
|
94
|
+
} catch (_error) {
|
|
95
|
+
app = createApp(component);
|
|
96
|
+
app.mount(container);
|
|
97
|
+
unmount = () => {
|
|
98
|
+
if (app) app.unmount();
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const cleanup = () => {
|
|
102
|
+
unmount();
|
|
103
|
+
rootEl.removeChild(container);
|
|
104
|
+
return Promise.resolve();
|
|
105
|
+
};
|
|
106
|
+
return new TestEngine(byAttribute(rootElementAttributeName, rootId), new VueInteractor(), { parts: partDefinitions }, cleanup);
|
|
107
|
+
}
|
|
108
|
+
function createRenderedTestEngine(rootElement, partDefinitions, _option) {
|
|
109
|
+
const rootId = getNextRootElementId();
|
|
110
|
+
rootElement.setAttribute(rootElementAttributeName, rootId);
|
|
111
|
+
const cleanup = () => {
|
|
112
|
+
rootElement.removeAttribute(rootElementAttributeName);
|
|
113
|
+
return Promise.resolve();
|
|
114
|
+
};
|
|
115
|
+
return new TestEngine(byAttribute(rootElementAttributeName, rootId), new VueInteractor(), { parts: partDefinitions }, cleanup);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
//#endregion
|
|
119
|
+
export { VueInteractor, createRenderedTestEngine, createTestEngine };
|
|
120
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["locator: PartLocator","text: string","option?: Partial<EnterTextOption>","option?: Partial<ClickOption>","option?: Partial<HoverOption>","option?: Partial<MouseMoveOption>","option?: Partial<MouseDownOption>","option?: Partial<MouseUpOption>","option?: Partial<MouseOutOption>","option?: Partial<MouseEnterOption>","option?: Partial<MouseLeaveOption>","option?: Partial<FocusOption>","values: string[]","ms: number","option: Partial<Readonly<WaitForOption>>","option: WaitUntilOption<T>","component: Component","partDefinitions: T","option?: Readonly<Partial<IVueTestEngineOption>>","unmount: () => void","app: App","rootElement: HTMLElement","_option?: Readonly<Partial<IVueTestEngineOption>>"],"sources":["../src/VueInteractor.ts","../src/createTestEngine.ts"],"sourcesContent":["import {\n ClickOption,\n defaultWaitForOption,\n EnterTextOption,\n FocusOption,\n HoverOption,\n Interactor,\n MouseDownOption,\n MouseEnterOption,\n MouseLeaveOption,\n MouseMoveOption,\n MouseOutOption,\n MouseUpOption,\n PartLocator,\n WaitForOption,\n WaitUntilOption,\n} from '@atomic-testing/core';\nimport { DOMInteractor } from '@atomic-testing/dom-core';\nimport { nextTick } from 'vue';\n\nexport class VueInteractor extends DOMInteractor {\n private async flush() {\n await nextTick();\n }\n\n override async enterText(\n locator: PartLocator,\n text: string,\n option?: Partial<EnterTextOption>,\n ): Promise<void> {\n await super.enterText(locator, text, option);\n await this.flush();\n }\n\n override async click(\n locator: PartLocator,\n option?: Partial<ClickOption>,\n ): Promise<void> {\n await super.click(locator, option);\n await this.flush();\n }\n\n override async hover(\n locator: PartLocator,\n option?: Partial<HoverOption>,\n ): Promise<void> {\n await super.hover(locator, option);\n await this.flush();\n }\n\n async mouseMove(\n locator: PartLocator,\n option?: Partial<MouseMoveOption>,\n ): Promise<void> {\n await super.mouseMove(locator, option);\n await this.flush();\n }\n\n async mouseDown(\n locator: PartLocator,\n option?: Partial<MouseDownOption>,\n ): Promise<void> {\n await super.mouseDown(locator, option);\n await this.flush();\n }\n\n async mouseUp(\n locator: PartLocator,\n option?: Partial<MouseUpOption>,\n ): Promise<void> {\n await super.mouseUp(locator, option);\n await this.flush();\n }\n\n async mouseOver(\n locator: PartLocator,\n option?: Partial<HoverOption>,\n ): Promise<void> {\n await super.mouseOver(locator, option);\n await this.flush();\n }\n\n async mouseOut(\n locator: PartLocator,\n option?: Partial<MouseOutOption>,\n ): Promise<void> {\n await super.mouseOut(locator, option);\n await this.flush();\n }\n\n async mouseEnter(\n locator: PartLocator,\n option?: Partial<MouseEnterOption>,\n ): Promise<void> {\n await super.mouseEnter(locator, option);\n await this.flush();\n }\n\n async mouseLeave(\n locator: PartLocator,\n option?: Partial<MouseLeaveOption>,\n ): Promise<void> {\n await super.mouseLeave(locator, option);\n await this.flush();\n }\n\n async focus(locator: PartLocator, option?: Partial<FocusOption>): Promise<void> {\n await super.focus(locator, option);\n await this.flush();\n }\n\n override async selectOptionValue(\n locator: PartLocator,\n values: string[],\n ): Promise<void> {\n await super.selectOptionValue(locator, values);\n await this.flush();\n }\n\n override async wait(ms: number): Promise<void> {\n await super.wait(ms);\n await this.flush();\n }\n\n override async waitUntilComponentState(\n locator: PartLocator,\n option: Partial<Readonly<WaitForOption>> = defaultWaitForOption,\n ): Promise<void> {\n await super.waitUntilComponentState(locator, option);\n await this.flush();\n }\n\n override async waitUntil<T>(option: WaitUntilOption<T>): Promise<T> {\n const result = await super.waitUntil(option);\n await this.flush();\n return result;\n }\n\n override clone(): Interactor {\n return new VueInteractor();\n }\n}\n","import { byAttribute, ScenePart, TestEngine } from '@atomic-testing/core';\nimport { render } from '@testing-library/vue';\nimport { App, Component, createApp } from 'vue';\n\nimport { VueInteractor } from './VueInteractor';\nimport { IVueTestEngineOption } from './types';\n\nlet _rootId = 0;\nfunction getNextRootElementId() {\n return `${_rootId++}`;\n}\n\nconst rootElementAttributeName = 'data-atomic-testing-vue';\n\nexport function createTestEngine<T extends ScenePart>(\n component: Component,\n partDefinitions: T,\n option?: Readonly<Partial<IVueTestEngineOption>>\n): TestEngine<T> {\n const rootEl = option?.rootElement ?? document.body;\n const container = rootEl.appendChild(document.createElement('div'));\n const rootId = getNextRootElementId();\n container.setAttribute(rootElementAttributeName, rootId);\n \n let unmount: () => void;\n let app: App;\n \n try {\n const renderResult = render(component, { container });\n unmount = renderResult.unmount;\n } catch (_error) {\n // Fallback to manual Vue app creation if render fails\n app = createApp(component);\n app.mount(container);\n unmount = () => {\n if (app) {\n app.unmount();\n }\n };\n }\n\n const cleanup = () => {\n unmount();\n rootEl.removeChild(container);\n return Promise.resolve();\n };\n\n return new TestEngine(\n byAttribute(rootElementAttributeName, rootId),\n new VueInteractor(),\n {\n parts: partDefinitions,\n },\n cleanup\n );\n}\n\nexport function createRenderedTestEngine<T extends ScenePart>(\n rootElement: HTMLElement,\n partDefinitions: T,\n _option?: Readonly<Partial<IVueTestEngineOption>>\n): TestEngine<T> {\n const rootId = getNextRootElementId();\n rootElement.setAttribute(rootElementAttributeName, rootId);\n\n const cleanup = () => {\n rootElement.removeAttribute(rootElementAttributeName);\n return Promise.resolve();\n };\n\n return new TestEngine(\n byAttribute(rootElementAttributeName, rootId),\n new VueInteractor(),\n {\n parts: partDefinitions,\n },\n cleanup\n );\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atomic-testing/vue-3",
|
|
3
|
+
"version": "0.71.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"src"
|
|
11
|
+
],
|
|
12
|
+
"author": "Tianzhen Lin <tangent@usa.net>",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"testing",
|
|
15
|
+
"vue",
|
|
16
|
+
"unit",
|
|
17
|
+
"integration"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/atomic-testing/atomic-testing.git",
|
|
23
|
+
"directory": "packages/vue-3"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@testing-library/dom": "^10.4.0",
|
|
27
|
+
"@testing-library/vue": "^8.1.0",
|
|
28
|
+
"@atomic-testing/core": "0.71.0",
|
|
29
|
+
"@atomic-testing/dom-core": "0.71.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"vue": "^3.5.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@testing-library/dom": ">=10.4.0",
|
|
36
|
+
"@testing-library/vue": ">=8.1.0",
|
|
37
|
+
"@testing-library/user-event": ">=14.0.0",
|
|
38
|
+
"vue": ">=3.0.0"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsdown",
|
|
42
|
+
"check:type": "tsc --noEmit"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ClickOption,
|
|
3
|
+
defaultWaitForOption,
|
|
4
|
+
EnterTextOption,
|
|
5
|
+
FocusOption,
|
|
6
|
+
HoverOption,
|
|
7
|
+
Interactor,
|
|
8
|
+
MouseDownOption,
|
|
9
|
+
MouseEnterOption,
|
|
10
|
+
MouseLeaveOption,
|
|
11
|
+
MouseMoveOption,
|
|
12
|
+
MouseOutOption,
|
|
13
|
+
MouseUpOption,
|
|
14
|
+
PartLocator,
|
|
15
|
+
WaitForOption,
|
|
16
|
+
WaitUntilOption,
|
|
17
|
+
} from '@atomic-testing/core';
|
|
18
|
+
import { DOMInteractor } from '@atomic-testing/dom-core';
|
|
19
|
+
import { nextTick } from 'vue';
|
|
20
|
+
|
|
21
|
+
export class VueInteractor extends DOMInteractor {
|
|
22
|
+
private async flush() {
|
|
23
|
+
await nextTick();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
override async enterText(
|
|
27
|
+
locator: PartLocator,
|
|
28
|
+
text: string,
|
|
29
|
+
option?: Partial<EnterTextOption>,
|
|
30
|
+
): Promise<void> {
|
|
31
|
+
await super.enterText(locator, text, option);
|
|
32
|
+
await this.flush();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override async click(
|
|
36
|
+
locator: PartLocator,
|
|
37
|
+
option?: Partial<ClickOption>,
|
|
38
|
+
): Promise<void> {
|
|
39
|
+
await super.click(locator, option);
|
|
40
|
+
await this.flush();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override async hover(
|
|
44
|
+
locator: PartLocator,
|
|
45
|
+
option?: Partial<HoverOption>,
|
|
46
|
+
): Promise<void> {
|
|
47
|
+
await super.hover(locator, option);
|
|
48
|
+
await this.flush();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async mouseMove(
|
|
52
|
+
locator: PartLocator,
|
|
53
|
+
option?: Partial<MouseMoveOption>,
|
|
54
|
+
): Promise<void> {
|
|
55
|
+
await super.mouseMove(locator, option);
|
|
56
|
+
await this.flush();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async mouseDown(
|
|
60
|
+
locator: PartLocator,
|
|
61
|
+
option?: Partial<MouseDownOption>,
|
|
62
|
+
): Promise<void> {
|
|
63
|
+
await super.mouseDown(locator, option);
|
|
64
|
+
await this.flush();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async mouseUp(
|
|
68
|
+
locator: PartLocator,
|
|
69
|
+
option?: Partial<MouseUpOption>,
|
|
70
|
+
): Promise<void> {
|
|
71
|
+
await super.mouseUp(locator, option);
|
|
72
|
+
await this.flush();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async mouseOver(
|
|
76
|
+
locator: PartLocator,
|
|
77
|
+
option?: Partial<HoverOption>,
|
|
78
|
+
): Promise<void> {
|
|
79
|
+
await super.mouseOver(locator, option);
|
|
80
|
+
await this.flush();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async mouseOut(
|
|
84
|
+
locator: PartLocator,
|
|
85
|
+
option?: Partial<MouseOutOption>,
|
|
86
|
+
): Promise<void> {
|
|
87
|
+
await super.mouseOut(locator, option);
|
|
88
|
+
await this.flush();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async mouseEnter(
|
|
92
|
+
locator: PartLocator,
|
|
93
|
+
option?: Partial<MouseEnterOption>,
|
|
94
|
+
): Promise<void> {
|
|
95
|
+
await super.mouseEnter(locator, option);
|
|
96
|
+
await this.flush();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async mouseLeave(
|
|
100
|
+
locator: PartLocator,
|
|
101
|
+
option?: Partial<MouseLeaveOption>,
|
|
102
|
+
): Promise<void> {
|
|
103
|
+
await super.mouseLeave(locator, option);
|
|
104
|
+
await this.flush();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async focus(locator: PartLocator, option?: Partial<FocusOption>): Promise<void> {
|
|
108
|
+
await super.focus(locator, option);
|
|
109
|
+
await this.flush();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
override async selectOptionValue(
|
|
113
|
+
locator: PartLocator,
|
|
114
|
+
values: string[],
|
|
115
|
+
): Promise<void> {
|
|
116
|
+
await super.selectOptionValue(locator, values);
|
|
117
|
+
await this.flush();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
override async wait(ms: number): Promise<void> {
|
|
121
|
+
await super.wait(ms);
|
|
122
|
+
await this.flush();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
override async waitUntilComponentState(
|
|
126
|
+
locator: PartLocator,
|
|
127
|
+
option: Partial<Readonly<WaitForOption>> = defaultWaitForOption,
|
|
128
|
+
): Promise<void> {
|
|
129
|
+
await super.waitUntilComponentState(locator, option);
|
|
130
|
+
await this.flush();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
override async waitUntil<T>(option: WaitUntilOption<T>): Promise<T> {
|
|
134
|
+
const result = await super.waitUntil(option);
|
|
135
|
+
await this.flush();
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
override clone(): Interactor {
|
|
140
|
+
return new VueInteractor();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { byAttribute, ScenePart, TestEngine } from '@atomic-testing/core';
|
|
2
|
+
import { render } from '@testing-library/vue';
|
|
3
|
+
import { App, Component, createApp } from 'vue';
|
|
4
|
+
|
|
5
|
+
import { VueInteractor } from './VueInteractor';
|
|
6
|
+
import { IVueTestEngineOption } from './types';
|
|
7
|
+
|
|
8
|
+
let _rootId = 0;
|
|
9
|
+
function getNextRootElementId() {
|
|
10
|
+
return `${_rootId++}`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const rootElementAttributeName = 'data-atomic-testing-vue';
|
|
14
|
+
|
|
15
|
+
export function createTestEngine<T extends ScenePart>(
|
|
16
|
+
component: Component,
|
|
17
|
+
partDefinitions: T,
|
|
18
|
+
option?: Readonly<Partial<IVueTestEngineOption>>
|
|
19
|
+
): TestEngine<T> {
|
|
20
|
+
const rootEl = option?.rootElement ?? document.body;
|
|
21
|
+
const container = rootEl.appendChild(document.createElement('div'));
|
|
22
|
+
const rootId = getNextRootElementId();
|
|
23
|
+
container.setAttribute(rootElementAttributeName, rootId);
|
|
24
|
+
|
|
25
|
+
let unmount: () => void;
|
|
26
|
+
let app: App;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const renderResult = render(component, { container });
|
|
30
|
+
unmount = renderResult.unmount;
|
|
31
|
+
} catch (_error) {
|
|
32
|
+
// Fallback to manual Vue app creation if render fails
|
|
33
|
+
app = createApp(component);
|
|
34
|
+
app.mount(container);
|
|
35
|
+
unmount = () => {
|
|
36
|
+
if (app) {
|
|
37
|
+
app.unmount();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const cleanup = () => {
|
|
43
|
+
unmount();
|
|
44
|
+
rootEl.removeChild(container);
|
|
45
|
+
return Promise.resolve();
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return new TestEngine(
|
|
49
|
+
byAttribute(rootElementAttributeName, rootId),
|
|
50
|
+
new VueInteractor(),
|
|
51
|
+
{
|
|
52
|
+
parts: partDefinitions,
|
|
53
|
+
},
|
|
54
|
+
cleanup
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function createRenderedTestEngine<T extends ScenePart>(
|
|
59
|
+
rootElement: HTMLElement,
|
|
60
|
+
partDefinitions: T,
|
|
61
|
+
_option?: Readonly<Partial<IVueTestEngineOption>>
|
|
62
|
+
): TestEngine<T> {
|
|
63
|
+
const rootId = getNextRootElementId();
|
|
64
|
+
rootElement.setAttribute(rootElementAttributeName, rootId);
|
|
65
|
+
|
|
66
|
+
const cleanup = () => {
|
|
67
|
+
rootElement.removeAttribute(rootElementAttributeName);
|
|
68
|
+
return Promise.resolve();
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return new TestEngine(
|
|
72
|
+
byAttribute(rootElementAttributeName, rootId),
|
|
73
|
+
new VueInteractor(),
|
|
74
|
+
{
|
|
75
|
+
parts: partDefinitions,
|
|
76
|
+
},
|
|
77
|
+
cleanup
|
|
78
|
+
);
|
|
79
|
+
}
|
package/src/index.ts
ADDED