@thinkwise/testwise 0.2.62 → 0.2.99
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 +83 -10
- package/components/filter/ExcelStyleFilterPopupObjects.ts +29 -3
- 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 +50 -14
- package/components/grid/GridObjects.ts +0 -15
- 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 +47 -9
- package/controls/DateControlObjects.ts +15 -0
- package/controls/FormComboBox.ts +43 -26
- package/controls/FormComboBoxObjects.ts +27 -0
- package/controls/GridColumnControl.ts +35 -4
- package/controls/GridColumnControlObjects.ts +1 -1
- package/controls/InputFieldControl.ts +61 -15
- package/controls/InputFieldControlObjects.ts +19 -0
- package/controls/LookupDropdown.ts +59 -31
- package/controls/LookupDropdownObjects.ts +19 -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 +25 -2
- package/dist/components/filter/ExcelStyleFilterPopup.js +60 -6
- package/dist/components/filter/ExcelStyleFilterPopup.js.map +1 -1
- package/dist/components/filter/ExcelStyleFilterPopupObjects.d.ts +8 -1
- package/dist/components/filter/ExcelStyleFilterPopupObjects.js +15 -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 +20 -1
- package/dist/components/grid/Grid.js +35 -25
- package/dist/components/grid/Grid.js.map +1 -1
- package/dist/components/grid/GridObjects.d.ts +0 -4
- package/dist/components/grid/GridObjects.js +0 -6
- package/dist/components/grid/GridObjects.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 +40 -2
- package/dist/controls/DateControl.js +24 -7
- package/dist/controls/DateControl.js.map +1 -1
- package/dist/controls/DateControlObjects.d.ts +8 -1
- package/dist/controls/DateControlObjects.js +8 -1
- package/dist/controls/DateControlObjects.js.map +1 -1
- package/dist/controls/FormComboBox.d.ts +30 -0
- package/dist/controls/FormComboBox.js +19 -16
- package/dist/controls/FormComboBox.js.map +1 -1
- package/dist/controls/FormComboBoxObjects.d.ts +12 -1
- package/dist/controls/FormComboBoxObjects.js +15 -1
- package/dist/controls/FormComboBoxObjects.js.map +1 -1
- package/dist/controls/GridColumnControl.d.ts +30 -0
- package/dist/controls/GridColumnControl.js +13 -4
- package/dist/controls/GridColumnControl.js.map +1 -1
- package/dist/controls/GridColumnControlObjects.js +1 -1
- package/dist/controls/GridColumnControlObjects.js.map +1 -1
- package/dist/controls/InputFieldControl.d.ts +50 -3
- package/dist/controls/InputFieldControl.js +40 -11
- package/dist/controls/InputFieldControl.js.map +1 -1
- package/dist/controls/InputFieldControlObjects.d.ts +10 -1
- package/dist/controls/InputFieldControlObjects.js +10 -1
- package/dist/controls/InputFieldControlObjects.js.map +1 -1
- package/dist/controls/LookupDropdown.d.ts +29 -0
- package/dist/controls/LookupDropdown.js +36 -25
- package/dist/controls/LookupDropdown.js.map +1 -1
- package/dist/controls/LookupDropdownObjects.d.ts +10 -0
- package/dist/controls/LookupDropdownObjects.js +11 -0
- package/dist/controls/LookupDropdownObjects.js.map +1 -0
- 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 +46 -66
- 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/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
|
+
}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { PipelinePaths } from '../artifact-builder/helpers/PipelinePaths.js';
|
|
4
|
+
import type { ScreenContext } from '../interfaces/ISubjectDetail.js';
|
|
5
|
+
|
|
6
|
+
/** All known screen context suffixes, ordered longest-first to avoid prefix clashes. */
|
|
7
|
+
const screenContexts: ScreenContext[] = ['Detail', 'Popup', 'Main', 'Zoom'];
|
|
8
|
+
|
|
9
|
+
/** Describes a single generated subject class discovered in the test-artifacts directory. */
|
|
10
|
+
export interface SubjectArtifactInfo {
|
|
11
|
+
/** PascalCase subject folder name (e.g. `"CustomerOrder"`). */
|
|
12
|
+
subject: string;
|
|
13
|
+
/** Exact generated class name (e.g. `"CustomerOrderMain"`). */
|
|
14
|
+
className: string;
|
|
15
|
+
/** Screen context encoded in the class name. */
|
|
16
|
+
screenContext: ScreenContext;
|
|
17
|
+
/**
|
|
18
|
+
* Module specifier that importing code should use, relative to the consumer
|
|
19
|
+
* project root (e.g. `"@thinkwise/testwise/test-artifacts/subjects/CustomerOrder/CustomerOrderMain.js"`).
|
|
20
|
+
*/
|
|
21
|
+
importPath: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Describes a single field or column on a screen interface. */
|
|
25
|
+
export interface ScreenFieldInfo {
|
|
26
|
+
/** camelCase property name as it appears on the screen interface (e.g. `"customerName"`, `"orderDate"`). */
|
|
27
|
+
propertyName: string;
|
|
28
|
+
/**
|
|
29
|
+
* Testwise control type suffix indicating which control helper to use
|
|
30
|
+
* (e.g. `"Field"`, `"Lookup"`, `"Dropdown"`, `"DatePicker"`, `"Checkbox"`, `"Textarea"`, `"ComboBox"`).
|
|
31
|
+
* Derived from the property name suffix in the generated interface.
|
|
32
|
+
*/
|
|
33
|
+
controlType: string;
|
|
34
|
+
/** The component this field belongs to — `"Form"` or `"Grid"`. */
|
|
35
|
+
componentType: 'Form' | 'Grid';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Describes a single typed component property on a generated subject class. */
|
|
39
|
+
export interface ComponentInfo {
|
|
40
|
+
/** camelCase property name as declared on the subject class (e.g. `"grid"`, `"actionBar"`). */
|
|
41
|
+
propertyName: string;
|
|
42
|
+
/** Testwise component class name (e.g. `"Grid"`, `"ActionBar"`, `"Form"`). */
|
|
43
|
+
componentType: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Runtime service that reads the generated test-artifact files to answer
|
|
48
|
+
* questions about available subjects, their screen-context variants, and the
|
|
49
|
+
* components exposed on each subject class.
|
|
50
|
+
*
|
|
51
|
+
* Intended to be used by the `@thinkwise/testwise-mcp` server so that AI
|
|
52
|
+
* tooling can discover the correct class names and component properties before
|
|
53
|
+
* generating test code — without having to guess or hallucinate names.
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* Runtime service that reads the generated test-artifact files to answer
|
|
57
|
+
* questions about available subjects, their screen-context variants, and the
|
|
58
|
+
* components exposed on each subject class.
|
|
59
|
+
*
|
|
60
|
+
* **What it does:** The `@thinkwise/testwise-mcp` MCP server calls these
|
|
61
|
+
* methods to surface information to AI tooling (e.g. GitHub Copilot agents)
|
|
62
|
+
* so the AI can write correct Testwise tests without guessing class names,
|
|
63
|
+
* property names, or field names.
|
|
64
|
+
*
|
|
65
|
+
* **How to use it (as a consumer of the MCP server):** You don't call this
|
|
66
|
+
* class directly — use the MCP tools:
|
|
67
|
+
* - `list_subjects()` — all available subject folder names
|
|
68
|
+
* - `list_artifacts(subject?, screenContext?)` — exact class names + import paths
|
|
69
|
+
* - `get_components(subject, screenContext)` — component properties on a class
|
|
70
|
+
* - `get_screen_interface(subject, screenContext)` — field/column names + control types
|
|
71
|
+
*
|
|
72
|
+
* **For contributors:** This class is intentionally side-effect-free — it
|
|
73
|
+
* only reads files and never writes anything. Do not add browser-interaction
|
|
74
|
+
* logic here.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* // Used internally by the MCP server:
|
|
78
|
+
* const resolver = new ArtifactResolver();
|
|
79
|
+
* const subjects = resolver.listSubjects();
|
|
80
|
+
* const artifacts = resolver.listArtifacts('Employee', 'Main');
|
|
81
|
+
*/
|
|
82
|
+
export class ArtifactResolver {
|
|
83
|
+
private readonly _paths: PipelinePaths;
|
|
84
|
+
|
|
85
|
+
constructor(paths?: PipelinePaths) {
|
|
86
|
+
this._paths = paths ?? new PipelinePaths();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Returns all subject folder names (PascalCase) that have been generated
|
|
91
|
+
* into the test-artifacts directory.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* resolver.listSubjects();
|
|
95
|
+
* // → ["CustomerOrder", "Product", "Employee"]
|
|
96
|
+
*/
|
|
97
|
+
public listSubjects(): string[] {
|
|
98
|
+
const subjectsDir = this._paths.subjects;
|
|
99
|
+
|
|
100
|
+
if (!fs.existsSync(subjectsDir)) return [];
|
|
101
|
+
|
|
102
|
+
return fs.readdirSync(subjectsDir).filter((entry) => fs.statSync(path.join(subjectsDir, entry)).isDirectory());
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Returns all artifacts for the given subject, optionally filtered to a
|
|
107
|
+
* specific screen context.
|
|
108
|
+
*
|
|
109
|
+
* When `subject` is omitted every generated artifact is returned.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* // All screen contexts for one subject
|
|
113
|
+
* resolver.listArtifacts('CustomerOrder');
|
|
114
|
+
* // → [{ className: "CustomerOrderMain", screenContext: "Main", ... }, ...]
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* // One specific artifact
|
|
118
|
+
* resolver.listArtifacts('CustomerOrder', 'Main');
|
|
119
|
+
* // → [{ className: "CustomerOrderMain", screenContext: "Main", ... }]
|
|
120
|
+
*/
|
|
121
|
+
public listArtifacts(subject?: string, screenContext?: ScreenContext): SubjectArtifactInfo[] {
|
|
122
|
+
const subjects = subject ? [subject] : this.listSubjects();
|
|
123
|
+
const results: SubjectArtifactInfo[] = [];
|
|
124
|
+
|
|
125
|
+
for (const subjectName of subjects) {
|
|
126
|
+
const subjectDir = path.join(this._paths.subjects, subjectName);
|
|
127
|
+
|
|
128
|
+
if (!fs.existsSync(subjectDir)) continue;
|
|
129
|
+
|
|
130
|
+
const files = fs.readdirSync(subjectDir).filter((f) => f.endsWith('.ts') && f !== 'index.ts');
|
|
131
|
+
|
|
132
|
+
for (const file of files) {
|
|
133
|
+
const className = file.replace('.ts', '');
|
|
134
|
+
const context = this.inferScreenContext(className);
|
|
135
|
+
|
|
136
|
+
if (!context) continue;
|
|
137
|
+
if (screenContext && context !== screenContext) continue;
|
|
138
|
+
|
|
139
|
+
results.push({
|
|
140
|
+
subject: subjectName,
|
|
141
|
+
className,
|
|
142
|
+
screenContext: context,
|
|
143
|
+
importPath: `@thinkwise/testwise/test-artifacts/subjects/${subjectName}/${className}.js`
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return results;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Returns the typed component properties declared on the generated subject
|
|
153
|
+
* class for the given subject + screen context combination.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* resolver.getComponents('CustomerOrder', 'Main');
|
|
157
|
+
* // → [
|
|
158
|
+
* // { propertyName: "grid", componentType: "Grid" },
|
|
159
|
+
* // { propertyName: "actionBar", componentType: "ActionBar" },
|
|
160
|
+
* // { propertyName: "filterForm",componentType: "FilterForm"},
|
|
161
|
+
* // ]
|
|
162
|
+
*/
|
|
163
|
+
public getComponents(subject: string, screenContext: ScreenContext): ComponentInfo[] {
|
|
164
|
+
const artifacts = this.listArtifacts(subject, screenContext);
|
|
165
|
+
|
|
166
|
+
if (artifacts.length === 0) return [];
|
|
167
|
+
|
|
168
|
+
const filePath = path.join(this._paths.subjects, subject, `${artifacts[0].className}.ts`);
|
|
169
|
+
|
|
170
|
+
if (!fs.existsSync(filePath)) return [];
|
|
171
|
+
|
|
172
|
+
return this.parseComponentProperties(fs.readFileSync(filePath, 'utf-8'));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Returns all fields and columns declared on the generated screen interface
|
|
177
|
+
* for the given subject + screen context combination.
|
|
178
|
+
*
|
|
179
|
+
* The interface lives in `test-artifacts/screens/` and contains every field
|
|
180
|
+
* name, column name, and control type for the screen — enough for an AI to
|
|
181
|
+
* write a complete, accurate test without inspecting a live browser.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* resolver.getScreenInterface('CustomerOrder', 'Main');
|
|
185
|
+
* // → [
|
|
186
|
+
* // { propertyName: "customerName", controlType: "Field", componentType: "Form" },
|
|
187
|
+
* // { propertyName: "orderDate", controlType: "DatePicker", componentType: "Form" },
|
|
188
|
+
* // { propertyName: "status", controlType: "Lookup", componentType: "Form" },
|
|
189
|
+
* // { propertyName: "orderId", controlType: "Column", componentType: "Grid" },
|
|
190
|
+
* // ]
|
|
191
|
+
*/
|
|
192
|
+
public getScreenInterface(subject: string, screenContext: ScreenContext): ScreenFieldInfo[] {
|
|
193
|
+
const artifacts = this.listArtifacts(subject, screenContext);
|
|
194
|
+
if (artifacts.length === 0) return [];
|
|
195
|
+
|
|
196
|
+
// Component files live in Components/ subfolder under the subject folder
|
|
197
|
+
const componentsDir = path.join(this._paths.subjects, subject, 'Components');
|
|
198
|
+
if (!fs.existsSync(componentsDir)) return [];
|
|
199
|
+
|
|
200
|
+
const results: ScreenFieldInfo[] = [];
|
|
201
|
+
const componentFiles = fs.readdirSync(componentsDir).filter((f) => f.endsWith('.ts'));
|
|
202
|
+
|
|
203
|
+
for (const file of componentFiles) {
|
|
204
|
+
const content = fs.readFileSync(path.join(componentsDir, file), 'utf-8');
|
|
205
|
+
const interfaceName = file.replace('.ts', '');
|
|
206
|
+
const fields = this.parseScreenInterface(content, interfaceName);
|
|
207
|
+
results.push(...fields);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return results;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ── Private helpers ────────────────────────────────────────────────────────
|
|
214
|
+
|
|
215
|
+
private inferScreenContext(className: string): ScreenContext | undefined {
|
|
216
|
+
for (const ctx of screenContexts) {
|
|
217
|
+
if (className.endsWith(ctx)) return ctx;
|
|
218
|
+
}
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Parses component properties from a generated subject class.
|
|
224
|
+
*
|
|
225
|
+
* Generated classes declare properties without `public`:
|
|
226
|
+
* actionBarVXE6V0YT: ActionBar;
|
|
227
|
+
* gridQT3UL7F8: EmployeeGrid;
|
|
228
|
+
*/
|
|
229
|
+
private parseComponentProperties(content: string): ComponentInfo[] {
|
|
230
|
+
const results: ComponentInfo[] = [];
|
|
231
|
+
|
|
232
|
+
// Match class-body property declarations: " name: Type;" (no public keyword)
|
|
233
|
+
// Excludes private fields (_name), constructor, and method declarations
|
|
234
|
+
const propertyRegex = /^\s{4}(\w+)\s*:\s*(\w+)\s*;/gm;
|
|
235
|
+
|
|
236
|
+
for (let match = propertyRegex.exec(content); match !== null; match = propertyRegex.exec(content)) {
|
|
237
|
+
const propertyName = match[1];
|
|
238
|
+
const componentType = match[2];
|
|
239
|
+
|
|
240
|
+
if (propertyName.startsWith('_')) continue;
|
|
241
|
+
if (['string', 'number', 'boolean', 'Page', 'Locator'].includes(componentType)) continue;
|
|
242
|
+
|
|
243
|
+
results.push({ propertyName, componentType });
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return results;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Parses fields/columns from the Components/ subfolder files for a subject.
|
|
251
|
+
*
|
|
252
|
+
* Generated component files (e.g. EmployeeGrid.ts, EmployeeForm.ts) declare
|
|
253
|
+
* getters like:
|
|
254
|
+
* public get firstNameColumn(): IGridColumnControl { ... }
|
|
255
|
+
* public get firstNameField(): IInputFieldControl { ... }
|
|
256
|
+
*/
|
|
257
|
+
private parseScreenInterface(content: string, interfaceName: string): ScreenFieldInfo[] {
|
|
258
|
+
const results: ScreenFieldInfo[] = [];
|
|
259
|
+
|
|
260
|
+
// Match readonly interface members: " readonly bioColumn: IGridColumnControl;"
|
|
261
|
+
const interfaceRegex = /^\s+readonly\s+(\w+)\s*:\s*(I?\w+Control)\s*;/gm;
|
|
262
|
+
for (let match = interfaceRegex.exec(content); match !== null; match = interfaceRegex.exec(content)) {
|
|
263
|
+
const propertyName = match[1];
|
|
264
|
+
const rawType = match[2];
|
|
265
|
+
const controlType = this.inferControlType(rawType, propertyName);
|
|
266
|
+
const componentType = interfaceName.toLowerCase().includes('grid') ? 'Grid' : 'Form';
|
|
267
|
+
results.push({ propertyName, controlType, componentType: componentType as 'Form' | 'Grid' });
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return results;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
private inferControlType(rawType: string, propertyName: string): string {
|
|
274
|
+
const typeMap: Record<string, string> = {
|
|
275
|
+
IGridColumnControl: 'Column',
|
|
276
|
+
GridColumnControl: 'Column',
|
|
277
|
+
IInputFieldControl: 'Field',
|
|
278
|
+
InputFieldControl: 'Field',
|
|
279
|
+
ILookupDropdown: 'Lookup',
|
|
280
|
+
LookupDropdown: 'Lookup',
|
|
281
|
+
IFormComboBox: 'ComboBox',
|
|
282
|
+
FormComboBox: 'ComboBox',
|
|
283
|
+
IDateControl: 'DatePicker',
|
|
284
|
+
DateControl: 'DatePicker',
|
|
285
|
+
ICheckboxControl: 'Checkbox',
|
|
286
|
+
CheckboxControl: 'Checkbox',
|
|
287
|
+
ITextareaControl: 'Textarea',
|
|
288
|
+
TextareaControl: 'Textarea'
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
if (typeMap[rawType]) return typeMap[rawType];
|
|
292
|
+
|
|
293
|
+
const suffixMatch = propertyName.match(/(Field|Lookup|Dropdown|DatePicker|Checkbox|Textarea|ComboBox|Column)$/i);
|
|
294
|
+
return suffixMatch ? suffixMatch[1] : rawType;
|
|
295
|
+
}
|
|
296
|
+
}
|
package/mcp/index.ts
ADDED