@thinkwise/testwise 0.2.20 → 0.2.62

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.
Files changed (230) hide show
  1. package/Testwise.ts +2 -0
  2. package/artifact-builder/SelectorBuilder.ts +2 -2
  3. package/artifact-builder/SubjectComponentGenerator.ts +21 -12
  4. package/artifact-builder/SubjectGenerator.ts +24 -8
  5. package/components/action-bar/ActionBar.ts +7 -7
  6. package/components/action-bar/CustomActionBar.ts +0 -5
  7. package/components/cardlist/Cardlist.ts +3 -3
  8. package/components/chart/Chart.ts +3 -3
  9. package/components/combined-filter/CombinedFilter.ts +3 -3
  10. package/components/cube-view-bar/CubeViewBar.ts +3 -3
  11. package/components/filter/ExcelStyleFilterPopup.ts +29 -0
  12. package/components/filter/ExcelStyleFilterPopupObjects.ts +20 -0
  13. package/components/filter/FilterForm.ts +3 -3
  14. package/components/filter/FilterPopup.ts +187 -0
  15. package/components/filter/FilterPopupObjects.ts +63 -0
  16. package/components/filter/ManagePrefilterPopup.ts +44 -0
  17. package/components/filter/ManagePrefilterPopupObjects.ts +28 -0
  18. package/components/form/Form.ts +3 -3
  19. package/components/grid/Grid.ts +15 -119
  20. package/components/grid/GridObjects.ts +0 -4
  21. package/components/index.ts +4 -0
  22. package/components/maps/Maps.ts +3 -3
  23. package/components/menu/ListBarMenuComponent.ts +11 -0
  24. package/components/menu/ListBarMenuComponentObjects.ts +6 -0
  25. package/components/pivot-grid/PivotGrid.ts +3 -3
  26. package/components/pivot-grid/PivotGridFieldList.ts +3 -3
  27. package/components/pop-up/AllRowsPopUp.ts +29 -0
  28. package/components/pop-up/AllRowsPopUpObjects.ts +22 -0
  29. package/components/prefilter-list/PrefilterList.ts +3 -3
  30. package/components/preview/Preview.ts +3 -3
  31. package/components/report-bar/ReportBar.ts +3 -3
  32. package/components/report-tiles/ReportTiles.ts +3 -3
  33. package/components/scheduler/Scheduler.ts +3 -3
  34. package/components/splitter/Splitter.ts +3 -3
  35. package/components/tab/BaseTab.ts +3 -3
  36. package/components/tab/DetailTabPage.ts +4 -4
  37. package/components/tab/Tab.ts +4 -4
  38. package/components/task/TaskBar.ts +3 -3
  39. package/components/task/TaskTiles.ts +3 -3
  40. package/components/topbar/TopBar.ts +2 -0
  41. package/components/tree-view/TreeView.ts +3 -3
  42. package/controls/DateControl.ts +6 -6
  43. package/controls/DateControlObjects.ts +0 -0
  44. package/controls/FormComboBox.ts +7 -7
  45. package/controls/FormComboBoxObjects.ts +0 -0
  46. package/controls/GridColumnControl.ts +68 -0
  47. package/controls/GridColumnControlObjects.ts +20 -0
  48. package/controls/InputFieldControl.ts +6 -6
  49. package/controls/InputFieldControlObjects.ts +0 -0
  50. package/controls/LookupDropdown.ts +58 -16
  51. package/controls/index.ts +1 -0
  52. package/dist/Testwise.d.ts +1 -0
  53. package/dist/Testwise.js +1 -0
  54. package/dist/Testwise.js.map +1 -1
  55. package/dist/artifact-builder/SelectorBuilder.d.ts +1 -1
  56. package/dist/artifact-builder/SelectorBuilder.js +2 -2
  57. package/dist/artifact-builder/SelectorBuilder.js.map +1 -1
  58. package/dist/artifact-builder/SubjectComponentGenerator.js +18 -12
  59. package/dist/artifact-builder/SubjectComponentGenerator.js.map +1 -1
  60. package/dist/artifact-builder/SubjectGenerator.d.ts +1 -0
  61. package/dist/artifact-builder/SubjectGenerator.js +20 -8
  62. package/dist/artifact-builder/SubjectGenerator.js.map +1 -1
  63. package/dist/components/action-bar/ActionBar.d.ts +2 -2
  64. package/dist/components/action-bar/ActionBar.js +7 -7
  65. package/dist/components/action-bar/ActionBar.js.map +1 -1
  66. package/dist/components/action-bar/CustomActionBar.d.ts +0 -2
  67. package/dist/components/action-bar/CustomActionBar.js +0 -3
  68. package/dist/components/action-bar/CustomActionBar.js.map +1 -1
  69. package/dist/components/cardlist/Cardlist.d.ts +2 -2
  70. package/dist/components/cardlist/Cardlist.js +2 -2
  71. package/dist/components/cardlist/Cardlist.js.map +1 -1
  72. package/dist/components/chart/Chart.d.ts +2 -2
  73. package/dist/components/chart/Chart.js +2 -2
  74. package/dist/components/chart/Chart.js.map +1 -1
  75. package/dist/components/combined-filter/CombinedFilter.d.ts +2 -2
  76. package/dist/components/combined-filter/CombinedFilter.js +2 -2
  77. package/dist/components/combined-filter/CombinedFilter.js.map +1 -1
  78. package/dist/components/cube-view-bar/CubeViewBar.d.ts +2 -2
  79. package/dist/components/cube-view-bar/CubeViewBar.js +2 -2
  80. package/dist/components/cube-view-bar/CubeViewBar.js.map +1 -1
  81. package/dist/components/filter/ExcelStyleFilterPopup.d.ts +9 -0
  82. package/dist/components/filter/ExcelStyleFilterPopup.js +22 -0
  83. package/dist/components/filter/ExcelStyleFilterPopup.js.map +1 -0
  84. package/dist/components/filter/ExcelStyleFilterPopupObjects.d.ts +9 -0
  85. package/dist/components/filter/ExcelStyleFilterPopupObjects.js +13 -0
  86. package/dist/components/filter/ExcelStyleFilterPopupObjects.js.map +1 -0
  87. package/dist/components/filter/FilterForm.d.ts +2 -2
  88. package/dist/components/filter/FilterForm.js +2 -2
  89. package/dist/components/filter/FilterForm.js.map +1 -1
  90. package/dist/components/filter/FilterPopup.d.ts +41 -0
  91. package/dist/components/filter/FilterPopup.js +126 -0
  92. package/dist/components/filter/FilterPopup.js.map +1 -0
  93. package/dist/components/filter/FilterPopupObjects.d.ts +29 -0
  94. package/dist/components/filter/FilterPopupObjects.js +30 -0
  95. package/dist/components/filter/FilterPopupObjects.js.map +1 -0
  96. package/dist/components/filter/ManagePrefilterPopup.d.ts +14 -0
  97. package/dist/components/filter/ManagePrefilterPopup.js +33 -0
  98. package/dist/components/filter/ManagePrefilterPopup.js.map +1 -0
  99. package/dist/components/filter/ManagePrefilterPopupObjects.d.ts +11 -0
  100. package/dist/components/filter/ManagePrefilterPopupObjects.js +19 -0
  101. package/dist/components/filter/ManagePrefilterPopupObjects.js.map +1 -0
  102. package/dist/components/form/Form.d.ts +2 -2
  103. package/dist/components/form/Form.js +2 -2
  104. package/dist/components/form/Form.js.map +1 -1
  105. package/dist/components/grid/Grid.d.ts +4 -36
  106. package/dist/components/grid/Grid.js +14 -102
  107. package/dist/components/grid/Grid.js.map +1 -1
  108. package/dist/components/grid/GridObjects.d.ts +0 -2
  109. package/dist/components/grid/GridObjects.js +0 -2
  110. package/dist/components/grid/GridObjects.js.map +1 -1
  111. package/dist/components/index.d.ts +4 -0
  112. package/dist/components/index.js +4 -0
  113. package/dist/components/index.js.map +1 -1
  114. package/dist/components/maps/Maps.d.ts +2 -2
  115. package/dist/components/maps/Maps.js +2 -2
  116. package/dist/components/maps/Maps.js.map +1 -1
  117. package/dist/components/menu/ListBarMenuComponent.d.ts +6 -0
  118. package/dist/components/menu/ListBarMenuComponent.js +10 -0
  119. package/dist/components/menu/ListBarMenuComponent.js.map +1 -1
  120. package/dist/components/menu/ListBarMenuComponentObjects.d.ts +2 -0
  121. package/dist/components/menu/ListBarMenuComponentObjects.js +2 -0
  122. package/dist/components/menu/ListBarMenuComponentObjects.js.map +1 -1
  123. package/dist/components/pivot-grid/PivotGrid.d.ts +2 -2
  124. package/dist/components/pivot-grid/PivotGrid.js +2 -2
  125. package/dist/components/pivot-grid/PivotGrid.js.map +1 -1
  126. package/dist/components/pivot-grid/PivotGridFieldList.d.ts +2 -2
  127. package/dist/components/pivot-grid/PivotGridFieldList.js +2 -2
  128. package/dist/components/pivot-grid/PivotGridFieldList.js.map +1 -1
  129. package/dist/components/pop-up/AllRowsPopUp.d.ts +12 -0
  130. package/dist/components/pop-up/AllRowsPopUp.js +19 -0
  131. package/dist/components/pop-up/AllRowsPopUp.js.map +1 -0
  132. package/dist/components/pop-up/AllRowsPopUpObjects.d.ts +11 -0
  133. package/dist/components/pop-up/AllRowsPopUpObjects.js +13 -0
  134. package/dist/components/pop-up/AllRowsPopUpObjects.js.map +1 -0
  135. package/dist/components/prefilter-list/PrefilterList.d.ts +2 -2
  136. package/dist/components/prefilter-list/PrefilterList.js +2 -2
  137. package/dist/components/prefilter-list/PrefilterList.js.map +1 -1
  138. package/dist/components/preview/Preview.d.ts +2 -2
  139. package/dist/components/preview/Preview.js +2 -2
  140. package/dist/components/preview/Preview.js.map +1 -1
  141. package/dist/components/report-bar/ReportBar.d.ts +2 -2
  142. package/dist/components/report-bar/ReportBar.js +2 -2
  143. package/dist/components/report-bar/ReportBar.js.map +1 -1
  144. package/dist/components/report-tiles/ReportTiles.d.ts +2 -2
  145. package/dist/components/report-tiles/ReportTiles.js +2 -2
  146. package/dist/components/report-tiles/ReportTiles.js.map +1 -1
  147. package/dist/components/scheduler/Scheduler.d.ts +2 -2
  148. package/dist/components/scheduler/Scheduler.js +2 -2
  149. package/dist/components/scheduler/Scheduler.js.map +1 -1
  150. package/dist/components/splitter/Splitter.d.ts +2 -2
  151. package/dist/components/splitter/Splitter.js +2 -2
  152. package/dist/components/splitter/Splitter.js.map +1 -1
  153. package/dist/components/tab/BaseTab.d.ts +2 -2
  154. package/dist/components/tab/BaseTab.js +2 -2
  155. package/dist/components/tab/BaseTab.js.map +1 -1
  156. package/dist/components/tab/DetailTabPage.d.ts +2 -2
  157. package/dist/components/tab/DetailTabPage.js +3 -3
  158. package/dist/components/tab/DetailTabPage.js.map +1 -1
  159. package/dist/components/tab/Tab.d.ts +2 -2
  160. package/dist/components/tab/Tab.js +3 -3
  161. package/dist/components/tab/Tab.js.map +1 -1
  162. package/dist/components/task/TaskBar.d.ts +2 -2
  163. package/dist/components/task/TaskBar.js +2 -2
  164. package/dist/components/task/TaskBar.js.map +1 -1
  165. package/dist/components/task/TaskTiles.d.ts +2 -2
  166. package/dist/components/task/TaskTiles.js +2 -2
  167. package/dist/components/task/TaskTiles.js.map +1 -1
  168. package/dist/components/topbar/TopBar.d.ts +1 -0
  169. package/dist/components/topbar/TopBar.js +1 -0
  170. package/dist/components/topbar/TopBar.js.map +1 -1
  171. package/dist/components/tree-view/TreeView.d.ts +2 -2
  172. package/dist/components/tree-view/TreeView.js +2 -2
  173. package/dist/components/tree-view/TreeView.js.map +1 -1
  174. package/dist/controls/DateControl.d.ts +3 -3
  175. package/dist/controls/DateControl.js +5 -5
  176. package/dist/controls/DateControl.js.map +1 -1
  177. package/dist/controls/DateControlObjects.d.ts +1 -0
  178. package/dist/controls/DateControlObjects.js +2 -0
  179. package/dist/controls/DateControlObjects.js.map +1 -0
  180. package/dist/controls/FormComboBox.d.ts +2 -2
  181. package/dist/controls/FormComboBox.js +6 -6
  182. package/dist/controls/FormComboBox.js.map +1 -1
  183. package/dist/controls/FormComboBoxObjects.d.ts +1 -0
  184. package/dist/controls/FormComboBoxObjects.js +2 -0
  185. package/dist/controls/FormComboBoxObjects.js.map +1 -0
  186. package/dist/controls/GridColumnControl.d.ts +10 -0
  187. package/dist/controls/GridColumnControl.js +43 -0
  188. package/dist/controls/GridColumnControl.js.map +1 -0
  189. package/dist/controls/GridColumnControlObjects.d.ts +9 -0
  190. package/dist/controls/GridColumnControlObjects.js +13 -0
  191. package/dist/controls/GridColumnControlObjects.js.map +1 -0
  192. package/dist/controls/InputFieldControl.d.ts +3 -3
  193. package/dist/controls/InputFieldControl.js +5 -5
  194. package/dist/controls/InputFieldControl.js.map +1 -1
  195. package/dist/controls/InputFieldControlObjects.d.ts +1 -0
  196. package/dist/controls/InputFieldControlObjects.js +2 -0
  197. package/dist/controls/InputFieldControlObjects.js.map +1 -0
  198. package/dist/controls/LookupDropdown.d.ts +6 -1
  199. package/dist/controls/LookupDropdown.js +42 -13
  200. package/dist/controls/LookupDropdown.js.map +1 -1
  201. package/dist/controls/index.d.ts +1 -0
  202. package/dist/controls/index.js +1 -0
  203. package/dist/controls/index.js.map +1 -1
  204. package/dist/enums/ElementTypes.d.ts +1 -1
  205. package/dist/enums/ElementTypes.js +1 -1
  206. package/dist/enums/ElementTypes.js.map +1 -1
  207. package/dist/helpers/FlightTracker.d.ts +7 -0
  208. package/dist/helpers/FlightTracker.js +63 -11
  209. package/dist/helpers/FlightTracker.js.map +1 -1
  210. package/dist/helpers/LoginHelper.d.ts +11 -3
  211. package/dist/helpers/LoginHelper.js +59 -13
  212. package/dist/helpers/LoginHelper.js.map +1 -1
  213. package/dist/index.d.ts +1 -1
  214. package/dist/index.js +1 -1
  215. package/dist/index.js.map +1 -1
  216. package/dist/page-extensions/GlobalComponents.d.ts +2 -1
  217. package/dist/page-extensions/GlobalComponents.js +2 -1
  218. package/dist/page-extensions/GlobalComponents.js.map +1 -1
  219. package/dist/page-overrides/ClickOverride.d.ts +1 -0
  220. package/dist/page-overrides/ClickOverride.js +57 -46
  221. package/dist/page-overrides/ClickOverride.js.map +1 -1
  222. package/dist/types/Universal.d.ts +1 -0
  223. package/enums/ElementTypes.ts +1 -1
  224. package/helpers/FlightTracker.ts +71 -11
  225. package/helpers/LoginHelper.ts +79 -21
  226. package/index.ts +1 -1
  227. package/package.json +6 -5
  228. package/page-extensions/GlobalComponents.ts +3 -0
  229. package/page-overrides/ClickOverride.ts +69 -64
  230. package/types/Universal.ts +1 -0
package/Testwise.ts CHANGED
@@ -7,6 +7,8 @@ import { ClickOverride } from './page-overrides/ClickOverride.js';
7
7
  import { FillOverride } from './page-overrides/FillOverride.js';
8
8
  import type { Test } from './types/Test.js';
9
9
 
10
+ export * from '@playwright/test';
11
+
10
12
  function combineExtensions(baseTest: Test, ...extensions: { new (test: Test): { test: Test } }[]) {
11
13
  return extensions.reduce((test, Extension) => new Extension(test).test, baseTest);
12
14
  }
@@ -60,7 +60,7 @@ export class SelectorBuilder {
60
60
  );
61
61
  }
62
62
 
63
- public getPageLocatorString(property: string, componentName: SubjectComponents): string {
63
+ public getLocatorString(property: string, componentName: SubjectComponents): string {
64
64
  let elementId = this.getElementId(property, componentName);
65
65
 
66
66
  if (componentName === 'Grid') elementId = elementId.replace(/-/g, '_');
@@ -69,7 +69,7 @@ export class SelectorBuilder {
69
69
  const defaultSuffix = this.getDefaultSuffix(componentName);
70
70
  const selectorSuffix = this.determineSelectorSuffix(property, componentName) || defaultSuffix;
71
71
 
72
- return `page.${this.getLocatorType(componentName)}('${selectorPrefix}${elementId}${selectorSuffix}')`;
72
+ return `this._context.${this.getLocatorType(componentName)}('${selectorPrefix}${elementId}${selectorSuffix}')`;
73
73
  }
74
74
 
75
75
  private getLocatorType(componentName: SubjectComponents): LocatorType {
@@ -118,9 +118,12 @@ export class SubjectComponentGenerator {
118
118
  const classBody =
119
119
  componentName === 'Grid'
120
120
  ? `\nexport class ${mainInterface}Component extends ${componentName} implements ${mainInterface} {\n\n` +
121
- ` constructor(page: Page, context: Locator | null = null) {\n super(page, context);\n }\n\n${gridGetters}}\n`
122
- : `\nexport class ${mainInterface}Component extends ${componentName} implements ${mainInterface} {\n${propertyDeclarations}\n\n` +
123
- ` constructor(page: Page, context: Locator | null = null) {\n super(page, context);\n${assignments}\n }\n}\n`;
121
+ ` private _context: Locator;\n\n` +
122
+ ` constructor(context: Locator) {\n super(context);\n this._context = context;\n }\n\n${gridGetters}}\n`
123
+ : `\nexport class ${mainInterface}Component extends ${componentName} implements ${mainInterface} {\n\n` +
124
+ ` private _context: Locator;\n` +
125
+ `${propertyDeclarations}\n\n` +
126
+ ` constructor(context: Locator) {\n super(context);\n this._context = context;\n${assignments}\n }\n}\n`;
124
127
 
125
128
  componentFile.content += classBody;
126
129
  }
@@ -145,7 +148,7 @@ export class SubjectComponentGenerator {
145
148
  const interfaceRegex = /export interface \w+ extends Grid \{([\s\S]*?)\}/g;
146
149
 
147
150
  componentFile.content = componentFile.content.replace(interfaceRegex, (match, body) => {
148
- const transformedBody = body.replace(/(\w+)\s*:\s*Locator(?:\[\])?;/g, 'readonly $1: Promise<Locator[]>;');
151
+ const transformedBody = body.replace(/(\w+)\s*:\s*Locator(?:\[\])?;/g, 'readonly $1: IGridColumnControl;');
149
152
  return match.replace(body, transformedBody);
150
153
  });
151
154
  }
@@ -154,9 +157,9 @@ export class SubjectComponentGenerator {
154
157
  return propertyLines
155
158
  .map((line) => {
156
159
  const property = line.replace('readonly', '').split(':')[0].trim();
157
- const pageLocatorString = this._selectorBuilder.getPageLocatorString(property, componentName);
160
+ const columnId = this._selectorBuilder.getElementId(property, componentName);
158
161
 
159
- return ` get ${property}(): Promise<Locator[]> {\n return this.${pageLocatorString}.all();\n }\n`;
162
+ return ` public get ${property}(): IGridColumnControl {\n return createGridColumnControl(this._context, '${columnId}');\n }\n`;
160
163
  })
161
164
  .join('\n');
162
165
  }
@@ -178,19 +181,20 @@ export class SubjectComponentGenerator {
178
181
  return propertyLines
179
182
  .map((line) => {
180
183
  const property = line.split(':')[0].replace(/\?$/, '').trim();
181
- const pageLocatorString = this._selectorBuilder.getPageLocatorString(property, componentName);
184
+ const pageLocatorString = this._selectorBuilder.getLocatorString(property, componentName);
182
185
 
183
186
  if (componentName === 'Form') {
184
- if (property.endsWith('Lookup')) return ` this.${property} = createLookupDropdown(${pageLocatorString});`;
187
+ if (property.endsWith('Lookup'))
188
+ return ` this.${property} = createLookupDropdown(this._context, '${this._selectorBuilder.getElementId(property, componentName)}');`;
185
189
 
186
190
  if (property.endsWith('DatePicker'))
187
- return ` this.${property} = createDateControl(page, '${this._selectorBuilder.getElementId(property, componentName)}');`;
191
+ return ` this.${property} = createDateControl(this._context, '${this._selectorBuilder.getElementId(property, componentName)}');`;
188
192
 
189
193
  if (property.endsWith('ComboBox'))
190
- return ` this.${property} = createFormComboBox(page, '${this._selectorBuilder.getElementId(property, componentName)}');`;
194
+ return ` this.${property} = createFormComboBox(this._context, '${this._selectorBuilder.getElementId(property, componentName)}');`;
191
195
 
192
196
  if (property.endsWith('Field'))
193
- return ` this.${property} = createInputFieldControl(page, '${this._selectorBuilder.getElementId(property, componentName)}');`;
197
+ return ` this.${property} = createInputFieldControl(this._context, '${this._selectorBuilder.getElementId(property, componentName)}');`;
194
198
  }
195
199
 
196
200
  return ` this.${property} = ${pageLocatorString};`;
@@ -304,7 +308,12 @@ export class SubjectComponentGenerator {
304
308
 
305
309
  private addComponentImports(componentFile: { content: string }, componentName: string): void {
306
310
  // biome-ignore lint/style/useTemplate: reason 42
307
- componentFile.content = `import type { Locator, Page } from '@playwright/test';\n\n` + componentFile.content;
311
+ componentFile.content = `import type { Locator } from '@playwright/test';\n\n` + componentFile.content;
312
+
313
+ if (componentName === 'Grid') {
314
+ componentFile.content = `import { createGridColumnControl, type IGridColumnControl } from '../../../../controls/GridColumnControl.js';\n${componentFile.content}`;
315
+ }
316
+
308
317
  componentFile.content = `import { ${componentName} } from '../../../../components/index.js';\n${componentFile.content}`;
309
318
  }
310
319
 
@@ -98,11 +98,20 @@ export class SubjectGenerator {
98
98
  this.addClassExport(subjectClass, screenInterfaceName);
99
99
  this.addComponentDeclarations(subjectClass, componentDictionary, subjectFolderName);
100
100
  this.addConstructor(subjectClass, componentDictionary, subjectFolderName, subject);
101
+ this.addGoToMethod(subjectClass, subject);
101
102
  this.addSubjectClassLineEndings(subjectClass);
102
103
  this.verifyDirectoryExists(subjectFolderPath);
103
104
  fs.writeFileSync(path.join(subjectFolderPath, `${subjectClass.name}.ts`), subjectClass.content, 'utf-8');
104
105
  }
105
106
 
107
+ private addGoToMethod(subjectClass: { content: string }, subject: ISubject): void {
108
+ let url = `subject=${subject.subject}`;
109
+
110
+ if (subject.variant !== '') url = `${url}/subjectVariant=${subject.variant}`;
111
+
112
+ subjectClass.content += `\n public async goTo() {\n await this._subjectPage.goToDeepLink(\`${url}\`);\n await this._subjectPage.waitForLoadState('networkidle');\n }\n`;
113
+ }
114
+
106
115
  private getAllComponentsFromInterface(
107
116
  screenFileContent: string,
108
117
  screenInterfaceName: string,
@@ -266,6 +275,8 @@ export class SubjectGenerator {
266
275
  const componentType = `${subjectFolderName}${component.type}`;
267
276
  subjectClass.content += ` ${propertyName}: ${componentType};\n`;
268
277
  });
278
+
279
+ subjectClass.content += ` private _subjectPage: Page;\n`;
269
280
  }
270
281
 
271
282
  private addConstructor(
@@ -284,23 +295,26 @@ export class SubjectGenerator {
284
295
  if (!screenComponents.includes(component.type)) return;
285
296
 
286
297
  if (coreComponents.includes(component.type)) {
287
- subjectClass.content += ` this.${propertyName} = ${this.getComponentInitializer(component)};\n`;
298
+ const componentId = this._namingHandler.toPascalCase(propertyName);
299
+ subjectClass.content += ` this.${propertyName} = ${this.getComponentInitializer(component, componentId)};\n`;
288
300
  return;
289
301
  }
290
302
 
291
303
  const componentName = component.type;
292
- subjectClass.content += ` this.${propertyName} = new ${subjectFolderName}${componentName}Component(page, ${component.context});\n`;
304
+ subjectClass.content += ` this.${propertyName} = new ${subjectFolderName}${componentName}Component(${component.context});\n`;
293
305
  });
306
+
307
+ subjectClass.content += ` this._subjectPage = this.context.page();\n`;
308
+ subjectClass.content += ` }\n`;
294
309
  }
295
310
 
296
- private getComponentInitializer(component: { type: string; context: string }): string {
311
+ private getComponentInitializer(component: { type: string; context: string }, componentId: string): string {
297
312
  const componentNamePascal = this._namingHandler.toPascalCase(component.type);
298
313
 
299
314
  switch (component.type) {
300
315
  case 'Cardlist':
301
316
  case 'TaskTiles':
302
317
  case 'PrefilterList':
303
- case 'TaskBar':
304
318
  case 'Chart':
305
319
  case 'CubeViewBar':
306
320
  case 'PivotGrid':
@@ -309,7 +323,7 @@ export class SubjectGenerator {
309
323
  case 'ReportBar':
310
324
  case 'ReportTiles':
311
325
  case 'Preview':
312
- return `new ${component.type}(page, this.context.locator('.${component.type}.${componentNamePascal}'))`;
326
+ return `new ${component.type}(this.context.locator('.${component.type}.${componentNamePascal}'))`;
313
327
  case 'CombinedFilter':
314
328
  case 'CustomActionBar':
315
329
  case 'ActionBar':
@@ -318,15 +332,17 @@ export class SubjectGenerator {
318
332
  case 'Tab':
319
333
  case 'FilterForm':
320
334
  case 'Scheduler':
321
- return `new ${component.type}(page, ${component.context})`;
335
+ return `new ${component.type}(${component.context})`;
322
336
  case 'TreeView':
323
- return `new ${component.type}(page, this.context.locator('.Tree.${componentNamePascal}'))`;
337
+ return `new ${component.type}(this.context.locator('.Tree.${componentNamePascal}'))`;
338
+ case 'TaskBar':
339
+ return `new ${component.type}(this.context.locator('.ActionBar.${componentId}'))`;
324
340
  default:
325
341
  throw new Error(`Unknown core component type: ${component.type}`);
326
342
  }
327
343
  }
328
344
 
329
345
  private addSubjectClassLineEndings(subjectClass: { content: string }): void {
330
- subjectClass.content += ` }\n}\n`;
346
+ subjectClass.content += `}\n`;
331
347
  }
332
348
  }
@@ -4,8 +4,8 @@ import { ActionBarObjects, ActionBarOverflowableObjects } from './ActionBarObjec
4
4
  class ActionBarActions {
5
5
  private _objects: ActionBarOverflowableObjects;
6
6
 
7
- constructor(page: Page, context: Locator | null = null) {
8
- this._objects = new ActionBarOverflowableObjects(page, context);
7
+ constructor(context: Locator) {
8
+ this._objects = new ActionBarOverflowableObjects(context.page(), context);
9
9
  }
10
10
 
11
11
  public getSearchInput = (): Locator => this._objects.searchInput();
@@ -90,10 +90,10 @@ export class ActionBar extends ActionBarActions {
90
90
  private _actionBarObjects: ActionBarObjects;
91
91
  private _overflowMenu: ActionBarOverflow;
92
92
 
93
- constructor(page: Page, actionBarContext: Locator | null = null) {
94
- super(page, actionBarContext);
95
- this._actionBarObjects = new ActionBarObjects(page, actionBarContext);
96
- this._overflowMenu = new ActionBarOverflow(page);
93
+ constructor(actionBarContext: Locator) {
94
+ super(actionBarContext);
95
+ this._actionBarObjects = new ActionBarObjects(actionBarContext.page(), actionBarContext);
96
+ this._overflowMenu = new ActionBarOverflow(actionBarContext.page());
97
97
  }
98
98
 
99
99
  public openOverflowMenu = async (): Promise<void> => {
@@ -148,7 +148,7 @@ export class ActionBar extends ActionBarActions {
148
148
 
149
149
  export class ActionBarOverflow extends ActionBarActions {
150
150
  constructor(page: Page) {
151
- super(page, page.getByTestId('actionbar__overflow-menu__context'));
151
+ super(page.getByTestId('actionbar__overflow-menu__context'));
152
152
  }
153
153
  }
154
154
 
@@ -1,10 +1,5 @@
1
- import type { Locator, Page } from '@playwright/test';
2
1
  import { ActionBar } from './ActionBar.js';
3
2
 
4
3
  export class CustomActionBar extends ActionBar {
5
- constructor(page: Page, context: Locator | null = null) {
6
- super(page, context);
7
- }
8
-
9
4
  // What should this do differently?
10
5
  }
@@ -1,11 +1,11 @@
1
- import type { Locator, Page } from '@playwright/test';
1
+ import type { Locator } from '@playwright/test';
2
2
  import { CardlistObjects } from './CardlistObjects.js';
3
3
 
4
4
  export class Cardlist {
5
5
  cardlistObjects: CardlistObjects;
6
6
 
7
- constructor(page: Page, context: Locator | null = null) {
8
- this.cardlistObjects = new CardlistObjects(page, context);
7
+ constructor(context: Locator) {
8
+ this.cardlistObjects = new CardlistObjects(context.page(), context);
9
9
  }
10
10
 
11
11
  public get context(): Locator | null {
@@ -1,11 +1,11 @@
1
- import type { Locator, Page } from '@playwright/test';
1
+ import type { Locator } from '@playwright/test';
2
2
  import { ChartObjects } from './ChartObjects.js';
3
3
 
4
4
  export class Chart {
5
5
  chartObjects: ChartObjects;
6
6
 
7
- constructor(page: Page, context: Locator | null = null) {
8
- this.chartObjects = new ChartObjects(page, context);
7
+ constructor(context: Locator) {
8
+ this.chartObjects = new ChartObjects(context.page(), context);
9
9
  }
10
10
 
11
11
  public get context(): Locator | null {
@@ -1,11 +1,11 @@
1
- import type { Locator, Page } from '@playwright/test';
1
+ import type { Locator } from '@playwright/test';
2
2
  import { CombinedFilterObjects } from './CombinedFIlterObjects.js';
3
3
 
4
4
  export class CombinedFilter {
5
5
  combinedFilterObjects: CombinedFilterObjects;
6
6
 
7
- constructor(page: Page, context: Locator | null = null) {
8
- this.combinedFilterObjects = new CombinedFilterObjects(page, context);
7
+ constructor(context: Locator) {
8
+ this.combinedFilterObjects = new CombinedFilterObjects(context.page(), context);
9
9
  }
10
10
 
11
11
  public get context(): Locator | null {
@@ -1,11 +1,11 @@
1
- import type { Locator, Page } from '@playwright/test';
1
+ import type { Locator } from '@playwright/test';
2
2
  import { CubeViewBarObjects } from './CubeViewBarObjects.js';
3
3
 
4
4
  export class CubeViewBar {
5
5
  cubeViewBarObjects: CubeViewBarObjects;
6
6
 
7
- constructor(page: Page, context: Locator | null = null) {
8
- this.cubeViewBarObjects = new CubeViewBarObjects(page, context);
7
+ constructor(context: Locator) {
8
+ this.cubeViewBarObjects = new CubeViewBarObjects(context.page(), context);
9
9
  }
10
10
 
11
11
  public get context(): Locator | null {
@@ -0,0 +1,29 @@
1
+ import type { Locator, Page } from '@playwright/test';
2
+ import { ExcelStyleFilterPopupObjects } from './ExcelStyleFilterPopupObjects.js';
3
+
4
+ export class ExcelStyleFilterPopup {
5
+ private _excelStyleFilterPopupObjects: ExcelStyleFilterPopupObjects;
6
+
7
+ constructor(page: Page) {
8
+ this._excelStyleFilterPopupObjects = new ExcelStyleFilterPopupObjects(page);
9
+ }
10
+
11
+ async waitForOpen(): Promise<void> {
12
+ await this._excelStyleFilterPopupObjects.anchor().waitFor({ state: 'visible' });
13
+ }
14
+
15
+ intervalFilters(): Locator {
16
+ return this._excelStyleFilterPopupObjects.intervalFilters();
17
+ }
18
+
19
+ fromDateInput(fieldTestId: string): Locator {
20
+ return this._excelStyleFilterPopupObjects.fromDateInput(fieldTestId);
21
+ }
22
+
23
+ async setFromDate(fieldTestId: string, value: string): Promise<void> {
24
+ await this.waitForOpen();
25
+ const input = this._excelStyleFilterPopupObjects.fromDateInput(fieldTestId);
26
+ await input.fill(value);
27
+ await input.press('Enter');
28
+ }
29
+ }
@@ -0,0 +1,20 @@
1
+ import type { Page } from '@playwright/test';
2
+ import { BaseComponentObjects } from '../BaseComponentObjects.js';
3
+
4
+ export class ExcelStyleFilterPopupObjects extends BaseComponentObjects {
5
+ private _page: Page;
6
+
7
+ constructor(page: Page) {
8
+ super(page, page.locator('body'));
9
+ this._page = page;
10
+ }
11
+
12
+ public anchor = () => this._page.locator('[data-testid^="date-time-excel-filter__"]').first();
13
+
14
+ public intervalFilters = () => this._page.getByTestId('excel-style-filter-popup__interval-filters');
15
+
16
+ public fromDateInput = (fieldTestId: string) =>
17
+ this._page
18
+ .getByTestId(`date-time-excel-filter__${fieldTestId}__from`)
19
+ .getByTestId(`form-field__${fieldTestId}__date__input`);
20
+ }
@@ -1,11 +1,11 @@
1
- import type { Locator, Page } from '@playwright/test';
1
+ import type { Locator } from '@playwright/test';
2
2
  import { FilterFormObjects } from './FilterFormObjects.js';
3
3
 
4
4
  export class FilterForm {
5
5
  filterFormObjects: FilterFormObjects;
6
6
 
7
- constructor(page: Page, context: Locator | null = null) {
8
- this.filterFormObjects = new FilterFormObjects(page, context);
7
+ constructor(context: Locator) {
8
+ this.filterFormObjects = new FilterFormObjects(context.page(), context);
9
9
  }
10
10
 
11
11
  public get context(): Locator | null {
@@ -0,0 +1,187 @@
1
+ import type { Locator, Page } from '@playwright/test';
2
+ import { PopUpComponent } from '../pop-up/PopUpComponent.js';
3
+ import { FilterPopupObjects } from './FilterPopupObjects.js';
4
+
5
+ export type IntervalType =
6
+ | 'date'
7
+ | 'date-and-time'
8
+ | 'time'
9
+ | 'year'
10
+ | 'quarter'
11
+ | 'month'
12
+ | 'week-of-the-year'
13
+ | 'day-of-the-month';
14
+
15
+ export type AutocompleteKey =
16
+ | IntervalType
17
+ | 'equal-to'
18
+ | 'smaller-than'
19
+ | 'q1'
20
+ | 'q2'
21
+ | 'q3'
22
+ | 'q4'
23
+ | 'january'
24
+ | 'february'
25
+ | 'march'
26
+ | 'april'
27
+ | 'may'
28
+ | 'june'
29
+ | 'july'
30
+ | 'august'
31
+ | 'september'
32
+ | 'october'
33
+ | 'november'
34
+ | 'december'
35
+ | 'all-of-the-following'
36
+ | 'any-of-the-following';
37
+
38
+ export class FilterPopup {
39
+ readonly page: Page;
40
+ private _filterPopupObjects: FilterPopupObjects;
41
+ private _body: Locator;
42
+
43
+ constructor(page: Page) {
44
+ this.page = page;
45
+ this._body = new PopUpComponent(page).getContentBody();
46
+ this._filterPopupObjects = new FilterPopupObjects(page, this._body);
47
+ }
48
+
49
+ // Root content locator (useful for occasional assertions)
50
+ public content(): Locator {
51
+ return this._body;
52
+ }
53
+
54
+ public async waitForOpen(): Promise<void> {
55
+ await this._filterPopupObjects.applyFilterButton().waitFor();
56
+ }
57
+
58
+ public async applyFilter(): Promise<void> {
59
+ await this.waitForOpen();
60
+ await this._filterPopupObjects.applyFilterButton().click();
61
+ }
62
+
63
+ public async applySaveAsPrefilterWithName(name: string): Promise<void> {
64
+ await this.waitForOpen();
65
+ await this._filterPopupObjects.applySaveButton().click();
66
+ await this._filterPopupObjects.saveAsOption().click();
67
+ await this.saveAsPrefilterPopup(name);
68
+ }
69
+
70
+ public async saveAsPrefilterPopup(name: string): Promise<void> {
71
+ await this.waitForOpen();
72
+ await this._filterPopupObjects.prefilterNameInput().fill(name);
73
+ await this._filterPopupObjects.saveButton().click();
74
+ }
75
+ public async setAdvanced(enabled: boolean): Promise<void> {
76
+ await this.waitForOpen();
77
+ const checkbox = this._filterPopupObjects.advancedToggleCheckbox();
78
+ if (enabled) await checkbox.check();
79
+ else await checkbox.uncheck();
80
+ }
81
+
82
+ public advancedGroupSelect(): Locator {
83
+ return this._filterPopupObjects.advancedGroupSelect();
84
+ }
85
+
86
+ public async setGroupCondition(key: 'all-of-the-following' | 'any-of-the-following'): Promise<void> {
87
+ await this.waitForOpen();
88
+ await this._filterPopupObjects.advancedGroupSelect().click();
89
+ await this._filterPopupObjects.groupConditionOption(key).click();
90
+ }
91
+
92
+ public fieldInput(fieldId: string): Locator {
93
+ return this._filterPopupObjects.fieldInput(fieldId);
94
+ }
95
+
96
+ public valueInput(fieldId: string, part: string): Locator {
97
+ return this._filterPopupObjects.valueInput(fieldId, part);
98
+ }
99
+
100
+ public dateInput(fieldId: string): Locator {
101
+ return this._filterPopupObjects.dateInput(fieldId);
102
+ }
103
+
104
+ public async setText(fieldId: string, value: string): Promise<void> {
105
+ await this.waitForOpen();
106
+ const input = this._filterPopupObjects.fieldInput(fieldId);
107
+ await input.click();
108
+ await input.press('ControlOrMeta+a');
109
+ await input.fill(value);
110
+ }
111
+
112
+ public async setValue(args: { fieldId: string; part: string; value: string }): Promise<void> {
113
+ await this.waitForOpen();
114
+ const input = this._filterPopupObjects.valueInput(args.fieldId, args.part);
115
+ await input.click();
116
+ await input.press('ControlOrMeta+a');
117
+ await input.fill(args.value);
118
+ }
119
+
120
+ // Some inputs (date picker) need a blur/commit to apply the value
121
+ public async commit(args: { fieldId: string; part: string }): Promise<void> {
122
+ await this.waitForOpen();
123
+ await this._filterPopupObjects.valueInput(args.fieldId, args.part).press('Tab');
124
+ }
125
+
126
+ public async openControl(fieldId: string, part: string): Promise<void> {
127
+ await this.waitForOpen();
128
+ await this._filterPopupObjects.fieldControl(fieldId, part).click();
129
+ }
130
+
131
+ public async openOperator(fieldId: string): Promise<void> {
132
+ await this.waitForOpen();
133
+ await this._filterPopupObjects.operatorControl(fieldId).click();
134
+ }
135
+
136
+ public async openTimeOperator(): Promise<void> {
137
+ await this.waitForOpen();
138
+ await this._filterPopupObjects.timeOperatorControl().click();
139
+ }
140
+
141
+ public intervalSelector(rowIndex: number, colId: string): Locator {
142
+ return this._filterPopupObjects.intervalSelector(rowIndex, colId);
143
+ }
144
+
145
+ public intervalSelectorInput(rowIndex: number, colId: string): Locator {
146
+ return this._filterPopupObjects.intervalSelectorInput(rowIndex, colId);
147
+ }
148
+
149
+ public async openInterval(rowIndex: number, colId: string): Promise<void> {
150
+ await this.waitForOpen();
151
+ await this._filterPopupObjects.intervalSelectorInput(rowIndex, colId).click();
152
+ }
153
+
154
+ public async setInterval(rowIndex: number, colId: string, kind: IntervalType): Promise<void> {
155
+ await this.openInterval(rowIndex, colId);
156
+ await this.pickAutocomplete(kind);
157
+ }
158
+
159
+ public autocompleteOption(key: AutocompleteKey): Locator {
160
+ return this._filterPopupObjects.autocompleteOption(key);
161
+ }
162
+
163
+ public async pickAutocomplete(key: AutocompleteKey): Promise<void> {
164
+ const option = this._filterPopupObjects.autocompleteOption(key);
165
+ await option.click();
166
+ }
167
+
168
+ public async selectField(field: string): Promise<void> {
169
+ await this.waitForOpen();
170
+ const emptyRow = this._filterPopupObjects.emptySelectFieldRow();
171
+
172
+ if (await emptyRow.count()) {
173
+ await this._filterPopupObjects.emptySelectFieldRowButton().click();
174
+ } else {
175
+ await this._filterPopupObjects.selectFieldButton().click();
176
+ }
177
+
178
+ await this._filterPopupObjects.colIdOption(field).click();
179
+ }
180
+
181
+ // In advanced mode: add a new row, then select a field into it
182
+ public async addField(field: string): Promise<void> {
183
+ await this.waitForOpen();
184
+ await this._filterPopupObjects.addFieldButton().click();
185
+ await this.selectField(field);
186
+ }
187
+ }
@@ -0,0 +1,63 @@
1
+ import type { Locator, Page } from '@playwright/test';
2
+ import { BaseComponentObjects } from '../BaseComponentObjects.js';
3
+ import type { AutocompleteKey } from './FilterPopup.js';
4
+
5
+ export class FilterPopupObjects extends BaseComponentObjects {
6
+ private _page: Page;
7
+
8
+ constructor(page: Page, body: Locator) {
9
+ super(page, body);
10
+ this._page = page;
11
+ }
12
+
13
+ public applyFilterButton = () => this.context.getByTestId('split-button-main');
14
+
15
+ public applySaveButton = () => this.context.getByTestId('split-button-arrow');
16
+
17
+ public advancedToggleCheckbox = () => this._page.getByRole('checkbox', { name: 'Advanced filter' });
18
+
19
+ public advancedGroupSelect = () => this.context.getByTestId('advanced-filter-group-select');
20
+
21
+ public groupConditionOption = (key: 'all-of-the-following' | 'any-of-the-following') =>
22
+ this._page.getByTestId(`group-condition-select__${key}`);
23
+
24
+ public fieldInput = (fieldId: string) => this.context.getByTestId(`form-field__${fieldId}__input`);
25
+
26
+ public prefilterNameInput = () => this.context.getByTestId('prefilter__name__input');
27
+
28
+ public saveAsOption = () => this._page.getByRole('menuitem', { name: 'Save' });
29
+
30
+ public saveButton = () => this._page.getByRole('button', { name: 'Save' });
31
+
32
+ public valueInput = (fieldId: string, part: string) =>
33
+ this.context.getByTestId(`form-field__${fieldId}__${part}__input`);
34
+
35
+ public dateInput = (fieldId: string) => this.valueInput(fieldId, 'date');
36
+
37
+ public fieldControl = (fieldId: string, part: string) =>
38
+ this.context.getByTestId(`form-field__${fieldId}__${part}__control`).getByRole('button', { name: 'Open' });
39
+
40
+ public operatorControl = (fieldId: string) =>
41
+ this.context.getByTestId(`form-field__${fieldId}__operator__control`).getByRole('button', { name: 'Open' });
42
+
43
+ public timeOperatorControl = () =>
44
+ this.context.getByTestId('form-field__event-time__operator__control').getByRole('button', { name: 'Open' });
45
+
46
+ public intervalSelector = (rowIndex: number, colId: string) =>
47
+ this.context.getByTestId(`advanced-filter-grid__row${rowIndex}__${colId}__select-interval`);
48
+
49
+ public intervalSelectorInput = (rowIndex: number, colId: string) =>
50
+ this.intervalSelector(rowIndex, colId).getByTestId('select-interval__input');
51
+
52
+ public autocompleteOption = (key: AutocompleteKey) => this._page.getByTestId(`autocomplete-option-${key}`);
53
+
54
+ public emptySelectFieldRow = () => this.context.getByTestId('advanced-filter-grid__row-empty-select-field');
55
+
56
+ public emptySelectFieldRowButton = () => this.emptySelectFieldRow().getByRole('button');
57
+
58
+ public selectFieldButton = () => this._page.getByRole('button', { name: 'Select field' });
59
+
60
+ public addFieldButton = () => this._page.getByRole('button', { name: 'Add field' });
61
+
62
+ public colIdOption = (field: string) => this._page.getByTestId(`col-id-${field}`);
63
+ }