@atomic-testing/react-legacy 0.88.0 → 0.89.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/README.md +7 -0
- package/dist/index.cjs +149 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +150 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -8
- package/src/LegacyReactInteractor.ts +200 -0
- package/src/createTestEngine.ts +3 -3
package/README.md
CHANGED
|
@@ -89,3 +89,10 @@ package for a dedicated example.
|
|
|
89
89
|
|
|
90
90
|
For more in‑depth information, visit
|
|
91
91
|
[https://atomic-testing.dev](https://atomic-testing.dev).
|
|
92
|
+
|
|
93
|
+
## Public API & stability
|
|
94
|
+
|
|
95
|
+
The stable surface of this package is its `.` barrel exports, frozen under
|
|
96
|
+
SemVer and machine-checked by the committed [API Extractor](https://api-extractor.com/)
|
|
97
|
+
report at [`etc/react-legacy.api.md`](etc/react-legacy.api.md). Exports tagged `@internal` are
|
|
98
|
+
not part of that guarantee. See the [1.0 API freeze & evolution policy](../../agent-docs/adr/006-1.0-api-freeze-and-evolution.md).
|
package/dist/index.cjs
CHANGED
|
@@ -22,10 +22,156 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
}) : target, mod));
|
|
23
23
|
//#endregion
|
|
24
24
|
let _atomic_testing_core = require("@atomic-testing/core");
|
|
25
|
-
let _atomic_testing_react_core = require("@atomic-testing/react-core");
|
|
26
25
|
let react_dom = require("react-dom");
|
|
27
26
|
react_dom = __toESM(react_dom);
|
|
28
27
|
let react_dom_test_utils_js = require("react-dom/test-utils.js");
|
|
28
|
+
let _atomic_testing_dom_core = require("@atomic-testing/dom-core");
|
|
29
|
+
//#region src/LegacyReactInteractor.ts
|
|
30
|
+
/**
|
|
31
|
+
* React 16/17 counterpart of `@atomic-testing/react-core`'s `ReactInteractor`.
|
|
32
|
+
*
|
|
33
|
+
* It is a deliberate parallel implementation rather than a subclass of the
|
|
34
|
+
* react-core interactor: react-core wraps actions with `act` from
|
|
35
|
+
* `@testing-library/react@16`, whose peer range is React 18/19. Reusing it would
|
|
36
|
+
* drag that dependency into react-legacy and make the package impossible to
|
|
37
|
+
* install on React 16/17 (the very versions this adapter exists to support). By
|
|
38
|
+
* extending `DOMInteractor` directly and wrapping with `act` from
|
|
39
|
+
* `react-dom/test-utils` (the React ≤17 act), react-legacy stays on a coherent
|
|
40
|
+
* React-16/17 dependency graph.
|
|
41
|
+
*/
|
|
42
|
+
var LegacyReactInteractor = class LegacyReactInteractor extends _atomic_testing_dom_core.DOMInteractor {
|
|
43
|
+
async enterText(locator, text, option) {
|
|
44
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
45
|
+
await super.enterText(locator, text, option);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async setRangeValue(locator, value) {
|
|
49
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
50
|
+
await super.setRangeValue(locator, value);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async click(locator, option) {
|
|
54
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
55
|
+
await super.click(locator, option);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async hover(locator, option) {
|
|
59
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
60
|
+
await super.hover(locator, option);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async mouseMove(locator, option) {
|
|
64
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
65
|
+
await super.mouseMove(locator, option);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async mouseDown(locator, option) {
|
|
69
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
70
|
+
await super.mouseDown(locator, option);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
async mouseUp(locator, option) {
|
|
74
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
75
|
+
await super.mouseUp(locator, option);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
async mouseOver(locator, option) {
|
|
79
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
80
|
+
await super.mouseOver(locator, option);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async mouseOut(locator, option) {
|
|
84
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
85
|
+
await super.mouseOut(locator, option);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async mouseEnter(locator, option) {
|
|
89
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
90
|
+
await super.mouseEnter(locator, option);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
async mouseLeave(locator, option) {
|
|
94
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
95
|
+
await super.mouseLeave(locator, option);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
async focus(locator, option) {
|
|
99
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
100
|
+
await super.focus(locator, option);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async blur(locator, option) {
|
|
104
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
105
|
+
await super.blur(locator, option);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
async pressKey(locator, key, option) {
|
|
109
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
110
|
+
await super.pressKey(locator, key, option);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async contextMenu(locator) {
|
|
114
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
115
|
+
await super.contextMenu(locator);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async activate(locator) {
|
|
119
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
120
|
+
await super.activate(locator);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
async selectOptionValue(locator, values) {
|
|
124
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
125
|
+
await super.selectOptionValue(locator, values);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
async setInputFiles(locator, files) {
|
|
129
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
130
|
+
await super.setInputFiles(locator, files);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async scrollIntoView(locator) {
|
|
134
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
135
|
+
await super.scrollIntoView(locator);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
async scrollBy(locator, delta) {
|
|
139
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
140
|
+
await super.scrollBy(locator, delta);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
async dragTo(source, target) {
|
|
144
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
145
|
+
await super.dragTo(source, target);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
async drag(locator, delta) {
|
|
149
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
150
|
+
await super.drag(locator, delta);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
async wait(ms) {
|
|
154
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
155
|
+
await super.wait(ms);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
async waitUntilComponentState(locator, option = _atomic_testing_core.defaultWaitForOption) {
|
|
159
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
160
|
+
await super.waitUntilComponentState(locator, option);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
async waitUntil(option) {
|
|
164
|
+
let result;
|
|
165
|
+
await (0, react_dom_test_utils_js.act)(async () => {
|
|
166
|
+
result = await super.waitUntil(option);
|
|
167
|
+
});
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
clone() {
|
|
171
|
+
return new LegacyReactInteractor(this.rootEl);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
//#endregion
|
|
29
175
|
//#region src/createTestEngine.ts
|
|
30
176
|
let _rootId = 0;
|
|
31
177
|
function getNextRootElementId() {
|
|
@@ -54,7 +200,7 @@ function createTestEngine(node, partDefinitions, option) {
|
|
|
54
200
|
rootEl.removeChild(container);
|
|
55
201
|
return Promise.resolve();
|
|
56
202
|
};
|
|
57
|
-
return new _atomic_testing_core.TestEngine((0, _atomic_testing_core.byAttribute)(rootElementAttributeName, rootId), new
|
|
203
|
+
return new _atomic_testing_core.TestEngine((0, _atomic_testing_core.byAttribute)(rootElementAttributeName, rootId), new LegacyReactInteractor(), { parts: partDefinitions }, cleanup);
|
|
58
204
|
}
|
|
59
205
|
/**
|
|
60
206
|
* Create test engine for React 17 or before, for React 18 or later, use @atomic-testing/react-18 or @atomic-testing/react-19
|
|
@@ -72,7 +218,7 @@ function createRenderedTestEngine(rootElement, partDefinitions, _option) {
|
|
|
72
218
|
rootElement.removeAttribute(rootElementAttributeName);
|
|
73
219
|
return Promise.resolve();
|
|
74
220
|
};
|
|
75
|
-
return new _atomic_testing_core.TestEngine((0, _atomic_testing_core.byAttribute)(rootElementAttributeName, rootId), new
|
|
221
|
+
return new _atomic_testing_core.TestEngine((0, _atomic_testing_core.byAttribute)(rootElementAttributeName, rootId), new LegacyReactInteractor(), { parts: partDefinitions }, cleanup);
|
|
76
222
|
}
|
|
77
223
|
//#endregion
|
|
78
224
|
exports.createRenderedTestEngine = createRenderedTestEngine;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["TestEngine","ReactInteractor"],"sources":["../src/createTestEngine.ts"],"sourcesContent":["import { byAttribute, ScenePart, TestEngine } from '@atomic-testing/core';\nimport { ReactInteractor } from '@atomic-testing/react-core';\nimport { ReactElement } from 'react';\nimport ReactDOM from 'react-dom';\nimport { act } from 'react-dom/test-utils';\n\nimport { IReactTestEngineOption } from './types';\n\nlet _rootId = 0;\nfunction getNextRootElementId() {\n return `${_rootId++}`;\n}\n\nconst rootElementAttributeName = 'data-atomic-testing-react-legacy';\n\n/**\n * Create test engine for React 17 or before, for React 18 or later, use @atomic-testing/react-18 or @atomic-testing/react-19\n * This function takes a react node and render it into a container element. For rendered\n * components, use createRenderedLegacyTestEngine\n * @param node The React node to render\n * @param partDefinitions The scene part definitions\n * @param option\n * @returns The test engine\n */\nexport function createTestEngine<T extends ScenePart>(\n node: ReactElement,\n partDefinitions: T,\n option?: Readonly<Partial<IReactTestEngineOption>>\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 act(() => {\n ReactDOM.render(node, container);\n });\n const cleanup = () => {\n ReactDOM.unmountComponentAtNode(container);\n rootEl.removeChild(container);\n return Promise.resolve();\n };\n\n const engine = new TestEngine(\n byAttribute(rootElementAttributeName, rootId),\n new ReactInteractor(),\n {\n parts: partDefinitions,\n },\n cleanup\n );\n\n return engine;\n}\n\n/**\n * Create test engine for React 17 or before, for React 18 or later, use @atomic-testing/react-18 or @atomic-testing/react-19\n * This function takes an html element purportedly rendered by React and create a test engine for it, it\n * can be useful in environment such as Storybook where Storybook renders the component and the test\n * @param rootElement The React node to render\n * @param partDefinitions The scene part definitions\n * @param option\n * @returns The test engine\n */\nexport function createRenderedTestEngine<T extends ScenePart>(\n rootElement: HTMLElement,\n partDefinitions: T,\n _option?: Readonly<Partial<IReactTestEngineOption>>\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 const engine = new TestEngine(\n byAttribute(rootElementAttributeName, rootId),\n new ReactInteractor(),\n {\n parts: partDefinitions,\n },\n cleanup\n );\n\n return engine;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,IAAI,UAAU;AACd,SAAS,uBAAuB;CAC9B,OAAO,GAAG;AACZ;AAEA,MAAM,2BAA2B;;;;;;;;;;AAWjC,SAAgB,iBACd,MACA,iBACA,QACe;CACf,MAAM,SAAS,QAAQ,eAAe,SAAS;CAC/C,MAAM,YAAY,OAAO,YAAY,SAAS,cAAc,KAAK,CAAC;CAClE,MAAM,SAAS,qBAAqB;CACpC,UAAU,aAAa,0BAA0B,MAAM;CAEvD,CAAA,GAAA,wBAAA,IAAA,OAAU;EACR,UAAA,QAAS,OAAO,MAAM,SAAS;CACjC,CAAC;CACD,MAAM,gBAAgB;EACpB,UAAA,QAAS,uBAAuB,SAAS;EACzC,OAAO,YAAY,SAAS;EAC5B,OAAO,QAAQ,QAAQ;CACzB;CAWA,OAAO,IATYA,qBAAAA,YAAAA,GAAAA,qBAAAA,YAAAA,CACL,0BAA0B,MAAM,GAC5C,IAAIC,2BAAAA,gBAAgB,GACpB,EACE,OAAO,gBACT,GACA,OAGU;AACd;;;;;;;;;;AAWA,SAAgB,yBACd,aACA,iBACA,SACe;CACf,MAAM,SAAS,qBAAqB;CACpC,YAAY,aAAa,0BAA0B,MAAM;CAEzD,MAAM,gBAAgB;EACpB,YAAY,gBAAgB,wBAAwB;EACpD,OAAO,QAAQ,QAAQ;CACzB;CAWA,OAAO,IATYD,qBAAAA,YAAAA,GAAAA,qBAAAA,YAAAA,CACL,0BAA0B,MAAM,GAC5C,IAAIC,2BAAAA,gBAAgB,GACpB,EACE,OAAO,gBACT,GACA,OAGU;AACd"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["DOMInteractor","defaultWaitForOption","TestEngine"],"sources":["../src/LegacyReactInteractor.ts","../src/createTestEngine.ts"],"sourcesContent":["import {\n BlurOption,\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 Point,\n PressKeyOption,\n WaitForOption,\n WaitUntilOption,\n} from '@atomic-testing/core';\nimport { DOMInteractor } from '@atomic-testing/dom-core';\nimport { act } from 'react-dom/test-utils';\n\n/**\n * React 16/17 counterpart of `@atomic-testing/react-core`'s `ReactInteractor`.\n *\n * It is a deliberate parallel implementation rather than a subclass of the\n * react-core interactor: react-core wraps actions with `act` from\n * `@testing-library/react@16`, whose peer range is React 18/19. Reusing it would\n * drag that dependency into react-legacy and make the package impossible to\n * install on React 16/17 (the very versions this adapter exists to support). By\n * extending `DOMInteractor` directly and wrapping with `act` from\n * `react-dom/test-utils` (the React ≤17 act), react-legacy stays on a coherent\n * React-16/17 dependency graph.\n */\nexport class LegacyReactInteractor extends DOMInteractor {\n override async enterText(locator: PartLocator, text: string, option?: Partial<EnterTextOption>): Promise<void> {\n await act(async () => {\n await super.enterText(locator, text, option);\n });\n }\n\n override async setRangeValue(locator: PartLocator, value: number): Promise<void> {\n await act(async () => {\n await super.setRangeValue(locator, value);\n });\n }\n\n override async click(locator: PartLocator, option?: Partial<ClickOption>): Promise<void> {\n await act(async () => {\n await super.click(locator, option);\n });\n }\n\n override async hover(locator: PartLocator, option?: Partial<HoverOption>): Promise<void> {\n await act(async () => {\n await super.hover(locator, option);\n });\n }\n\n override async mouseMove(locator: PartLocator, option?: Partial<MouseMoveOption>): Promise<void> {\n await act(async () => {\n await super.mouseMove(locator, option);\n });\n }\n\n override async mouseDown(locator: PartLocator, option?: Partial<MouseDownOption>): Promise<void> {\n await act(async () => {\n await super.mouseDown(locator, option);\n });\n }\n\n override async mouseUp(locator: PartLocator, option?: Partial<MouseUpOption>): Promise<void> {\n await act(async () => {\n await super.mouseUp(locator, option);\n });\n }\n\n override async mouseOver(locator: PartLocator, option?: Partial<HoverOption>): Promise<void> {\n await act(async () => {\n await super.mouseOver(locator, option);\n });\n }\n\n override async mouseOut(locator: PartLocator, option?: Partial<MouseOutOption>): Promise<void> {\n await act(async () => {\n await super.mouseOut(locator, option);\n });\n }\n\n override async mouseEnter(locator: PartLocator, option?: Partial<MouseEnterOption>): Promise<void> {\n await act(async () => {\n await super.mouseEnter(locator, option);\n });\n }\n\n override async mouseLeave(locator: PartLocator, option?: Partial<MouseLeaveOption>): Promise<void> {\n await act(async () => {\n await super.mouseLeave(locator, option);\n });\n }\n\n override async focus(locator: PartLocator, option?: Partial<FocusOption>): Promise<void> {\n await act(async () => {\n await super.focus(locator, option);\n });\n }\n\n override async blur(locator: PartLocator, option?: Partial<BlurOption>): Promise<void> {\n await act(async () => {\n await super.blur(locator, option);\n });\n }\n\n override async pressKey(locator: PartLocator, key: string, option?: Partial<PressKeyOption>): Promise<void> {\n await act(async () => {\n await super.pressKey(locator, key, option);\n });\n }\n\n override async contextMenu(locator: PartLocator): Promise<void> {\n await act(async () => {\n await super.contextMenu(locator);\n });\n }\n\n override async activate(locator: PartLocator): Promise<void> {\n await act(async () => {\n await super.activate(locator);\n });\n }\n\n override async selectOptionValue(locator: PartLocator, values: string[]): Promise<void> {\n await act(async () => {\n await super.selectOptionValue(locator, values);\n });\n }\n\n override async setInputFiles(locator: PartLocator, files: string | string[]): Promise<void> {\n await act(async () => {\n await super.setInputFiles(locator, files);\n });\n }\n\n override async scrollIntoView(locator: PartLocator): Promise<void> {\n await act(async () => {\n await super.scrollIntoView(locator);\n });\n }\n\n override async scrollBy(locator: PartLocator, delta: Point): Promise<void> {\n await act(async () => {\n await super.scrollBy(locator, delta);\n });\n }\n\n override async dragTo(source: PartLocator, target: PartLocator): Promise<void> {\n await act(async () => {\n await super.dragTo(source, target);\n });\n }\n\n override async drag(locator: PartLocator, delta: Point): Promise<void> {\n await act(async () => {\n await super.drag(locator, delta);\n });\n }\n\n //#region wait condition\n override async wait(ms: number): Promise<void> {\n await act(async () => {\n await super.wait(ms);\n });\n }\n\n override async waitUntilComponentState(\n locator: PartLocator,\n option: Partial<Readonly<WaitForOption>> = defaultWaitForOption\n ): Promise<void> {\n await act(async () => {\n await super.waitUntilComponentState(locator, option);\n });\n }\n\n override async waitUntil<T>(option: WaitUntilOption<T>): Promise<T> {\n // The React ≤17 `act` async overload resolves to `undefined`, not the\n // callback's value (unlike React 18's act), so capture the result via a\n // closure instead of returning it through `act`.\n let result!: T;\n await act(async () => {\n result = await super.waitUntil(option);\n });\n return result;\n }\n //#endregion\n\n override clone(): Interactor {\n return new LegacyReactInteractor(this.rootEl);\n }\n}\n","import { byAttribute, ScenePart, TestEngine } from '@atomic-testing/core';\nimport { ReactElement } from 'react';\nimport ReactDOM from 'react-dom';\nimport { act } from 'react-dom/test-utils';\n\nimport { LegacyReactInteractor } from './LegacyReactInteractor';\nimport { IReactTestEngineOption } from './types';\n\nlet _rootId = 0;\nfunction getNextRootElementId() {\n return `${_rootId++}`;\n}\n\nconst rootElementAttributeName = 'data-atomic-testing-react-legacy';\n\n/**\n * Create test engine for React 17 or before, for React 18 or later, use @atomic-testing/react-18 or @atomic-testing/react-19\n * This function takes a react node and render it into a container element. For rendered\n * components, use createRenderedLegacyTestEngine\n * @param node The React node to render\n * @param partDefinitions The scene part definitions\n * @param option\n * @returns The test engine\n */\nexport function createTestEngine<T extends ScenePart>(\n node: ReactElement,\n partDefinitions: T,\n option?: Readonly<Partial<IReactTestEngineOption>>\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 act(() => {\n ReactDOM.render(node, container);\n });\n const cleanup = () => {\n ReactDOM.unmountComponentAtNode(container);\n rootEl.removeChild(container);\n return Promise.resolve();\n };\n\n const engine = new TestEngine(\n byAttribute(rootElementAttributeName, rootId),\n new LegacyReactInteractor(),\n {\n parts: partDefinitions,\n },\n cleanup\n );\n\n return engine;\n}\n\n/**\n * Create test engine for React 17 or before, for React 18 or later, use @atomic-testing/react-18 or @atomic-testing/react-19\n * This function takes an html element purportedly rendered by React and create a test engine for it, it\n * can be useful in environment such as Storybook where Storybook renders the component and the test\n * @param rootElement The React node to render\n * @param partDefinitions The scene part definitions\n * @param option\n * @returns The test engine\n */\nexport function createRenderedTestEngine<T extends ScenePart>(\n rootElement: HTMLElement,\n partDefinitions: T,\n _option?: Readonly<Partial<IReactTestEngineOption>>\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 const engine = new TestEngine(\n byAttribute(rootElementAttributeName, rootId),\n new LegacyReactInteractor(),\n {\n parts: partDefinitions,\n },\n cleanup\n );\n\n return engine;\n}\n"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,153 @@
|
|
|
1
|
-
import { TestEngine, byAttribute } from "@atomic-testing/core";
|
|
2
|
-
import { ReactInteractor } from "@atomic-testing/react-core";
|
|
1
|
+
import { TestEngine, byAttribute, defaultWaitForOption } from "@atomic-testing/core";
|
|
3
2
|
import ReactDOM from "react-dom";
|
|
4
3
|
import { act } from "react-dom/test-utils.js";
|
|
4
|
+
import { DOMInteractor } from "@atomic-testing/dom-core";
|
|
5
|
+
//#region src/LegacyReactInteractor.ts
|
|
6
|
+
/**
|
|
7
|
+
* React 16/17 counterpart of `@atomic-testing/react-core`'s `ReactInteractor`.
|
|
8
|
+
*
|
|
9
|
+
* It is a deliberate parallel implementation rather than a subclass of the
|
|
10
|
+
* react-core interactor: react-core wraps actions with `act` from
|
|
11
|
+
* `@testing-library/react@16`, whose peer range is React 18/19. Reusing it would
|
|
12
|
+
* drag that dependency into react-legacy and make the package impossible to
|
|
13
|
+
* install on React 16/17 (the very versions this adapter exists to support). By
|
|
14
|
+
* extending `DOMInteractor` directly and wrapping with `act` from
|
|
15
|
+
* `react-dom/test-utils` (the React ≤17 act), react-legacy stays on a coherent
|
|
16
|
+
* React-16/17 dependency graph.
|
|
17
|
+
*/
|
|
18
|
+
var LegacyReactInteractor = class LegacyReactInteractor extends DOMInteractor {
|
|
19
|
+
async enterText(locator, text, option) {
|
|
20
|
+
await act(async () => {
|
|
21
|
+
await super.enterText(locator, text, option);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
async setRangeValue(locator, value) {
|
|
25
|
+
await act(async () => {
|
|
26
|
+
await super.setRangeValue(locator, value);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async click(locator, option) {
|
|
30
|
+
await act(async () => {
|
|
31
|
+
await super.click(locator, option);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async hover(locator, option) {
|
|
35
|
+
await act(async () => {
|
|
36
|
+
await super.hover(locator, option);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
async mouseMove(locator, option) {
|
|
40
|
+
await act(async () => {
|
|
41
|
+
await super.mouseMove(locator, option);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async mouseDown(locator, option) {
|
|
45
|
+
await act(async () => {
|
|
46
|
+
await super.mouseDown(locator, option);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async mouseUp(locator, option) {
|
|
50
|
+
await act(async () => {
|
|
51
|
+
await super.mouseUp(locator, option);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
async mouseOver(locator, option) {
|
|
55
|
+
await act(async () => {
|
|
56
|
+
await super.mouseOver(locator, option);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async mouseOut(locator, option) {
|
|
60
|
+
await act(async () => {
|
|
61
|
+
await super.mouseOut(locator, option);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async mouseEnter(locator, option) {
|
|
65
|
+
await act(async () => {
|
|
66
|
+
await super.mouseEnter(locator, option);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
async mouseLeave(locator, option) {
|
|
70
|
+
await act(async () => {
|
|
71
|
+
await super.mouseLeave(locator, option);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async focus(locator, option) {
|
|
75
|
+
await act(async () => {
|
|
76
|
+
await super.focus(locator, option);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async blur(locator, option) {
|
|
80
|
+
await act(async () => {
|
|
81
|
+
await super.blur(locator, option);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async pressKey(locator, key, option) {
|
|
85
|
+
await act(async () => {
|
|
86
|
+
await super.pressKey(locator, key, option);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async contextMenu(locator) {
|
|
90
|
+
await act(async () => {
|
|
91
|
+
await super.contextMenu(locator);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async activate(locator) {
|
|
95
|
+
await act(async () => {
|
|
96
|
+
await super.activate(locator);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
async selectOptionValue(locator, values) {
|
|
100
|
+
await act(async () => {
|
|
101
|
+
await super.selectOptionValue(locator, values);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
async setInputFiles(locator, files) {
|
|
105
|
+
await act(async () => {
|
|
106
|
+
await super.setInputFiles(locator, files);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async scrollIntoView(locator) {
|
|
110
|
+
await act(async () => {
|
|
111
|
+
await super.scrollIntoView(locator);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
async scrollBy(locator, delta) {
|
|
115
|
+
await act(async () => {
|
|
116
|
+
await super.scrollBy(locator, delta);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
async dragTo(source, target) {
|
|
120
|
+
await act(async () => {
|
|
121
|
+
await super.dragTo(source, target);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
async drag(locator, delta) {
|
|
125
|
+
await act(async () => {
|
|
126
|
+
await super.drag(locator, delta);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async wait(ms) {
|
|
130
|
+
await act(async () => {
|
|
131
|
+
await super.wait(ms);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
async waitUntilComponentState(locator, option = defaultWaitForOption) {
|
|
135
|
+
await act(async () => {
|
|
136
|
+
await super.waitUntilComponentState(locator, option);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
async waitUntil(option) {
|
|
140
|
+
let result;
|
|
141
|
+
await act(async () => {
|
|
142
|
+
result = await super.waitUntil(option);
|
|
143
|
+
});
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
clone() {
|
|
147
|
+
return new LegacyReactInteractor(this.rootEl);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
//#endregion
|
|
5
151
|
//#region src/createTestEngine.ts
|
|
6
152
|
let _rootId = 0;
|
|
7
153
|
function getNextRootElementId() {
|
|
@@ -30,7 +176,7 @@ function createTestEngine(node, partDefinitions, option) {
|
|
|
30
176
|
rootEl.removeChild(container);
|
|
31
177
|
return Promise.resolve();
|
|
32
178
|
};
|
|
33
|
-
return new TestEngine(byAttribute(rootElementAttributeName, rootId), new
|
|
179
|
+
return new TestEngine(byAttribute(rootElementAttributeName, rootId), new LegacyReactInteractor(), { parts: partDefinitions }, cleanup);
|
|
34
180
|
}
|
|
35
181
|
/**
|
|
36
182
|
* Create test engine for React 17 or before, for React 18 or later, use @atomic-testing/react-18 or @atomic-testing/react-19
|
|
@@ -48,7 +194,7 @@ function createRenderedTestEngine(rootElement, partDefinitions, _option) {
|
|
|
48
194
|
rootElement.removeAttribute(rootElementAttributeName);
|
|
49
195
|
return Promise.resolve();
|
|
50
196
|
};
|
|
51
|
-
return new TestEngine(byAttribute(rootElementAttributeName, rootId), new
|
|
197
|
+
return new TestEngine(byAttribute(rootElementAttributeName, rootId), new LegacyReactInteractor(), { parts: partDefinitions }, cleanup);
|
|
52
198
|
}
|
|
53
199
|
//#endregion
|
|
54
200
|
export { createRenderedTestEngine, createTestEngine };
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/createTestEngine.ts"],"sourcesContent":["import { byAttribute, ScenePart, TestEngine } from '@atomic-testing/core';\nimport { ReactInteractor } from '@atomic-testing/react-core';\nimport { ReactElement } from 'react';\nimport ReactDOM from 'react-dom';\nimport { act } from 'react-dom/test-utils';\n\nimport { IReactTestEngineOption } from './types';\n\nlet _rootId = 0;\nfunction getNextRootElementId() {\n return `${_rootId++}`;\n}\n\nconst rootElementAttributeName = 'data-atomic-testing-react-legacy';\n\n/**\n * Create test engine for React 17 or before, for React 18 or later, use @atomic-testing/react-18 or @atomic-testing/react-19\n * This function takes a react node and render it into a container element. For rendered\n * components, use createRenderedLegacyTestEngine\n * @param node The React node to render\n * @param partDefinitions The scene part definitions\n * @param option\n * @returns The test engine\n */\nexport function createTestEngine<T extends ScenePart>(\n node: ReactElement,\n partDefinitions: T,\n option?: Readonly<Partial<IReactTestEngineOption>>\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 act(() => {\n ReactDOM.render(node, container);\n });\n const cleanup = () => {\n ReactDOM.unmountComponentAtNode(container);\n rootEl.removeChild(container);\n return Promise.resolve();\n };\n\n const engine = new TestEngine(\n byAttribute(rootElementAttributeName, rootId),\n new ReactInteractor(),\n {\n parts: partDefinitions,\n },\n cleanup\n );\n\n return engine;\n}\n\n/**\n * Create test engine for React 17 or before, for React 18 or later, use @atomic-testing/react-18 or @atomic-testing/react-19\n * This function takes an html element purportedly rendered by React and create a test engine for it, it\n * can be useful in environment such as Storybook where Storybook renders the component and the test\n * @param rootElement The React node to render\n * @param partDefinitions The scene part definitions\n * @param option\n * @returns The test engine\n */\nexport function createRenderedTestEngine<T extends ScenePart>(\n rootElement: HTMLElement,\n partDefinitions: T,\n _option?: Readonly<Partial<IReactTestEngineOption>>\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 const engine = new TestEngine(\n byAttribute(rootElementAttributeName, rootId),\n new ReactInteractor(),\n {\n parts: partDefinitions,\n },\n cleanup\n );\n\n return engine;\n}\n"],"mappings":";;;;;AAQA,IAAI,UAAU;AACd,SAAS,uBAAuB;CAC9B,OAAO,GAAG;AACZ;AAEA,MAAM,2BAA2B;;;;;;;;;;AAWjC,SAAgB,iBACd,MACA,iBACA,QACe;CACf,MAAM,SAAS,QAAQ,eAAe,SAAS;CAC/C,MAAM,YAAY,OAAO,YAAY,SAAS,cAAc,KAAK,CAAC;CAClE,MAAM,SAAS,qBAAqB;CACpC,UAAU,aAAa,0BAA0B,MAAM;CAEvD,UAAU;EACR,SAAS,OAAO,MAAM,SAAS;CACjC,CAAC;CACD,MAAM,gBAAgB;EACpB,SAAS,uBAAuB,SAAS;EACzC,OAAO,YAAY,SAAS;EAC5B,OAAO,QAAQ,QAAQ;CACzB;CAWA,OAAO,IATY,WACjB,YAAY,0BAA0B,MAAM,GAC5C,IAAI,gBAAgB,GACpB,EACE,OAAO,gBACT,GACA,OAGU;AACd;;;;;;;;;;AAWA,SAAgB,yBACd,aACA,iBACA,SACe;CACf,MAAM,SAAS,qBAAqB;CACpC,YAAY,aAAa,0BAA0B,MAAM;CAEzD,MAAM,gBAAgB;EACpB,YAAY,gBAAgB,wBAAwB;EACpD,OAAO,QAAQ,QAAQ;CACzB;CAWA,OAAO,IATY,WACjB,YAAY,0BAA0B,MAAM,GAC5C,IAAI,gBAAgB,GACpB,EACE,OAAO,gBACT,GACA,OAGU;AACd"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/LegacyReactInteractor.ts","../src/createTestEngine.ts"],"sourcesContent":["import {\n BlurOption,\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 Point,\n PressKeyOption,\n WaitForOption,\n WaitUntilOption,\n} from '@atomic-testing/core';\nimport { DOMInteractor } from '@atomic-testing/dom-core';\nimport { act } from 'react-dom/test-utils';\n\n/**\n * React 16/17 counterpart of `@atomic-testing/react-core`'s `ReactInteractor`.\n *\n * It is a deliberate parallel implementation rather than a subclass of the\n * react-core interactor: react-core wraps actions with `act` from\n * `@testing-library/react@16`, whose peer range is React 18/19. Reusing it would\n * drag that dependency into react-legacy and make the package impossible to\n * install on React 16/17 (the very versions this adapter exists to support). By\n * extending `DOMInteractor` directly and wrapping with `act` from\n * `react-dom/test-utils` (the React ≤17 act), react-legacy stays on a coherent\n * React-16/17 dependency graph.\n */\nexport class LegacyReactInteractor extends DOMInteractor {\n override async enterText(locator: PartLocator, text: string, option?: Partial<EnterTextOption>): Promise<void> {\n await act(async () => {\n await super.enterText(locator, text, option);\n });\n }\n\n override async setRangeValue(locator: PartLocator, value: number): Promise<void> {\n await act(async () => {\n await super.setRangeValue(locator, value);\n });\n }\n\n override async click(locator: PartLocator, option?: Partial<ClickOption>): Promise<void> {\n await act(async () => {\n await super.click(locator, option);\n });\n }\n\n override async hover(locator: PartLocator, option?: Partial<HoverOption>): Promise<void> {\n await act(async () => {\n await super.hover(locator, option);\n });\n }\n\n override async mouseMove(locator: PartLocator, option?: Partial<MouseMoveOption>): Promise<void> {\n await act(async () => {\n await super.mouseMove(locator, option);\n });\n }\n\n override async mouseDown(locator: PartLocator, option?: Partial<MouseDownOption>): Promise<void> {\n await act(async () => {\n await super.mouseDown(locator, option);\n });\n }\n\n override async mouseUp(locator: PartLocator, option?: Partial<MouseUpOption>): Promise<void> {\n await act(async () => {\n await super.mouseUp(locator, option);\n });\n }\n\n override async mouseOver(locator: PartLocator, option?: Partial<HoverOption>): Promise<void> {\n await act(async () => {\n await super.mouseOver(locator, option);\n });\n }\n\n override async mouseOut(locator: PartLocator, option?: Partial<MouseOutOption>): Promise<void> {\n await act(async () => {\n await super.mouseOut(locator, option);\n });\n }\n\n override async mouseEnter(locator: PartLocator, option?: Partial<MouseEnterOption>): Promise<void> {\n await act(async () => {\n await super.mouseEnter(locator, option);\n });\n }\n\n override async mouseLeave(locator: PartLocator, option?: Partial<MouseLeaveOption>): Promise<void> {\n await act(async () => {\n await super.mouseLeave(locator, option);\n });\n }\n\n override async focus(locator: PartLocator, option?: Partial<FocusOption>): Promise<void> {\n await act(async () => {\n await super.focus(locator, option);\n });\n }\n\n override async blur(locator: PartLocator, option?: Partial<BlurOption>): Promise<void> {\n await act(async () => {\n await super.blur(locator, option);\n });\n }\n\n override async pressKey(locator: PartLocator, key: string, option?: Partial<PressKeyOption>): Promise<void> {\n await act(async () => {\n await super.pressKey(locator, key, option);\n });\n }\n\n override async contextMenu(locator: PartLocator): Promise<void> {\n await act(async () => {\n await super.contextMenu(locator);\n });\n }\n\n override async activate(locator: PartLocator): Promise<void> {\n await act(async () => {\n await super.activate(locator);\n });\n }\n\n override async selectOptionValue(locator: PartLocator, values: string[]): Promise<void> {\n await act(async () => {\n await super.selectOptionValue(locator, values);\n });\n }\n\n override async setInputFiles(locator: PartLocator, files: string | string[]): Promise<void> {\n await act(async () => {\n await super.setInputFiles(locator, files);\n });\n }\n\n override async scrollIntoView(locator: PartLocator): Promise<void> {\n await act(async () => {\n await super.scrollIntoView(locator);\n });\n }\n\n override async scrollBy(locator: PartLocator, delta: Point): Promise<void> {\n await act(async () => {\n await super.scrollBy(locator, delta);\n });\n }\n\n override async dragTo(source: PartLocator, target: PartLocator): Promise<void> {\n await act(async () => {\n await super.dragTo(source, target);\n });\n }\n\n override async drag(locator: PartLocator, delta: Point): Promise<void> {\n await act(async () => {\n await super.drag(locator, delta);\n });\n }\n\n //#region wait condition\n override async wait(ms: number): Promise<void> {\n await act(async () => {\n await super.wait(ms);\n });\n }\n\n override async waitUntilComponentState(\n locator: PartLocator,\n option: Partial<Readonly<WaitForOption>> = defaultWaitForOption\n ): Promise<void> {\n await act(async () => {\n await super.waitUntilComponentState(locator, option);\n });\n }\n\n override async waitUntil<T>(option: WaitUntilOption<T>): Promise<T> {\n // The React ≤17 `act` async overload resolves to `undefined`, not the\n // callback's value (unlike React 18's act), so capture the result via a\n // closure instead of returning it through `act`.\n let result!: T;\n await act(async () => {\n result = await super.waitUntil(option);\n });\n return result;\n }\n //#endregion\n\n override clone(): Interactor {\n return new LegacyReactInteractor(this.rootEl);\n }\n}\n","import { byAttribute, ScenePart, TestEngine } from '@atomic-testing/core';\nimport { ReactElement } from 'react';\nimport ReactDOM from 'react-dom';\nimport { act } from 'react-dom/test-utils';\n\nimport { LegacyReactInteractor } from './LegacyReactInteractor';\nimport { IReactTestEngineOption } from './types';\n\nlet _rootId = 0;\nfunction getNextRootElementId() {\n return `${_rootId++}`;\n}\n\nconst rootElementAttributeName = 'data-atomic-testing-react-legacy';\n\n/**\n * Create test engine for React 17 or before, for React 18 or later, use @atomic-testing/react-18 or @atomic-testing/react-19\n * This function takes a react node and render it into a container element. For rendered\n * components, use createRenderedLegacyTestEngine\n * @param node The React node to render\n * @param partDefinitions The scene part definitions\n * @param option\n * @returns The test engine\n */\nexport function createTestEngine<T extends ScenePart>(\n node: ReactElement,\n partDefinitions: T,\n option?: Readonly<Partial<IReactTestEngineOption>>\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 act(() => {\n ReactDOM.render(node, container);\n });\n const cleanup = () => {\n ReactDOM.unmountComponentAtNode(container);\n rootEl.removeChild(container);\n return Promise.resolve();\n };\n\n const engine = new TestEngine(\n byAttribute(rootElementAttributeName, rootId),\n new LegacyReactInteractor(),\n {\n parts: partDefinitions,\n },\n cleanup\n );\n\n return engine;\n}\n\n/**\n * Create test engine for React 17 or before, for React 18 or later, use @atomic-testing/react-18 or @atomic-testing/react-19\n * This function takes an html element purportedly rendered by React and create a test engine for it, it\n * can be useful in environment such as Storybook where Storybook renders the component and the test\n * @param rootElement The React node to render\n * @param partDefinitions The scene part definitions\n * @param option\n * @returns The test engine\n */\nexport function createRenderedTestEngine<T extends ScenePart>(\n rootElement: HTMLElement,\n partDefinitions: T,\n _option?: Readonly<Partial<IReactTestEngineOption>>\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 const engine = new TestEngine(\n byAttribute(rootElementAttributeName, rootId),\n new LegacyReactInteractor(),\n {\n parts: partDefinitions,\n },\n cleanup\n );\n\n return engine;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atomic-testing/react-legacy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.89.0",
|
|
4
4
|
"description": "Adapter for testing React 17 and earlier",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"legacy",
|
|
@@ -29,26 +29,26 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"
|
|
33
|
-
"@atomic-testing/core": "0.
|
|
34
|
-
"@atomic-testing/react-core": "0.88.0",
|
|
35
|
-
"@atomic-testing/dom-core": "0.88.0"
|
|
32
|
+
"@atomic-testing/core": "0.89.0",
|
|
33
|
+
"@atomic-testing/dom-core": "0.89.0"
|
|
36
34
|
},
|
|
37
35
|
"devDependencies": {
|
|
38
36
|
"@types/react": "^17.0.0",
|
|
39
37
|
"@types/react-dom": "^17.0.0",
|
|
40
38
|
"react": "^17.0.0",
|
|
41
|
-
"react-dom": "^17.0.0"
|
|
39
|
+
"react-dom": "^17.0.0",
|
|
40
|
+
"@atomic-testing/component-driver-html": "0.89.0"
|
|
42
41
|
},
|
|
43
42
|
"peerDependencies": {
|
|
44
43
|
"@testing-library/dom": ">=10.4.1",
|
|
45
|
-
"@testing-library/react": ">=12.0.0",
|
|
46
44
|
"@testing-library/user-event": ">=14.0.0",
|
|
47
45
|
"react": "^16 || ^17",
|
|
48
46
|
"react-dom": "^16 || ^17"
|
|
49
47
|
},
|
|
50
48
|
"scripts": {
|
|
51
49
|
"build": "tsdown",
|
|
52
|
-
"check:type": "tsgo --noEmit"
|
|
50
|
+
"check:type": "tsgo --noEmit",
|
|
51
|
+
"check:api": "api-extractor run",
|
|
52
|
+
"test:dom": "jest"
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BlurOption,
|
|
3
|
+
ClickOption,
|
|
4
|
+
defaultWaitForOption,
|
|
5
|
+
EnterTextOption,
|
|
6
|
+
FocusOption,
|
|
7
|
+
HoverOption,
|
|
8
|
+
Interactor,
|
|
9
|
+
MouseDownOption,
|
|
10
|
+
MouseEnterOption,
|
|
11
|
+
MouseLeaveOption,
|
|
12
|
+
MouseMoveOption,
|
|
13
|
+
MouseOutOption,
|
|
14
|
+
MouseUpOption,
|
|
15
|
+
PartLocator,
|
|
16
|
+
Point,
|
|
17
|
+
PressKeyOption,
|
|
18
|
+
WaitForOption,
|
|
19
|
+
WaitUntilOption,
|
|
20
|
+
} from '@atomic-testing/core';
|
|
21
|
+
import { DOMInteractor } from '@atomic-testing/dom-core';
|
|
22
|
+
import { act } from 'react-dom/test-utils';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* React 16/17 counterpart of `@atomic-testing/react-core`'s `ReactInteractor`.
|
|
26
|
+
*
|
|
27
|
+
* It is a deliberate parallel implementation rather than a subclass of the
|
|
28
|
+
* react-core interactor: react-core wraps actions with `act` from
|
|
29
|
+
* `@testing-library/react@16`, whose peer range is React 18/19. Reusing it would
|
|
30
|
+
* drag that dependency into react-legacy and make the package impossible to
|
|
31
|
+
* install on React 16/17 (the very versions this adapter exists to support). By
|
|
32
|
+
* extending `DOMInteractor` directly and wrapping with `act` from
|
|
33
|
+
* `react-dom/test-utils` (the React ≤17 act), react-legacy stays on a coherent
|
|
34
|
+
* React-16/17 dependency graph.
|
|
35
|
+
*/
|
|
36
|
+
export class LegacyReactInteractor extends DOMInteractor {
|
|
37
|
+
override async enterText(locator: PartLocator, text: string, option?: Partial<EnterTextOption>): Promise<void> {
|
|
38
|
+
await act(async () => {
|
|
39
|
+
await super.enterText(locator, text, option);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override async setRangeValue(locator: PartLocator, value: number): Promise<void> {
|
|
44
|
+
await act(async () => {
|
|
45
|
+
await super.setRangeValue(locator, value);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
override async click(locator: PartLocator, option?: Partial<ClickOption>): Promise<void> {
|
|
50
|
+
await act(async () => {
|
|
51
|
+
await super.click(locator, option);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
override async hover(locator: PartLocator, option?: Partial<HoverOption>): Promise<void> {
|
|
56
|
+
await act(async () => {
|
|
57
|
+
await super.hover(locator, option);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
override async mouseMove(locator: PartLocator, option?: Partial<MouseMoveOption>): Promise<void> {
|
|
62
|
+
await act(async () => {
|
|
63
|
+
await super.mouseMove(locator, option);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
override async mouseDown(locator: PartLocator, option?: Partial<MouseDownOption>): Promise<void> {
|
|
68
|
+
await act(async () => {
|
|
69
|
+
await super.mouseDown(locator, option);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
override async mouseUp(locator: PartLocator, option?: Partial<MouseUpOption>): Promise<void> {
|
|
74
|
+
await act(async () => {
|
|
75
|
+
await super.mouseUp(locator, option);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
override async mouseOver(locator: PartLocator, option?: Partial<HoverOption>): Promise<void> {
|
|
80
|
+
await act(async () => {
|
|
81
|
+
await super.mouseOver(locator, option);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
override async mouseOut(locator: PartLocator, option?: Partial<MouseOutOption>): Promise<void> {
|
|
86
|
+
await act(async () => {
|
|
87
|
+
await super.mouseOut(locator, option);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
override async mouseEnter(locator: PartLocator, option?: Partial<MouseEnterOption>): Promise<void> {
|
|
92
|
+
await act(async () => {
|
|
93
|
+
await super.mouseEnter(locator, option);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
override async mouseLeave(locator: PartLocator, option?: Partial<MouseLeaveOption>): Promise<void> {
|
|
98
|
+
await act(async () => {
|
|
99
|
+
await super.mouseLeave(locator, option);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
override async focus(locator: PartLocator, option?: Partial<FocusOption>): Promise<void> {
|
|
104
|
+
await act(async () => {
|
|
105
|
+
await super.focus(locator, option);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
override async blur(locator: PartLocator, option?: Partial<BlurOption>): Promise<void> {
|
|
110
|
+
await act(async () => {
|
|
111
|
+
await super.blur(locator, option);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
override async pressKey(locator: PartLocator, key: string, option?: Partial<PressKeyOption>): Promise<void> {
|
|
116
|
+
await act(async () => {
|
|
117
|
+
await super.pressKey(locator, key, option);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
override async contextMenu(locator: PartLocator): Promise<void> {
|
|
122
|
+
await act(async () => {
|
|
123
|
+
await super.contextMenu(locator);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
override async activate(locator: PartLocator): Promise<void> {
|
|
128
|
+
await act(async () => {
|
|
129
|
+
await super.activate(locator);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
override async selectOptionValue(locator: PartLocator, values: string[]): Promise<void> {
|
|
134
|
+
await act(async () => {
|
|
135
|
+
await super.selectOptionValue(locator, values);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
override async setInputFiles(locator: PartLocator, files: string | string[]): Promise<void> {
|
|
140
|
+
await act(async () => {
|
|
141
|
+
await super.setInputFiles(locator, files);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
override async scrollIntoView(locator: PartLocator): Promise<void> {
|
|
146
|
+
await act(async () => {
|
|
147
|
+
await super.scrollIntoView(locator);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
override async scrollBy(locator: PartLocator, delta: Point): Promise<void> {
|
|
152
|
+
await act(async () => {
|
|
153
|
+
await super.scrollBy(locator, delta);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
override async dragTo(source: PartLocator, target: PartLocator): Promise<void> {
|
|
158
|
+
await act(async () => {
|
|
159
|
+
await super.dragTo(source, target);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
override async drag(locator: PartLocator, delta: Point): Promise<void> {
|
|
164
|
+
await act(async () => {
|
|
165
|
+
await super.drag(locator, delta);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
//#region wait condition
|
|
170
|
+
override async wait(ms: number): Promise<void> {
|
|
171
|
+
await act(async () => {
|
|
172
|
+
await super.wait(ms);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
override async waitUntilComponentState(
|
|
177
|
+
locator: PartLocator,
|
|
178
|
+
option: Partial<Readonly<WaitForOption>> = defaultWaitForOption
|
|
179
|
+
): Promise<void> {
|
|
180
|
+
await act(async () => {
|
|
181
|
+
await super.waitUntilComponentState(locator, option);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
override async waitUntil<T>(option: WaitUntilOption<T>): Promise<T> {
|
|
186
|
+
// The React ≤17 `act` async overload resolves to `undefined`, not the
|
|
187
|
+
// callback's value (unlike React 18's act), so capture the result via a
|
|
188
|
+
// closure instead of returning it through `act`.
|
|
189
|
+
let result!: T;
|
|
190
|
+
await act(async () => {
|
|
191
|
+
result = await super.waitUntil(option);
|
|
192
|
+
});
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
//#endregion
|
|
196
|
+
|
|
197
|
+
override clone(): Interactor {
|
|
198
|
+
return new LegacyReactInteractor(this.rootEl);
|
|
199
|
+
}
|
|
200
|
+
}
|
package/src/createTestEngine.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { byAttribute, ScenePart, TestEngine } from '@atomic-testing/core';
|
|
2
|
-
import { ReactInteractor } from '@atomic-testing/react-core';
|
|
3
2
|
import { ReactElement } from 'react';
|
|
4
3
|
import ReactDOM from 'react-dom';
|
|
5
4
|
import { act } from 'react-dom/test-utils';
|
|
6
5
|
|
|
6
|
+
import { LegacyReactInteractor } from './LegacyReactInteractor';
|
|
7
7
|
import { IReactTestEngineOption } from './types';
|
|
8
8
|
|
|
9
9
|
let _rootId = 0;
|
|
@@ -43,7 +43,7 @@ export function createTestEngine<T extends ScenePart>(
|
|
|
43
43
|
|
|
44
44
|
const engine = new TestEngine(
|
|
45
45
|
byAttribute(rootElementAttributeName, rootId),
|
|
46
|
-
new
|
|
46
|
+
new LegacyReactInteractor(),
|
|
47
47
|
{
|
|
48
48
|
parts: partDefinitions,
|
|
49
49
|
},
|
|
@@ -77,7 +77,7 @@ export function createRenderedTestEngine<T extends ScenePart>(
|
|
|
77
77
|
|
|
78
78
|
const engine = new TestEngine(
|
|
79
79
|
byAttribute(rootElementAttributeName, rootId),
|
|
80
|
-
new
|
|
80
|
+
new LegacyReactInteractor(),
|
|
81
81
|
{
|
|
82
82
|
parts: partDefinitions,
|
|
83
83
|
},
|