@thinkwise/testwise 0.2.67 → 0.2.103
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 +35 -0
- package/artifact-builder/ArtifactManager.ts +25 -2
- package/artifact-builder/ComponentClassModelBuilder.ts +148 -0
- package/artifact-builder/InterfaceGenerator.ts +31 -33
- package/artifact-builder/ModelDataBuilder.ts +18 -20
- package/artifact-builder/ModelDataRefiner.ts +23 -3
- package/artifact-builder/SchemaGenerator.ts +45 -35
- package/artifact-builder/ScreenInterfaceRefiner.ts +25 -10
- package/artifact-builder/SelectorBuilder.ts +30 -24
- package/artifact-builder/SubjectClassModelBuilder.ts +209 -0
- package/artifact-builder/SubjectComponentGenerator.ts +67 -246
- package/artifact-builder/SubjectGenerator.ts +117 -230
- package/artifact-builder/SubjectRegistration.ts +41 -32
- package/artifact-builder/TsFileModel.ts +94 -0
- package/artifact-builder/TsFileSerializer.ts +247 -0
- package/artifact-builder/helpers/DataRetriever.ts +64 -27
- package/artifact-builder/helpers/NamingHandler.ts +23 -78
- package/artifact-builder/helpers/PipelinePaths.ts +123 -0
- package/artifact-builder/helpers/Stopwatch.ts +10 -0
- package/artifact-builder/helpers/index.ts +1 -0
- package/artifact-builder/index.ts +4 -0
- package/components/BaseComponentObjects.ts +17 -0
- package/components/action-bar/ActionBar.ts +35 -47
- package/components/action-bar/ActionBarObjects.ts +2 -0
- package/components/action-bar/CustomActionBar.ts +6 -0
- package/components/cardlist/Cardlist.ts +6 -0
- package/components/chart/Chart.ts +6 -0
- package/components/combined-filter/CombinedFilter.ts +9 -0
- package/components/cube-view-bar/CubeViewBar.ts +6 -0
- package/components/export/ExportComponent.ts +12 -0
- package/components/filter/ExcelStyleFilterPopup.ts +35 -2
- package/components/filter/FilterForm.ts +10 -0
- package/components/filter/FilterPopup.ts +30 -9
- package/components/filter/FilterPopupObjects.ts +10 -3
- package/components/filter/FindForm.ts +7 -0
- package/components/filter/ManagePrefilterPopup.ts +11 -0
- package/components/form/Form.ts +16 -0
- package/components/grid/Grid.ts +18 -1
- package/components/maps/Maps.ts +6 -0
- package/components/menu/ListBarMenuComponent.ts +10 -0
- package/components/pivot-grid/PivotGrid.ts +6 -0
- package/components/pivot-grid/PivotGridFieldList.ts +7 -0
- package/components/pop-up/AllRowsPopUp.ts +12 -0
- package/components/pop-up/PopUpComponent.ts +11 -0
- package/components/prefilter-list/PrefilterList.ts +9 -0
- package/components/preview/Preview.ts +6 -0
- package/components/report-bar/ReportBar.ts +6 -0
- package/components/report-tiles/ReportTiles.ts +6 -0
- package/components/scheduler/Scheduler.ts +6 -0
- package/components/snackbar/SnackBar.ts +12 -0
- package/components/splitter/Splitter.ts +6 -0
- package/components/tab/BaseTab.ts +5 -0
- package/components/tab/DetailTabPage.ts +11 -0
- package/components/tab/Tab.ts +10 -0
- package/components/task/TaskBar.ts +13 -3
- package/components/task/TaskTiles.ts +12 -3
- package/components/topbar/TopBar.ts +10 -0
- package/components/tree-view/TreeView.ts +9 -0
- package/controls/DateControl.ts +40 -1
- package/controls/FormComboBox.ts +30 -0
- package/controls/GridColumnControl.ts +34 -3
- package/controls/InputFieldControl.ts +49 -0
- package/controls/LookupDropdown.ts +29 -0
- package/dist/Testwise.js +35 -0
- package/dist/Testwise.js.map +1 -1
- package/dist/artifact-builder/ArtifactManager.d.ts +18 -1
- package/dist/artifact-builder/ArtifactManager.js +24 -2
- package/dist/artifact-builder/ArtifactManager.js.map +1 -1
- package/dist/artifact-builder/ComponentClassModelBuilder.d.ts +22 -0
- package/dist/artifact-builder/ComponentClassModelBuilder.js +115 -0
- package/dist/artifact-builder/ComponentClassModelBuilder.js.map +1 -0
- package/dist/artifact-builder/InterfaceGenerator.d.ts +15 -6
- package/dist/artifact-builder/InterfaceGenerator.js +27 -26
- package/dist/artifact-builder/InterfaceGenerator.js.map +1 -1
- package/dist/artifact-builder/ModelDataBuilder.d.ts +7 -0
- package/dist/artifact-builder/ModelDataBuilder.js +13 -5
- package/dist/artifact-builder/ModelDataBuilder.js.map +1 -1
- package/dist/artifact-builder/ModelDataRefiner.d.ts +18 -1
- package/dist/artifact-builder/ModelDataRefiner.js +18 -3
- package/dist/artifact-builder/ModelDataRefiner.js.map +1 -1
- package/dist/artifact-builder/SchemaGenerator.d.ts +21 -5
- package/dist/artifact-builder/SchemaGenerator.js +38 -26
- package/dist/artifact-builder/SchemaGenerator.js.map +1 -1
- package/dist/artifact-builder/ScreenInterfaceRefiner.d.ts +18 -1
- package/dist/artifact-builder/ScreenInterfaceRefiner.js +23 -9
- package/dist/artifact-builder/ScreenInterfaceRefiner.js.map +1 -1
- package/dist/artifact-builder/SelectorBuilder.d.ts +18 -5
- package/dist/artifact-builder/SelectorBuilder.js +29 -14
- package/dist/artifact-builder/SelectorBuilder.js.map +1 -1
- package/dist/artifact-builder/SubjectClassModelBuilder.d.ts +38 -0
- package/dist/artifact-builder/SubjectClassModelBuilder.js +158 -0
- package/dist/artifact-builder/SubjectClassModelBuilder.js.map +1 -0
- package/dist/artifact-builder/SubjectComponentGenerator.d.ts +25 -14
- package/dist/artifact-builder/SubjectComponentGenerator.js +65 -189
- package/dist/artifact-builder/SubjectComponentGenerator.js.map +1 -1
- package/dist/artifact-builder/SubjectGenerator.d.ts +32 -13
- package/dist/artifact-builder/SubjectGenerator.js +81 -165
- package/dist/artifact-builder/SubjectGenerator.js.map +1 -1
- package/dist/artifact-builder/SubjectRegistration.d.ts +22 -8
- package/dist/artifact-builder/SubjectRegistration.js +29 -14
- package/dist/artifact-builder/SubjectRegistration.js.map +1 -1
- package/dist/artifact-builder/TsFileModel.d.ts +86 -0
- package/dist/artifact-builder/TsFileModel.js +2 -0
- package/dist/artifact-builder/TsFileModel.js.map +1 -0
- package/dist/artifact-builder/TsFileSerializer.d.ts +19 -0
- package/dist/artifact-builder/TsFileSerializer.js +225 -0
- package/dist/artifact-builder/TsFileSerializer.js.map +1 -0
- package/dist/artifact-builder/helpers/DataRetriever.d.ts +22 -3
- package/dist/artifact-builder/helpers/DataRetriever.js +56 -26
- package/dist/artifact-builder/helpers/DataRetriever.js.map +1 -1
- package/dist/artifact-builder/helpers/NamingHandler.d.ts +18 -6
- package/dist/artifact-builder/helpers/NamingHandler.js +20 -61
- package/dist/artifact-builder/helpers/NamingHandler.js.map +1 -1
- package/dist/artifact-builder/helpers/PipelinePaths.d.ts +52 -0
- package/dist/artifact-builder/helpers/PipelinePaths.js +99 -0
- package/dist/artifact-builder/helpers/PipelinePaths.js.map +1 -0
- package/dist/artifact-builder/helpers/Stopwatch.d.ts +10 -0
- package/dist/artifact-builder/helpers/Stopwatch.js +10 -0
- package/dist/artifact-builder/helpers/Stopwatch.js.map +1 -1
- package/dist/artifact-builder/helpers/index.d.ts +1 -0
- package/dist/artifact-builder/helpers/index.js +1 -0
- package/dist/artifact-builder/helpers/index.js.map +1 -1
- package/dist/artifact-builder/index.d.ts +4 -0
- package/dist/artifact-builder/index.js +4 -0
- package/dist/artifact-builder/index.js.map +1 -1
- package/dist/components/BaseComponentObjects.d.ts +17 -0
- package/dist/components/BaseComponentObjects.js +17 -0
- package/dist/components/BaseComponentObjects.js.map +1 -1
- package/dist/components/action-bar/ActionBar.d.ts +21 -24
- package/dist/components/action-bar/ActionBar.js +31 -24
- package/dist/components/action-bar/ActionBar.js.map +1 -1
- package/dist/components/action-bar/ActionBarObjects.d.ts +1 -0
- package/dist/components/action-bar/ActionBarObjects.js +1 -0
- package/dist/components/action-bar/ActionBarObjects.js.map +1 -1
- package/dist/components/action-bar/CustomActionBar.d.ts +6 -0
- package/dist/components/action-bar/CustomActionBar.js +6 -0
- package/dist/components/action-bar/CustomActionBar.js.map +1 -1
- package/dist/components/cardlist/Cardlist.d.ts +6 -0
- package/dist/components/cardlist/Cardlist.js +6 -0
- package/dist/components/cardlist/Cardlist.js.map +1 -1
- package/dist/components/chart/Chart.d.ts +6 -0
- package/dist/components/chart/Chart.js +6 -0
- package/dist/components/chart/Chart.js.map +1 -1
- package/dist/components/combined-filter/CombinedFilter.d.ts +9 -0
- package/dist/components/combined-filter/CombinedFilter.js +9 -0
- package/dist/components/combined-filter/CombinedFilter.js.map +1 -1
- package/dist/components/cube-view-bar/CubeViewBar.d.ts +6 -0
- package/dist/components/cube-view-bar/CubeViewBar.js +6 -0
- package/dist/components/cube-view-bar/CubeViewBar.js.map +1 -1
- package/dist/components/export/ExportComponent.d.ts +12 -0
- package/dist/components/export/ExportComponent.js +12 -0
- package/dist/components/export/ExportComponent.js.map +1 -1
- package/dist/components/filter/ExcelStyleFilterPopup.d.ts +17 -4
- package/dist/components/filter/ExcelStyleFilterPopup.js +35 -23
- package/dist/components/filter/ExcelStyleFilterPopup.js.map +1 -1
- package/dist/components/filter/ExcelStyleFilterPopupObjects.d.ts +1 -1
- package/dist/components/filter/ExcelStyleFilterPopupObjects.js +2 -2
- package/dist/components/filter/ExcelStyleFilterPopupObjects.js.map +1 -1
- package/dist/components/filter/FilterForm.d.ts +10 -0
- package/dist/components/filter/FilterForm.js +10 -0
- package/dist/components/filter/FilterForm.js.map +1 -1
- package/dist/components/filter/FilterPopup.d.ts +22 -4
- package/dist/components/filter/FilterPopup.js +17 -9
- package/dist/components/filter/FilterPopup.js.map +1 -1
- package/dist/components/filter/FilterPopupObjects.d.ts +5 -2
- package/dist/components/filter/FilterPopupObjects.js +5 -2
- package/dist/components/filter/FilterPopupObjects.js.map +1 -1
- package/dist/components/filter/FindForm.d.ts +7 -0
- package/dist/components/filter/FindForm.js +7 -0
- package/dist/components/filter/FindForm.js.map +1 -1
- package/dist/components/filter/ManagePrefilterPopup.d.ts +11 -0
- package/dist/components/filter/ManagePrefilterPopup.js +11 -0
- package/dist/components/filter/ManagePrefilterPopup.js.map +1 -1
- package/dist/components/form/Form.d.ts +16 -0
- package/dist/components/form/Form.js +16 -0
- package/dist/components/form/Form.js.map +1 -1
- package/dist/components/grid/Grid.d.ts +17 -0
- package/dist/components/grid/Grid.js +18 -1
- package/dist/components/grid/Grid.js.map +1 -1
- package/dist/components/maps/Maps.d.ts +6 -0
- package/dist/components/maps/Maps.js +6 -0
- package/dist/components/maps/Maps.js.map +1 -1
- package/dist/components/menu/ListBarMenuComponent.d.ts +10 -0
- package/dist/components/menu/ListBarMenuComponent.js +10 -0
- package/dist/components/menu/ListBarMenuComponent.js.map +1 -1
- package/dist/components/pivot-grid/PivotGrid.d.ts +6 -0
- package/dist/components/pivot-grid/PivotGrid.js +6 -0
- package/dist/components/pivot-grid/PivotGrid.js.map +1 -1
- package/dist/components/pivot-grid/PivotGridFieldList.d.ts +7 -0
- package/dist/components/pivot-grid/PivotGridFieldList.js +7 -0
- package/dist/components/pivot-grid/PivotGridFieldList.js.map +1 -1
- package/dist/components/pop-up/AllRowsPopUp.d.ts +12 -0
- package/dist/components/pop-up/AllRowsPopUp.js +12 -0
- package/dist/components/pop-up/AllRowsPopUp.js.map +1 -1
- package/dist/components/pop-up/PopUpComponent.d.ts +11 -0
- package/dist/components/pop-up/PopUpComponent.js +11 -0
- package/dist/components/pop-up/PopUpComponent.js.map +1 -1
- package/dist/components/prefilter-list/PrefilterList.d.ts +9 -0
- package/dist/components/prefilter-list/PrefilterList.js +9 -0
- package/dist/components/prefilter-list/PrefilterList.js.map +1 -1
- package/dist/components/preview/Preview.d.ts +6 -0
- package/dist/components/preview/Preview.js +6 -0
- package/dist/components/preview/Preview.js.map +1 -1
- package/dist/components/report-bar/ReportBar.d.ts +6 -0
- package/dist/components/report-bar/ReportBar.js +6 -0
- package/dist/components/report-bar/ReportBar.js.map +1 -1
- package/dist/components/report-tiles/ReportTiles.d.ts +6 -0
- package/dist/components/report-tiles/ReportTiles.js +6 -0
- package/dist/components/report-tiles/ReportTiles.js.map +1 -1
- package/dist/components/scheduler/Scheduler.d.ts +6 -0
- package/dist/components/scheduler/Scheduler.js +6 -0
- package/dist/components/scheduler/Scheduler.js.map +1 -1
- package/dist/components/snackbar/SnackBar.d.ts +12 -0
- package/dist/components/snackbar/SnackBar.js +12 -0
- package/dist/components/snackbar/SnackBar.js.map +1 -1
- package/dist/components/splitter/Splitter.d.ts +6 -0
- package/dist/components/splitter/Splitter.js +6 -0
- package/dist/components/splitter/Splitter.js.map +1 -1
- package/dist/components/tab/BaseTab.d.ts +5 -0
- package/dist/components/tab/BaseTab.js +5 -0
- package/dist/components/tab/BaseTab.js.map +1 -1
- package/dist/components/tab/DetailTabPage.d.ts +11 -0
- package/dist/components/tab/DetailTabPage.js +11 -0
- package/dist/components/tab/DetailTabPage.js.map +1 -1
- package/dist/components/tab/Tab.d.ts +10 -0
- package/dist/components/tab/Tab.js +10 -0
- package/dist/components/tab/Tab.js.map +1 -1
- package/dist/components/task/TaskBar.d.ts +12 -2
- package/dist/components/task/TaskBar.js +13 -3
- package/dist/components/task/TaskBar.js.map +1 -1
- package/dist/components/task/TaskTiles.d.ts +11 -2
- package/dist/components/task/TaskTiles.js +12 -3
- package/dist/components/task/TaskTiles.js.map +1 -1
- package/dist/components/topbar/TopBar.d.ts +10 -0
- package/dist/components/topbar/TopBar.js +10 -0
- package/dist/components/topbar/TopBar.js.map +1 -1
- package/dist/components/tree-view/TreeView.d.ts +9 -0
- package/dist/components/tree-view/TreeView.js +9 -0
- package/dist/components/tree-view/TreeView.js.map +1 -1
- package/dist/controls/DateControl.d.ts +39 -0
- package/dist/controls/DateControl.js +18 -1
- package/dist/controls/DateControl.js.map +1 -1
- package/dist/controls/FormComboBox.d.ts +30 -0
- package/dist/controls/FormComboBox.js +8 -0
- package/dist/controls/FormComboBox.js.map +1 -1
- package/dist/controls/GridColumnControl.d.ts +30 -0
- package/dist/controls/GridColumnControl.js +12 -3
- package/dist/controls/GridColumnControl.js.map +1 -1
- package/dist/controls/InputFieldControl.d.ts +49 -0
- package/dist/controls/InputFieldControl.js +30 -0
- package/dist/controls/InputFieldControl.js.map +1 -1
- package/dist/controls/LookupDropdown.d.ts +29 -0
- package/dist/controls/LookupDropdown.js +8 -0
- package/dist/controls/LookupDropdown.js.map +1 -1
- package/dist/enums/ElementTypes.d.ts +18 -0
- package/dist/enums/ElementTypes.js +18 -0
- package/dist/enums/ElementTypes.js.map +1 -1
- package/dist/enums/ExportFormat.d.ts +8 -0
- package/dist/enums/ExportFormat.js +8 -0
- package/dist/enums/ExportFormat.js.map +1 -1
- package/dist/enums/LogLevel.d.ts +17 -0
- package/dist/enums/LogLevel.js +17 -1
- package/dist/enums/LogLevel.js.map +1 -1
- package/dist/enums/index.d.ts +1 -0
- package/dist/enums/index.js +1 -0
- package/dist/enums/index.js.map +1 -1
- package/dist/helpers/ConfigChecker.d.ts +13 -0
- package/dist/helpers/ConfigChecker.js +13 -0
- package/dist/helpers/ConfigChecker.js.map +1 -1
- package/dist/helpers/Ensure.d.ts +13 -0
- package/dist/helpers/Ensure.js +13 -0
- package/dist/helpers/Ensure.js.map +1 -1
- package/dist/helpers/FlightTracker.d.ts +13 -3
- package/dist/helpers/FlightTracker.js +103 -17
- package/dist/helpers/FlightTracker.js.map +1 -1
- package/dist/helpers/GlobalWaitEventHandler.d.ts +13 -0
- package/dist/helpers/GlobalWaitEventHandler.js +13 -0
- package/dist/helpers/GlobalWaitEventHandler.js.map +1 -1
- package/dist/helpers/LoginHelper.d.ts +35 -1
- package/dist/helpers/LoginHelper.js +46 -11
- package/dist/helpers/LoginHelper.js.map +1 -1
- package/dist/helpers/PathResolver.d.ts +22 -0
- package/dist/helpers/PathResolver.js +22 -0
- package/dist/helpers/PathResolver.js.map +1 -1
- package/dist/helpers/Poll.d.ts +13 -1
- package/dist/helpers/Poll.js +12 -0
- package/dist/helpers/Poll.js.map +1 -1
- package/dist/helpers/RegexHelper.d.ts +15 -0
- package/dist/helpers/RegexHelper.js +15 -3
- package/dist/helpers/RegexHelper.js.map +1 -1
- package/dist/helpers/SubjectNavigator.d.ts +26 -0
- package/dist/helpers/SubjectNavigator.js +51 -0
- package/dist/helpers/SubjectNavigator.js.map +1 -0
- package/dist/helpers/UserSimulationHelper.d.ts +14 -0
- package/dist/helpers/UserSimulationHelper.js +14 -0
- package/dist/helpers/UserSimulationHelper.js.map +1 -1
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.js +1 -0
- package/dist/helpers/index.js.map +1 -1
- package/dist/index.d.ts +6 -20
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces/IComponentObjects.d.ts +12 -0
- package/dist/interfaces/IComponentSchemaMeta.d.ts +15 -0
- package/dist/interfaces/IComponentSchemaMeta.js +2 -0
- package/dist/interfaces/IComponentSchemaMeta.js.map +1 -0
- package/dist/interfaces/IProperty.d.ts +13 -0
- package/dist/interfaces/IRegisteredSubjects.d.ts +12 -0
- package/dist/interfaces/ISeedSubjectDraft.d.ts +16 -0
- package/dist/interfaces/ISeedSubjectDraft.js +2 -0
- package/dist/interfaces/ISeedSubjectDraft.js.map +1 -0
- package/dist/interfaces/ISubject.d.ts +13 -0
- package/dist/interfaces/ISubjectDetail.d.ts +11 -0
- package/dist/interfaces/ISubjectDetail.js +2 -0
- package/dist/interfaces/ISubjectDetail.js.map +1 -0
- package/dist/mcp/ArtifactResolver.d.ts +152 -0
- package/dist/mcp/ArtifactResolver.js +232 -0
- package/dist/mcp/ArtifactResolver.js.map +1 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.js +2 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/page-extensions/GlobalComponents.d.ts +30 -0
- package/dist/page-extensions/GlobalComponents.js +30 -0
- package/dist/page-extensions/GlobalComponents.js.map +1 -1
- package/dist/page-extensions/GoToDeepLink.d.ts +9 -0
- package/dist/page-extensions/GoToDeepLink.js +9 -0
- package/dist/page-extensions/GoToDeepLink.js.map +1 -1
- package/dist/page-extensions/LoginFeatures.d.ts +8 -0
- package/dist/page-extensions/LoginFeatures.js +8 -0
- package/dist/page-extensions/LoginFeatures.js.map +1 -1
- package/dist/page-extensions/SubjectRegistry.d.ts +31 -0
- package/dist/page-extensions/SubjectRegistry.js +31 -0
- package/dist/page-extensions/SubjectRegistry.js.map +1 -1
- package/dist/page-extensions/UserSimulation.d.ts +21 -0
- package/dist/page-extensions/UserSimulation.js +21 -0
- package/dist/page-extensions/UserSimulation.js.map +1 -1
- package/dist/page-extensions/WaitEventHandler.d.ts +20 -0
- package/dist/page-extensions/WaitEventHandler.js +20 -0
- package/dist/page-extensions/WaitEventHandler.js.map +1 -1
- package/dist/page-overrides/ClickOverride.d.ts +23 -2
- package/dist/page-overrides/ClickOverride.js +34 -50
- package/dist/page-overrides/ClickOverride.js.map +1 -1
- package/dist/page-overrides/FillOverride.d.ts +23 -0
- package/dist/page-overrides/FillOverride.js +56 -61
- package/dist/page-overrides/FillOverride.js.map +1 -1
- package/dist/services/ConfigBuilder.d.ts +24 -0
- package/dist/services/ConfigBuilder.js +24 -0
- package/dist/services/ConfigBuilder.js.map +1 -1
- package/dist/services/IndiciumApi.service.d.ts +26 -0
- package/dist/services/IndiciumApi.service.js +40 -5
- package/dist/services/IndiciumApi.service.js.map +1 -1
- package/dist/services/Logger.d.ts +13 -0
- package/dist/services/Logger.js +39 -0
- package/dist/services/Logger.js.map +1 -1
- package/dist/types/Components.d.ts +18 -1
- package/dist/types/Components.js +0 -1
- package/dist/types/Components.js.map +1 -1
- package/dist/types/LocatorType.d.ts +5 -0
- package/dist/types/LocatorType.js +2 -0
- package/dist/types/LocatorType.js.map +1 -0
- package/dist/types/PollTypes.d.ts +8 -0
- package/dist/types/Test.d.ts +18 -0
- package/dist/types/Universal.d.ts +12 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/enums/ElementTypes.ts +18 -0
- package/enums/ExportFormat.ts +8 -0
- package/enums/LogLevel.ts +17 -1
- package/enums/index.ts +1 -0
- package/helpers/ConfigChecker.ts +13 -0
- package/helpers/Ensure.ts +13 -0
- package/helpers/FlightTracker.ts +109 -20
- package/helpers/GlobalWaitEventHandler.ts +13 -0
- package/helpers/LoginHelper.ts +49 -12
- package/helpers/PathResolver.ts +22 -0
- package/helpers/Poll.ts +13 -1
- package/helpers/RegexHelper.ts +15 -3
- package/helpers/SubjectNavigator.ts +57 -0
- package/helpers/UserSimulationHelper.ts +14 -0
- package/helpers/index.ts +1 -0
- package/index.ts +1 -0
- package/interfaces/IComponentObjects.ts +12 -0
- package/interfaces/IComponentSchemaMeta.ts +17 -0
- package/interfaces/IProperty.ts +13 -0
- package/interfaces/IRegisteredSubjects.ts +12 -0
- package/interfaces/ISeedSubjectDraft.ts +17 -0
- package/interfaces/ISubject.ts +13 -0
- package/interfaces/ISubjectDetail.ts +12 -0
- package/mcp/ArtifactResolver.ts +296 -0
- package/mcp/index.ts +2 -0
- package/package.json +20 -8
- package/page-extensions/GlobalComponents.ts +30 -0
- package/page-extensions/GoToDeepLink.ts +9 -0
- package/page-extensions/LoginFeatures.ts +8 -0
- package/page-extensions/SubjectRegistry.ts +32 -0
- package/page-extensions/UserSimulation.ts +21 -0
- package/page-extensions/WaitEventHandler.ts +20 -0
- package/page-overrides/ClickOverride.ts +36 -55
- package/page-overrides/FillOverride.ts +59 -73
- package/promptCredentials.js +1 -1
- package/scripts/Testwise.template.json +1 -1
- package/scripts/diagram.js +2267 -0
- package/scripts/main.js +84 -63
- package/scripts/postinstall.js +55 -42
- package/scripts/setup.js +91 -37
- package/scripts/sync.js +767 -748
- package/services/ConfigBuilder.ts +24 -0
- package/services/IndiciumApi.service.ts +44 -6
- package/services/Logger.ts +40 -0
- package/templates/copilot-instructions.md +130 -0
- package/templates/mcp.json +9 -0
- package/templates/testwise-test-expert.agent.md +453 -0
- package/tests/tsconfig.json +12 -0
- package/tsconfig.json +6 -2
- package/types/Components.ts +17 -2
- package/types/LocatorType.ts +5 -0
- package/types/PollTypes.ts +8 -0
- package/types/Test.ts +18 -0
- package/types/Universal.ts +12 -0
- package/types/index.ts +2 -0
- package/dist/interfaces/IStoredTestResults.d.ts +0 -5
- package/dist/interfaces/IStoredTestResults.js +0 -2
- package/dist/interfaces/IStoredTestResults.js.map +0 -1
- package/dist/templates/test-artifacts/SubjectPageBase.d.ts +0 -5
- package/dist/templates/test-artifacts/SubjectPageBase.js +0 -6
- package/dist/templates/test-artifacts/SubjectPageBase.js.map +0 -1
- package/dist/templates/test-artifacts/screens/index.d.ts +0 -1
- package/dist/templates/test-artifacts/screens/index.js +0 -2
- package/dist/templates/test-artifacts/screens/index.js.map +0 -1
- package/dist/templates/test-artifacts/subjects/index.d.ts +0 -1
- package/dist/templates/test-artifacts/subjects/index.js +0 -2
- package/dist/templates/test-artifacts/subjects/index.js.map +0 -1
- package/interfaces/IStoredTestResults.ts +0 -6
package/helpers/FlightTracker.ts
CHANGED
|
@@ -1,22 +1,54 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import { testwiseConfig } from '../services/ConfigBuilder.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Tracks in-flight XHR requests made by the Thinkwise application and blocks
|
|
6
|
+
* test execution until the network has been idle for a short stability window.
|
|
7
|
+
*
|
|
8
|
+
* **Why this exists:** The Thinkwise Platform performs fire-and-forget XHR calls
|
|
9
|
+
* for things like navigation, saves, and data loads. Raw Playwright `waitFor*`
|
|
10
|
+
* helpers don't know about these — tests that proceed too early will act on
|
|
11
|
+
* stale data or a half-rendered screen. `FlightTracker` listens to every
|
|
12
|
+
* request/response cycle and exposes `waitToContinue()` which returns only
|
|
13
|
+
* once all tracked requests have finished AND the page has been quiet for at
|
|
14
|
+
* least `stabilityTime` milliseconds.
|
|
15
|
+
*
|
|
16
|
+
* **How to use it in tests:** You don't — it is wired up automatically inside
|
|
17
|
+
* `SubjectNavigator.navigateTo()`, `ClickOverride`, and `FillOverride`. You
|
|
18
|
+
* only need to know it exists if you are writing a new page-extension or
|
|
19
|
+
* override that performs navigation.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Inside a page-override or page-extension:
|
|
23
|
+
* const tracker = new FlightTracker();
|
|
24
|
+
* page.on('request', req => tracker.handleRequestStarted(req.url(), req.resourceType()));
|
|
25
|
+
* page.on('response', res => tracker.handleRequestFinished(res.request().url()));
|
|
26
|
+
* await myAction();
|
|
27
|
+
* await tracker.waitToContinue();
|
|
28
|
+
*/
|
|
29
|
+
const minTimeout = 30000;
|
|
30
|
+
const timeout = Math.max(testwiseConfig().get<number>('featureSettings.InflightRequests.waitTimeout') ?? 0, minTimeout);
|
|
31
|
+
|
|
5
32
|
const stabilityTime = 150;
|
|
6
33
|
|
|
7
34
|
export class FlightTracker {
|
|
8
35
|
public requestsInFlight: number = 0;
|
|
9
|
-
private activeRequests = new
|
|
36
|
+
private activeRequests = new Map<string, number>();
|
|
10
37
|
public eventEmitter: EventEmitter = new EventEmitter();
|
|
11
38
|
|
|
12
39
|
/**
|
|
13
|
-
*
|
|
40
|
+
* Returns true for XHR requests that should block test execution.
|
|
41
|
+
* Filters out non-XHR traffic and known noise endpoints.
|
|
14
42
|
*/
|
|
15
|
-
public isEssentialRequest(url: string): boolean {
|
|
43
|
+
public isEssentialRequest(url: string, resourceType: string): boolean {
|
|
44
|
+
if (resourceType !== 'xhr') return false;
|
|
45
|
+
|
|
16
46
|
const noisePatterns = [
|
|
17
|
-
'
|
|
18
|
-
'
|
|
19
|
-
'
|
|
47
|
+
'/detect_change(',
|
|
48
|
+
'/set_gui_start_use_log_session',
|
|
49
|
+
'download_icon',
|
|
50
|
+
'download_list_bar_grp_icon',
|
|
51
|
+
'download_form_next_grp_icon',
|
|
20
52
|
'/badge()',
|
|
21
53
|
'universal_background_picture',
|
|
22
54
|
'i_ui_theme'
|
|
@@ -25,17 +57,44 @@ export class FlightTracker {
|
|
|
25
57
|
return !noisePatterns.some((pattern) => url.includes(pattern));
|
|
26
58
|
}
|
|
27
59
|
|
|
28
|
-
public handleRequestStarted = (url: string) => {
|
|
29
|
-
if (this.isEssentialRequest(url)) {
|
|
30
|
-
this.activeRequests.
|
|
31
|
-
this.
|
|
60
|
+
public handleRequestStarted = (url: string, resourceType: string) => {
|
|
61
|
+
if (this.isEssentialRequest(url, resourceType)) {
|
|
62
|
+
const wasIdle = this.activeRequests.size === 0;
|
|
63
|
+
this.activeRequests.set(url, (this.activeRequests.get(url) ?? 0) + 1);
|
|
64
|
+
this.requestsInFlight++;
|
|
65
|
+
if (wasIdle) this.eventEmitter.emit('active');
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
public reset = (): void => {
|
|
70
|
+
this.activeRequests.clear();
|
|
71
|
+
this.requestsInFlight = 0;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
public handleRequestFailed = (url: string) => {
|
|
75
|
+
const count = this.activeRequests.get(url);
|
|
76
|
+
if (count !== undefined) {
|
|
77
|
+
if (count <= 1) {
|
|
78
|
+
this.activeRequests.delete(url);
|
|
79
|
+
} else {
|
|
80
|
+
this.activeRequests.set(url, count - 1);
|
|
81
|
+
}
|
|
82
|
+
this.requestsInFlight = Math.max(0, this.requestsInFlight - 1);
|
|
83
|
+
if (this.requestsInFlight === 0) {
|
|
84
|
+
this.eventEmitter.emit('idle');
|
|
85
|
+
}
|
|
32
86
|
}
|
|
33
87
|
};
|
|
34
88
|
|
|
35
89
|
public handleRequestFinished = (url: string) => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
90
|
+
const count = this.activeRequests.get(url);
|
|
91
|
+
if (count !== undefined) {
|
|
92
|
+
if (count <= 1) {
|
|
93
|
+
this.activeRequests.delete(url);
|
|
94
|
+
} else {
|
|
95
|
+
this.activeRequests.set(url, count - 1);
|
|
96
|
+
}
|
|
97
|
+
this.requestsInFlight = Math.max(0, this.requestsInFlight - 1);
|
|
39
98
|
if (this.requestsInFlight === 0) {
|
|
40
99
|
this.eventEmitter.emit('idle');
|
|
41
100
|
}
|
|
@@ -64,14 +123,14 @@ export class FlightTracker {
|
|
|
64
123
|
this.eventEmitter.on('idle', checkIdle);
|
|
65
124
|
});
|
|
66
125
|
|
|
67
|
-
const timeoutPromise = new Promise<void>((
|
|
126
|
+
const timeoutPromise = new Promise<void>((resolve) => {
|
|
68
127
|
timeoutId = setTimeout(() => {
|
|
69
|
-
const pending = Array.from(this.activeRequests).join('\n -> ');
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
`Timeout waiting for ${this.requestsInFlight} requests to complete (${timeout}ms).\nPending Essential Requests:\n -> ${pending}`
|
|
73
|
-
)
|
|
128
|
+
const pending = Array.from(this.activeRequests.keys()).join('\n -> ');
|
|
129
|
+
console.warn(
|
|
130
|
+
`FlightTracker: timed out after ${timeout}ms waiting for ${this.requestsInFlight} request(s) to complete.\nPending Essential Requests:\n -> ${pending}\nContinuing test execution.`
|
|
74
131
|
);
|
|
132
|
+
this.reset();
|
|
133
|
+
resolve();
|
|
75
134
|
}, timeout);
|
|
76
135
|
});
|
|
77
136
|
|
|
@@ -83,4 +142,34 @@ export class FlightTracker {
|
|
|
83
142
|
this.eventEmitter.removeAllListeners('idle');
|
|
84
143
|
}
|
|
85
144
|
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* For use after hash-based SPA navigation. Waits for the SPA to begin firing
|
|
148
|
+
* XHR requests (within `spaStartupTimeout`), then waits for all of them to
|
|
149
|
+
* settle. If no requests appear within the startup window the page is
|
|
150
|
+
* considered already loaded.
|
|
151
|
+
*/
|
|
152
|
+
public waitForNavigationToSettle = async (spaStartupTimeout = 3000): Promise<void> => {
|
|
153
|
+
if (this.requestsInFlight > 0) {
|
|
154
|
+
return this.waitToContinue();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
await new Promise<void>((resolve) => {
|
|
158
|
+
const timer = setTimeout(() => {
|
|
159
|
+
this.eventEmitter.off('active', onActive);
|
|
160
|
+
resolve();
|
|
161
|
+
}, spaStartupTimeout);
|
|
162
|
+
|
|
163
|
+
const onActive = () => {
|
|
164
|
+
clearTimeout(timer);
|
|
165
|
+
resolve();
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
this.eventEmitter.once('active', onActive);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
if (this.requestsInFlight > 0) {
|
|
172
|
+
await this.waitToContinue();
|
|
173
|
+
}
|
|
174
|
+
};
|
|
86
175
|
}
|
|
@@ -2,6 +2,19 @@ import { EventEmitter } from 'node:events';
|
|
|
2
2
|
import type { Page, Response } from '@playwright/test';
|
|
3
3
|
import { testwiseConfig } from '../services/ConfigBuilder.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Waits for a specific response URL pattern before allowing test execution
|
|
7
|
+
* to continue. Used when you need to block until a known async API response
|
|
8
|
+
* has arrived, as opposed to waiting for XHR idle (which `FlightTracker` does).
|
|
9
|
+
*
|
|
10
|
+
* Attached to the page as `page.waitEventHandler` by the `WaitEventHandler`
|
|
11
|
+
* page extension. Call `page.waitEventHandler.waitForUrl(pattern)` to block
|
|
12
|
+
* until a response matching that URL has been received.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Wait for a specific background endpoint before asserting:
|
|
16
|
+
* await page.waitEventHandler.waitForUrl('/api/employees/load');
|
|
17
|
+
*/
|
|
5
18
|
export class GlobalWaitEventHandler {
|
|
6
19
|
private _canContinue: boolean = true;
|
|
7
20
|
private _eventEmitter: EventEmitter = new EventEmitter();
|
package/helpers/LoginHelper.ts
CHANGED
|
@@ -9,10 +9,22 @@ import { pollUntil } from './Poll.js';
|
|
|
9
9
|
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
10
|
const configFixture = JSON.parse(fs.readFileSync(path.resolve(dirname, '../../config.json'), 'utf-8'));
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Handles authentication against the Thinkwise Indicium API and the
|
|
14
|
+
* web application login screen.
|
|
15
|
+
*
|
|
16
|
+
* Exposed on the page fixture via `LoginFeatures` as `page.logIn()`,
|
|
17
|
+
* `page.logInWithCredentials()`, `page.logInWithOptions()`, and `page.logOut()`.
|
|
18
|
+
* You do not instantiate `LoginHelper` directly in tests.
|
|
19
|
+
*
|
|
20
|
+
* Credentials are read from `Testwise.json` (`environmentSettings.username`
|
|
21
|
+
* and `environmentSettings.password`) by default, and can be overridden
|
|
22
|
+
* per-call via `logInWithCredentials()` or `logInWithOptions()`.
|
|
23
|
+
*/
|
|
12
24
|
export class LoginHelper {
|
|
13
25
|
private _page: Page;
|
|
14
|
-
protected serviceUrl = String(testwiseConfig().get('environmentSettings.serviceUrl'));
|
|
15
|
-
protected metaEndpoint = String(testwiseConfig().get('environmentSettings.metaEndpoint'));
|
|
26
|
+
protected serviceUrl = String(testwiseConfig().get('environmentSettings.serviceUrl')).replace(/\/+$/, '');
|
|
27
|
+
protected metaEndpoint = String(testwiseConfig().get('environmentSettings.metaEndpoint')).replace(/\/+$/, '');
|
|
16
28
|
|
|
17
29
|
constructor(page: Page) {
|
|
18
30
|
if (!this.serviceUrl || this.serviceUrl === 'undefined') throw new Error('Service URL not found');
|
|
@@ -56,20 +68,23 @@ export class LoginHelper {
|
|
|
56
68
|
}
|
|
57
69
|
|
|
58
70
|
/**
|
|
59
|
-
* Navigate to the home page and wait for the menu to load
|
|
71
|
+
* Navigate to the home page and wait for the menu to load.
|
|
60
72
|
*/
|
|
61
73
|
private async navigateHomeAndWaitForMenuToLoad() {
|
|
62
|
-
const baseUrl = testwiseConfig().get<string>('environmentSettings.baseUrl');
|
|
74
|
+
const baseUrl = testwiseConfig().get<string>('environmentSettings.baseUrl')?.replace(/\/+$/, '');
|
|
75
|
+
const minimumTimeout = 60000;
|
|
76
|
+
|
|
63
77
|
if (!baseUrl) {
|
|
64
78
|
throw new Error('Base URL is not defined in the configuration.');
|
|
65
79
|
}
|
|
66
|
-
await this._page.goto(baseUrl);
|
|
67
80
|
|
|
68
|
-
|
|
69
|
-
route.continue();
|
|
70
|
-
});
|
|
81
|
+
let timeout = Number(testwiseConfig().get<string | number>('featureSettings.other.loginTimeout') ?? minimumTimeout);
|
|
71
82
|
|
|
72
|
-
|
|
83
|
+
if (Number.isNaN(timeout) || timeout < minimumTimeout) {
|
|
84
|
+
timeout = minimumTimeout;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
await this._page.goto(baseUrl);
|
|
73
88
|
|
|
74
89
|
await pollUntil(async () => this._page.url().includes('#application='), {
|
|
75
90
|
timeout,
|
|
@@ -93,8 +108,8 @@ export class LoginHelper {
|
|
|
93
108
|
}
|
|
94
109
|
|
|
95
110
|
if (serviceUrl && metaEndpoint) {
|
|
96
|
-
this.serviceUrl = serviceUrl;
|
|
97
|
-
this.metaEndpoint = metaEndpoint;
|
|
111
|
+
this.serviceUrl = serviceUrl.replace(/\/+$/, '');
|
|
112
|
+
this.metaEndpoint = metaEndpoint.replace(/\/+$/, '');
|
|
98
113
|
}
|
|
99
114
|
|
|
100
115
|
const response = await this._page.request.post(`${this.serviceUrl}/account/api/login`, {
|
|
@@ -171,6 +186,10 @@ export class LoginHelper {
|
|
|
171
186
|
});
|
|
172
187
|
}
|
|
173
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Logs out the current session by POSTing to the logout endpoint (accepts 204 or 401
|
|
191
|
+
* as valid responses), then clears all browser cookies.
|
|
192
|
+
*/
|
|
174
193
|
public async logOut() {
|
|
175
194
|
const response = await this._page.request.post(`${this.serviceUrl}/account/api/logout`);
|
|
176
195
|
|
|
@@ -188,6 +207,14 @@ export class UserPreferences {
|
|
|
188
207
|
public readonly guiApplAlias = String(testwiseConfig().get<string>('environmentSettings.guiApplAlias'));
|
|
189
208
|
public readonly url: string;
|
|
190
209
|
|
|
210
|
+
/**
|
|
211
|
+
* Initialises the `UserPreferences` service, resolving the service URL, meta endpoint,
|
|
212
|
+
* and GUI application alias from config (overridable via optional parameters) and
|
|
213
|
+
* constructing the full Indicium endpoint URL.
|
|
214
|
+
* @param requestContext - The Playwright `Page` used to make API requests.
|
|
215
|
+
* @param serviceUrl - Optional override for the service URL from config.
|
|
216
|
+
* @param metaEndpoint - Optional override for the meta endpoint from config.
|
|
217
|
+
*/
|
|
191
218
|
constructor(requestContext: Page, serviceUrl?: string, metaEndpoint?: string) {
|
|
192
219
|
this._page = requestContext;
|
|
193
220
|
|
|
@@ -198,9 +225,14 @@ export class UserPreferences {
|
|
|
198
225
|
if (!metaEndpoint) throw new Error('Meta endpoint not found or is empty');
|
|
199
226
|
if (!this.guiApplAlias) throw new Error('GUI application alias not found or is empty');
|
|
200
227
|
|
|
201
|
-
this.url = `${serviceUrl}/${metaEndpoint}/${this.guiApplAlias}`;
|
|
228
|
+
this.url = `${serviceUrl.replace(/\/+$/, '')}/${metaEndpoint.replace(/\/+$/, '')}/${this.guiApplAlias}`;
|
|
202
229
|
}
|
|
203
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Activates a specific user preference configuration for the current session by POSTing
|
|
233
|
+
* to the `set_up_configuration` endpoint with the given configuration ID.
|
|
234
|
+
* @param upConfigurationId - The ID of the user preference configuration to activate.
|
|
235
|
+
*/
|
|
204
236
|
public async run(upConfigurationId: number) {
|
|
205
237
|
const fullUrl = `${this.url}/set_up_configuration`;
|
|
206
238
|
|
|
@@ -211,6 +243,11 @@ export class UserPreferences {
|
|
|
211
243
|
await this._page.request.post(fullUrl, { headers: { 'Content-Type': 'application/json; charset=utf-8' }, data });
|
|
212
244
|
}
|
|
213
245
|
|
|
246
|
+
/**
|
|
247
|
+
* Disables all active user preferences for the current session by POSTing to the
|
|
248
|
+
* `disable_up` endpoint.
|
|
249
|
+
* @returns The raw Playwright `APIResponse`.
|
|
250
|
+
*/
|
|
214
251
|
public async disable(): Promise<APIResponse> {
|
|
215
252
|
const fullUrl = `${this.url}/disable_up`;
|
|
216
253
|
|
package/helpers/PathResolver.ts
CHANGED
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Locates the root directory of the **consumer project** (the project that has
|
|
6
|
+
* `@thinkwise/testwise` installed as a dependency) at runtime.
|
|
7
|
+
*
|
|
8
|
+
* **Why this exists:** Testwise runs from inside `node_modules` but needs to
|
|
9
|
+
* read and write files that belong to the consuming project (e.g.
|
|
10
|
+
* `registeredSubjects.json`, `Testwise.json`). Simply using `process.cwd()`
|
|
11
|
+
* is unreliable when scripts are invoked from sub-directories. This class
|
|
12
|
+
* walks up the directory tree looking for the first `package.json` whose
|
|
13
|
+
* `name` is NOT `@thinkwise/testwise`, which is guaranteed to be the consumer
|
|
14
|
+
* project root.
|
|
15
|
+
*
|
|
16
|
+
* **How to use it:** Inject it into any pipeline helper that needs to write
|
|
17
|
+
* to the consumer project. `PipelinePaths` already does this — you rarely
|
|
18
|
+
* need to instantiate `PathResolver` directly.
|
|
19
|
+
*/
|
|
4
20
|
export class PathResolver {
|
|
21
|
+
/**
|
|
22
|
+
* Walks up the directory tree from `process.cwd()` to find the nearest `package.json`
|
|
23
|
+
* whose `name` is not `@thinkwise/testwise`, returning that directory as the consumer
|
|
24
|
+
* project root. Falls back to `process.cwd()` if no such package is found.
|
|
25
|
+
* @returns Absolute path to the consumer project's root directory.
|
|
26
|
+
*/
|
|
5
27
|
public getConsumerRootDirectory(): string {
|
|
6
28
|
let directory = process.cwd();
|
|
7
29
|
let lastDir = '';
|
package/helpers/Poll.ts
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
import type { PollOptions } from '../types/PollTypes.
|
|
1
|
+
import type { PollOptions } from '../types/PollTypes.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Repeatedly calls `fn` at a configurable interval until the optional `predicate` returns
|
|
5
|
+
* truthy or the `timeout` is exceeded, at which point it throws.
|
|
6
|
+
* `onTick` is called with the last value and elapsed time after each failing attempt.
|
|
7
|
+
* @param fn - The async or sync function to poll.
|
|
8
|
+
* @param opts.timeout - Maximum wait time in milliseconds (default `10 000`).
|
|
9
|
+
* @param opts.interval - Polling interval in milliseconds (default `200`).
|
|
10
|
+
* @param opts.predicate - Returns `true` when the result is acceptable (default: truthy check).
|
|
11
|
+
* @param opts.onTick - Called after each failing attempt with the last value and elapsed ms.
|
|
12
|
+
* @returns The first value for which `predicate` returns `true`.
|
|
13
|
+
* @throws If `timeout` is exceeded before `predicate` returns `true`.
|
|
14
|
+
*/
|
|
3
15
|
export async function pollUntil<T>(fn: () => Promise<T> | T, opts: PollOptions<T> = {}): Promise<T> {
|
|
4
16
|
const timeout = opts.timeout ?? 10_000;
|
|
5
17
|
const interval = opts.interval ?? 200;
|
package/helpers/RegexHelper.ts
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Escapes all characters with special meaning in regular expressions so that `input`
|
|
3
|
+
* can be safely embedded inside a `RegExp` constructor without unintended pattern matching.
|
|
4
|
+
* @param input - The raw string to escape.
|
|
5
|
+
* @returns The escaped string.
|
|
6
|
+
*/
|
|
2
7
|
export function escapeRegex(input: string): string {
|
|
3
8
|
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
4
9
|
}
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Builds a case-insensitive, Unicode-safe `RegExp` that exactly matches `input`.
|
|
13
|
+
* Optionally trims leading/trailing whitespace and collapses internal whitespace runs
|
|
14
|
+
* to a single space to match typical UI text normalization.
|
|
15
|
+
* @param input - The text to match exactly.
|
|
16
|
+
* @param opts.trim - Trim leading/trailing whitespace before matching (default `true`).
|
|
17
|
+
* @param opts.collapseWhitespace - Collapse runs of whitespace to a single space (default `false`).
|
|
18
|
+
* @returns A case-insensitive `RegExp` anchored with `^` and `$`.
|
|
19
|
+
*/
|
|
8
20
|
export function exactTextRegex(input: string, opts?: { trim?: boolean; collapseWhitespace?: boolean }) {
|
|
9
21
|
const { trim = true, collapseWhitespace = false } = opts ?? {};
|
|
10
22
|
let s = trim ? input.trim() : input;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Page } from '@playwright/test';
|
|
2
|
+
import { FlightTracker } from './FlightTracker.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Navigates the browser to a Thinkwise subject deep-link URL and waits for
|
|
6
|
+
* the application to fully settle before returning control to the test.
|
|
7
|
+
*
|
|
8
|
+
* **Why this exists:** Calling `page.goto()` directly does not account for
|
|
9
|
+
* the asynchronous XHR requests that the Thinkwise app fires after a navigation
|
|
10
|
+
* event. Tests that act immediately after a bare `goto` frequently encounter
|
|
11
|
+
* loading spinners, empty grids, or incomplete form data. `SubjectNavigator`
|
|
12
|
+
* wraps navigation in a `FlightTracker` session so the test only continues
|
|
13
|
+
* once the network is truly idle.
|
|
14
|
+
*
|
|
15
|
+
* **How to use it:** You typically don't call this directly — it is used
|
|
16
|
+
* internally by the generated subject class `goTo()` methods. If you need
|
|
17
|
+
* to navigate imperatively in a test, prefer `page.subject.MySubjectClass.goTo()`.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Inside a generated subject class:
|
|
21
|
+
* const navigator = new SubjectNavigator(page);
|
|
22
|
+
* await navigator.navigateTo('subjects/Employee/Editable1/Main');
|
|
23
|
+
*/
|
|
24
|
+
export class SubjectNavigator {
|
|
25
|
+
private readonly _page: Page;
|
|
26
|
+
|
|
27
|
+
constructor(page: Page) {
|
|
28
|
+
this._page = page;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public async navigateTo(url: string): Promise<void> {
|
|
32
|
+
const flightTracker = new FlightTracker();
|
|
33
|
+
|
|
34
|
+
const onRequest = (request: import('@playwright/test').Request) => {
|
|
35
|
+
flightTracker.handleRequestStarted(request.url(), request.resourceType());
|
|
36
|
+
};
|
|
37
|
+
const onResponse = (response: import('@playwright/test').Response) => {
|
|
38
|
+
flightTracker.handleRequestFinished(response.request().url());
|
|
39
|
+
};
|
|
40
|
+
const onRequestFailed = (request: import('@playwright/test').Request) => {
|
|
41
|
+
flightTracker.handleRequestFailed(request.url());
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
this._page.on('request', onRequest);
|
|
45
|
+
this._page.on('response', onResponse);
|
|
46
|
+
this._page.on('requestfailed', onRequestFailed);
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
await this._page.goToDeepLink(url);
|
|
50
|
+
await flightTracker.waitForNavigationToSettle();
|
|
51
|
+
} finally {
|
|
52
|
+
this._page.off('request', onRequest);
|
|
53
|
+
this._page.off('response', onResponse);
|
|
54
|
+
this._page.off('requestfailed', onRequestFailed);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -2,6 +2,20 @@ import type { Page } from '@playwright/test';
|
|
|
2
2
|
import { testwiseConfig } from '../services/ConfigBuilder.js';
|
|
3
3
|
import { pollUntil } from './Poll.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Simulates switching the active user identity in the Thinkwise application
|
|
7
|
+
* at runtime, without logging out and back in. Useful for testing
|
|
8
|
+
* role-based access control (RBAC) and user-specific workflows.
|
|
9
|
+
*
|
|
10
|
+
* Exposed on the page fixture via `UserSimulation` as `page.simulateUser()`,
|
|
11
|
+
* `page.getSimulatedUser()`, and `page.stopSimulation()`. You do not
|
|
12
|
+
* instantiate `UserSimulationHelper` directly in tests.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* await page.simulateUser('john.doe@example.com');
|
|
16
|
+
* // ... assert behaviour for this user ...
|
|
17
|
+
* await page.stopSimulation();
|
|
18
|
+
*/
|
|
5
19
|
export class UserSimulationHelper {
|
|
6
20
|
private _page: Page;
|
|
7
21
|
private _serviceUrl: string;
|
package/helpers/index.ts
CHANGED
package/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ export * from './components/index.js';
|
|
|
17
17
|
export * from './controls/index.js';
|
|
18
18
|
export * from './enums/index.js';
|
|
19
19
|
export * from './helpers/index.js';
|
|
20
|
+
export * from './mcp/index.js';
|
|
20
21
|
export * from './page-extensions/index.js';
|
|
21
22
|
export * from './page-overrides/index.js';
|
|
22
23
|
export * from './services/index.js';
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import type { Locator } from '@playwright/test';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Base contract that every `*Objects` class in `components/` and `controls/`
|
|
5
|
+
* must implement.
|
|
6
|
+
*
|
|
7
|
+
* **Why this exists:** Each component is split into two files — a `<Name>.ts`
|
|
8
|
+
* (public API with interaction methods) and a `<Name>Objects.ts` (raw locator
|
|
9
|
+
* accessors). `IComponentObjects` enforces that every `Objects` class exposes
|
|
10
|
+
* the two locators that all Thinkwise screens share: the scoped `context`
|
|
11
|
+
* locator and the page-level `mainHeader` locator used for presence checks.
|
|
12
|
+
*/
|
|
3
13
|
export interface IComponentObjects {
|
|
14
|
+
/** The scoped Playwright `Locator` that roots all locator lookups for this component instance. */
|
|
4
15
|
context: Locator;
|
|
16
|
+
/** Locator for `main header` — used as a presence anchor to confirm the screen has rendered. */
|
|
5
17
|
mainHeader: Locator;
|
|
6
18
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SubjectComponents } from '../types/Components.js';
|
|
2
|
+
|
|
3
|
+
/** Metadata for a single property within a generated component schema. */
|
|
4
|
+
export interface IComponentPropertyMeta {
|
|
5
|
+
colId: string;
|
|
6
|
+
elementType: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The full meta file that SchemaGenerator writes alongside each `.json`
|
|
11
|
+
* schema file, and that SubjectComponentGenerator reads back to drive code
|
|
12
|
+
* generation.
|
|
13
|
+
*/
|
|
14
|
+
export interface IComponentSchemaMeta {
|
|
15
|
+
componentType: SubjectComponents;
|
|
16
|
+
properties: Record<string, IComponentPropertyMeta>;
|
|
17
|
+
}
|
package/interfaces/IProperty.ts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Describes a single field or column on a Thinkwise screen, as returned by
|
|
3
|
+
* the Indicium API and stored in `seed-data/subjects.json`.
|
|
4
|
+
*
|
|
5
|
+
* The `control_type` drives which Testwise control helper gets generated for
|
|
6
|
+
* the property (e.g. `"field"` → `InputFieldControl`, `"lookup"` → `LookupDropdown`).
|
|
7
|
+
*/
|
|
1
8
|
export interface IProperty {
|
|
9
|
+
/** The field or column identifier as defined in the Thinkwise model (e.g. `"employee_id"`). */
|
|
2
10
|
col: string;
|
|
11
|
+
/**
|
|
12
|
+
* The Thinkwise UI control type for this property.
|
|
13
|
+
* Drives the control class suffix appended in generated subject components.
|
|
14
|
+
* Common values: `"field"`, `"lookup"`, `"dropdown"`, `"checkbox"`, `"date_picker"`, `"combo_box"`.
|
|
15
|
+
*/
|
|
3
16
|
control_type: string;
|
|
4
17
|
}
|
|
@@ -1,5 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Describes a subject that has been registered in the consumer project's
|
|
3
|
+
* `registeredSubjects.json` file.
|
|
4
|
+
*
|
|
5
|
+
* The `SubjectRegistration` pipeline step reads generated subject classes and
|
|
6
|
+
* writes an entry here for each one. The `SubjectRegistry` page-extension
|
|
7
|
+
* reads this file at test startup to make all subjects available on
|
|
8
|
+
* `page.subject.<ClassName>`.
|
|
9
|
+
*/
|
|
1
10
|
export interface IRegisteredSubjects {
|
|
11
|
+
/** Thinkwise subject identifier (e.g. `"Employee"`). */
|
|
2
12
|
subject: string;
|
|
13
|
+
/** Optional variant discriminator when the same subject has multiple variants (e.g. `"Editable1"`). */
|
|
3
14
|
variant?: string;
|
|
15
|
+
/** Screen type context — `"Main"`, `"Popup"`, `"Zoom"`, or `"Detail"`. */
|
|
4
16
|
screen_type: string;
|
|
5
17
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IProperty } from './IProperty.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents a subject as it is built from the Indicium API before properties
|
|
5
|
+
* are fully populated. `properties` is optional here because it is assigned
|
|
6
|
+
* after the initial object is constructed during the build phase.
|
|
7
|
+
*
|
|
8
|
+
* Once written to `subjects.json` and read back via `DataRetriever`, the data
|
|
9
|
+
* is typed as the narrower `ISubject` (which requires `properties`).
|
|
10
|
+
*/
|
|
11
|
+
export interface ISeedSubjectDraft {
|
|
12
|
+
subject: string;
|
|
13
|
+
variant: string;
|
|
14
|
+
screentype_context: string;
|
|
15
|
+
screentype_id: string;
|
|
16
|
+
properties?: IProperty[];
|
|
17
|
+
}
|
package/interfaces/ISubject.ts
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import type { IProperty } from './IProperty.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Represents a single Thinkwise subject as stored in `seed-data/subjects.json`
|
|
5
|
+
* after the `ModelDataBuilder` pipeline step fetches it from the Indicium API.
|
|
6
|
+
*
|
|
7
|
+
* Each subject maps to one screen variant in the Thinkwise application. The
|
|
8
|
+
* `SubjectClassModelBuilder` reads these records and turns them into generated
|
|
9
|
+
* TypeScript subject classes under `test-artifacts/subjects/`.
|
|
10
|
+
*/
|
|
3
11
|
export interface ISubject {
|
|
12
|
+
/** Internal Thinkwise subject identifier (e.g. `"Employee"`). */
|
|
4
13
|
subject: string;
|
|
14
|
+
/** Subject variant, used to distinguish multiple configurations of the same subject (e.g. `"Editable1"`). */
|
|
5
15
|
variant: string;
|
|
16
|
+
/** Human-readable screen context: `"Main"`, `"Popup"`, `"Zoom"`, or `"Detail"`. */
|
|
6
17
|
screentype_context: string;
|
|
18
|
+
/** Thinkwise screen type identifier used to look up the correct screen schema file. */
|
|
7
19
|
screentype_id: string;
|
|
20
|
+
/** All field/column properties available on this screen. */
|
|
8
21
|
properties: IProperty[];
|
|
9
22
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Screen context variants produced by the artifact-builder pipeline. */
|
|
2
|
+
export type ScreenContext = 'Main' | 'Popup' | 'Zoom' | 'Detail';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Describes a single generated subject class that the SubjectRegistration
|
|
6
|
+
* step registers in the SubjectRegistry.
|
|
7
|
+
*/
|
|
8
|
+
export interface ISubjectDetail {
|
|
9
|
+
subject: string;
|
|
10
|
+
variant?: string;
|
|
11
|
+
screen: ScreenContext;
|
|
12
|
+
}
|