@vuu-ui/vuu-playwright-helpers 4.0.0-beta.6 → 4.0.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 +91 -2
- package/package.json +2 -2
- package/src/PwChart.js +77 -0
- package/src/PwChartDataPoint.js +61 -0
- package/src/PwColumnPicker.js +44 -0
- package/src/PwComponent.js +29 -0
- package/src/PwContextMenu.js +53 -0
- package/src/PwMenuItem.js +58 -0
- package/src/PwTable.js +105 -34
- package/src/PwTableFooter.js +16 -0
- package/src/PwTableHeaderCell.js +15 -7
- package/src/index.js +7 -0
- package/src/selector-utils.js +7 -0
- package/types/PwChart.d.ts +124 -0
- package/types/PwChartDataPoint.d.ts +116 -0
- package/types/PwColumnPicker.d.ts +116 -0
- package/types/PwComponent.d.ts +88 -0
- package/types/PwContextMenu.d.ts +173 -0
- package/types/PwMenuItem.d.ts +196 -0
- package/types/PwTable.d.ts +374 -15
- package/types/PwTableFooter.d.ts +40 -0
- package/types/PwTableHeaderCell.d.ts +51 -4
- package/types/index.d.ts +8 -1
- package/types/selector-utils.d.ts +3 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { type Locator } from "@playwright/test";
|
|
2
|
+
import { PwComponent } from "./PwComponent";
|
|
3
|
+
import { PwContextMenu } from "./PwContextMenu";
|
|
4
|
+
/**
|
|
5
|
+
* A single item within a PwContextMenu. Usually obtained from
|
|
6
|
+
* PwContextMenu.menuItem rather than constructed directly.
|
|
7
|
+
*
|
|
8
|
+
* The boolean query methods (hasChildren, isDisabled, hasIcon etc) read the
|
|
9
|
+
* current state and do not retry. For state that changes after an action, use
|
|
10
|
+
* a web-first assertion on `locator`, e.g.
|
|
11
|
+
* `await expect(item.locator).toHaveAttribute("aria-expanded", "true")`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* test("menu item state", async ({ page }) => {
|
|
15
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
16
|
+
* const item = menu.menuItem("Copy text");
|
|
17
|
+
* expect(await item.isEnabled()).toBe(true);
|
|
18
|
+
* expect(await item.hasIcon("edit")).toBe(true);
|
|
19
|
+
* await item.click();
|
|
20
|
+
* });
|
|
21
|
+
*/
|
|
22
|
+
export declare class PwMenuItem extends PwComponent {
|
|
23
|
+
protected readonly defaultCssSelector = "[role=\"menuitem\"]";
|
|
24
|
+
/**
|
|
25
|
+
* The text label of the menu item.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* test("second item is Filter", async ({ page }) => {
|
|
29
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
30
|
+
* expect(await menu.menuItem(1).label()).toEqual("Filter");
|
|
31
|
+
* });
|
|
32
|
+
*/
|
|
33
|
+
label(): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Does this menu item open a sub menu (aria-haspopup="menu").
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* test("Filter has a sub menu", async ({ page }) => {
|
|
39
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
40
|
+
* expect(await menu.menuItem("Filter").hasChildren()).toBe(true);
|
|
41
|
+
* expect(await menu.menuItem("Copy text").hasChildren()).toBe(false);
|
|
42
|
+
* });
|
|
43
|
+
*/
|
|
44
|
+
hasChildren(): Promise<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* Is the menu item disabled (aria-disabled="true"). Disabled items cannot be
|
|
47
|
+
* clicked and are skipped by keyboard navigation.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* test("Delete row is disabled", async ({ page }) => {
|
|
51
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
52
|
+
* expect(await menu.menuItem("Delete row").isDisabled()).toBe(true);
|
|
53
|
+
* });
|
|
54
|
+
*/
|
|
55
|
+
isDisabled(): Promise<boolean>;
|
|
56
|
+
/**
|
|
57
|
+
* Is the menu item enabled. The inverse of isDisabled.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* test("Copy text is enabled", async ({ page }) => {
|
|
61
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
62
|
+
* expect(await menu.menuItem("Copy text").isEnabled()).toBe(true);
|
|
63
|
+
* });
|
|
64
|
+
*/
|
|
65
|
+
isEnabled(): Promise<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* Is the sub menu of this menu item open (aria-expanded="true"). Always
|
|
68
|
+
* false for leaf items.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* test("Filter expands on hover", async ({ page }) => {
|
|
72
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
73
|
+
* const filter = menu.menuItem("Filter");
|
|
74
|
+
* expect(await filter.isExpanded()).toBe(false);
|
|
75
|
+
* await filter.openSubMenu();
|
|
76
|
+
* expect(await filter.isExpanded()).toBe(true);
|
|
77
|
+
* });
|
|
78
|
+
*/
|
|
79
|
+
isExpanded(): Promise<boolean>;
|
|
80
|
+
/**
|
|
81
|
+
* Does the menu item have DOM focus. Does not wait or retry, prefer
|
|
82
|
+
* PwContextMenu.assertFocusedMenuItem after a key press.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* test("Copy text focused", async ({ page }) => {
|
|
86
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
87
|
+
* await menu.press("ArrowDown");
|
|
88
|
+
* await menu.assertFocusedMenuItem("Copy text");
|
|
89
|
+
* expect(await menu.menuItem("Copy text").isFocused()).toBe(true);
|
|
90
|
+
* });
|
|
91
|
+
*/
|
|
92
|
+
isFocused(): Promise<boolean>;
|
|
93
|
+
/**
|
|
94
|
+
* Is the menu item decorated with the given icon (data-icon attribute).
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* test("Copy text has edit icon", async ({ page }) => {
|
|
98
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
99
|
+
* expect(await menu.menuItem("Copy text").hasIcon("edit")).toBe(true);
|
|
100
|
+
* });
|
|
101
|
+
*/
|
|
102
|
+
hasIcon(iconName: string): Promise<boolean>;
|
|
103
|
+
/**
|
|
104
|
+
* Click the menu item. Playwright will not click a disabled item unless
|
|
105
|
+
* { force: true } is passed.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* test("click invokes menu action", async ({ page }) => {
|
|
109
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
110
|
+
* await menu.menuItem("Copy text").click();
|
|
111
|
+
* await menu.assertNotAttached();
|
|
112
|
+
* });
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* test("clicking disabled item does nothing", async ({ page }) => {
|
|
116
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
117
|
+
* await menu.menuItem("Delete row").click({ force: true });
|
|
118
|
+
* await menu.assertVisible();
|
|
119
|
+
* });
|
|
120
|
+
*/
|
|
121
|
+
click(options?: Parameters<Locator["click"]>[0]): Promise<void>;
|
|
122
|
+
/**
|
|
123
|
+
* Hover over the menu item. Hovering an item with children opens its sub
|
|
124
|
+
* menu, use openSubMenu to also wait for the sub menu.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* test("hover expands Filter", async ({ page }) => {
|
|
128
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
129
|
+
* const filter = menu.menuItem("Filter");
|
|
130
|
+
* await filter.hover();
|
|
131
|
+
* await expect(filter.locator).toHaveAttribute("aria-expanded", "true");
|
|
132
|
+
* });
|
|
133
|
+
*/
|
|
134
|
+
hover(): Promise<void>;
|
|
135
|
+
/**
|
|
136
|
+
* Give the menu item DOM focus.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* test("focus Sort then open with keyboard", async ({ page }) => {
|
|
140
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
141
|
+
* const sort = menu.menuItem("Sort");
|
|
142
|
+
* await sort.focus();
|
|
143
|
+
* await sort.press("ArrowRight");
|
|
144
|
+
* await expect(sort.locator).toHaveAttribute("aria-expanded", "true");
|
|
145
|
+
* });
|
|
146
|
+
*/
|
|
147
|
+
focus(): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Press a key with the menu item as target. Focuses the item first.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* test("Enter on item invokes action", async ({ page }) => {
|
|
153
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
154
|
+
* await menu.menuItem("Copy text").press("Enter");
|
|
155
|
+
* await menu.assertNotAttached();
|
|
156
|
+
* });
|
|
157
|
+
*/
|
|
158
|
+
press(key: string): Promise<void>;
|
|
159
|
+
/**
|
|
160
|
+
* The sub menu opened by this menu item. The sub menu must already be open,
|
|
161
|
+
* use openSubMenu to open it.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* test("sub menu opened by hover", async ({ page }) => {
|
|
165
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
166
|
+
* const filter = menu.menuItem("Filter");
|
|
167
|
+
* await filter.hover();
|
|
168
|
+
* const filterMenu = await filter.subMenu();
|
|
169
|
+
* expect(await filterMenu.hasMenuItems()).toBe(true);
|
|
170
|
+
* });
|
|
171
|
+
*/
|
|
172
|
+
subMenu(): Promise<PwContextMenu>;
|
|
173
|
+
/**
|
|
174
|
+
* Open the sub menu of this menu item, using the mouse (hover) or keyboard
|
|
175
|
+
* (ArrowRight). Resolves once the sub menu is visible and, when opened with
|
|
176
|
+
* the keyboard, once focus has moved into the sub menu.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* test("open sub menu with mouse", async ({ page }) => {
|
|
180
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
181
|
+
* const filterMenu = await menu.menuItem("Filter").openSubMenu();
|
|
182
|
+
* await filterMenu.menuItem("Include value").click();
|
|
183
|
+
* await menu.assertNotAttached();
|
|
184
|
+
* });
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* test("open sub menu with keyboard", async ({ page }) => {
|
|
188
|
+
* const menu = await new PwTable(page).showContextMenu("ric", 2);
|
|
189
|
+
* const sortMenu = await menu.menuItem("Sort").openSubMenu("keyboard");
|
|
190
|
+
* await sortMenu.assertFocusedMenuItem("Ascending");
|
|
191
|
+
* await sortMenu.press("ArrowLeft");
|
|
192
|
+
* await sortMenu.assertNotAttached();
|
|
193
|
+
* });
|
|
194
|
+
*/
|
|
195
|
+
openSubMenu(using?: "mouse" | "keyboard"): Promise<PwContextMenu>;
|
|
196
|
+
}
|
package/types/PwTable.d.ts
CHANGED
|
@@ -1,27 +1,170 @@
|
|
|
1
|
-
import { type Locator
|
|
1
|
+
import { type Locator } from "@playwright/test";
|
|
2
2
|
import type { VuuRange } from "@vuu-ui/vuu-protocol-types";
|
|
3
|
-
import {
|
|
3
|
+
import { PwComponent } from "./PwComponent";
|
|
4
|
+
import { PwContextMenu } from "./PwContextMenu";
|
|
4
5
|
import { PwTableHeaderCell } from "./PwTableHeaderCell";
|
|
5
6
|
type AriaRole = "cell" | "textbox" | "combobox";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* How far to scroll: 'start' or 'end' scroll to that end of the axis, a number
|
|
9
|
+
* scrolls by that many pixels in the direction of the method.
|
|
10
|
+
*/
|
|
11
|
+
export type ScrollDistance = "start" | "end" | number;
|
|
12
|
+
/**
|
|
13
|
+
* As ScrollDistance, plus 'page' to scroll vertically by the height of the
|
|
14
|
+
* viewport (as the PageUp and PageDown keys do).
|
|
15
|
+
*/
|
|
16
|
+
export type VerticalScrollDistance = ScrollDistance | "page";
|
|
17
|
+
export interface ScrollPosition {
|
|
18
|
+
scrollLeft: number;
|
|
19
|
+
scrollTop: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A Vuu Table. Rows are located by 1-based aria row index, which includes
|
|
23
|
+
* header rows (with one header, the first data row is 2).
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* test("table renders instruments", async ({ mount, page }) => {
|
|
27
|
+
* await mount("Table/ContextMenu/LocalContextMenu");
|
|
28
|
+
* const table = new PwTable(page);
|
|
29
|
+
* await table.assertVisible();
|
|
30
|
+
* await expect(await table.cell("ric", 2)).toHaveText("AAOO.L");
|
|
31
|
+
* });
|
|
32
|
+
*/
|
|
33
|
+
export declare class PwTable extends PwComponent {
|
|
9
34
|
protected readonly defaultCssSelector = ".vuuTable";
|
|
10
35
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
36
|
+
* Locator for the scrollable content container (the rendered rows).
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* test("rows are zebra striped", async ({ page }) => {
|
|
40
|
+
* const table = new PwTable(page);
|
|
41
|
+
* await expect(table.contentContainer).toContainClass("vuuTable-zebra");
|
|
42
|
+
* });
|
|
13
43
|
*/
|
|
14
|
-
constructor(page: Page, cssSelector?: string | undefined);
|
|
15
44
|
get contentContainer(): Locator;
|
|
45
|
+
/**
|
|
46
|
+
* Locator for the scrollbar container, the element that scrolls.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* test("scrolls vertically", async ({ page }) => {
|
|
50
|
+
* const table = new PwTable(page);
|
|
51
|
+
* await table.scrollbarContainer.evaluate((el) => el.scrollTo(0, 1000));
|
|
52
|
+
* await expect(table.row(2)).not.toBeInViewport();
|
|
53
|
+
* });
|
|
54
|
+
*/
|
|
16
55
|
get scrollbarContainer(): Locator;
|
|
17
56
|
/**
|
|
18
|
-
*
|
|
57
|
+
* The scroll position of the scrollbar container.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* test("scrolled to top", async ({ page }) => {
|
|
61
|
+
* const table = new PwTable(page);
|
|
62
|
+
* expect((await table.scrollPosition()).scrollTop).toBe(0);
|
|
63
|
+
* });
|
|
64
|
+
*/
|
|
65
|
+
scrollPosition(): Promise<ScrollPosition>;
|
|
66
|
+
/**
|
|
67
|
+
* Scroll up, by a number of pixels, a page (the height of the viewport), or
|
|
68
|
+
* to the 'start' (top) or 'end' (bottom). Scrolls the scrollbar container,
|
|
69
|
+
* as a user dragging the scrollbar would, and resolves once the content
|
|
70
|
+
* container has been scrolled to match.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* test("scroll back to top", async ({ page }) => {
|
|
74
|
+
* const table = new PwTable(page);
|
|
75
|
+
* await table.scrollDown("page");
|
|
76
|
+
* await table.scrollUp("start");
|
|
77
|
+
* await expect(table.row(2)).toBeInViewport();
|
|
78
|
+
* });
|
|
79
|
+
*/
|
|
80
|
+
scrollUp(distance: VerticalScrollDistance): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Scroll down, by a number of pixels, a page (the height of the viewport),
|
|
83
|
+
* or to the 'start' (top) or 'end' (bottom). Scrolls the scrollbar
|
|
84
|
+
* container, as a user dragging the scrollbar would, and resolves once the
|
|
85
|
+
* content container has been scrolled to match.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* test("scroll to last row", async ({ page }) => {
|
|
89
|
+
* const table = new PwTable(page);
|
|
90
|
+
* await table.scrollDown("end");
|
|
91
|
+
* await expect(table.row(1001)).toBeInViewport();
|
|
92
|
+
* });
|
|
93
|
+
*/
|
|
94
|
+
scrollDown(distance: VerticalScrollDistance): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Scroll left, by a number of pixels, or to the 'start' (leftmost) or 'end'
|
|
97
|
+
* (rightmost). Scrolls the scrollbar container, as a user dragging the
|
|
98
|
+
* scrollbar would, and resolves once the content container has been
|
|
99
|
+
* scrolled to match.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* test("scroll back to first column", async ({ page }) => {
|
|
103
|
+
* const table = new PwTable(page);
|
|
104
|
+
* await table.scrollRight("end");
|
|
105
|
+
* await table.scrollLeft("start");
|
|
106
|
+
* await expect(table.locateCell(2, 1)).toBeInViewport();
|
|
107
|
+
* });
|
|
108
|
+
*/
|
|
109
|
+
scrollLeft(distance: ScrollDistance): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* Scroll right, by a number of pixels, or to the 'start' (leftmost) or
|
|
112
|
+
* 'end' (rightmost). Scrolls the scrollbar container, as a user dragging the
|
|
113
|
+
* scrollbar would, and resolves once the content container has been
|
|
114
|
+
* scrolled to match.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* test("scroll right by 200px", async ({ page }) => {
|
|
118
|
+
* const table = new PwTable(page);
|
|
119
|
+
* await table.scrollRight(200);
|
|
120
|
+
* expect((await table.scrollPosition()).scrollLeft).toBe(200);
|
|
121
|
+
* });
|
|
122
|
+
*/
|
|
123
|
+
scrollRight(distance: ScrollDistance): Promise<void>;
|
|
124
|
+
private scroll;
|
|
125
|
+
/**
|
|
126
|
+
* The table keeps the content container at the same proportional scroll
|
|
127
|
+
* position as the scrollbar container.
|
|
128
|
+
*/
|
|
129
|
+
private isContentScrollSynced;
|
|
130
|
+
/**
|
|
131
|
+
* Row Locator by 1-based aria row index, including headers.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* test("first data row is selected", async ({ page }) => {
|
|
135
|
+
* const table = new PwTable(page);
|
|
136
|
+
* await (await table.cell("ric", 2)).click();
|
|
137
|
+
* await expect(table.row(2)).toHaveAttribute("aria-selected", "true");
|
|
138
|
+
* });
|
|
19
139
|
*/
|
|
20
140
|
row(row: number): Locator;
|
|
21
141
|
/**
|
|
22
142
|
* Locate cell by column name and 1-based aria row index, including headers.
|
|
143
|
+
* Preferred over locateCell for new usage.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* test("first ric", async ({ page }) => {
|
|
147
|
+
* const table = new PwTable(page);
|
|
148
|
+
* await expect(await table.cell("ric", 2)).toHaveText("AAOO.L");
|
|
149
|
+
* });
|
|
23
150
|
*/
|
|
24
151
|
cell(colName: string, ariaRowIndex: number): Promise<Locator>;
|
|
152
|
+
/**
|
|
153
|
+
* Double click a cell to edit it, fill the editor with value, then commit
|
|
154
|
+
* (Enter) or cancel (Escape) the edit.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* test("edit bbg", async ({ mount, page }) => {
|
|
158
|
+
* await mount("Table/Editing/EditableInstrumentsInlineEdit");
|
|
159
|
+
* await page.getByRole("radio", { name: "Edit" }).click();
|
|
160
|
+
* const table = new PwTable(page);
|
|
161
|
+
* const textbox = (await table.cell("bbg", 2)).getByRole("textbox");
|
|
162
|
+
* await table.editCell("bbg", 2, "X", "cancel");
|
|
163
|
+
* await expect(textbox).not.toHaveValue("X");
|
|
164
|
+
* await table.editCell("bbg", 2, "X");
|
|
165
|
+
* await expect(textbox).toHaveValue("X");
|
|
166
|
+
* });
|
|
167
|
+
*/
|
|
25
168
|
editCell(columnName: string, ariaRowIndex: number, value: string, action?: "commit" | "cancel"): Promise<void>;
|
|
26
169
|
/**
|
|
27
170
|
* The labels displayed in the column headers, in rendered order.
|
|
@@ -34,6 +177,28 @@ export declare class PwTable extends PlaywrightPageObject {
|
|
|
34
177
|
* });
|
|
35
178
|
*/
|
|
36
179
|
columnNames(): Promise<string[]>;
|
|
180
|
+
/**
|
|
181
|
+
* The names (not labels) of the columns in the table, from the
|
|
182
|
+
* data-column-name of the header cells, in rendered order.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* test("renders expected columns", async ({ page }) => {
|
|
186
|
+
* const table = new PwTable(page);
|
|
187
|
+
* expect(await table.headerColumnNames()).toEqual(["ccy", "exchange"]);
|
|
188
|
+
* });
|
|
189
|
+
*/
|
|
190
|
+
headerColumnNames(): Promise<string[]>;
|
|
191
|
+
/**
|
|
192
|
+
* Assert the names (not labels) of the columns in the table, in order,
|
|
193
|
+
* retrying until the expect timeout.
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* test("column added", async ({ page }) => {
|
|
197
|
+
* const table = new PwTable(page);
|
|
198
|
+
* await table.assertColumns(["ccy", "exchange", "lotSize"]);
|
|
199
|
+
* });
|
|
200
|
+
*/
|
|
201
|
+
assertColumns(columnNames: string[]): Promise<void>;
|
|
37
202
|
/**
|
|
38
203
|
* The total row count, read from aria-rowcount on the element with role="table".
|
|
39
204
|
* This is the dataSource size, not the number of rendered rows.
|
|
@@ -45,6 +210,32 @@ export declare class PwTable extends PlaywrightPageObject {
|
|
|
45
210
|
* });
|
|
46
211
|
*/
|
|
47
212
|
rowCount(): Promise<number>;
|
|
213
|
+
/**
|
|
214
|
+
* Wait until the table has loaded data, i.e. rowCount is greater than zero.
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* test("table loads", async ({ mount, page }) => {
|
|
218
|
+
* await mount("Filters/FilterContainer/FilterContainerWithTable");
|
|
219
|
+
* const table = new PwTable(page);
|
|
220
|
+
* await table.dataLoaded;
|
|
221
|
+
* });
|
|
222
|
+
*/
|
|
223
|
+
get dataLoaded(): Promise<void>;
|
|
224
|
+
/**
|
|
225
|
+
* The text content of the data cells in a column, exactly as formatted in
|
|
226
|
+
* the table, in row order. These are the cells in data rows with the same
|
|
227
|
+
* aria-colindex as the column header. The table is virtualised, so only
|
|
228
|
+
* rendered rows are included.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* test("filter on currency", async ({ page }) => {
|
|
232
|
+
* const table = new PwTable(page);
|
|
233
|
+
* await expect
|
|
234
|
+
* .poll(async () => new Set(await table.columnValues("currency")))
|
|
235
|
+
* .toEqual(new Set(["GBP"]));
|
|
236
|
+
* });
|
|
237
|
+
*/
|
|
238
|
+
columnValues(columnName: string): Promise<string[]>;
|
|
48
239
|
/**
|
|
49
240
|
* Locate the icon with the given data-icon name within a cell.
|
|
50
241
|
*
|
|
@@ -66,34 +257,202 @@ export declare class PwTable extends PlaywrightPageObject {
|
|
|
66
257
|
* });
|
|
67
258
|
*/
|
|
68
259
|
cellsWithIcon(iconName: string): Locator;
|
|
260
|
+
/**
|
|
261
|
+
* The column header cell for the named column.
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* test("currency column not selected", async ({ page }) => {
|
|
265
|
+
* const table = new PwTable(page);
|
|
266
|
+
* expect(await table.headerCell("currency").isSelected).toBe(false);
|
|
267
|
+
* });
|
|
268
|
+
*/
|
|
69
269
|
headerCell(columnName: string): PwTableHeaderCell;
|
|
70
270
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
271
|
+
* Right click a cell to invoke the context menu. Resolves once the menu is
|
|
272
|
+
* visible and has focus, so keyboard navigation can begin immediately.
|
|
273
|
+
* Waits until the test timeout if no context menu is shown, use
|
|
274
|
+
* assertNoContextMenu to test for that.
|
|
275
|
+
*
|
|
276
|
+
* @param columnName name of the column
|
|
277
|
+
* @param ariaRowIndex 1-based aria row index, including headers (with one header, the first data row is 2)
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* test("shows cell menu", async ({ page }) => {
|
|
281
|
+
* const table = new PwTable(page);
|
|
282
|
+
* const menu = await table.showContextMenu("ric", 2);
|
|
283
|
+
* expect(await menu.menuItem("Copy text").isEnabled()).toBe(true);
|
|
284
|
+
* });
|
|
285
|
+
*/
|
|
286
|
+
showContextMenu(columnName: string, ariaRowIndex: number): Promise<PwContextMenu>;
|
|
287
|
+
/**
|
|
288
|
+
* Right click a cell and assert that no context menu is shown and the cell
|
|
289
|
+
* is not marked as having an open context menu.
|
|
290
|
+
*
|
|
291
|
+
* A negative assertion passes as soon as the menu is absent, which may be
|
|
292
|
+
* before a menu would have rendered. To avoid false passes we wait for two
|
|
293
|
+
* animation frames after the right click, allowing React to commit and the
|
|
294
|
+
* menu to be positioned, before asserting.
|
|
295
|
+
*
|
|
296
|
+
* @param columnName name of the column
|
|
297
|
+
* @param ariaRowIndex 1-based aria row index, including headers (with one header, the first data row is 2)
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* test("no menu when none configured", async ({ page }) => {
|
|
301
|
+
* const table = new PwTable(page);
|
|
302
|
+
* await table.assertNoContextMenu("ccy", 2);
|
|
303
|
+
* });
|
|
304
|
+
*/
|
|
305
|
+
assertNoContextMenu(columnName: string, ariaRowIndex: number): Promise<void>;
|
|
306
|
+
/**
|
|
307
|
+
* Locate cell(s) by accessible name (cell contents). May match several cells.
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* test("right click ric", async ({ page }) => {
|
|
311
|
+
* const table = new PwTable(page);
|
|
312
|
+
* await table.locateCell("AAOP N").click({ button: "right" });
|
|
313
|
+
* });
|
|
73
314
|
*/
|
|
74
315
|
locateCell(text: string): Locator;
|
|
75
316
|
/**
|
|
76
|
-
* Locate cell by aria row index and aria col index
|
|
77
|
-
*
|
|
317
|
+
* Locate cell by 1-based aria row index and 1-based aria col index.
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* test("down arrow from header focuses first cell", async ({ page }) => {
|
|
321
|
+
* const table = new PwTable(page);
|
|
322
|
+
* await table.locateColumnHeader(1).press("ArrowDown");
|
|
323
|
+
* await expect(table.locateCell(2, 1)).toBeFocused();
|
|
324
|
+
* });
|
|
78
325
|
*/
|
|
79
326
|
locateCell(row: number, column: number): Locator;
|
|
80
327
|
/**
|
|
81
|
-
* Locate cell by aria row index and column name
|
|
328
|
+
* Locate cell by 1-based aria row index and column name. Prefer cell(columnName, ariaRowIndex).
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* test("first ric", async ({ page }) => {
|
|
332
|
+
* const table = new PwTable(page);
|
|
333
|
+
* await expect(await table.locateCell(2, "ric")).toHaveText("AAOO.L");
|
|
334
|
+
* });
|
|
82
335
|
*/
|
|
83
336
|
locateCell(row: number, columnName: string): Promise<Locator>;
|
|
337
|
+
/**
|
|
338
|
+
* Locate a column header cell by 1-based aria col index.
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* test("click header focuses it", async ({ page }) => {
|
|
342
|
+
* const table = new PwTable(page);
|
|
343
|
+
* const header = table.locateColumnHeader(1);
|
|
344
|
+
* await header.click();
|
|
345
|
+
* await expect(header).toBeFocused();
|
|
346
|
+
* });
|
|
347
|
+
*/
|
|
84
348
|
locateColumnHeader(column: number): Locator;
|
|
349
|
+
/**
|
|
350
|
+
* When isEditable is true, assert the cell is editable but not currently in
|
|
351
|
+
* edit mode and, if value is passed, that its textbox has that value. When
|
|
352
|
+
* isEditable is false or undefined, nothing is asserted.
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* test("first cell is editable", async ({ mount, page }) => {
|
|
356
|
+
* await mount("Table/Editing/EditableInstruments");
|
|
357
|
+
* await page.getByRole("radio", { name: "Edit" }).click();
|
|
358
|
+
* const table = new PwTable(page);
|
|
359
|
+
* await table.assertCellIsEditable(2, 1, true, "AAOO L");
|
|
360
|
+
* });
|
|
361
|
+
*/
|
|
85
362
|
assertCellIsEditable(row: number, column: number, isEditable: boolean | undefined, value?: string): Promise<void>;
|
|
86
|
-
assertVisible(): Promise<void>;
|
|
87
363
|
private getCellText;
|
|
364
|
+
/**
|
|
365
|
+
* Assert the value of a cell input (toHaveValue). Pass a role to target an
|
|
366
|
+
* element within the cell, e.g. "textbox" for an editable cell.
|
|
367
|
+
*
|
|
368
|
+
* @example
|
|
369
|
+
* test("editable cell value", async ({ mount, page }) => {
|
|
370
|
+
* await mount("Table/Editing/EditableInstruments");
|
|
371
|
+
* await page.getByRole("radio", { name: "Edit" }).click();
|
|
372
|
+
* const table = new PwTable(page);
|
|
373
|
+
* await table.assertCellValue(2, 1, "AAOO L", "textbox");
|
|
374
|
+
* await table.assertCellValue(table.locateCell(2, 1), "AAOO L", "textbox");
|
|
375
|
+
* });
|
|
376
|
+
*/
|
|
88
377
|
assertCellValue(cell: Locator, text: string, role?: AriaRole): Promise<void>;
|
|
89
378
|
assertCellValue(row: number, column: number, text: string, role?: AriaRole): Promise<void>;
|
|
379
|
+
/**
|
|
380
|
+
* Assert the text content of a cell (toHaveText). Pass a role to target an
|
|
381
|
+
* element within the cell, e.g. "combobox" for a dropdown cell.
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* test("first cell text", async ({ page }) => {
|
|
385
|
+
* const table = new PwTable(page);
|
|
386
|
+
* await table.assertCellContent(2, 1, "AAOO L");
|
|
387
|
+
* await table.assertCellContent(table.locateCell(2, 1), "AAOO L");
|
|
388
|
+
* });
|
|
389
|
+
*/
|
|
90
390
|
assertCellContent(cell: Locator, text: string, role?: AriaRole): Promise<void>;
|
|
91
391
|
assertCellContent(row: number, column: number, text: string, role?: AriaRole): Promise<void>;
|
|
392
|
+
/**
|
|
393
|
+
* Assert a cell, or an element within it with the given role, is focused.
|
|
394
|
+
*
|
|
395
|
+
* @example
|
|
396
|
+
* test("click focuses editable cell", async ({ mount, page }) => {
|
|
397
|
+
* await mount("Table/Editing/EditableInstruments");
|
|
398
|
+
* await page.getByRole("radio", { name: "Edit" }).click();
|
|
399
|
+
* const table = new PwTable(page);
|
|
400
|
+
* const cell = table.locateCell(3, 3);
|
|
401
|
+
* await cell.click();
|
|
402
|
+
* await table.assertCellIsFocused(cell, "textbox");
|
|
403
|
+
* await table.assertCellIsFocused(3, 3, "textbox");
|
|
404
|
+
* });
|
|
405
|
+
*/
|
|
92
406
|
assertCellIsFocused(cell: Locator, role?: AriaRole): Promise<void>;
|
|
93
407
|
assertCellIsFocused(row: number, column: number, role?: AriaRole): Promise<void>;
|
|
408
|
+
/**
|
|
409
|
+
* Assert a cell is (default) or is not in edit mode.
|
|
410
|
+
*
|
|
411
|
+
* @example
|
|
412
|
+
* test("Enter starts editing, Escape stops", async ({ mount, page }) => {
|
|
413
|
+
* await mount("Table/Editing/EditableInstruments");
|
|
414
|
+
* await page.getByRole("radio", { name: "Edit" }).click();
|
|
415
|
+
* const table = new PwTable(page);
|
|
416
|
+
* const cell = table.locateCell(3, 3);
|
|
417
|
+
* await cell.click();
|
|
418
|
+
* await cell.press("Enter");
|
|
419
|
+
* await table.assertCellIsEditing(cell);
|
|
420
|
+
* await cell.press("Escape");
|
|
421
|
+
* await table.assertCellIsEditing(cell, false);
|
|
422
|
+
* });
|
|
423
|
+
*/
|
|
94
424
|
assertCellIsEditing(cell: Locator, isEditing?: boolean): Promise<void>;
|
|
95
425
|
assertCellIsEditing(row: number, column: number, isEditing?: boolean): Promise<void>;
|
|
426
|
+
/**
|
|
427
|
+
* Assert which rows are rendered, given the visible range of data rows.
|
|
428
|
+
* Checks the rendered row count includes the leading and trailing buffers
|
|
429
|
+
* and that buffered rows beyond the viewport are not in view.
|
|
430
|
+
*
|
|
431
|
+
* @param range the visible range of (0-based) data rows
|
|
432
|
+
* @param renderBufferSize number of rows rendered beyond each end of the viewport
|
|
433
|
+
* @param totalRowCount size of the dataSource
|
|
434
|
+
* @param headerCount number of header rows, default 1
|
|
435
|
+
*
|
|
436
|
+
* @example
|
|
437
|
+
* test("initial render", async ({ page }) => {
|
|
438
|
+
* const table = new PwTable(page);
|
|
439
|
+
* await table.assertRenderedRows({ from: 0, to: 30 }, 5, 1000);
|
|
440
|
+
* });
|
|
441
|
+
*/
|
|
96
442
|
assertRenderedRows({ from, to }: VuuRange, renderBufferSize: number, totalRowCount: number, headerCount?: number): Promise<void>;
|
|
443
|
+
/**
|
|
444
|
+
* Assert which columns are rendered and which are in the viewport, checked
|
|
445
|
+
* against the first data row. Ranges are inclusive, 1-based aria col indexes.
|
|
446
|
+
*
|
|
447
|
+
* @example
|
|
448
|
+
* test("column virtualization", async ({ page }) => {
|
|
449
|
+
* const table = new PwTable(page);
|
|
450
|
+
* await table.assertRenderedColumns({
|
|
451
|
+
* rendered: { from: 1, to: 8 },
|
|
452
|
+
* visible: { from: 1, to: 6 },
|
|
453
|
+
* });
|
|
454
|
+
* });
|
|
455
|
+
*/
|
|
97
456
|
assertRenderedColumns({ rendered, visible, }: {
|
|
98
457
|
rendered: VuuRange;
|
|
99
458
|
visible: VuuRange;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Locator } from "@playwright/test";
|
|
2
|
+
import { PwColumnPicker } from "./PwColumnPicker";
|
|
3
|
+
import { PwComponent } from "./PwComponent";
|
|
4
|
+
/**
|
|
5
|
+
* A TableFooter, usually rendered below a Table. Holds DataSourceStats and
|
|
6
|
+
* a tray of actions, e.g. the ColumnPickerAction.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* test("footer shows column picker", async ({ page }) => {
|
|
10
|
+
* const footer = new PwTableFooter(page);
|
|
11
|
+
* const picker = await footer.showColumnPicker();
|
|
12
|
+
* await picker.assertVisible();
|
|
13
|
+
* });
|
|
14
|
+
*/
|
|
15
|
+
export declare class PwTableFooter extends PwComponent {
|
|
16
|
+
protected readonly defaultCssSelector = ".vuuTableFooter";
|
|
17
|
+
/**
|
|
18
|
+
* An action button in the footer, by accessible name.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* test("column picker action", async ({ page }) => {
|
|
22
|
+
* const footer = new PwTableFooter(page);
|
|
23
|
+
* await expect(footer.action("Show column picker")).toBeVisible();
|
|
24
|
+
* });
|
|
25
|
+
*/
|
|
26
|
+
action(name: string): Locator;
|
|
27
|
+
/**
|
|
28
|
+
* Click the ColumnPickerAction. Resolves with the ColumnPicker once it is
|
|
29
|
+
* visible.
|
|
30
|
+
*
|
|
31
|
+
* @param name accessible name of the action, if not the default
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* test("open column picker", async ({ page }) => {
|
|
35
|
+
* const picker = await new PwTableFooter(page).showColumnPicker();
|
|
36
|
+
* expect(await picker.selectedColumns()).toContain("bbg");
|
|
37
|
+
* });
|
|
38
|
+
*/
|
|
39
|
+
showColumnPicker(name?: string): Promise<PwColumnPicker>;
|
|
40
|
+
}
|