@vuu-ui/vuu-playwright-helpers 4.0.0-alpha.22 → 4.0.0-alpha.24

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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.0.0-alpha.22",
2
+ "version": "4.0.0-alpha.24",
3
3
  "author": "heswell",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./src/index.js",
@@ -9,7 +9,7 @@
9
9
  "type-defs": "node ../../scripts/build-type-defs.mjs"
10
10
  },
11
11
  "dependencies": {
12
- "@vuu-ui/vuu-protocol-types": "4.0.0-alpha.22"
12
+ "@vuu-ui/vuu-protocol-types": "4.0.0-alpha.24"
13
13
  },
14
14
  "peerDependencies": {
15
15
  "@playwright/test": "^1.62.1"
@@ -0,0 +1,124 @@
1
+ import { type Locator } from "@playwright/test";
2
+ import { PwComponent } from "./PwComponent";
3
+ import { PwContextMenu } from "./PwContextMenu";
4
+ import { PwChartDataPoint } from "./PwChartDataPoint";
5
+ /**
6
+ * A Vuu Chart (VuuChart, an ECharts line chart). Data points are identified by
7
+ * series name, which is the Vuu column name, and 0 based data index, which is
8
+ * also the index of the category on the x axis.
9
+ *
10
+ * The chart must use the svg renderer for symbol locators (PwChartDataPoint.symbol).
11
+ *
12
+ * @example
13
+ * test("chart renders price and volume", async ({ mount, page }) => {
14
+ * await mount("Chart/LineChart/SimpleLineChart");
15
+ * const chart = await new PwChart(page).isReady();
16
+ * expect(await chart.seriesNames()).toEqual(["price", "volume"]);
17
+ * const point = await chart.dataPoint("price", 0);
18
+ * expect(point.value).toEqual(100);
19
+ * });
20
+ */
21
+ export declare class PwChart extends PwComponent {
22
+ protected readonly defaultCssSelector = ".vuuChart";
23
+ /**
24
+ * Locator for the element that renders the chart. This element receives
25
+ * mouse events and holds the ECharts instance.
26
+ *
27
+ * @example
28
+ * test("chart renders svg", async ({ page }) => {
29
+ * const chart = new PwChart(page);
30
+ * await expect(chart.canvas.locator("svg")).toBeVisible();
31
+ * });
32
+ */
33
+ get canvas(): Locator;
34
+ /**
35
+ * Wait until the chart is visible and has rendered series data. Resolves
36
+ * with the chart, so it can be chained.
37
+ *
38
+ * @example
39
+ * test("chart is ready", async ({ mount, page }) => {
40
+ * await mount("Chart/LineChart/SimpleLineChart");
41
+ * const chart = await new PwChart(page).isReady();
42
+ * expect(await chart.categories()).toHaveLength(25);
43
+ * });
44
+ */
45
+ isReady(options?: {
46
+ timeout?: number;
47
+ }): Promise<this>;
48
+ /**
49
+ * The names of the rendered series, in render order. These are the Vuu
50
+ * column names of the series columns.
51
+ *
52
+ * @example
53
+ * test("price only", async ({ page }) => {
54
+ * await page.getByRole("button", { name: "Price Only" }).click();
55
+ * const chart = await new PwChart(page).isReady();
56
+ * await expect.poll(() => chart.seriesNames()).toEqual(["price"]);
57
+ * });
58
+ */
59
+ seriesNames(): Promise<string[]>;
60
+ /**
61
+ * The category (x axis) values, in order.
62
+ *
63
+ * @example
64
+ * test("first category", async ({ page }) => {
65
+ * const chart = await new PwChart(page).isReady();
66
+ * expect((await chart.categories())[0]).toEqual("2026-04-02");
67
+ * });
68
+ */
69
+ categories(): Promise<string[]>;
70
+ /**
71
+ * Locate a data point by series name and 0 based data index, or by category
72
+ * (x axis) value. Waits for the chart to be ready. Rejects if the series or
73
+ * data point does not exist, or the data point has no value.
74
+ *
75
+ * @param seriesName the series (Vuu column) name
76
+ * @param dataIndexOrCategory 0 based data index, or category value
77
+ *
78
+ * @example
79
+ * test("locate data points", async ({ page }) => {
80
+ * const chart = new PwChart(page);
81
+ * const byIndex = await chart.dataPoint("price", 3);
82
+ * const byCategory = await chart.dataPoint("price", "2026-04-05");
83
+ * expect(byIndex.value).toEqual(byCategory.value);
84
+ * });
85
+ */
86
+ dataPoint(seriesName: string, dataIndexOrCategory: number | string): Promise<PwChartDataPoint>;
87
+ private resolveDataPoint;
88
+ /**
89
+ * Right click a data point to invoke the context menu. Resolves once the
90
+ * menu is visible and has focus. Waits until the test timeout if no context
91
+ * menu is shown, use assertNoContextMenu to test for that.
92
+ *
93
+ * @param seriesName the series (Vuu column) name
94
+ * @param dataIndexOrCategory 0 based data index, or category value
95
+ *
96
+ * @example
97
+ * test("exclude data point", async ({ mount, page }) => {
98
+ * await mount("Chart/LineChart/DataExclusions");
99
+ * const chart = new PwChart(page);
100
+ * const menu = await chart.showContextMenu("price", 3);
101
+ * expect(await menu.hasMenuItems(["Exclude Item"])).toBe(true);
102
+ * await menu.menuItem("Exclude Item").click();
103
+ * await expect
104
+ * .poll(async () => (await chart.dataPoint("price", 3)).isExcluded)
105
+ * .toBe(true);
106
+ * });
107
+ */
108
+ showContextMenu(seriesName: string, dataIndexOrCategory: number | string): Promise<PwContextMenu>;
109
+ /**
110
+ * Right click a data point and assert that no context menu is shown. Waits
111
+ * for the page to render after the right click before asserting, so it
112
+ * cannot pass before a menu would have appeared.
113
+ *
114
+ * @param seriesName the series (Vuu column) name
115
+ * @param dataIndexOrCategory 0 based data index, or category value
116
+ *
117
+ * @example
118
+ * test("no context menu in view mode", async ({ mount, page }) => {
119
+ * await mount("Chart/LineChart/EditableChart");
120
+ * await new PwChart(page).assertNoContextMenu("price", 3);
121
+ * });
122
+ */
123
+ assertNoContextMenu(seriesName: string, dataIndexOrCategory: number | string): Promise<void>;
124
+ }
@@ -0,0 +1,116 @@
1
+ import type { Locator, Page } from "@playwright/test";
2
+ import { PlaywrightPageObject } from "./PlaywrightPageObject";
3
+ import { PwContextMenu } from "./PwContextMenu";
4
+ /**
5
+ * Position and value of a chart data point, as resolved by PwChart.
6
+ */
7
+ export interface ChartDataPointInfo {
8
+ seriesName: string;
9
+ /**
10
+ * 0 based index into the series data (and the category axis).
11
+ */
12
+ dataIndex: number;
13
+ /**
14
+ * The category (x axis) value at dataIndex.
15
+ */
16
+ category: string;
17
+ value: number;
18
+ /**
19
+ * True when the data point is rendered as an excluded data item.
20
+ */
21
+ isExcluded: boolean;
22
+ /**
23
+ * Pixel position of the data point, relative to the chart canvas.
24
+ */
25
+ x: number;
26
+ y: number;
27
+ }
28
+ /**
29
+ * A single data point within a PwChart. Obtained from PwChart.dataPoint.
30
+ *
31
+ * The properties (value, x, y etc) are a snapshot, taken when the data point is
32
+ * obtained. Interactions (click, hover, right click) are performed with the
33
+ * mouse at the data point's current position, which is resolved again before
34
+ * each action, waiting until the position is stable (e.g. while the chart is
35
+ * resizing). This mirrors Playwright Locator actionability checks.
36
+ *
37
+ * @example
38
+ * test("select a data point", async ({ page }) => {
39
+ * const chart = new PwChart(page);
40
+ * const point = await chart.dataPoint("price", 3);
41
+ * expect(point.value).toEqual(103);
42
+ * await point.click();
43
+ * await expect(point.symbol).toHaveAttribute("fill", "purple");
44
+ * });
45
+ */
46
+ export declare class PwChartDataPoint extends PlaywrightPageObject implements ChartDataPointInfo {
47
+ private readonly canvas;
48
+ private readonly resolve;
49
+ readonly seriesName: string;
50
+ readonly dataIndex: number;
51
+ readonly category: string;
52
+ readonly value: number;
53
+ readonly isExcluded: boolean;
54
+ readonly x: number;
55
+ readonly y: number;
56
+ /**
57
+ * @param page the Playwright page
58
+ * @param canvas Locator for the element that renders the chart (and receives mouse events)
59
+ * @param info position and value of the data point
60
+ * @param resolve resolves the current position and value of the data point
61
+ */
62
+ constructor(page: Page, canvas: Locator, info: ChartDataPointInfo, resolve: () => Promise<ChartDataPointInfo>);
63
+ /**
64
+ * Locator for the symbol rendered at this data point (an SVG path, requires
65
+ * the svg renderer). Matched by position only, so its size and color can be
66
+ * asserted as they change, e.g. on hover or selection. Uses the position
67
+ * when the data point was obtained.
68
+ *
69
+ * @example
70
+ * test("hover enlarges symbol", async ({ page }) => {
71
+ * const point = await new PwChart(page).dataPoint("price", 3);
72
+ * await expect(point.symbol).toBeAttached();
73
+ * await point.hover();
74
+ * await expect(point.symbol).toHaveAttribute("transform", /^matrix\(8,/);
75
+ * });
76
+ */
77
+ get symbol(): Locator;
78
+ /**
79
+ * Click the data point. With a chart selectionModel, this toggles selection.
80
+ *
81
+ * @example
82
+ * test("click selects data point", async ({ page }) => {
83
+ * const point = await new PwChart(page).dataPoint("price", 3);
84
+ * await point.click();
85
+ * await expect(point.symbol).toHaveAttribute("fill", "purple");
86
+ * });
87
+ */
88
+ click(options?: Omit<Parameters<Locator["click"]>[0], "position">): Promise<void>;
89
+ /**
90
+ * Move the mouse over the data point.
91
+ *
92
+ * @example
93
+ * test("hover highlights data point", async ({ page }) => {
94
+ * const point = await new PwChart(page).dataPoint("price", 3);
95
+ * await point.hover();
96
+ * await expect(point.symbol).toHaveAttribute("transform", /^matrix\(8,/);
97
+ * });
98
+ */
99
+ hover(): Promise<void>;
100
+ /**
101
+ * Right click the data point to invoke the context menu. Resolves once the
102
+ * menu is visible and has focus.
103
+ *
104
+ * @example
105
+ * test("exclude data point", async ({ page }) => {
106
+ * const point = await new PwChart(page).dataPoint("price", 3);
107
+ * const menu = await point.showContextMenu();
108
+ * await menu.menuItem("Exclude Item").click();
109
+ * });
110
+ */
111
+ showContextMenu(): Promise<PwContextMenu>;
112
+ /**
113
+ * The current position of the data point, once it has stopped moving.
114
+ */
115
+ private stablePosition;
116
+ }
@@ -0,0 +1,88 @@
1
+ import { type Locator, type Page } from "@playwright/test";
2
+ import { PlaywrightPageObject } from "./PlaywrightPageObject";
3
+ /**
4
+ * Identifies the element a component helper operates on. Either a css selector,
5
+ * resolved against the page, or a Locator.
6
+ */
7
+ export type PwComponentTarget = string | Locator;
8
+ /**
9
+ * Base class for helpers that wrap a single component instance. Subclasses
10
+ * provide a defaultCssSelector, which can be overridden at runtime by passing
11
+ * a css selector or Locator to the constructor.
12
+ *
13
+ * @example
14
+ * // a hypothetical helper for a toolbar component
15
+ * export class PwToolbar extends PwComponent {
16
+ * protected readonly defaultCssSelector = ".vuuToolbar";
17
+ * }
18
+ *
19
+ * test("toolbar renders", async ({ page }) => {
20
+ * await new PwToolbar(page).assertVisible();
21
+ * await new PwToolbar(page, "#main-toolbar").assertVisible();
22
+ * await new PwToolbar(page, page.getByTestId("toolbar")).assertVisible();
23
+ * });
24
+ */
25
+ export declare abstract class PwComponent extends PlaywrightPageObject {
26
+ protected readonly target?: PwComponentTarget | undefined;
27
+ protected abstract readonly defaultCssSelector: string;
28
+ /**
29
+ * @param page the Playwright page
30
+ * @param target optional css selector or Locator for the component, overrides defaultCssSelector
31
+ */
32
+ constructor(page: Page, target?: PwComponentTarget | undefined);
33
+ /**
34
+ * Locator for the component root element. Use this for web-first assertions
35
+ * that are not covered by a helper method.
36
+ *
37
+ * @example
38
+ * test("menu is vertical", async ({ page }) => {
39
+ * const menu = await new PwTable(page).showContextMenu("ric", 2);
40
+ * await expect(menu.locator).toHaveAttribute("aria-orientation", "vertical");
41
+ * });
42
+ */
43
+ get locator(): Locator;
44
+ /**
45
+ * Wait until the component is attached and visible. Resolves with the
46
+ * component, so it can be chained.
47
+ *
48
+ * @example
49
+ * const menu = await new PwContextMenu(page).isReady();
50
+ */
51
+ isReady(options?: {
52
+ timeout?: number;
53
+ }): Promise<this>;
54
+ /**
55
+ * Is the component currently visible. Does not wait or retry, prefer
56
+ * assertVisible within tests unless the component is known to be stable.
57
+ *
58
+ * @example
59
+ * test("menu is open", async ({ page }) => {
60
+ * const menu = await new PwTable(page).showContextMenu("ric", 2);
61
+ * expect(await menu.isVisible()).toBe(true);
62
+ * });
63
+ */
64
+ isVisible(): Promise<boolean>;
65
+ /**
66
+ * Assert the component is visible, retrying until the expect timeout.
67
+ *
68
+ * @example
69
+ * test("table renders", async ({ mount, page }) => {
70
+ * await mount("Table/ContextMenu/LocalContextMenu");
71
+ * await new PwTable(page).assertVisible();
72
+ * });
73
+ */
74
+ assertVisible(): Promise<void>;
75
+ /**
76
+ * Assert the component is not in the DOM, retrying until the expect timeout.
77
+ * Passes as soon as the element is absent, so it does not prove an element
78
+ * will not appear later (see PwTable.assertNoContextMenu).
79
+ *
80
+ * @example
81
+ * test("menu closes after click", async ({ page }) => {
82
+ * const menu = await new PwTable(page).showContextMenu("ric", 2);
83
+ * await menu.menuItem("Copy text").click();
84
+ * await menu.assertNotAttached();
85
+ * });
86
+ */
87
+ assertNotAttached(): Promise<void>;
88
+ }
@@ -0,0 +1,173 @@
1
+ import { type Locator, type Page } from "@playwright/test";
2
+ import { PwComponent } from "./PwComponent";
3
+ import { PwMenuItem } from "./PwMenuItem";
4
+ /**
5
+ * A context menu (or one of its sub menus). Usually obtained from
6
+ * PwTable.showContextMenu.
7
+ *
8
+ * @example
9
+ * test("cell menu", async ({ page }) => {
10
+ * const table = new PwTable(page);
11
+ * const menu = await table.showContextMenu("ric", 2);
12
+ * expect(
13
+ * await menu.hasMenuItems(["Copy text", "Filter", "Sort", "Delete row"]),
14
+ * ).toBe(true);
15
+ * const filterMenu = await menu.menuItem("Filter").openSubMenu();
16
+ * await filterMenu.menuItem("Include value").click();
17
+ * await menu.assertNotAttached();
18
+ * });
19
+ */
20
+ export declare class PwContextMenu extends PwComponent {
21
+ protected readonly defaultCssSelector = ".vuuContextMenuPanel[role=\"menu\"]";
22
+ /**
23
+ * Perform the action that opens a context menu (e.g. a right click), then
24
+ * resolve with the menu once it is visible and has focus. Component helpers
25
+ * use this to implement showContextMenu.
26
+ *
27
+ * @example
28
+ * test("context menu from custom element", async ({ page }) => {
29
+ * const menu = await PwContextMenu.open(page, () =>
30
+ * page.getByTestId("panel").click({ button: "right" }),
31
+ * );
32
+ * expect(await menu.hasMenuItems()).toBe(true);
33
+ * });
34
+ */
35
+ static open(page: Page, openAction: () => Promise<unknown>): Promise<PwContextMenu>;
36
+ /**
37
+ * Perform the action that would open a context menu (e.g. a right click),
38
+ * then assert that no context menu is shown.
39
+ *
40
+ * A negative assertion passes as soon as the menu is absent, which may be
41
+ * before a menu would have rendered. To avoid false passes we wait for two
42
+ * animation frames after the action, allowing React to commit and the menu
43
+ * to be positioned, before asserting.
44
+ *
45
+ * @example
46
+ * test("no context menu on panel", async ({ page }) => {
47
+ * await PwContextMenu.assertNotOpened(page, () =>
48
+ * page.getByTestId("panel").click({ button: "right" }),
49
+ * );
50
+ * });
51
+ */
52
+ static assertNotOpened(page: Page, openAction: () => Promise<unknown>): Promise<void>;
53
+ /**
54
+ * Locator for the menu items of this menu. Sub menus are rendered in their
55
+ * own (portalled) panels, so their items are not included.
56
+ *
57
+ * @example
58
+ * test("menu has four items", async ({ page }) => {
59
+ * const menu = await new PwTable(page).showContextMenu("ric", 2);
60
+ * await expect(menu.menuItems).toHaveCount(4);
61
+ * });
62
+ */
63
+ get menuItems(): Locator;
64
+ /**
65
+ * The labels of the menu items, in rendered order.
66
+ *
67
+ * @example
68
+ * test("menu items are in expected order", async ({ page }) => {
69
+ * const menu = await new PwTable(page).showContextMenu("ric", 2);
70
+ * expect(await menu.menuItemLabels()).toEqual([
71
+ * "Copy text",
72
+ * "Filter",
73
+ * "Sort",
74
+ * "Delete row",
75
+ * ]);
76
+ * });
77
+ */
78
+ menuItemLabels(): Promise<string[]>;
79
+ /**
80
+ * With no argument, does the menu have any menu items. With labels, does
81
+ * the menu have exactly these menu items, in this order. Labels are compared
82
+ * exactly, a partial list returns false.
83
+ *
84
+ * Does not wait or retry. The menu items are rendered with the menu, so this
85
+ * is safe to call once the menu is ready (e.g. after showContextMenu).
86
+ *
87
+ * @example
88
+ * test("cell menu has expected items", async ({ page }) => {
89
+ * const menu = await new PwTable(page).showContextMenu("ric", 2);
90
+ * expect(await menu.hasMenuItems()).toBe(true);
91
+ * expect(
92
+ * await menu.hasMenuItems(["Copy text", "Filter", "Sort", "Delete row"]),
93
+ * ).toBe(true);
94
+ * // exact match, a partial list is false
95
+ * expect(await menu.hasMenuItems(["Copy text", "Filter"])).toBe(false);
96
+ * });
97
+ *
98
+ * @example
99
+ * test("sub menu has expected items", async ({ page }) => {
100
+ * const menu = await new PwTable(page).showContextMenu("ric", 2);
101
+ * const filterMenu = await menu.menuItem("Filter").openSubMenu();
102
+ * expect(
103
+ * await filterMenu.hasMenuItems(["Include value", "Exclude value"]),
104
+ * ).toBe(true);
105
+ * });
106
+ */
107
+ hasMenuItems(labels?: string[]): Promise<boolean>;
108
+ /**
109
+ * Menu item by label (exact match), or by 0 based index.
110
+ *
111
+ * @example
112
+ * test("locate menu items", async ({ page }) => {
113
+ * const menu = await new PwTable(page).showContextMenu("ric", 2);
114
+ * const copy = menu.menuItem("Copy text");
115
+ * expect(await copy.isEnabled()).toBe(true);
116
+ * expect(await menu.menuItem(1).label()).toEqual("Filter");
117
+ * });
118
+ */
119
+ menuItem(labelOrIndex: string | number): PwMenuItem;
120
+ /**
121
+ * The menu item that currently has keyboard focus. The item must also be the
122
+ * menu's active item (tabindex="0"), which confirms the menu has processed the
123
+ * focus change and is ready for the next key press.
124
+ *
125
+ * @example
126
+ * test("first item focused after ArrowDown", async ({ page }) => {
127
+ * const menu = await new PwTable(page).showContextMenu("ric", 2);
128
+ * await menu.press("ArrowDown");
129
+ * await expect(menu.focusedMenuItem.locator).toHaveText("Copy text");
130
+ * });
131
+ */
132
+ get focusedMenuItem(): PwMenuItem;
133
+ /**
134
+ * Assert the focused menu item. Wait on this between key presses, keys
135
+ * pressed before the menu has processed a focus change may be misdirected.
136
+ *
137
+ * @example
138
+ * test("arrow keys move focus", async ({ page }) => {
139
+ * const menu = await new PwTable(page).showContextMenu("ric", 2);
140
+ * await menu.press("ArrowDown");
141
+ * await menu.assertFocusedMenuItem("Copy text");
142
+ * await menu.press("ArrowDown");
143
+ * await menu.assertFocusedMenuItem("Filter");
144
+ * });
145
+ */
146
+ assertFocusedMenuItem(label: string): Promise<void>;
147
+ /**
148
+ * Press key(s) within the menu. Keys are sent to the focused element, which
149
+ * is assumed to be within the menu. Multiple keys are pressed without waiting
150
+ * for the menu to respond, use assertFocusedMenuItem between key presses where
151
+ * a key depends on the focus change of the previous key.
152
+ *
153
+ * @example
154
+ * test("Enter invokes focused item", async ({ page }) => {
155
+ * const menu = await new PwTable(page).showContextMenu("ric", 2);
156
+ * await menu.press("ArrowDown");
157
+ * await menu.assertFocusedMenuItem("Copy text");
158
+ * await menu.press("Enter");
159
+ * await menu.assertNotAttached();
160
+ * });
161
+ */
162
+ press(...keys: string[]): Promise<void>;
163
+ /**
164
+ * Close the menu by pressing Escape. Resolves once the menu is removed.
165
+ *
166
+ * @example
167
+ * test("Escape closes menu", async ({ page }) => {
168
+ * const menu = await new PwTable(page).showContextMenu("ric", 2);
169
+ * await menu.close();
170
+ * });
171
+ */
172
+ close(): Promise<void>;
173
+ }
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ export declare const cssAttributeValue: (value: string) => string;
2
+ export declare const byDataIcon: (iconName: string) => string;
3
+ export declare const byId: (id: string) => string;