@thinkwise/testwise 0.0.2-alpha.2 → 0.1.63
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/Testwise.ts +5 -1
- package/components/actionbar/Actionbar.ts +126 -18
- package/components/actionbar/ActionbarObjects.ts +46 -41
- package/components/filter/FilterForm.ts +1 -1
- package/components/filter/FindForm.ts +1 -1
- package/components/form/Form.ts +23 -24
- package/components/form/FormObjects.ts +25 -0
- package/components/grid/Grid.ts +88 -12
- package/components/grid/GridObjects.ts +16 -8
- package/components/index.ts +7 -3
- package/components/pop-up/PopUpComponent.ts +5 -1
- package/components/pop-up/{PopUpComponentModels.ts → PopUpComponentObjects.ts} +4 -0
- package/components/tab/BaseTab.ts +42 -0
- package/components/tab/BaseTabObjects.ts +23 -0
- package/components/tab/ComponentTab.ts +35 -0
- package/components/tab/ComponentTabObjects.ts +14 -0
- package/components/tab/DetailTab.ts +20 -0
- package/components/tab/DetailTabObjects.ts +10 -0
- package/components/task/TaskBar.ts +29 -9
- package/components/task/TaskBarObjects.ts +24 -0
- package/components/task/TaskTile.ts +28 -0
- package/components/task/TaskTileObjects.ts +20 -0
- package/controls/LookupDropdown.ts +54 -0
- package/controls/index.ts +1 -0
- package/dist/Testwise.js +4 -2
- package/dist/Testwise.js.map +1 -1
- package/dist/biome.json +52 -0
- package/dist/components/actionbar/Actionbar.d.ts +53 -7
- package/dist/components/actionbar/Actionbar.js +74 -14
- package/dist/components/actionbar/Actionbar.js.map +1 -1
- package/dist/components/actionbar/ActionbarObjects.d.ts +17 -4
- package/dist/components/actionbar/ActionbarObjects.js +35 -24
- package/dist/components/actionbar/ActionbarObjects.js.map +1 -1
- package/dist/components/filter/FilterForm.d.ts +5 -0
- package/dist/components/filter/FilterForm.js +10 -0
- package/dist/components/filter/FilterForm.js.map +1 -0
- package/dist/components/filter/FindForm.d.ts +5 -0
- package/dist/components/filter/FindForm.js +10 -0
- package/dist/components/filter/FindForm.js.map +1 -0
- package/dist/components/form/Form.d.ts +7 -5
- package/dist/components/form/Form.js +17 -25
- package/dist/components/form/Form.js.map +1 -1
- package/dist/components/form/FormObjects.d.ts +9 -0
- package/dist/components/form/FormObjects.js +20 -0
- package/dist/components/form/FormObjects.js.map +1 -0
- package/dist/components/grid/Grid.d.ts +25 -6
- package/dist/components/grid/Grid.js +80 -16
- package/dist/components/grid/Grid.js.map +1 -1
- package/dist/components/grid/GridObjects.d.ts +5 -3
- package/dist/components/grid/GridObjects.js +9 -6
- package/dist/components/grid/GridObjects.js.map +1 -1
- package/dist/components/index.d.ts +7 -3
- package/dist/components/index.js +7 -3
- package/dist/components/index.js.map +1 -1
- package/dist/components/pop-up/PopUpComponent.d.ts +2 -0
- package/dist/components/pop-up/PopUpComponent.js +3 -1
- package/dist/components/pop-up/PopUpComponent.js.map +1 -1
- package/dist/components/pop-up/{PopUpComponentModels.d.ts → PopUpComponentObjects.d.ts} +2 -0
- package/dist/components/pop-up/{PopUpComponentModels.js → PopUpComponentObjects.js} +3 -1
- package/dist/components/pop-up/PopUpComponentObjects.js.map +1 -0
- package/dist/components/tab/BaseTab.d.ts +11 -0
- package/dist/components/tab/BaseTab.js +34 -0
- package/dist/components/tab/BaseTab.js.map +1 -0
- package/dist/components/tab/BaseTabObjects.d.ts +10 -0
- package/dist/components/tab/BaseTabObjects.js +14 -0
- package/dist/components/tab/BaseTabObjects.js.map +1 -0
- package/dist/components/tab/ComponentTab.d.ts +11 -0
- package/dist/components/tab/ComponentTab.js +27 -0
- package/dist/components/tab/ComponentTab.js.map +1 -0
- package/dist/components/tab/ComponentTabObjects.d.ts +7 -0
- package/dist/components/tab/ComponentTabObjects.js +10 -0
- package/dist/components/tab/ComponentTabObjects.js.map +1 -0
- package/dist/components/tab/DetailTab.d.ts +9 -0
- package/dist/components/tab/DetailTab.js +15 -0
- package/dist/components/tab/DetailTab.js.map +1 -0
- package/dist/components/tab/DetailTabObjects.d.ts +5 -0
- package/dist/components/tab/DetailTabObjects.js +7 -0
- package/dist/components/tab/DetailTabObjects.js.map +1 -0
- package/dist/components/task/TaskBar.d.ts +17 -0
- package/dist/components/task/TaskBar.js +23 -0
- package/dist/components/task/TaskBar.js.map +1 -0
- package/dist/components/task/TaskBarObjects.d.ts +17 -0
- package/dist/components/task/TaskBarObjects.js +19 -0
- package/dist/components/task/TaskBarObjects.js.map +1 -0
- package/dist/components/task/TaskTile.d.ts +14 -0
- package/dist/components/task/TaskTile.js +20 -0
- package/dist/components/task/TaskTile.js.map +1 -0
- package/dist/components/task/TaskTileObjects.d.ts +13 -0
- package/dist/components/task/TaskTileObjects.js +15 -0
- package/dist/components/task/TaskTileObjects.js.map +1 -0
- package/dist/config.json +10 -10
- package/dist/controls/LookupDropdown.d.ts +11 -0
- package/dist/controls/LookupDropdown.js +39 -0
- package/dist/controls/LookupDropdown.js.map +1 -0
- package/dist/controls/index.d.ts +1 -0
- package/dist/controls/index.js +2 -0
- package/dist/controls/index.js.map +1 -0
- package/dist/enums/LogLevel.d.ts +2 -3
- package/dist/enums/LogLevel.js +1 -2
- package/dist/enums/LogLevel.js.map +1 -1
- package/dist/enums/index.d.ts +1 -0
- package/dist/enums/index.js +2 -0
- package/dist/enums/index.js.map +1 -0
- package/dist/example-code/TestifyService.js +22 -12
- package/dist/example-code/TestifyService.js.map +1 -1
- package/dist/helpers/Ensure.d.ts +2 -0
- package/dist/helpers/Ensure.js +10 -0
- package/dist/helpers/Ensure.js.map +1 -0
- package/dist/helpers/FlightTracker.d.ts +6 -0
- package/dist/helpers/FlightTracker.js +25 -0
- package/dist/helpers/FlightTracker.js.map +1 -0
- package/dist/helpers/GlobalWaitEventHandler.d.ts +12 -0
- package/dist/helpers/GlobalWaitEventHandler.js +53 -0
- package/dist/helpers/GlobalWaitEventHandler.js.map +1 -0
- package/dist/helpers/LoginHelper.d.ts +3 -2
- package/dist/helpers/LoginHelper.js +20 -4
- package/dist/helpers/LoginHelper.js.map +1 -1
- package/dist/helpers/Poll.d.ts +2 -0
- package/dist/helpers/Poll.js +17 -0
- package/dist/helpers/Poll.js.map +1 -0
- package/dist/helpers/RegexHelper.d.ts +5 -0
- package/dist/helpers/RegexHelper.js +16 -0
- package/dist/helpers/RegexHelper.js.map +1 -0
- package/dist/helpers/UserSimulationHelper.d.ts +1 -1
- package/dist/helpers/UserSimulationHelper.js +10 -6
- package/dist/helpers/UserSimulationHelper.js.map +1 -1
- package/dist/helpers/index.d.ts +2 -0
- package/dist/helpers/index.js +3 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/index.d.ts +8 -12
- package/dist/index.js +9 -13
- package/dist/index.js.map +1 -1
- package/dist/package-lock.json +4087 -0
- package/dist/package.json +57 -0
- package/dist/page-extensions/GoToDeepLink.js +15 -1
- package/dist/page-extensions/GoToDeepLink.js.map +1 -1
- package/dist/page-extensions/LoginFeatures.d.ts +2 -1
- package/dist/page-extensions/LoginFeatures.js +3 -0
- package/dist/page-extensions/LoginFeatures.js.map +1 -1
- package/dist/page-extensions/WaitEventHandler.d.ts +12 -0
- package/dist/page-extensions/WaitEventHandler.js +15 -0
- package/dist/page-extensions/WaitEventHandler.js.map +1 -0
- package/dist/page-extensions/index.d.ts +3 -0
- package/dist/page-extensions/index.js +4 -0
- package/dist/page-extensions/index.js.map +1 -0
- package/dist/page-overrides/ClickOverride.d.ts +1 -0
- package/dist/page-overrides/ClickOverride.js +46 -25
- package/dist/page-overrides/ClickOverride.js.map +1 -1
- package/dist/page-overrides/FillOverride.d.ts +7 -0
- package/dist/page-overrides/FillOverride.js +106 -0
- package/dist/page-overrides/FillOverride.js.map +1 -0
- package/dist/page-overrides/index.d.ts +1 -0
- package/dist/page-overrides/index.js +2 -0
- package/dist/page-overrides/index.js.map +1 -0
- package/dist/scripts/Testwise.template.json +25 -0
- package/dist/services/ConfigBuilder.js +23 -1
- package/dist/services/ConfigBuilder.js.map +1 -1
- package/dist/services/Logger.d.ts +1 -2
- package/dist/services/Logger.js +69 -15
- package/dist/services/Logger.js.map +1 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +2 -0
- package/dist/services/index.js.map +1 -0
- package/dist/tsconfig.json +20 -0
- package/dist/types/PollTypes.d.ts +6 -0
- package/dist/types/PollTypes.js +2 -0
- package/dist/types/PollTypes.js.map +1 -0
- package/dist/types/Universal.js +2 -0
- package/dist/types/Universal.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/enums/LogLevel.ts +2 -3
- package/enums/index.ts +1 -0
- package/example-code/TestifyService.ts +26 -12
- package/helpers/Ensure.ts +9 -0
- package/helpers/FlightTracker.ts +26 -0
- package/helpers/GlobalWaitEventHandler.ts +66 -0
- package/helpers/LoginHelper.ts +26 -5
- package/helpers/Poll.ts +19 -0
- package/helpers/RegexHelper.ts +17 -0
- package/helpers/UserSimulationHelper.ts +11 -6
- package/helpers/index.ts +2 -0
- package/index.ts +9 -13
- package/package.json +21 -4
- package/page-extensions/GoToDeepLink.ts +17 -1
- package/page-extensions/LoginFeatures.ts +6 -1
- package/page-extensions/WaitEventHandler.ts +26 -0
- package/page-extensions/index.ts +3 -0
- package/page-overrides/ClickOverride.ts +60 -26
- package/page-overrides/FillOverride.ts +133 -0
- package/page-overrides/index.ts +1 -0
- package/promptCredentials.js +41 -30
- package/scripts/Testwise.template.json +7 -1
- package/scripts/add-config.js +2 -2
- package/services/ConfigBuilder.ts +27 -1
- package/services/Logger.ts +73 -15
- package/services/index.ts +1 -0
- package/tsconfig.json +20 -0
- package/types/PollTypes.ts +6 -0
- package/types/index.ts +2 -0
- package/.ci/azure-pipelines.yaml +0 -80
- package/.eslintcache +0 -1
- package/.gitattributes +0 -3
- package/.gitconfig +0 -2
- package/.vscode/settings.json +0 -18
- package/components/tab/Tab.ts +0 -29
- package/components/task/TaskTiles.ts +0 -11
- package/dist/components/pop-up/PopUpComponentModels.js.map +0 -1
- package/dist/enums/ActionbarRegions.d.ts +0 -5
- package/dist/enums/ActionbarRegions.js +0 -7
- package/dist/enums/ActionbarRegions.js.map +0 -1
- package/dist/enums/ButtonEnums.d.ts +0 -24
- package/dist/enums/ButtonEnums.js +0 -29
- package/dist/enums/ButtonEnums.js.map +0 -1
- package/dist/helpers/InflightRequestTracker.d.ts +0 -10
- package/dist/helpers/InflightRequestTracker.js +0 -26
- package/dist/helpers/InflightRequestTracker.js.map +0 -1
- package/dist/types/universal.js +0 -2
- package/dist/types/universal.js.map +0 -1
- package/enums/ActionbarRegions.ts +0 -5
- package/enums/ButtonEnums.ts +0 -28
- package/helpers/InflightRequestTracker.ts +0 -33
- /package/dist/types/{universal.d.ts → Universal.d.ts} +0 -0
- /package/types/{universal.ts → Universal.ts} +0 -0
package/Testwise.ts
CHANGED
|
@@ -2,7 +2,9 @@ import { test as base } from '@playwright/test';
|
|
|
2
2
|
import { GoToDeepLink } from './page-extensions/GoToDeepLink.js';
|
|
3
3
|
import { LoginFeatures } from './page-extensions/LoginFeatures.js';
|
|
4
4
|
import { UserSimulation } from './page-extensions/UserSimulation.js';
|
|
5
|
+
import { WaitEventHandler } from './page-extensions/WaitEventHandler.js';
|
|
5
6
|
import { ClickOverride } from './page-overrides/ClickOverride.js';
|
|
7
|
+
import { FillOverride } from './page-overrides/FillOverride.js';
|
|
6
8
|
import type { Test } from './types/CoreTypes.js';
|
|
7
9
|
|
|
8
10
|
function combineExtensions(baseTest: Test, ...extensions: { new (test: Test): { test: Test } }[]) {
|
|
@@ -14,9 +16,11 @@ export const test: Test = combineExtensions(
|
|
|
14
16
|
|
|
15
17
|
// Override section
|
|
16
18
|
ClickOverride,
|
|
19
|
+
FillOverride,
|
|
17
20
|
|
|
18
21
|
// Extend section
|
|
19
22
|
GoToDeepLink,
|
|
20
23
|
LoginFeatures,
|
|
21
|
-
UserSimulation
|
|
24
|
+
UserSimulation,
|
|
25
|
+
WaitEventHandler
|
|
22
26
|
);
|
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
import type { Locator, Page } from '@playwright/test';
|
|
2
|
-
import { ActionbarObjects } from './ActionbarObjects.js';
|
|
2
|
+
import { ActionbarObjects, ActionbarOverflowableObjects } from './ActionbarObjects.js';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
private _objects:
|
|
4
|
+
class ActionbarActions {
|
|
5
|
+
private _objects: ActionbarOverflowableObjects;
|
|
6
6
|
|
|
7
|
-
constructor(page: Page,
|
|
8
|
-
this._objects = new
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Opens the Actionbar’s overflow menu and clicks on the 'Export' button inside it.
|
|
13
|
-
*/
|
|
14
|
-
public async clickExportButton(): Promise<void> {
|
|
15
|
-
await this._objects.overflowMenuButton().click();
|
|
16
|
-
await this._objects.exportButton().click();
|
|
7
|
+
constructor(page: Page, context: Locator | null = null) {
|
|
8
|
+
this._objects = new ActionbarOverflowableObjects(page, context);
|
|
17
9
|
}
|
|
18
10
|
|
|
19
|
-
// CRUD Buttons
|
|
20
11
|
public getAddButton = (): Locator => this._objects.addButton();
|
|
21
12
|
|
|
22
13
|
public getCancelButton = (): Locator => this._objects.cancelButton();
|
|
@@ -31,9 +22,6 @@ export class Actionbar {
|
|
|
31
22
|
|
|
32
23
|
public getUpdateButton = (): Locator => this._objects.updateButton();
|
|
33
24
|
|
|
34
|
-
// Overflow Menu
|
|
35
|
-
public getOverflowMenuButton = (): Locator => this._objects.overflowMenuButton();
|
|
36
|
-
|
|
37
25
|
public getExportButton = (): Locator => this._objects.exportButton();
|
|
38
26
|
|
|
39
27
|
public getImportButton = (): Locator => this._objects.importButton();
|
|
@@ -52,6 +40,126 @@ export class Actionbar {
|
|
|
52
40
|
|
|
53
41
|
public getSortButton = (): Locator => this._objects.sortButton();
|
|
54
42
|
|
|
55
|
-
// Other Elements
|
|
56
43
|
public getSearchInput = (): Locator => this._objects.searchInput();
|
|
44
|
+
|
|
45
|
+
public getUpScreenTypeButton = (): Locator => this._objects.upScreenTypeButton();
|
|
46
|
+
|
|
47
|
+
public getUpDetailSettingsButton = (): Locator => this._objects.upDetailSettingsButton();
|
|
48
|
+
|
|
49
|
+
public getUpManagePrefiltersButton = (): Locator => this._objects.upManagePrefiltersButton();
|
|
50
|
+
|
|
51
|
+
public getUpGridSettingsButton = (): Locator => this._objects.upGridSettingsButton();
|
|
52
|
+
|
|
53
|
+
public getCubeSortButton = (): Locator => this._objects.cubeSortButton();
|
|
54
|
+
|
|
55
|
+
public getCubePivotSettingsButton = (): Locator => this._objects.cubePivotSettingsButton();
|
|
56
|
+
|
|
57
|
+
public getCubeChartSettingsButton = (): Locator => this._objects.cubeChartSettingsButton();
|
|
58
|
+
|
|
59
|
+
public getSaveAsCubeViewButton = (): Locator => this._objects.saveAsCubeViewButton();
|
|
60
|
+
|
|
61
|
+
public getDeleteCubeViewButton = (): Locator => this._objects.deleteCubeViewButton();
|
|
62
|
+
|
|
63
|
+
public getCollapseAllButton = (): Locator => this._objects.collapseAllButton();
|
|
64
|
+
|
|
65
|
+
public getExpandAllButton = (): Locator => this._objects.expandAllButton();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export class Actionbar extends ActionbarActions {
|
|
69
|
+
private _actionbarObjects: ActionbarObjects;
|
|
70
|
+
private _overflowMenu: ActionbarOverflow;
|
|
71
|
+
|
|
72
|
+
constructor(page: Page, actionbarContext: Locator | null = null) {
|
|
73
|
+
super(page, actionbarContext);
|
|
74
|
+
this._actionbarObjects = new ActionbarObjects(page, actionbarContext);
|
|
75
|
+
this._overflowMenu = new ActionbarOverflow(page);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public openOverflowMenu = async (): Promise<void> => {
|
|
79
|
+
await this._actionbarObjects.overflowMenuButton().click();
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
overflowMenu = {
|
|
83
|
+
getAddButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getAddButton()),
|
|
84
|
+
|
|
85
|
+
getCancelButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getCancelButton()),
|
|
86
|
+
|
|
87
|
+
getCopyButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getCopyButton()),
|
|
88
|
+
|
|
89
|
+
getDeleteButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getDeleteButton()),
|
|
90
|
+
|
|
91
|
+
getRefreshButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getRefreshButton()),
|
|
92
|
+
|
|
93
|
+
getSaveButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getSaveButton()),
|
|
94
|
+
|
|
95
|
+
getUpdateButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getUpdateButton()),
|
|
96
|
+
|
|
97
|
+
getExportButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getExportButton()),
|
|
98
|
+
|
|
99
|
+
getImportButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getImportButton()),
|
|
100
|
+
|
|
101
|
+
getExportImmediatelyButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getExportImmediatelyButton()),
|
|
102
|
+
|
|
103
|
+
getMassUpdateButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getMassUpdateButton()),
|
|
104
|
+
|
|
105
|
+
getQuickFilterButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getQuickFilterButton()),
|
|
106
|
+
|
|
107
|
+
getFilterButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getFilterButton()),
|
|
108
|
+
|
|
109
|
+
getClearAllFiltersButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getClearAllFiltersButton()),
|
|
110
|
+
|
|
111
|
+
getRestoreSortOrderButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getRestoreSortOrderButton()),
|
|
112
|
+
|
|
113
|
+
getSortButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getSortButton()),
|
|
114
|
+
|
|
115
|
+
getSearchInput: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getSearchInput()),
|
|
116
|
+
|
|
117
|
+
getUpScreenTypeButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getUpScreenTypeButton()),
|
|
118
|
+
|
|
119
|
+
getUpDetailSettingsButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getUpDetailSettingsButton()),
|
|
120
|
+
|
|
121
|
+
getUpManagePrefiltersButton: () =>
|
|
122
|
+
wrapWithOverflowOpen(this, () => this._overflowMenu.getUpManagePrefiltersButton()),
|
|
123
|
+
|
|
124
|
+
getUpGridSettingsButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getUpGridSettingsButton()),
|
|
125
|
+
|
|
126
|
+
getCubeSortButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getCubeSortButton()),
|
|
127
|
+
|
|
128
|
+
getCubePivotSettingsButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getCubePivotSettingsButton()),
|
|
129
|
+
|
|
130
|
+
getCubeChartSettingsButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getCubeChartSettingsButton()),
|
|
131
|
+
|
|
132
|
+
getSaveAsCubeViewButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getSaveAsCubeViewButton()),
|
|
133
|
+
|
|
134
|
+
getDeleteCubeViewButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getDeleteCubeViewButton()),
|
|
135
|
+
|
|
136
|
+
getCollapseAllButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getCollapseAllButton()),
|
|
137
|
+
|
|
138
|
+
getExpandAllButton: () => wrapWithOverflowOpen(this, () => this._overflowMenu.getExpandAllButton())
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export class ActionbarOverflow extends ActionbarActions {
|
|
143
|
+
constructor(page: Page) {
|
|
144
|
+
super(page, page.getByTestId('actionbar__overflow-menu__context'));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function wrapWithOverflowOpen(actionBarInstance: Actionbar, getLocatorFn: () => Locator): Locator {
|
|
149
|
+
const locator = getLocatorFn();
|
|
150
|
+
|
|
151
|
+
return new Proxy(locator, {
|
|
152
|
+
get(target, prop, receiver) {
|
|
153
|
+
const original = Reflect.get(target, prop, receiver);
|
|
154
|
+
|
|
155
|
+
if (typeof original === 'function') {
|
|
156
|
+
return async (...args: unknown[]) => {
|
|
157
|
+
await actionBarInstance.openOverflowMenu();
|
|
158
|
+
return (original as (...args: unknown[]) => unknown).apply(target, args);
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return original;
|
|
163
|
+
}
|
|
164
|
+
}) as unknown as Locator;
|
|
57
165
|
}
|
|
@@ -1,67 +1,72 @@
|
|
|
1
1
|
import type { Locator, Page } from '@playwright/test';
|
|
2
2
|
import { BaseComponentObjects } from '../BaseComponentObjects.js';
|
|
3
3
|
|
|
4
|
-
export class
|
|
5
|
-
private _page: Page;
|
|
6
|
-
|
|
4
|
+
export class ActionbarOverflowableObjects extends BaseComponentObjects {
|
|
7
5
|
constructor(page: Page, context: Locator | null = null) {
|
|
8
6
|
super(page, context);
|
|
9
|
-
this._page = page;
|
|
10
7
|
}
|
|
11
8
|
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
public addButton = () => this.context.getByTestId('actionbar__add');
|
|
10
|
+
|
|
11
|
+
public cancelButton = () => this.context.getByTestId('actionbar__cancel');
|
|
12
|
+
|
|
13
|
+
public copyButton = () => this.context.getByTestId('actionbar__copy');
|
|
14
|
+
|
|
15
|
+
public deleteButton = () => this.context.getByTestId('actionbar__delete');
|
|
16
|
+
|
|
17
|
+
public refreshButton = () => this.context.getByTestId('actionbar__refresh');
|
|
18
|
+
|
|
19
|
+
public saveButton = () => this.context.getByTestId('actionbar__save');
|
|
20
|
+
|
|
21
|
+
public updateButton = () => this.context.getByTestId('actionbar__update');
|
|
22
|
+
|
|
23
|
+
public searchInput = () => this.context.getByTestId('actionbar__search__input').locator('input');
|
|
14
24
|
|
|
15
|
-
public
|
|
25
|
+
public exportButton = () => this.context.getByTestId('actionbar__export');
|
|
16
26
|
|
|
17
|
-
public
|
|
27
|
+
public importButton = () => this.context.getByTestId('actionbar__import');
|
|
18
28
|
|
|
19
|
-
public
|
|
29
|
+
public exportImmediatelyButton = () => this.context.getByTestId('actionbar__export-immediately');
|
|
20
30
|
|
|
21
|
-
public
|
|
31
|
+
public massUpdateButton = () => this.context.getByTestId('actionbar__mass-update');
|
|
22
32
|
|
|
23
|
-
public
|
|
33
|
+
public quickFilterButton = () => this.context.getByTestId('actionbar__quick-filter');
|
|
24
34
|
|
|
25
|
-
public
|
|
35
|
+
public filterButton = () => this.context.getByTestId('actionbar__filter');
|
|
26
36
|
|
|
27
|
-
|
|
28
|
-
public overflowMenuButton = () => this.context.locator(' [data-testid="actionbar__overflow-menu__button"]');
|
|
37
|
+
public clearAllFiltersButton = () => this.context.getByTestId('actionbar__clear-filters');
|
|
29
38
|
|
|
30
|
-
|
|
39
|
+
public restoreSortOrderButton = () => this.context.getByTestId('actionbar__restore-sort-order');
|
|
31
40
|
|
|
32
|
-
public
|
|
33
|
-
this._page.locator('[data-testid="actionbar__overflow-menu__context"] [data-testid="actionbar__export"]');
|
|
41
|
+
public sortButton = () => this.context.getByTestId('actionbar__sort');
|
|
34
42
|
|
|
35
|
-
public
|
|
36
|
-
this._page.locator('[data-testid="actionbar__overflow-menu__context"] [data-testid="actionbar__import"]');
|
|
43
|
+
public upScreenTypeButton = () => this.context.getByTestId('actionbar__up-screen-type');
|
|
37
44
|
|
|
38
|
-
public
|
|
39
|
-
this._page.locator(
|
|
40
|
-
'[data-testid="actionbar__overflow-menu__context"] [data-testid="actionbar__export-immediately"]'
|
|
41
|
-
);
|
|
45
|
+
public upDetailSettingsButton = () => this.context.getByTestId('actionbar__up-details');
|
|
42
46
|
|
|
43
|
-
public
|
|
44
|
-
this._page.locator('[data-testid="actionbar__overflow-menu__context"] [data-testid="actionbar__mass-update"]');
|
|
47
|
+
public upManagePrefiltersButton = () => this.context.getByTestId('actionbar__up-prefilters');
|
|
45
48
|
|
|
46
|
-
public
|
|
47
|
-
this._page.locator('[data-testid="actionbar__overflow-menu__context"] [data-testid="actionbar__quick-filter"]');
|
|
49
|
+
public upGridSettingsButton = () => this.context.getByTestId('actionbar__up-grid');
|
|
48
50
|
|
|
49
|
-
public
|
|
50
|
-
this._page.locator('[data-testid="actionbar__overflow-menu__context"] [data-testid="actionbar__filter"]');
|
|
51
|
+
public cubeSortButton = () => this.context.getByTestId('actionbar__cube-sort');
|
|
51
52
|
|
|
52
|
-
public
|
|
53
|
-
this._page.locator(
|
|
54
|
-
'[data-testid="actionbar__overflow-menu__context"] [data-testid="actionbar__clear-all-filters"]'
|
|
55
|
-
);
|
|
53
|
+
public cubePivotSettingsButton = () => this.context.getByTestId('actionbar__pivot-settings');
|
|
56
54
|
|
|
57
|
-
public
|
|
58
|
-
this._page.locator(
|
|
59
|
-
'[data-testid="actionbar__overflow-menu__context"] [data-testid="actionbar__restore-sort-order"]'
|
|
60
|
-
);
|
|
55
|
+
public cubeChartSettingsButton = () => this.context.getByTestId('actionbar__chart-settings');
|
|
61
56
|
|
|
62
|
-
public
|
|
63
|
-
|
|
57
|
+
public saveAsCubeViewButton = () => this.context.getByTestId('actionbar__save-as-cube-view');
|
|
58
|
+
|
|
59
|
+
public deleteCubeViewButton = () => this.context.getByTestId('actionbar__delete-cube-view');
|
|
60
|
+
|
|
61
|
+
public collapseAllButton = () => this.context.getByTestId('actionbar__collapse-all');
|
|
62
|
+
|
|
63
|
+
public expandAllButton = () => this.context.getByTestId('actionbar__expand-all');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export class ActionbarObjects extends ActionbarOverflowableObjects {
|
|
67
|
+
constructor(page: Page, context: Locator | null = null) {
|
|
68
|
+
super(page, context);
|
|
69
|
+
}
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
public searchInput = () => this.context.locator(' [data-testid="actionbar__search__input"] input');
|
|
71
|
+
public overflowMenuButton = () => this.context.locator('[data-testid="actionbar__overflow-menu__button"]');
|
|
67
72
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Locator } from '@playwright/test';
|
|
2
|
-
import { BaseComponent } from '../BaseComponent';
|
|
2
|
+
import { BaseComponent } from '../BaseComponent.js';
|
|
3
3
|
|
|
4
4
|
export class FilterForm extends BaseComponent {
|
|
5
5
|
public async getLocator(context?: Locator): Promise<Locator> {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Locator } from '@playwright/test';
|
|
2
|
-
import { BaseComponent } from '../BaseComponent';
|
|
2
|
+
import { BaseComponent } from '../BaseComponent.js';
|
|
3
3
|
|
|
4
4
|
export class FindForm extends BaseComponent {
|
|
5
5
|
public async getLocator(context?: Locator): Promise<Locator> {
|
package/components/form/Form.ts
CHANGED
|
@@ -1,31 +1,30 @@
|
|
|
1
|
-
import type { Locator } from '@playwright/test';
|
|
2
|
-
import {
|
|
1
|
+
import type { Locator, Page } from '@playwright/test';
|
|
2
|
+
import { FormObjects } from './FormObjects.js';
|
|
3
3
|
|
|
4
|
-
export class Form
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return this.page.getByTestId(this.id);
|
|
4
|
+
export class Form {
|
|
5
|
+
private _objects: FormObjects;
|
|
6
|
+
|
|
7
|
+
constructor(page: Page, formContext: Locator | null = null) {
|
|
8
|
+
this._objects = new FormObjects(page, formContext);
|
|
10
9
|
}
|
|
11
10
|
|
|
12
|
-
public
|
|
13
|
-
this.
|
|
14
|
-
if (component) {
|
|
15
|
-
return component.getByTestId(`form-field__${colId}`);
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
// Fallback to page locator if component is not found
|
|
19
|
-
return this.page.getByTestId(`form-field__${colId}`);
|
|
11
|
+
public getFieldByValue = (value: string): Locator => {
|
|
12
|
+
return this._objects.getFieldByValue(value);
|
|
20
13
|
};
|
|
21
14
|
|
|
22
|
-
public
|
|
23
|
-
this.
|
|
24
|
-
if (component) {
|
|
25
|
-
return component.locator('[data-form="field"]', { hasText: value });
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
// Fallback to page locator if component is not found
|
|
29
|
-
return this.page.locator('[data-form="field"]', { hasText: value });
|
|
15
|
+
public getFieldByColId = (colId: string): Locator => {
|
|
16
|
+
return this._objects.getFieldByColId(colId);
|
|
30
17
|
};
|
|
18
|
+
|
|
19
|
+
// Returns true if the form is currently in edit mode, based on the `data-edit-mode` attribute.
|
|
20
|
+
public async isInEditMode(): Promise<boolean> {
|
|
21
|
+
const control = this._objects.getEditModeAttribute();
|
|
22
|
+
const mode = await control.getAttribute('data-edit-mode');
|
|
23
|
+
return mode === 'true';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Clicks the lookup (magnifier) icon in the specified form field.
|
|
27
|
+
public async clickInFieldLookup(colId: string): Promise<void> {
|
|
28
|
+
await this._objects.getLookupButtonByColId(colId).click();
|
|
29
|
+
}
|
|
31
30
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Locator, Page } from '@playwright/test';
|
|
2
|
+
import { BaseComponentObjects } from '../BaseComponentObjects.js';
|
|
3
|
+
|
|
4
|
+
export class FormObjects extends BaseComponentObjects {
|
|
5
|
+
constructor(page: Page, context: Locator | null = null) {
|
|
6
|
+
super(page, context);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Field selectors
|
|
10
|
+
public getFieldByColId = (colId: string): Locator => {
|
|
11
|
+
return this.context.locator(`[data-testid="form-field__${colId}__input"]`);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
public getFieldByValue = (value: string): Locator => {
|
|
15
|
+
return this.context.locator(`input[value="${value}"]`);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
public getEditModeAttribute = (): Locator => {
|
|
19
|
+
return this.context.locator('[data-testid^="form-field__"][data-testid$="__control"]').first();
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
public getLookupButtonByColId = (colId: string): Locator => {
|
|
23
|
+
return this.context.locator(`[data-testid="form-field__${colId}__open"]`);
|
|
24
|
+
};
|
|
25
|
+
}
|
package/components/grid/Grid.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { Locator, Page } from '@playwright/test';
|
|
2
|
+
import { pollUntil } from '../../helpers/Poll.js';
|
|
3
|
+
import { escapeRegex } from '../../helpers/RegexHelper.js';
|
|
2
4
|
import { GridObjects } from './GridObjects.js';
|
|
3
5
|
|
|
4
6
|
export class Grid {
|
|
@@ -29,7 +31,10 @@ export class Grid {
|
|
|
29
31
|
* @param value - The exact text value of the cell to retrieve.
|
|
30
32
|
* @returns A Locator for the cell containing the specified value.
|
|
31
33
|
*/
|
|
32
|
-
public getCellByExactValue
|
|
34
|
+
public getCellByExactValue(value: string): Locator {
|
|
35
|
+
const valueToFindRegex = new RegExp(`^${escapeRegex(value)}$`);
|
|
36
|
+
return this._gridObjects.cellByValue(valueToFindRegex);
|
|
37
|
+
}
|
|
33
38
|
|
|
34
39
|
/**
|
|
35
40
|
* Opens the Excel-style filter popup for the specified grid column.
|
|
@@ -54,7 +59,9 @@ export class Grid {
|
|
|
54
59
|
|
|
55
60
|
const filteredRows = await Promise.all(
|
|
56
61
|
allRows.map(async (row) => {
|
|
57
|
-
const
|
|
62
|
+
const cellLocator = row.locator(`[col-id="${colIdToMatchOn}"]`);
|
|
63
|
+
if ((await cellLocator.count()) === 0) return null; // Cell not found, skip row
|
|
64
|
+
const text = await cellLocator.textContent();
|
|
58
65
|
return text === valueToMatch ? row : null;
|
|
59
66
|
})
|
|
60
67
|
);
|
|
@@ -200,22 +207,91 @@ export class Grid {
|
|
|
200
207
|
}
|
|
201
208
|
|
|
202
209
|
/**
|
|
203
|
-
* Filters a column
|
|
210
|
+
* Filters a grid column using the Excel-style filter popup.
|
|
211
|
+
*
|
|
212
|
+
* @param columnName - The column to filter
|
|
213
|
+
* @param valueToSelect - The value to select
|
|
214
|
+
* @param deselectAll - If true, clears existing selections first (default: true)
|
|
204
215
|
*
|
|
205
|
-
* @
|
|
206
|
-
*
|
|
207
|
-
*
|
|
216
|
+
* @example
|
|
217
|
+
* await grid.filterByColumnValueExcelStyle('Status', 'Active');
|
|
218
|
+
* await grid.filterByColumnValueExcelStyle('Status', 'Pending', false);
|
|
208
219
|
*/
|
|
209
|
-
public async filterByColumnValueExcelStyle(
|
|
220
|
+
public async filterByColumnValueExcelStyle(
|
|
221
|
+
columnName: string,
|
|
222
|
+
valueToSelect: string,
|
|
223
|
+
deselectAll: boolean = true
|
|
224
|
+
): Promise<void> {
|
|
210
225
|
await this.openExcelStyleFilterPopup(columnName);
|
|
211
|
-
|
|
226
|
+
|
|
227
|
+
// Get column ID from header and normalize it (snake_case -> kebab-case)
|
|
228
|
+
const header = this._gridObjects.columnHeaderByName(columnName);
|
|
229
|
+
const rawColumnId = await header.getAttribute('col-id');
|
|
230
|
+
if (!rawColumnId) {
|
|
231
|
+
throw new Error(`Could not find col-id for column "${columnName}"`);
|
|
232
|
+
}
|
|
233
|
+
const columnId = rawColumnId.toLowerCase().replace(/_/g, '-');
|
|
234
|
+
|
|
235
|
+
const popup = this._gridObjects.excelStyleFilterPopup(columnId);
|
|
212
236
|
await popup.waitFor({ state: 'visible' });
|
|
213
|
-
const checkbox = this._gridObjects.excelStyleFilterPopupOptionByText(valueToSelect);
|
|
214
|
-
await checkbox.check();
|
|
215
237
|
|
|
216
|
-
|
|
217
|
-
|
|
238
|
+
if (deselectAll) {
|
|
239
|
+
await this._gridObjects.excelStyleFilterSelectAllCheckbox(columnId).uncheck();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const valueRegex = new RegExp(`^${escapeRegex(valueToSelect)}$`, 'i');
|
|
243
|
+
const optionButton = this._gridObjects.excelStyleFilterPopupOptionByText(columnId, valueRegex);
|
|
244
|
+
await optionButton.locator('input[type="checkbox"]').check();
|
|
218
245
|
|
|
246
|
+
await this._gridObjects.gridCell().first().click();
|
|
219
247
|
await popup.waitFor({ state: 'detached' });
|
|
220
248
|
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Returns a Locator for all rows in the grid.
|
|
252
|
+
* @returns {Locator} Locator for grid rows.
|
|
253
|
+
*/
|
|
254
|
+
public rows(): Locator {
|
|
255
|
+
return this._gridObjects.rows();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Verifies the number of rows in the grid and checks for "No result" overlay if zero.
|
|
260
|
+
* @param expectedRowCount The expected number of rows.
|
|
261
|
+
*/
|
|
262
|
+
public async verifyNumberOfRowsInGrid(expectedRowCount: number): Promise<void> {
|
|
263
|
+
if (expectedRowCount === 0) {
|
|
264
|
+
if (await this.hasNoRowsOverlay()) {
|
|
265
|
+
return;
|
|
266
|
+
} else {
|
|
267
|
+
throw new Error('Expected "No result" overlay to be visible');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
await pollUntil(() => this.rows().count(), {
|
|
272
|
+
predicate: (n: number) => n === expectedRowCount
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Verifies if the "No result" overlay is visible in the grid.
|
|
278
|
+
* @returns A promise that resolves to true if the overlay is visible, otherwise false.
|
|
279
|
+
*/
|
|
280
|
+
public async hasNoRowsOverlay(): Promise<boolean> {
|
|
281
|
+
try {
|
|
282
|
+
const overlay = this._gridObjects.noRowsOverlay();
|
|
283
|
+
await pollUntil(
|
|
284
|
+
async () => {
|
|
285
|
+
const txt = (await overlay.textContent())?.trim() ?? '';
|
|
286
|
+
return txt.includes('No result');
|
|
287
|
+
},
|
|
288
|
+
{ predicate: Boolean }
|
|
289
|
+
);
|
|
290
|
+
} catch {
|
|
291
|
+
console.error('The "No result" overlay is not displaying the expected text.');
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return await this._gridObjects.noRowsOverlay().isVisible();
|
|
296
|
+
}
|
|
221
297
|
}
|
|
@@ -20,8 +20,10 @@ export class GridObjects extends BaseComponentObjects {
|
|
|
20
20
|
|
|
21
21
|
public rowByIndex = (row: number) => this.context.locator(`[role="row"][row-index="${row}"]`);
|
|
22
22
|
|
|
23
|
-
public cellByValue = (value:
|
|
24
|
-
this.context.locator('[role="button"]', {
|
|
23
|
+
public cellByValue = (value: RegExp) =>
|
|
24
|
+
this.context.locator('[role="button"]', {
|
|
25
|
+
hasText: value
|
|
26
|
+
});
|
|
25
27
|
|
|
26
28
|
public rows = () => this.context.locator('[role="row"]');
|
|
27
29
|
|
|
@@ -33,13 +35,19 @@ export class GridObjects extends BaseComponentObjects {
|
|
|
33
35
|
|
|
34
36
|
public columnByRowLocator = (rowLocator: Locator) => rowLocator.locator('.ag-cell');
|
|
35
37
|
|
|
36
|
-
public excelStyleFilterPopup = () => this._page.
|
|
38
|
+
public excelStyleFilterPopup = (columnId: string) => this._page.getByTestId(`lookup-excel-filter__${columnId}__list`);
|
|
37
39
|
|
|
38
|
-
public
|
|
39
|
-
this.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
public excelStyleFilterSelectAllCheckbox = (columnId: string) =>
|
|
41
|
+
this._page.locator(
|
|
42
|
+
`[data-testid="lookup-excel-filter__${columnId}__list-item-select-all-checkbox"] input[type="checkbox"]`
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
public excelStyleFilterPopupOptionByText = (columnId: string, optionText: RegExp) =>
|
|
46
|
+
this._page
|
|
47
|
+
.locator(`[data-testid^="lookup-excel-filter__${columnId}__list-item-button__"]`)
|
|
48
|
+
.filter({ hasText: optionText });
|
|
43
49
|
|
|
44
50
|
public gridCell = () => this.context.locator('[role="gridcell"]');
|
|
51
|
+
|
|
52
|
+
public noRowsOverlay = () => this.context.locator('.ag-overlay-no-rows-center');
|
|
45
53
|
}
|
package/components/index.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
export * from './form/Form.js';
|
|
2
|
-
export * from './grid/Grid.js';
|
|
3
|
-
export * from './Splitter.js';
|
|
4
1
|
export * from './actionbar/Actionbar.js';
|
|
5
2
|
export * from './export/ExportComponent.js';
|
|
3
|
+
export * from './form/Form.js';
|
|
4
|
+
export * from './grid/Grid.js';
|
|
6
5
|
export * from './pop-up/PopUpComponent.js';
|
|
6
|
+
export * from './Splitter.js';
|
|
7
|
+
export * from './tab/ComponentTab.js';
|
|
8
|
+
export * from './tab/DetailTab.js';
|
|
9
|
+
export * from './task/TaskBar.js';
|
|
10
|
+
export * from './task/TaskTile.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Page } from '@playwright/test';
|
|
2
|
-
import { PopUpComponentObjects } from './
|
|
2
|
+
import { PopUpComponentObjects } from './PopUpComponentObjects.js';
|
|
3
3
|
|
|
4
4
|
export class PopUpComponent {
|
|
5
5
|
private _objects: PopUpComponentObjects;
|
|
@@ -11,4 +11,8 @@ export class PopUpComponent {
|
|
|
11
11
|
public confirmYes = async () => await this._objects.actionYesButton().click();
|
|
12
12
|
|
|
13
13
|
public confirmNo = async () => await this._objects.actionNoButton().click();
|
|
14
|
+
|
|
15
|
+
public getContentMessage = async () => await this._objects.contentMessage().textContent();
|
|
16
|
+
|
|
17
|
+
public clickCloseButton = async () => await this._objects.closeButton().click();
|
|
14
18
|
}
|
|
@@ -10,4 +10,8 @@ export class PopUpComponentObjects {
|
|
|
10
10
|
public actionNoButton = () => this._page.getByTestId('popup__translatemessage__actions__no');
|
|
11
11
|
|
|
12
12
|
public actionYesButton = () => this._page.getByTestId('popup__translatemessage__actions__yes');
|
|
13
|
+
|
|
14
|
+
public contentMessage = () => this._page.getByTestId('popup__tsfmessage__content__title').locator('span');
|
|
15
|
+
|
|
16
|
+
public closeButton = () => this._page.getByTestId('popup__tsfmessage__actions__close');
|
|
13
17
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Locator, Page } from '@playwright/test';
|
|
2
|
+
import { BaseTabObjects } from './BaseTabObjects.js';
|
|
3
|
+
|
|
4
|
+
export class BaseTab {
|
|
5
|
+
protected _objects: BaseTabObjects;
|
|
6
|
+
|
|
7
|
+
constructor(page: Page, context: Locator | null = null) {
|
|
8
|
+
this._objects = new BaseTabObjects(page, context);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// --- Common actions ---
|
|
12
|
+
|
|
13
|
+
// Clicks a tab by its tabstrip test id prefix (e.g., "form", "users", "list").
|
|
14
|
+
// Uses the role="tab" element with data-testid^="tabstrip__tab__{name}".
|
|
15
|
+
public async openById(name: string): Promise<void> {
|
|
16
|
+
await this._objects.tabByTestId(name).click();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Clicks a tab by index within the scoped tablist context.
|
|
20
|
+
public async openByIndex(index: number): Promise<void> {
|
|
21
|
+
await this._objects.tabByIndex(index).click();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// --- Useful getters ---
|
|
25
|
+
public async getTabById(name: string): Promise<Locator> {
|
|
26
|
+
return this._objects.tabByTestId(name);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public async getTabByIndex(index: number): Promise<Locator> {
|
|
30
|
+
return this._objects.tabByIndex(index);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Reads the badge value on a tab. Non-visible/invalid → 0.
|
|
34
|
+
public async getBadgeCount(name: string): Promise<number> {
|
|
35
|
+
const badge = this._objects.badgeByName(name);
|
|
36
|
+
const visible = await badge.isVisible().catch(() => false);
|
|
37
|
+
if (!visible) return 0;
|
|
38
|
+
const txt = (await badge.textContent())?.trim() ?? '0';
|
|
39
|
+
const n = Number.parseInt(txt, 10);
|
|
40
|
+
return Number.isNaN(n) ? 0 : n;
|
|
41
|
+
}
|
|
42
|
+
}
|