@react-aria/test-utils 1.0.0-nightly.5041 → 1.0.0-rc.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 +70 -0
- package/dist/import.mjs +6 -4
- package/dist/main.js +15 -23
- package/dist/main.js.map +1 -1
- package/dist/module.js +6 -4
- package/dist/module.js.map +1 -1
- package/dist/private/act.cjs +33 -0
- package/dist/private/act.cjs.map +1 -0
- package/dist/private/act.js +28 -0
- package/dist/private/act.js.map +1 -0
- package/dist/private/checkboxgroup.cjs +107 -0
- package/dist/private/checkboxgroup.cjs.map +1 -0
- package/dist/private/checkboxgroup.js +102 -0
- package/dist/private/checkboxgroup.js.map +1 -0
- package/dist/private/combobox.cjs +199 -0
- package/dist/private/combobox.cjs.map +1 -0
- package/dist/private/combobox.js +194 -0
- package/dist/private/combobox.js.map +1 -0
- package/dist/private/dialog.cjs +110 -0
- package/dist/private/dialog.cjs.map +1 -0
- package/dist/private/dialog.js +105 -0
- package/dist/private/dialog.js.map +1 -0
- package/dist/private/gridlist.cjs +173 -0
- package/dist/private/gridlist.cjs.map +1 -0
- package/dist/private/gridlist.js +168 -0
- package/dist/private/gridlist.js.map +1 -0
- package/dist/private/listbox.cjs +163 -0
- package/dist/private/listbox.cjs.map +1 -0
- package/dist/private/listbox.js +158 -0
- package/dist/private/listbox.js.map +1 -0
- package/dist/private/menu.cjs +265 -0
- package/dist/private/menu.cjs.map +1 -0
- package/dist/private/menu.js +260 -0
- package/dist/private/menu.js.map +1 -0
- package/dist/private/radiogroup.cjs +122 -0
- package/dist/private/radiogroup.cjs.map +1 -0
- package/dist/private/radiogroup.js +117 -0
- package/dist/private/radiogroup.js.map +1 -0
- package/dist/private/select.cjs +169 -0
- package/dist/private/select.cjs.map +1 -0
- package/dist/private/select.js +164 -0
- package/dist/private/select.js.map +1 -0
- package/dist/private/table.cjs +346 -0
- package/dist/private/table.cjs.map +1 -0
- package/dist/private/table.js +341 -0
- package/dist/private/table.js.map +1 -0
- package/dist/private/tabs.cjs +131 -0
- package/dist/private/tabs.cjs.map +1 -0
- package/dist/private/tabs.js +126 -0
- package/dist/private/tabs.js.map +1 -0
- package/dist/private/testSetup.cjs +87 -0
- package/dist/private/testSetup.cjs.map +1 -0
- package/dist/private/testSetup.js +81 -0
- package/dist/private/testSetup.js.map +1 -0
- package/dist/private/tree.cjs +181 -0
- package/dist/private/tree.cjs.map +1 -0
- package/dist/private/tree.js +176 -0
- package/dist/private/tree.js.map +1 -0
- package/dist/private/user.cjs +85 -0
- package/dist/private/user.cjs.map +1 -0
- package/dist/private/user.js +76 -0
- package/dist/private/user.js.map +1 -0
- package/dist/{userEventMaps.main.js → private/userEventMaps.cjs} +3 -3
- package/dist/private/userEventMaps.cjs.map +1 -0
- package/dist/{userEventMaps.mjs → private/userEventMaps.js} +3 -3
- package/dist/private/userEventMaps.js.map +1 -0
- package/dist/private/utils.cjs +136 -0
- package/dist/private/utils.cjs.map +1 -0
- package/dist/private/utils.js +127 -0
- package/dist/private/utils.js.map +1 -0
- package/dist/types/src/act.d.ts +4 -0
- package/dist/types/src/checkboxgroup.d.ts +47 -0
- package/dist/types/src/combobox.d.ts +87 -0
- package/dist/types/src/dialog.d.ts +37 -0
- package/dist/types/src/events.d.ts +25 -0
- package/dist/types/src/gridlist.d.ts +56 -0
- package/dist/types/src/index.d.ts +16 -0
- package/dist/types/src/listbox.d.ts +91 -0
- package/dist/types/src/menu.d.ts +112 -0
- package/dist/types/src/radiogroup.d.ts +47 -0
- package/dist/types/src/select.d.ts +74 -0
- package/dist/types/src/table.d.ts +120 -0
- package/dist/types/src/tabs.d.ts +59 -0
- package/dist/types/src/testSetup.d.ts +6 -0
- package/dist/types/src/tree.d.ts +62 -0
- package/dist/types/src/types.d.ts +143 -0
- package/dist/types/src/user.d.ts +49 -0
- package/dist/types/src/userEventMaps.d.ts +2 -0
- package/dist/types/src/utils.d.ts +29 -0
- package/package.json +26 -18
- package/src/act.ts +35 -0
- package/src/checkboxgroup.ts +165 -0
- package/src/combobox.ts +307 -0
- package/src/dialog.ts +155 -0
- package/src/gridlist.ts +278 -0
- package/src/index.ts +17 -3
- package/src/listbox.ts +300 -0
- package/src/menu.ts +479 -0
- package/src/radiogroup.ts +179 -0
- package/src/select.ts +273 -0
- package/src/table.ts +589 -0
- package/src/tabs.ts +204 -0
- package/src/testSetup.ts +41 -36
- package/src/tree.ts +290 -0
- package/src/types.ts +171 -0
- package/src/user.ts +153 -0
- package/src/userEventMaps.ts +1 -1
- package/src/utils.ts +155 -0
- package/dist/events.main.js +0 -37
- package/dist/events.main.js.map +0 -1
- package/dist/events.mjs +0 -31
- package/dist/events.module.js +0 -31
- package/dist/events.module.js.map +0 -1
- package/dist/testSetup.main.js +0 -82
- package/dist/testSetup.main.js.map +0 -1
- package/dist/testSetup.mjs +0 -76
- package/dist/testSetup.module.js +0 -76
- package/dist/testSetup.module.js.map +0 -1
- package/dist/types.d.ts +0 -16
- package/dist/types.d.ts.map +0 -1
- package/dist/userEventMaps.main.js.map +0 -1
- package/dist/userEventMaps.module.js +0 -38
- package/dist/userEventMaps.module.js.map +0 -1
- package/src/events.ts +0 -28
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import {act as $1350703ef3ac1acc$export$3ba232387fd5d6dd} from "./act.js";
|
|
2
|
+
import {formatTargetNode as $b4e037a2907521c6$export$bc3bc4a9206bf789, pressElement as $b4e037a2907521c6$export$6ffa3eb717517feb} from "./utils.js";
|
|
3
|
+
import {within as $7d80g$within} from "@testing-library/dom";
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* Copyright 2024 Adobe. All rights reserved.
|
|
7
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
9
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
12
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
13
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
14
|
+
* governing permissions and limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class $e1a5bc7455cf5719$export$f1539bff3fc7d485 {
|
|
19
|
+
constructor(opts){
|
|
20
|
+
let { root: root, user: user, interactionType: interactionType, direction: direction } = opts;
|
|
21
|
+
this.user = user;
|
|
22
|
+
this._interactionType = interactionType || 'mouse';
|
|
23
|
+
this._direction = direction || 'ltr';
|
|
24
|
+
this._tablist = root;
|
|
25
|
+
let tablist = (0, $7d80g$within)(root).queryAllByRole('tablist');
|
|
26
|
+
if (tablist.length > 0) this._tablist = tablist[0];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Set the interaction type used by the tabs tester.
|
|
30
|
+
*/ setInteractionType(type) {
|
|
31
|
+
this._interactionType = type;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Returns a tab matching the specified index or text content.
|
|
35
|
+
*/ findTab(opts) {
|
|
36
|
+
let { indexOrText: indexOrText } = opts;
|
|
37
|
+
let tab;
|
|
38
|
+
let tabs = this.getTabs();
|
|
39
|
+
if (typeof indexOrText === 'number') tab = tabs[indexOrText];
|
|
40
|
+
else if (typeof indexOrText === 'string') tab = (0, $7d80g$within)(this._tablist).getByText(indexOrText).closest('[role=tab]');
|
|
41
|
+
return tab;
|
|
42
|
+
}
|
|
43
|
+
async keyboardNavigateToTab(opts) {
|
|
44
|
+
let { tab: tab, orientation: orientation = 'vertical' } = opts;
|
|
45
|
+
let tabs = this.getTabs();
|
|
46
|
+
tabs = tabs.filter((tab)=>!(tab.hasAttribute('disabled') || tab.getAttribute('aria-disabled') === 'true'));
|
|
47
|
+
if (tabs.length === 0) throw new Error('Tablist doesnt have any non-disabled tabs. Please double check your tabs implementation.');
|
|
48
|
+
let targetIndex = tabs.indexOf(tab);
|
|
49
|
+
if (targetIndex === -1) throw new Error('Tab provided is not in the tablist');
|
|
50
|
+
if (!this._tablist.contains(document.activeElement)) {
|
|
51
|
+
let selectedTab = this.getSelectedTab();
|
|
52
|
+
if (selectedTab != null) (0, $1350703ef3ac1acc$export$3ba232387fd5d6dd)(()=>selectedTab.focus());
|
|
53
|
+
else (0, $1350703ef3ac1acc$export$3ba232387fd5d6dd)(()=>tabs[0]?.focus());
|
|
54
|
+
}
|
|
55
|
+
let currIndex = tabs.indexOf(document.activeElement);
|
|
56
|
+
if (currIndex === -1) throw new Error('ActiveElement is not in the tablist');
|
|
57
|
+
let arrowUp = 'ArrowUp';
|
|
58
|
+
let arrowDown = 'ArrowDown';
|
|
59
|
+
if (orientation === 'horizontal') {
|
|
60
|
+
if (this._direction === 'ltr') {
|
|
61
|
+
arrowUp = 'ArrowLeft';
|
|
62
|
+
arrowDown = 'ArrowRight';
|
|
63
|
+
} else {
|
|
64
|
+
arrowUp = 'ArrowRight';
|
|
65
|
+
arrowDown = 'ArrowLeft';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
let movementDirection = targetIndex > currIndex ? 'down' : 'up';
|
|
69
|
+
for(let i = 0; i < Math.abs(targetIndex - currIndex); i++)await this.user.keyboard(`[${movementDirection === 'down' ? arrowDown : arrowUp}]`);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Triggers the specified tab. Defaults to using the interaction type set on the tabs tester.
|
|
73
|
+
*/ async triggerTab(opts) {
|
|
74
|
+
let { tab: tab, interactionType: interactionType = this._interactionType, manualActivation: manualActivation } = opts;
|
|
75
|
+
if (typeof tab === 'string' || typeof tab === 'number') tab = this.findTab({
|
|
76
|
+
indexOrText: tab
|
|
77
|
+
});
|
|
78
|
+
if (!tab) throw new Error(`Target tab "${(0, $b4e037a2907521c6$export$bc3bc4a9206bf789)(opts.tab)}" not found in the tablist.`);
|
|
79
|
+
else if (tab.hasAttribute('disabled')) throw new Error(`Target tab "${(0, $b4e037a2907521c6$export$bc3bc4a9206bf789)(opts.tab)}" is disabled.`);
|
|
80
|
+
if (interactionType === 'keyboard') {
|
|
81
|
+
if (document.activeElement !== this._tablist && !this._tablist.contains(document.activeElement)) (0, $1350703ef3ac1acc$export$3ba232387fd5d6dd)(()=>this._tablist.focus());
|
|
82
|
+
let tabsOrientation = this._tablist.getAttribute('aria-orientation') || 'horizontal';
|
|
83
|
+
await this.keyboardNavigateToTab({
|
|
84
|
+
tab: tab,
|
|
85
|
+
orientation: tabsOrientation
|
|
86
|
+
});
|
|
87
|
+
if (manualActivation) await this.user.keyboard('[Enter]');
|
|
88
|
+
} else await (0, $b4e037a2907521c6$export$6ffa3eb717517feb)(this.user, tab, interactionType);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Returns the tablist.
|
|
92
|
+
*/ getTablist() {
|
|
93
|
+
return this._tablist;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Returns the tabpanels.
|
|
97
|
+
*/ getTabpanels() {
|
|
98
|
+
let tabpanels = [];
|
|
99
|
+
for (let tab of this.getTabs()){
|
|
100
|
+
let controlId = tab.getAttribute('aria-controls');
|
|
101
|
+
let panel = controlId != null ? document.getElementById(controlId) : null;
|
|
102
|
+
if (panel != null) tabpanels.push(panel);
|
|
103
|
+
}
|
|
104
|
+
return tabpanels;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Returns the tabs in the tablist.
|
|
108
|
+
*/ getTabs() {
|
|
109
|
+
return (0, $7d80g$within)(this.getTablist()).queryAllByRole('tab');
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Returns the currently selected tab in the tablist if any.
|
|
113
|
+
*/ getSelectedTab() {
|
|
114
|
+
return this.getTabs().find((tab)=>tab.getAttribute('aria-selected') === 'true') || null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Returns the currently active tabpanel if any.
|
|
118
|
+
*/ getActiveTabpanel() {
|
|
119
|
+
let activeTabpanelId = this.getSelectedTab()?.getAttribute('aria-controls');
|
|
120
|
+
return activeTabpanelId ? document.getElementById(activeTabpanelId) : null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
export {$e1a5bc7455cf5719$export$f1539bff3fc7d485 as TabsTester};
|
|
126
|
+
//# sourceMappingURL=tabs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/test-utils/src/tabs.ts"],"sourcesContent":["/*\n * Copyright 2024 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {act} from './act';\nimport {Direction, Orientation, TabsTesterOpts, UserOpts} from './types';\nimport {formatTargetNode, pressElement} from './utils';\nimport {within} from '@testing-library/dom';\n\ninterface TriggerTabOptions {\n /**\n * What interaction type to use when triggering a tab. Defaults to the interaction type set on the\n * tester.\n */\n interactionType?: UserOpts['interactionType'];\n /**\n * The index, text, or node of the tab to toggle selection for.\n */\n tab: number | string | HTMLElement;\n /**\n * Whether the tab needs to be activated manually rather than on focus.\n */\n manualActivation?: boolean;\n}\n\nexport class TabsTester {\n private user;\n private _interactionType: UserOpts['interactionType'];\n private _tablist: HTMLElement;\n private _direction: Direction;\n\n constructor(opts: TabsTesterOpts) {\n let {root, user, interactionType, direction} = opts;\n this.user = user;\n this._interactionType = interactionType || 'mouse';\n this._direction = direction || 'ltr';\n\n this._tablist = root;\n let tablist = within(root).queryAllByRole('tablist');\n if (tablist.length > 0) {\n this._tablist = tablist[0];\n }\n }\n\n /**\n * Set the interaction type used by the tabs tester.\n */\n setInteractionType(type: UserOpts['interactionType']): void {\n this._interactionType = type;\n }\n\n /**\n * Returns a tab matching the specified index or text content.\n */\n findTab(opts: {indexOrText: number | string}): HTMLElement {\n let {indexOrText} = opts;\n\n let tab;\n let tabs = this.getTabs();\n if (typeof indexOrText === 'number') {\n tab = tabs[indexOrText];\n } else if (typeof indexOrText === 'string') {\n tab = within(this._tablist).getByText(indexOrText).closest('[role=tab]')! as HTMLElement;\n }\n\n return tab;\n }\n\n private async keyboardNavigateToTab(opts: {tab: HTMLElement; orientation?: Orientation}) {\n let {tab, orientation = 'vertical'} = opts;\n let tabs = this.getTabs();\n tabs = tabs.filter(\n tab => !(tab.hasAttribute('disabled') || tab.getAttribute('aria-disabled') === 'true')\n );\n if (tabs.length === 0) {\n throw new Error(\n 'Tablist doesnt have any non-disabled tabs. Please double check your tabs implementation.'\n );\n }\n\n let targetIndex = tabs.indexOf(tab);\n if (targetIndex === -1) {\n throw new Error('Tab provided is not in the tablist');\n }\n\n if (!this._tablist.contains(document.activeElement)) {\n let selectedTab = this.getSelectedTab();\n if (selectedTab != null) {\n act(() => selectedTab.focus());\n } else {\n act(() => tabs[0]?.focus());\n }\n }\n\n let currIndex = tabs.indexOf(document.activeElement as HTMLElement);\n if (currIndex === -1) {\n throw new Error('ActiveElement is not in the tablist');\n }\n\n let arrowUp = 'ArrowUp';\n let arrowDown = 'ArrowDown';\n if (orientation === 'horizontal') {\n if (this._direction === 'ltr') {\n arrowUp = 'ArrowLeft';\n arrowDown = 'ArrowRight';\n } else {\n arrowUp = 'ArrowRight';\n arrowDown = 'ArrowLeft';\n }\n }\n\n let movementDirection = targetIndex > currIndex ? 'down' : 'up';\n for (let i = 0; i < Math.abs(targetIndex - currIndex); i++) {\n await this.user.keyboard(`[${movementDirection === 'down' ? arrowDown : arrowUp}]`);\n }\n }\n\n /**\n * Triggers the specified tab. Defaults to using the interaction type set on the tabs tester.\n */\n async triggerTab(opts: TriggerTabOptions): Promise<void> {\n let {tab, interactionType = this._interactionType, manualActivation} = opts;\n\n if (typeof tab === 'string' || typeof tab === 'number') {\n tab = this.findTab({indexOrText: tab});\n }\n\n if (!tab) {\n throw new Error(`Target tab \"${formatTargetNode(opts.tab)}\" not found in the tablist.`);\n } else if (tab.hasAttribute('disabled')) {\n throw new Error(`Target tab \"${formatTargetNode(opts.tab)}\" is disabled.`);\n }\n\n if (interactionType === 'keyboard') {\n if (\n document.activeElement !== this._tablist &&\n !this._tablist.contains(document.activeElement)\n ) {\n act(() => this._tablist.focus());\n }\n\n let tabsOrientation = this._tablist.getAttribute('aria-orientation') || 'horizontal';\n await this.keyboardNavigateToTab({tab, orientation: tabsOrientation as Orientation});\n if (manualActivation) {\n await this.user.keyboard('[Enter]');\n }\n } else {\n await pressElement(this.user, tab, interactionType);\n }\n }\n\n /**\n * Returns the tablist.\n */\n getTablist(): HTMLElement {\n return this._tablist;\n }\n\n /**\n * Returns the tabpanels.\n */\n getTabpanels(): HTMLElement[] {\n let tabpanels = [] as HTMLElement[];\n for (let tab of this.getTabs()) {\n let controlId = tab.getAttribute('aria-controls');\n let panel = controlId != null ? document.getElementById(controlId) : null;\n if (panel != null) {\n tabpanels.push(panel);\n }\n }\n\n return tabpanels;\n }\n\n /**\n * Returns the tabs in the tablist.\n */\n getTabs(): HTMLElement[] {\n return within(this.getTablist()).queryAllByRole('tab');\n }\n\n /**\n * Returns the currently selected tab in the tablist if any.\n */\n getSelectedTab(): HTMLElement | null {\n return this.getTabs().find(tab => tab.getAttribute('aria-selected') === 'true') || null;\n }\n\n /**\n * Returns the currently active tabpanel if any.\n */\n getActiveTabpanel(): HTMLElement | null {\n let activeTabpanelId = this.getSelectedTab()?.getAttribute('aria-controls');\n return activeTabpanelId ? document.getElementById(activeTabpanelId) : null;\n }\n}\n"],"names":[],"version":3,"file":"tabs.js.map"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
|
|
2
|
+
var $parcel$global =
|
|
3
|
+
typeof globalThis !== 'undefined'
|
|
4
|
+
? globalThis
|
|
5
|
+
: typeof self !== 'undefined'
|
|
6
|
+
? self
|
|
7
|
+
: typeof window !== 'undefined'
|
|
8
|
+
? window
|
|
9
|
+
: typeof global !== 'undefined'
|
|
10
|
+
? global
|
|
11
|
+
: {};
|
|
12
|
+
|
|
13
|
+
function $parcel$export(e, n, v, s) {
|
|
14
|
+
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
$parcel$export(module.exports, "installMouseEvent", function () { return $5e3c75beb0dad42b$export$de31e3987c917741; });
|
|
18
|
+
$parcel$export(module.exports, "installPointerEvent", function () { return $5e3c75beb0dad42b$export$82f0b04c1d69a901; });
|
|
19
|
+
/*
|
|
20
|
+
* Copyright 2023 Adobe. All rights reserved.
|
|
21
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
22
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
23
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
24
|
+
*
|
|
25
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
26
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
27
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
28
|
+
* governing permissions and limitations under the License.
|
|
29
|
+
*/ /**
|
|
30
|
+
* Enables reading pageX/pageY from fireEvent.mouse*(..., {pageX: ..., pageY: ...}).
|
|
31
|
+
*/ function $5e3c75beb0dad42b$export$de31e3987c917741() {
|
|
32
|
+
let oldMouseEvent = MouseEvent;
|
|
33
|
+
beforeAll(()=>{
|
|
34
|
+
$parcel$global.MouseEvent = class FakeMouseEvent extends MouseEvent {
|
|
35
|
+
constructor(name, init){
|
|
36
|
+
super(name, init);
|
|
37
|
+
this._init = init;
|
|
38
|
+
}
|
|
39
|
+
get pageX() {
|
|
40
|
+
return this._init.pageX;
|
|
41
|
+
}
|
|
42
|
+
get pageY() {
|
|
43
|
+
return this._init.pageY;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
afterAll(()=>{
|
|
48
|
+
$parcel$global.MouseEvent = oldMouseEvent;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function $5e3c75beb0dad42b$export$93965c727ae9548a() {
|
|
52
|
+
// @ts-ignore
|
|
53
|
+
$parcel$global.PointerEvent = class FakePointerEvent extends MouseEvent {
|
|
54
|
+
constructor(name, init){
|
|
55
|
+
super(name, init);
|
|
56
|
+
this._init = init;
|
|
57
|
+
}
|
|
58
|
+
get pointerType() {
|
|
59
|
+
return this._init.pointerType ?? 'mouse';
|
|
60
|
+
}
|
|
61
|
+
get pointerId() {
|
|
62
|
+
return this._init.pointerId;
|
|
63
|
+
}
|
|
64
|
+
get pageX() {
|
|
65
|
+
return this._init.pageX;
|
|
66
|
+
}
|
|
67
|
+
get pageY() {
|
|
68
|
+
return this._init.pageY;
|
|
69
|
+
}
|
|
70
|
+
get width() {
|
|
71
|
+
return this._init.width;
|
|
72
|
+
}
|
|
73
|
+
get height() {
|
|
74
|
+
return this._init.height;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function $5e3c75beb0dad42b$export$82f0b04c1d69a901() {
|
|
79
|
+
beforeAll($5e3c75beb0dad42b$export$93965c727ae9548a);
|
|
80
|
+
afterAll(()=>{
|
|
81
|
+
// @ts-ignore
|
|
82
|
+
delete $parcel$global.PointerEvent;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
//# sourceMappingURL=testSetup.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":";;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;CAUC,GAED;;CAEC,GACM,SAAS;IACd,IAAI,gBAAgB;IACpB,UAAU;QACR,eAAO,UAAU,GAAG,MAAM,uBAAuB;YAE/C,YAAY,IAAI,EAAE,IAAI,CAAE;gBACtB,KAAK,CAAC,MAAM;gBACZ,IAAI,CAAC,KAAK,GAAG;YACf;YACA,IAAI,QAAQ;gBACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK;YACzB;YACA,IAAI,QAAQ;gBACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK;YACzB;QACF;IACF;IACA,SAAS;QACP,eAAO,UAAU,GAAG;IACtB;AACF;AAEO,SAAS;IACd,aAAa;IACb,eAAO,YAAY,GAAG,MAAM,yBAAyB;QASnD,YAAY,IAAI,EAAE,IAAI,CAAE;YACtB,KAAK,CAAC,MAAM;YACZ,IAAI,CAAC,KAAK,GAAG;QACf;QACA,IAAI,cAAc;YAChB,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI;QACnC;QACA,IAAI,YAAY;YACd,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS;QAC7B;QACA,IAAI,QAAQ;YACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK;QACzB;QACA,IAAI,QAAQ;YACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK;QACzB;QACA,IAAI,QAAQ;YACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK;QACzB;QACA,IAAI,SAAS;YACX,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM;QAC1B;IACF;AACF;AAEO,SAAS;IACd,UAAU;IACV,SAAS;QACP,aAAa;QACb,OAAO,eAAO,YAAY;IAC5B;AACF","sources":["packages/@react-aria/test-utils/src/testSetup.ts"],"sourcesContent":["/*\n * Copyright 2023 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Enables reading pageX/pageY from fireEvent.mouse*(..., {pageX: ..., pageY: ...}).\n */\nexport function installMouseEvent(): void {\n let oldMouseEvent = MouseEvent;\n beforeAll(() => {\n global.MouseEvent = class FakeMouseEvent extends MouseEvent {\n _init: {pageX: number; pageY: number};\n constructor(name, init) {\n super(name, init);\n this._init = init;\n }\n get pageX() {\n return this._init.pageX;\n }\n get pageY() {\n return this._init.pageY;\n }\n };\n });\n afterAll(() => {\n global.MouseEvent = oldMouseEvent;\n });\n}\n\nexport function definePointerEvent(): void {\n // @ts-ignore\n global.PointerEvent = class FakePointerEvent extends MouseEvent {\n _init: {\n pageX: number;\n pageY: number;\n pointerType: string;\n pointerId: number;\n width: number;\n height: number;\n };\n constructor(name, init) {\n super(name, init);\n this._init = init;\n }\n get pointerType() {\n return this._init.pointerType ?? 'mouse';\n }\n get pointerId() {\n return this._init.pointerId;\n }\n get pageX() {\n return this._init.pageX;\n }\n get pageY() {\n return this._init.pageY;\n }\n get width() {\n return this._init.width;\n }\n get height() {\n return this._init.height;\n }\n };\n}\n\nexport function installPointerEvent(): void {\n beforeAll(definePointerEvent);\n afterAll(() => {\n // @ts-ignore\n delete global.PointerEvent;\n });\n}\n"],"names":[],"version":3,"file":"testSetup.cjs.map"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
|
|
2
|
+
var $parcel$global =
|
|
3
|
+
typeof globalThis !== 'undefined'
|
|
4
|
+
? globalThis
|
|
5
|
+
: typeof self !== 'undefined'
|
|
6
|
+
? self
|
|
7
|
+
: typeof window !== 'undefined'
|
|
8
|
+
? window
|
|
9
|
+
: typeof global !== 'undefined'
|
|
10
|
+
? global
|
|
11
|
+
: {};
|
|
12
|
+
/*
|
|
13
|
+
* Copyright 2023 Adobe. All rights reserved.
|
|
14
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
15
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
16
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
+
*
|
|
18
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
19
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
20
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
21
|
+
* governing permissions and limitations under the License.
|
|
22
|
+
*/ /**
|
|
23
|
+
* Enables reading pageX/pageY from fireEvent.mouse*(..., {pageX: ..., pageY: ...}).
|
|
24
|
+
*/ function $448e93e3748c7958$export$de31e3987c917741() {
|
|
25
|
+
let oldMouseEvent = MouseEvent;
|
|
26
|
+
beforeAll(()=>{
|
|
27
|
+
$parcel$global.MouseEvent = class FakeMouseEvent extends MouseEvent {
|
|
28
|
+
constructor(name, init){
|
|
29
|
+
super(name, init);
|
|
30
|
+
this._init = init;
|
|
31
|
+
}
|
|
32
|
+
get pageX() {
|
|
33
|
+
return this._init.pageX;
|
|
34
|
+
}
|
|
35
|
+
get pageY() {
|
|
36
|
+
return this._init.pageY;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
afterAll(()=>{
|
|
41
|
+
$parcel$global.MouseEvent = oldMouseEvent;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function $448e93e3748c7958$export$93965c727ae9548a() {
|
|
45
|
+
// @ts-ignore
|
|
46
|
+
$parcel$global.PointerEvent = class FakePointerEvent extends MouseEvent {
|
|
47
|
+
constructor(name, init){
|
|
48
|
+
super(name, init);
|
|
49
|
+
this._init = init;
|
|
50
|
+
}
|
|
51
|
+
get pointerType() {
|
|
52
|
+
return this._init.pointerType ?? 'mouse';
|
|
53
|
+
}
|
|
54
|
+
get pointerId() {
|
|
55
|
+
return this._init.pointerId;
|
|
56
|
+
}
|
|
57
|
+
get pageX() {
|
|
58
|
+
return this._init.pageX;
|
|
59
|
+
}
|
|
60
|
+
get pageY() {
|
|
61
|
+
return this._init.pageY;
|
|
62
|
+
}
|
|
63
|
+
get width() {
|
|
64
|
+
return this._init.width;
|
|
65
|
+
}
|
|
66
|
+
get height() {
|
|
67
|
+
return this._init.height;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function $448e93e3748c7958$export$82f0b04c1d69a901() {
|
|
72
|
+
beforeAll($448e93e3748c7958$export$93965c727ae9548a);
|
|
73
|
+
afterAll(()=>{
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
delete $parcel$global.PointerEvent;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
export {$448e93e3748c7958$export$de31e3987c917741 as installMouseEvent, $448e93e3748c7958$export$93965c727ae9548a as definePointerEvent, $448e93e3748c7958$export$82f0b04c1d69a901 as installPointerEvent};
|
|
81
|
+
//# sourceMappingURL=testSetup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":";;;;;;;;;;;AAAA;;;;;;;;;;CAUC,GAED;;CAEC,GACM,SAAS;IACd,IAAI,gBAAgB;IACpB,UAAU;QACR,eAAO,UAAU,GAAG,MAAM,uBAAuB;YAE/C,YAAY,IAAI,EAAE,IAAI,CAAE;gBACtB,KAAK,CAAC,MAAM;gBACZ,IAAI,CAAC,KAAK,GAAG;YACf;YACA,IAAI,QAAQ;gBACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK;YACzB;YACA,IAAI,QAAQ;gBACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK;YACzB;QACF;IACF;IACA,SAAS;QACP,eAAO,UAAU,GAAG;IACtB;AACF;AAEO,SAAS;IACd,aAAa;IACb,eAAO,YAAY,GAAG,MAAM,yBAAyB;QASnD,YAAY,IAAI,EAAE,IAAI,CAAE;YACtB,KAAK,CAAC,MAAM;YACZ,IAAI,CAAC,KAAK,GAAG;QACf;QACA,IAAI,cAAc;YAChB,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI;QACnC;QACA,IAAI,YAAY;YACd,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS;QAC7B;QACA,IAAI,QAAQ;YACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK;QACzB;QACA,IAAI,QAAQ;YACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK;QACzB;QACA,IAAI,QAAQ;YACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK;QACzB;QACA,IAAI,SAAS;YACX,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM;QAC1B;IACF;AACF;AAEO,SAAS;IACd,UAAU;IACV,SAAS;QACP,aAAa;QACb,OAAO,eAAO,YAAY;IAC5B;AACF","sources":["packages/@react-aria/test-utils/src/testSetup.ts"],"sourcesContent":["/*\n * Copyright 2023 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\n/**\n * Enables reading pageX/pageY from fireEvent.mouse*(..., {pageX: ..., pageY: ...}).\n */\nexport function installMouseEvent(): void {\n let oldMouseEvent = MouseEvent;\n beforeAll(() => {\n global.MouseEvent = class FakeMouseEvent extends MouseEvent {\n _init: {pageX: number; pageY: number};\n constructor(name, init) {\n super(name, init);\n this._init = init;\n }\n get pageX() {\n return this._init.pageX;\n }\n get pageY() {\n return this._init.pageY;\n }\n };\n });\n afterAll(() => {\n global.MouseEvent = oldMouseEvent;\n });\n}\n\nexport function definePointerEvent(): void {\n // @ts-ignore\n global.PointerEvent = class FakePointerEvent extends MouseEvent {\n _init: {\n pageX: number;\n pageY: number;\n pointerType: string;\n pointerId: number;\n width: number;\n height: number;\n };\n constructor(name, init) {\n super(name, init);\n this._init = init;\n }\n get pointerType() {\n return this._init.pointerType ?? 'mouse';\n }\n get pointerId() {\n return this._init.pointerId;\n }\n get pageX() {\n return this._init.pageX;\n }\n get pageY() {\n return this._init.pageY;\n }\n get width() {\n return this._init.width;\n }\n get height() {\n return this._init.height;\n }\n };\n}\n\nexport function installPointerEvent(): void {\n beforeAll(definePointerEvent);\n afterAll(() => {\n // @ts-ignore\n delete global.PointerEvent;\n });\n}\n"],"names":[],"version":3,"file":"testSetup.js.map"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
var $a84d573878cc1e5e$exports = require("./act.cjs");
|
|
2
|
+
var $022fcf8e360befed$exports = require("./utils.cjs");
|
|
3
|
+
var $6QyUo$testinglibrarydom = require("@testing-library/dom");
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
function $parcel$export(e, n, v, s) {
|
|
7
|
+
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
$parcel$export(module.exports, "TreeTester", function () { return $c7f71a5a893f714a$export$4445864b14128396; });
|
|
11
|
+
/*
|
|
12
|
+
* Copyright 2024 Adobe. All rights reserved.
|
|
13
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
14
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
15
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
+
*
|
|
17
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
18
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
19
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
20
|
+
* governing permissions and limitations under the License.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class $c7f71a5a893f714a$export$4445864b14128396 {
|
|
25
|
+
constructor(opts){
|
|
26
|
+
let { root: root, user: user, interactionType: interactionType, advanceTimer: advanceTimer, direction: direction } = opts;
|
|
27
|
+
this.user = user;
|
|
28
|
+
this._interactionType = interactionType || 'mouse';
|
|
29
|
+
this._advanceTimer = advanceTimer;
|
|
30
|
+
this._direction = direction || 'ltr';
|
|
31
|
+
this._tree = root;
|
|
32
|
+
if (root.getAttribute('role') !== 'treegrid') {
|
|
33
|
+
let tree = (0, $6QyUo$testinglibrarydom.within)(root).queryByRole('treegrid');
|
|
34
|
+
if (tree) this._tree = tree;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Set the interaction type used by the tree tester.
|
|
39
|
+
*/ setInteractionType(type) {
|
|
40
|
+
this._interactionType = type;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Returns a row matching the specified index or text content.
|
|
44
|
+
*/ findRow(opts) {
|
|
45
|
+
let { indexOrText: indexOrText } = opts;
|
|
46
|
+
let row;
|
|
47
|
+
if (typeof indexOrText === 'number') row = this.getRows()[indexOrText];
|
|
48
|
+
else if (typeof indexOrText === 'string') row = (0, $6QyUo$testinglibrarydom.within)(this.getTree()).getByText(indexOrText).closest('[role=row]');
|
|
49
|
+
return row;
|
|
50
|
+
}
|
|
51
|
+
async keyboardNavigateToRow(opts) {
|
|
52
|
+
let { row: row, selectionOnNav: selectionOnNav = 'default' } = opts;
|
|
53
|
+
let altKey = (0, $022fcf8e360befed$exports.getAltKey)();
|
|
54
|
+
let rows = this.getRows();
|
|
55
|
+
let targetIndex = rows.indexOf(row);
|
|
56
|
+
if (targetIndex === -1) throw new Error('Row provided is not in the tree');
|
|
57
|
+
if (document.activeElement !== this._tree && !this._tree.contains(document.activeElement)) (0, $a84d573878cc1e5e$exports.act)(()=>this._tree.focus());
|
|
58
|
+
let focusPrevKey = this._direction === 'rtl' ? 'ArrowRight' : 'ArrowLeft';
|
|
59
|
+
if (document.activeElement === this.getTree()) await this.user.keyboard(`${selectionOnNav === 'none' ? `[${altKey}>]` : ''}[ArrowDown]${selectionOnNav === 'none' ? `[/${altKey}]` : ''}`);
|
|
60
|
+
else if (this._tree.contains(document.activeElement) && document.activeElement.getAttribute('role') !== 'row') do await this.user.keyboard(`[${focusPrevKey}]`);
|
|
61
|
+
while (document.activeElement.getAttribute('role') !== 'row');
|
|
62
|
+
let currIndex = rows.indexOf(document.activeElement);
|
|
63
|
+
if (currIndex === -1) throw new Error('ActiveElement is not in the tree');
|
|
64
|
+
let direction = targetIndex > currIndex ? 'down' : 'up';
|
|
65
|
+
if (selectionOnNav === 'none') await this.user.keyboard(`[${altKey}>]`);
|
|
66
|
+
for(let i = 0; i < Math.abs(targetIndex - currIndex); i++)await this.user.keyboard(`[${direction === 'down' ? 'ArrowDown' : 'ArrowUp'}]`);
|
|
67
|
+
if (selectionOnNav === 'none') await this.user.keyboard(`[/${altKey}]`);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Toggles the selection for the specified tree row. Defaults to using the interaction type set on
|
|
71
|
+
* the tree tester. Note that this will endevor to always add/remove JUST the provided row to the
|
|
72
|
+
* set of selected rows.
|
|
73
|
+
*/ async toggleRowSelection(opts) {
|
|
74
|
+
let { row: row, needsLongPress: needsLongPress, checkboxSelection: checkboxSelection = true, interactionType: interactionType = this._interactionType, selectionBehavior: selectionBehavior = 'toggle' } = opts;
|
|
75
|
+
let altKey = (0, $022fcf8e360befed$exports.getAltKey)();
|
|
76
|
+
let metaKey = (0, $022fcf8e360befed$exports.getMetaKey)();
|
|
77
|
+
if (typeof row === 'string' || typeof row === 'number') row = this.findRow({
|
|
78
|
+
indexOrText: row
|
|
79
|
+
});
|
|
80
|
+
if (!row) throw new Error(`Target row "${(0, $022fcf8e360befed$exports.formatTargetNode)(opts.row)}" not found in the tree.`);
|
|
81
|
+
let rowCheckbox = (0, $6QyUo$testinglibrarydom.within)(row).queryByRole('checkbox');
|
|
82
|
+
if (rowCheckbox?.getAttribute('disabled') === '' || row?.getAttribute('aria-disabled') === 'true') throw new Error(`Cannot toggle selection on disabled row "${(0, $022fcf8e360befed$exports.formatTargetNode)(opts.row)}".`);
|
|
83
|
+
// this would be better than the check to do nothing in events.ts
|
|
84
|
+
// also, it'd be good to be able to trigger selection on the row instead of having to go to the checkbox directly
|
|
85
|
+
if (interactionType === 'keyboard' && (!checkboxSelection || !rowCheckbox)) {
|
|
86
|
+
await this.keyboardNavigateToRow({
|
|
87
|
+
row: row,
|
|
88
|
+
selectionOnNav: selectionBehavior === 'replace' ? 'none' : 'default'
|
|
89
|
+
});
|
|
90
|
+
if (selectionBehavior === 'replace') await this.user.keyboard(`[${altKey}>]`);
|
|
91
|
+
await this.user.keyboard('[Space]');
|
|
92
|
+
if (selectionBehavior === 'replace') await this.user.keyboard(`[/${altKey}]`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (rowCheckbox && checkboxSelection) await (0, $022fcf8e360befed$exports.pressElement)(this.user, rowCheckbox, interactionType);
|
|
96
|
+
else {
|
|
97
|
+
let cell = (0, $6QyUo$testinglibrarydom.within)(row).getAllByRole('gridcell')[0];
|
|
98
|
+
if (needsLongPress && interactionType === 'touch') // Note that long press interactions with rows is strictly touch only for grid rows
|
|
99
|
+
await (0, $022fcf8e360befed$exports.triggerLongPress)({
|
|
100
|
+
element: cell,
|
|
101
|
+
advanceTimer: this._advanceTimer,
|
|
102
|
+
pointerOpts: {
|
|
103
|
+
pointerType: 'touch'
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
else {
|
|
107
|
+
if (selectionBehavior === 'replace' && interactionType !== 'touch') await this.user.keyboard(`[${metaKey}>]`);
|
|
108
|
+
await (0, $022fcf8e360befed$exports.pressElement)(this.user, row, interactionType);
|
|
109
|
+
if (selectionBehavior === 'replace' && interactionType !== 'touch') await this.user.keyboard(`[/${metaKey}]`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Toggles the expansion for the specified tree row. Defaults to using the interaction type set on
|
|
115
|
+
* the tree tester.
|
|
116
|
+
*/ async toggleRowExpansion(opts) {
|
|
117
|
+
let { row: row, interactionType: interactionType = this._interactionType } = opts;
|
|
118
|
+
if (!this.getTree().contains(document.activeElement)) (0, $a84d573878cc1e5e$exports.act)(()=>this.getTree().focus());
|
|
119
|
+
if (typeof row === 'string' || typeof row === 'number') row = this.findRow({
|
|
120
|
+
indexOrText: row
|
|
121
|
+
});
|
|
122
|
+
if (!row) throw new Error(`Target row "${(0, $022fcf8e360befed$exports.formatTargetNode)(opts.row)}" not found in the tree.`);
|
|
123
|
+
else if (row.getAttribute('aria-expanded') == null) throw new Error(`Target row "${(0, $022fcf8e360befed$exports.formatTargetNode)(opts.row)}" is not expandable.`);
|
|
124
|
+
if (row.getAttribute('aria-disabled') === 'true') throw new Error(`Cannot toggle expansion on disabled row "${(0, $022fcf8e360befed$exports.formatTargetNode)(opts.row)}".`);
|
|
125
|
+
if (interactionType === 'mouse' || interactionType === 'touch') {
|
|
126
|
+
let rowExpander = (0, $6QyUo$testinglibrarydom.within)(row).getAllByRole('button')[0]; // what happens if the button is not first? how can we differentiate?
|
|
127
|
+
await (0, $022fcf8e360befed$exports.pressElement)(this.user, rowExpander, interactionType);
|
|
128
|
+
} else if (interactionType === 'keyboard') {
|
|
129
|
+
await this.keyboardNavigateToRow({
|
|
130
|
+
row: row
|
|
131
|
+
});
|
|
132
|
+
let collapseKey = this._direction === 'rtl' ? 'ArrowRight' : 'ArrowLeft';
|
|
133
|
+
let expandKey = this._direction === 'rtl' ? 'ArrowLeft' : 'ArrowRight';
|
|
134
|
+
if (row.getAttribute('aria-expanded') === 'true') await this.user.keyboard(`[${collapseKey}]`);
|
|
135
|
+
else await this.user.keyboard(`[${expandKey}]`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Triggers the action for the specified tree row. Defaults to using the interaction type set on
|
|
140
|
+
* the tree tester.
|
|
141
|
+
*/ async triggerRowAction(opts) {
|
|
142
|
+
let { row: row, needsDoubleClick: needsDoubleClick, interactionType: interactionType = this._interactionType } = opts;
|
|
143
|
+
if (typeof row === 'string' || typeof row === 'number') row = this.findRow({
|
|
144
|
+
indexOrText: row
|
|
145
|
+
});
|
|
146
|
+
if (!row) throw new Error(`Target row "${(0, $022fcf8e360befed$exports.formatTargetNode)(opts.row)}" not found in the tree.`);
|
|
147
|
+
if (row.getAttribute('aria-disabled') === 'true') throw new Error(`Cannot trigger row action on disabled row "${(0, $022fcf8e360befed$exports.formatTargetNode)(opts.row)}".`);
|
|
148
|
+
if (needsDoubleClick) await this.user.dblClick(row);
|
|
149
|
+
else if (interactionType === 'keyboard') {
|
|
150
|
+
await this.keyboardNavigateToRow({
|
|
151
|
+
row: row
|
|
152
|
+
});
|
|
153
|
+
await this.user.keyboard('[Enter]');
|
|
154
|
+
} else await (0, $022fcf8e360befed$exports.pressElement)(this.user, row, interactionType);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Returns the tree.
|
|
158
|
+
*/ getTree() {
|
|
159
|
+
return this._tree;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Returns the tree's rows if any.
|
|
163
|
+
*/ getRows() {
|
|
164
|
+
return (0, $6QyUo$testinglibrarydom.within)(this.getTree()).queryAllByRole('row');
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Returns the tree's selected rows if any.
|
|
168
|
+
*/ getSelectedRows() {
|
|
169
|
+
return this.getRows().filter((row)=>row.getAttribute('aria-selected') === 'true');
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Returns the tree's cells if any. Can be filtered against a specific row if provided via
|
|
173
|
+
* `element`.
|
|
174
|
+
*/ getCells(opts = {}) {
|
|
175
|
+
let { element: element = this.getTree() } = opts;
|
|
176
|
+
return (0, $6QyUo$testinglibrarydom.within)(element).queryAllByRole('gridcell');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
//# sourceMappingURL=tree.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":"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","sources":["packages/@react-aria/test-utils/src/tree.ts"],"sourcesContent":["/*\n * Copyright 2024 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {act} from './act';\nimport {\n BaseGridRowInteractionOpts,\n Direction,\n GridRowActionOpts,\n ToggleGridRowOpts,\n TreeTesterOpts,\n UserOpts\n} from './types';\nimport {formatTargetNode, getAltKey, getMetaKey, pressElement, triggerLongPress} from './utils';\nimport {within} from '@testing-library/dom';\n\ninterface TreeToggleExpansionOpts extends BaseGridRowInteractionOpts {}\ninterface TreeToggleRowOpts extends ToggleGridRowOpts {}\ninterface TreeRowActionOpts extends GridRowActionOpts {}\n\nexport class TreeTester {\n private user;\n private _interactionType: UserOpts['interactionType'];\n private _advanceTimer: UserOpts['advanceTimer'];\n private _direction: Direction;\n private _tree: HTMLElement;\n\n constructor(opts: TreeTesterOpts) {\n let {root, user, interactionType, advanceTimer, direction} = opts;\n this.user = user;\n this._interactionType = interactionType || 'mouse';\n this._advanceTimer = advanceTimer;\n this._direction = direction || 'ltr';\n this._tree = root;\n if (root.getAttribute('role') !== 'treegrid') {\n let tree = within(root).queryByRole('treegrid');\n if (tree) {\n this._tree = tree;\n }\n }\n }\n\n /**\n * Set the interaction type used by the tree tester.\n */\n setInteractionType(type: UserOpts['interactionType']): void {\n this._interactionType = type;\n }\n\n /**\n * Returns a row matching the specified index or text content.\n */\n findRow(opts: {indexOrText: number | string}): HTMLElement {\n let {indexOrText} = opts;\n\n let row;\n if (typeof indexOrText === 'number') {\n row = this.getRows()[indexOrText];\n } else if (typeof indexOrText === 'string') {\n row = within(this.getTree()!).getByText(indexOrText).closest('[role=row]')! as HTMLElement;\n }\n\n return row;\n }\n\n private async keyboardNavigateToRow(opts: {\n row: HTMLElement;\n selectionOnNav?: 'default' | 'none';\n }) {\n let {row, selectionOnNav = 'default'} = opts;\n let altKey = getAltKey();\n let rows = this.getRows();\n let targetIndex = rows.indexOf(row);\n if (targetIndex === -1) {\n throw new Error('Row provided is not in the tree');\n }\n\n if (document.activeElement !== this._tree && !this._tree.contains(document.activeElement)) {\n act(() => this._tree.focus());\n }\n\n let focusPrevKey = this._direction === 'rtl' ? 'ArrowRight' : 'ArrowLeft';\n if (document.activeElement === this.getTree()) {\n await this.user.keyboard(\n `${selectionOnNav === 'none' ? `[${altKey}>]` : ''}[ArrowDown]${selectionOnNav === 'none' ? `[/${altKey}]` : ''}`\n );\n } else if (\n this._tree.contains(document.activeElement) &&\n document.activeElement!.getAttribute('role') !== 'row'\n ) {\n do {\n await this.user.keyboard(`[${focusPrevKey}]`);\n } while (document.activeElement!.getAttribute('role') !== 'row');\n }\n let currIndex = rows.indexOf(document.activeElement as HTMLElement);\n if (currIndex === -1) {\n throw new Error('ActiveElement is not in the tree');\n }\n let direction = targetIndex > currIndex ? 'down' : 'up';\n\n if (selectionOnNav === 'none') {\n await this.user.keyboard(`[${altKey}>]`);\n }\n for (let i = 0; i < Math.abs(targetIndex - currIndex); i++) {\n await this.user.keyboard(`[${direction === 'down' ? 'ArrowDown' : 'ArrowUp'}]`);\n }\n if (selectionOnNav === 'none') {\n await this.user.keyboard(`[/${altKey}]`);\n }\n }\n\n /**\n * Toggles the selection for the specified tree row. Defaults to using the interaction type set on\n * the tree tester. Note that this will endevor to always add/remove JUST the provided row to the\n * set of selected rows.\n */\n async toggleRowSelection(opts: TreeToggleRowOpts): Promise<void> {\n let {\n row,\n needsLongPress,\n checkboxSelection = true,\n interactionType = this._interactionType,\n selectionBehavior = 'toggle'\n } = opts;\n\n let altKey = getAltKey();\n let metaKey = getMetaKey();\n\n if (typeof row === 'string' || typeof row === 'number') {\n row = this.findRow({indexOrText: row});\n }\n\n if (!row) {\n throw new Error(`Target row \"${formatTargetNode(opts.row)}\" not found in the tree.`);\n }\n\n let rowCheckbox = within(row).queryByRole('checkbox');\n\n if (\n rowCheckbox?.getAttribute('disabled') === '' ||\n row?.getAttribute('aria-disabled') === 'true'\n ) {\n throw new Error(`Cannot toggle selection on disabled row \"${formatTargetNode(opts.row)}\".`);\n }\n\n // this would be better than the check to do nothing in events.ts\n // also, it'd be good to be able to trigger selection on the row instead of having to go to the checkbox directly\n if (interactionType === 'keyboard' && (!checkboxSelection || !rowCheckbox)) {\n await this.keyboardNavigateToRow({\n row,\n selectionOnNav: selectionBehavior === 'replace' ? 'none' : 'default'\n });\n if (selectionBehavior === 'replace') {\n await this.user.keyboard(`[${altKey}>]`);\n }\n await this.user.keyboard('[Space]');\n if (selectionBehavior === 'replace') {\n await this.user.keyboard(`[/${altKey}]`);\n }\n return;\n }\n if (rowCheckbox && checkboxSelection) {\n await pressElement(this.user, rowCheckbox, interactionType);\n } else {\n let cell = within(row).getAllByRole('gridcell')[0];\n if (needsLongPress && interactionType === 'touch') {\n // Note that long press interactions with rows is strictly touch only for grid rows\n await triggerLongPress({\n element: cell,\n advanceTimer: this._advanceTimer!,\n pointerOpts: {pointerType: 'touch'}\n });\n } else {\n if (selectionBehavior === 'replace' && interactionType !== 'touch') {\n await this.user.keyboard(`[${metaKey}>]`);\n }\n await pressElement(this.user, row, interactionType);\n if (selectionBehavior === 'replace' && interactionType !== 'touch') {\n await this.user.keyboard(`[/${metaKey}]`);\n }\n }\n }\n }\n\n /**\n * Toggles the expansion for the specified tree row. Defaults to using the interaction type set on\n * the tree tester.\n */\n async toggleRowExpansion(opts: TreeToggleExpansionOpts): Promise<void> {\n let {row, interactionType = this._interactionType} = opts;\n if (!this.getTree().contains(document.activeElement)) {\n act(() => this.getTree().focus());\n }\n\n if (typeof row === 'string' || typeof row === 'number') {\n row = this.findRow({indexOrText: row});\n }\n\n if (!row) {\n throw new Error(`Target row \"${formatTargetNode(opts.row)}\" not found in the tree.`);\n } else if (row.getAttribute('aria-expanded') == null) {\n throw new Error(`Target row \"${formatTargetNode(opts.row)}\" is not expandable.`);\n }\n\n if (row.getAttribute('aria-disabled') === 'true') {\n throw new Error(`Cannot toggle expansion on disabled row \"${formatTargetNode(opts.row)}\".`);\n }\n\n if (interactionType === 'mouse' || interactionType === 'touch') {\n let rowExpander = within(row).getAllByRole('button')[0]; // what happens if the button is not first? how can we differentiate?\n await pressElement(this.user, rowExpander, interactionType);\n } else if (interactionType === 'keyboard') {\n await this.keyboardNavigateToRow({row});\n let collapseKey = this._direction === 'rtl' ? 'ArrowRight' : 'ArrowLeft';\n let expandKey = this._direction === 'rtl' ? 'ArrowLeft' : 'ArrowRight';\n if (row.getAttribute('aria-expanded') === 'true') {\n await this.user.keyboard(`[${collapseKey}]`);\n } else {\n await this.user.keyboard(`[${expandKey}]`);\n }\n }\n }\n\n /**\n * Triggers the action for the specified tree row. Defaults to using the interaction type set on\n * the tree tester.\n */\n async triggerRowAction(opts: TreeRowActionOpts): Promise<void> {\n let {row, needsDoubleClick, interactionType = this._interactionType} = opts;\n\n if (typeof row === 'string' || typeof row === 'number') {\n row = this.findRow({indexOrText: row});\n }\n\n if (!row) {\n throw new Error(`Target row \"${formatTargetNode(opts.row)}\" not found in the tree.`);\n }\n\n if (row.getAttribute('aria-disabled') === 'true') {\n throw new Error(`Cannot trigger row action on disabled row \"${formatTargetNode(opts.row)}\".`);\n }\n\n if (needsDoubleClick) {\n await this.user.dblClick(row);\n } else if (interactionType === 'keyboard') {\n await this.keyboardNavigateToRow({row});\n await this.user.keyboard('[Enter]');\n } else {\n await pressElement(this.user, row, interactionType);\n }\n }\n\n /**\n * Returns the tree.\n */\n getTree(): HTMLElement {\n return this._tree;\n }\n\n /**\n * Returns the tree's rows if any.\n */\n getRows(): HTMLElement[] {\n return within(this.getTree()).queryAllByRole('row');\n }\n\n /**\n * Returns the tree's selected rows if any.\n */\n getSelectedRows(): HTMLElement[] {\n return this.getRows().filter(row => row.getAttribute('aria-selected') === 'true');\n }\n\n /**\n * Returns the tree's cells if any. Can be filtered against a specific row if provided via\n * `element`.\n */\n getCells(opts: {element?: HTMLElement} = {}): HTMLElement[] {\n let {element = this.getTree()} = opts;\n return within(element).queryAllByRole('gridcell');\n }\n}\n"],"names":[],"version":3,"file":"tree.cjs.map"}
|