tm1npm 1.0.0
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/.env.example +16 -0
- package/.eslintrc.js +28 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +36 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/ISSUE_TEMPLATE/question.md +24 -0
- package/.github/workflows/publish-npm.yml +53 -0
- package/.github/workflows/test-on-tag.yml +172 -0
- package/DEVELOPMENT_GUIDE.md +587 -0
- package/LICENSE +21 -0
- package/README.md +580 -0
- package/jest.ci.config.js +83 -0
- package/jest.config.js +68 -0
- package/lib/exceptions/TM1Exception.d.ts +17 -0
- package/lib/exceptions/TM1Exception.d.ts.map +1 -0
- package/lib/exceptions/TM1Exception.js +36 -0
- package/lib/exceptions/TM1RestException.d.ts +10 -0
- package/lib/exceptions/TM1RestException.d.ts.map +1 -0
- package/lib/exceptions/TM1RestException.js +17 -0
- package/lib/exceptions/TM1TimeoutException.d.ts +9 -0
- package/lib/exceptions/TM1TimeoutException.d.ts.map +1 -0
- package/lib/exceptions/TM1TimeoutException.js +16 -0
- package/lib/index.d.ts +41 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +132 -0
- package/lib/objects/Annotation.d.ts +36 -0
- package/lib/objects/Annotation.d.ts.map +1 -0
- package/lib/objects/Annotation.js +134 -0
- package/lib/objects/Application.d.ts +67 -0
- package/lib/objects/Application.d.ts.map +1 -0
- package/lib/objects/Application.js +125 -0
- package/lib/objects/Axis.d.ts +36 -0
- package/lib/objects/Axis.d.ts.map +1 -0
- package/lib/objects/Axis.js +103 -0
- package/lib/objects/Chore.d.ts +43 -0
- package/lib/objects/Chore.d.ts.map +1 -0
- package/lib/objects/Chore.js +129 -0
- package/lib/objects/ChoreFrequency.d.ts +23 -0
- package/lib/objects/ChoreFrequency.d.ts.map +1 -0
- package/lib/objects/ChoreFrequency.js +61 -0
- package/lib/objects/ChoreStartTime.d.ts +15 -0
- package/lib/objects/ChoreStartTime.d.ts.map +1 -0
- package/lib/objects/ChoreStartTime.js +85 -0
- package/lib/objects/ChoreTask.d.ts +28 -0
- package/lib/objects/ChoreTask.d.ts.map +1 -0
- package/lib/objects/ChoreTask.js +66 -0
- package/lib/objects/Cube.d.ts +26 -0
- package/lib/objects/Cube.d.ts.map +1 -0
- package/lib/objects/Cube.js +109 -0
- package/lib/objects/Dimension.d.ts +26 -0
- package/lib/objects/Dimension.d.ts.map +1 -0
- package/lib/objects/Dimension.js +86 -0
- package/lib/objects/Element.d.ts +35 -0
- package/lib/objects/Element.d.ts.map +1 -0
- package/lib/objects/Element.js +115 -0
- package/lib/objects/ElementAttribute.d.ts +28 -0
- package/lib/objects/ElementAttribute.d.ts.map +1 -0
- package/lib/objects/ElementAttribute.js +97 -0
- package/lib/objects/Git.d.ts +21 -0
- package/lib/objects/Git.d.ts.map +1 -0
- package/lib/objects/Git.js +49 -0
- package/lib/objects/GitCommit.d.ts +12 -0
- package/lib/objects/GitCommit.d.ts.map +1 -0
- package/lib/objects/GitCommit.js +26 -0
- package/lib/objects/GitPlan.d.ts +35 -0
- package/lib/objects/GitPlan.d.ts.map +1 -0
- package/lib/objects/GitPlan.js +78 -0
- package/lib/objects/GitRemote.d.ts +12 -0
- package/lib/objects/GitRemote.d.ts.map +1 -0
- package/lib/objects/GitRemote.js +26 -0
- package/lib/objects/Hierarchy.d.ts +47 -0
- package/lib/objects/Hierarchy.d.ts.map +1 -0
- package/lib/objects/Hierarchy.js +165 -0
- package/lib/objects/MDXView.d.ts +19 -0
- package/lib/objects/MDXView.d.ts.map +1 -0
- package/lib/objects/MDXView.js +67 -0
- package/lib/objects/NativeView.d.ts +39 -0
- package/lib/objects/NativeView.d.ts.map +1 -0
- package/lib/objects/NativeView.js +209 -0
- package/lib/objects/Process.d.ts +70 -0
- package/lib/objects/Process.d.ts.map +1 -0
- package/lib/objects/Process.js +210 -0
- package/lib/objects/ProcessDebugBreakpoint.d.ts +60 -0
- package/lib/objects/ProcessDebugBreakpoint.d.ts.map +1 -0
- package/lib/objects/ProcessDebugBreakpoint.js +168 -0
- package/lib/objects/ProcessParameter.d.ts +23 -0
- package/lib/objects/ProcessParameter.d.ts.map +1 -0
- package/lib/objects/ProcessParameter.js +55 -0
- package/lib/objects/ProcessVariable.d.ts +26 -0
- package/lib/objects/ProcessVariable.d.ts.map +1 -0
- package/lib/objects/ProcessVariable.js +63 -0
- package/lib/objects/Rules.d.ts +30 -0
- package/lib/objects/Rules.d.ts.map +1 -0
- package/lib/objects/Rules.js +103 -0
- package/lib/objects/Sandbox.d.ts +21 -0
- package/lib/objects/Sandbox.d.ts.map +1 -0
- package/lib/objects/Sandbox.js +64 -0
- package/lib/objects/Server.d.ts +27 -0
- package/lib/objects/Server.d.ts.map +1 -0
- package/lib/objects/Server.js +26 -0
- package/lib/objects/Subset.d.ts +44 -0
- package/lib/objects/Subset.d.ts.map +1 -0
- package/lib/objects/Subset.js +222 -0
- package/lib/objects/TM1Object.d.ts +8 -0
- package/lib/objects/TM1Object.d.ts.map +1 -0
- package/lib/objects/TM1Object.js +17 -0
- package/lib/objects/TM1Project.d.ts +74 -0
- package/lib/objects/TM1Project.d.ts.map +1 -0
- package/lib/objects/TM1Project.js +409 -0
- package/lib/objects/User.d.ts +42 -0
- package/lib/objects/User.d.ts.map +1 -0
- package/lib/objects/User.js +157 -0
- package/lib/objects/View.d.ts +19 -0
- package/lib/objects/View.d.ts.map +1 -0
- package/lib/objects/View.js +33 -0
- package/lib/objects/index.d.ts +30 -0
- package/lib/objects/index.d.ts.map +1 -0
- package/lib/objects/index.js +68 -0
- package/lib/services/AnnotationService.d.ts +17 -0
- package/lib/services/AnnotationService.d.ts.map +1 -0
- package/lib/services/AnnotationService.js +91 -0
- package/lib/services/ApplicationService.d.ts +21 -0
- package/lib/services/ApplicationService.d.ts.map +1 -0
- package/lib/services/ApplicationService.js +227 -0
- package/lib/services/AuditLogService.d.ts +15 -0
- package/lib/services/AuditLogService.d.ts.map +1 -0
- package/lib/services/AuditLogService.js +153 -0
- package/lib/services/CellService.d.ts +191 -0
- package/lib/services/CellService.d.ts.map +1 -0
- package/lib/services/CellService.js +597 -0
- package/lib/services/ChoreService.d.ts +24 -0
- package/lib/services/ChoreService.d.ts.map +1 -0
- package/lib/services/ChoreService.js +219 -0
- package/lib/services/ConfigurationService.d.ts +18 -0
- package/lib/services/ConfigurationService.d.ts.map +1 -0
- package/lib/services/ConfigurationService.js +60 -0
- package/lib/services/CubeService.d.ts +43 -0
- package/lib/services/CubeService.d.ts.map +1 -0
- package/lib/services/CubeService.js +296 -0
- package/lib/services/DimensionService.d.ts +21 -0
- package/lib/services/DimensionService.d.ts.map +1 -0
- package/lib/services/DimensionService.js +146 -0
- package/lib/services/ElementService.d.ts +132 -0
- package/lib/services/ElementService.d.ts.map +1 -0
- package/lib/services/ElementService.js +579 -0
- package/lib/services/FileService.d.ts +14 -0
- package/lib/services/FileService.d.ts.map +1 -0
- package/lib/services/FileService.js +65 -0
- package/lib/services/GitService.d.ts +23 -0
- package/lib/services/GitService.d.ts.map +1 -0
- package/lib/services/GitService.js +225 -0
- package/lib/services/HierarchyService.d.ts +32 -0
- package/lib/services/HierarchyService.d.ts.map +1 -0
- package/lib/services/HierarchyService.js +235 -0
- package/lib/services/JobService.d.ts +13 -0
- package/lib/services/JobService.d.ts.map +1 -0
- package/lib/services/JobService.js +83 -0
- package/lib/services/LoggerService.d.ts +16 -0
- package/lib/services/LoggerService.d.ts.map +1 -0
- package/lib/services/LoggerService.js +101 -0
- package/lib/services/ManageService.d.ts +47 -0
- package/lib/services/ManageService.d.ts.map +1 -0
- package/lib/services/ManageService.js +221 -0
- package/lib/services/MessageLogService.d.ts +13 -0
- package/lib/services/MessageLogService.d.ts.map +1 -0
- package/lib/services/MessageLogService.js +175 -0
- package/lib/services/MonitoringService.d.ts +29 -0
- package/lib/services/MonitoringService.d.ts.map +1 -0
- package/lib/services/MonitoringService.js +86 -0
- package/lib/services/ObjectService.d.ts +8 -0
- package/lib/services/ObjectService.d.ts.map +1 -0
- package/lib/services/ObjectService.js +20 -0
- package/lib/services/PowerBiService.d.ts +13 -0
- package/lib/services/PowerBiService.d.ts.map +1 -0
- package/lib/services/PowerBiService.js +52 -0
- package/lib/services/ProcessService.d.ts +57 -0
- package/lib/services/ProcessService.d.ts.map +1 -0
- package/lib/services/ProcessService.js +499 -0
- package/lib/services/RestService.d.ts +68 -0
- package/lib/services/RestService.d.ts.map +1 -0
- package/lib/services/RestService.js +166 -0
- package/lib/services/SandboxService.d.ts +28 -0
- package/lib/services/SandboxService.d.ts.map +1 -0
- package/lib/services/SandboxService.js +197 -0
- package/lib/services/SecurityService.d.ts +33 -0
- package/lib/services/SecurityService.d.ts.map +1 -0
- package/lib/services/SecurityService.js +249 -0
- package/lib/services/ServerService.d.ts +55 -0
- package/lib/services/ServerService.d.ts.map +1 -0
- package/lib/services/ServerService.js +247 -0
- package/lib/services/SessionService.d.ts +15 -0
- package/lib/services/SessionService.d.ts.map +1 -0
- package/lib/services/SessionService.js +68 -0
- package/lib/services/SubsetService.d.ts +13 -0
- package/lib/services/SubsetService.d.ts.map +1 -0
- package/lib/services/SubsetService.js +46 -0
- package/lib/services/TM1Service.d.ts +39 -0
- package/lib/services/TM1Service.d.ts.map +1 -0
- package/lib/services/TM1Service.js +94 -0
- package/lib/services/ThreadService.d.ts +15 -0
- package/lib/services/ThreadService.d.ts.map +1 -0
- package/lib/services/ThreadService.js +104 -0
- package/lib/services/TransactionLogService.d.ts +11 -0
- package/lib/services/TransactionLogService.d.ts.map +1 -0
- package/lib/services/TransactionLogService.js +124 -0
- package/lib/services/UserService.d.ts +14 -0
- package/lib/services/UserService.d.ts.map +1 -0
- package/lib/services/UserService.js +103 -0
- package/lib/services/ViewService.d.ts +30 -0
- package/lib/services/ViewService.d.ts.map +1 -0
- package/lib/services/ViewService.js +331 -0
- package/lib/services/index.d.ts +26 -0
- package/lib/services/index.d.ts.map +1 -0
- package/lib/services/index.js +56 -0
- package/lib/tests/100PercentParityCheck.test.d.ts +6 -0
- package/lib/tests/100PercentParityCheck.test.d.ts.map +1 -0
- package/lib/tests/100PercentParityCheck.test.js +143 -0
- package/lib/tests/basic.test.d.ts +6 -0
- package/lib/tests/basic.test.d.ts.map +1 -0
- package/lib/tests/basic.test.js +52 -0
- package/lib/tests/cellService.test.d.ts +6 -0
- package/lib/tests/cellService.test.d.ts.map +1 -0
- package/lib/tests/cellService.test.js +311 -0
- package/lib/tests/ciSetup.d.ts +6 -0
- package/lib/tests/ciSetup.d.ts.map +1 -0
- package/lib/tests/ciSetup.js +23 -0
- package/lib/tests/comprehensive.service.test.d.ts +6 -0
- package/lib/tests/comprehensive.service.test.d.ts.map +1 -0
- package/lib/tests/comprehensive.service.test.js +507 -0
- package/lib/tests/connection.test.d.ts +6 -0
- package/lib/tests/connection.test.d.ts.map +1 -0
- package/lib/tests/connection.test.js +89 -0
- package/lib/tests/cubeService.test.d.ts +6 -0
- package/lib/tests/cubeService.test.d.ts.map +1 -0
- package/lib/tests/cubeService.test.js +368 -0
- package/lib/tests/dimensionService.comprehensive.test.d.ts +7 -0
- package/lib/tests/dimensionService.comprehensive.test.d.ts.map +1 -0
- package/lib/tests/dimensionService.comprehensive.test.js +614 -0
- package/lib/tests/dimensionService.test.d.ts +6 -0
- package/lib/tests/dimensionService.test.d.ts.map +1 -0
- package/lib/tests/dimensionService.test.js +293 -0
- package/lib/tests/edgeCases.test.d.ts +6 -0
- package/lib/tests/edgeCases.test.d.ts.map +1 -0
- package/lib/tests/edgeCases.test.js +301 -0
- package/lib/tests/elementService.comprehensive.test.d.ts +7 -0
- package/lib/tests/elementService.comprehensive.test.d.ts.map +1 -0
- package/lib/tests/elementService.comprehensive.test.js +846 -0
- package/lib/tests/elementService.test.d.ts +6 -0
- package/lib/tests/elementService.test.d.ts.map +1 -0
- package/lib/tests/elementService.test.js +350 -0
- package/lib/tests/enhancedCellService.test.d.ts +2 -0
- package/lib/tests/enhancedCellService.test.d.ts.map +1 -0
- package/lib/tests/enhancedCellService.test.js +152 -0
- package/lib/tests/enhancedCubeService.test.d.ts +2 -0
- package/lib/tests/enhancedCubeService.test.d.ts.map +1 -0
- package/lib/tests/enhancedCubeService.test.js +246 -0
- package/lib/tests/enhancedElementService.test.d.ts +2 -0
- package/lib/tests/enhancedElementService.test.d.ts.map +1 -0
- package/lib/tests/enhancedElementService.test.js +199 -0
- package/lib/tests/enhancedViewService.test.d.ts +2 -0
- package/lib/tests/enhancedViewService.test.d.ts.map +1 -0
- package/lib/tests/enhancedViewService.test.js +260 -0
- package/lib/tests/errorHandling.test.d.ts +6 -0
- package/lib/tests/errorHandling.test.d.ts.map +1 -0
- package/lib/tests/errorHandling.test.js +227 -0
- package/lib/tests/exceptions.test.d.ts +7 -0
- package/lib/tests/exceptions.test.d.ts.map +1 -0
- package/lib/tests/exceptions.test.js +257 -0
- package/lib/tests/hierarchyService.test.d.ts +6 -0
- package/lib/tests/hierarchyService.test.d.ts.map +1 -0
- package/lib/tests/hierarchyService.test.js +294 -0
- package/lib/tests/index.test.d.ts +6 -0
- package/lib/tests/index.test.d.ts.map +1 -0
- package/lib/tests/index.test.js +346 -0
- package/lib/tests/integration.test.d.ts +6 -0
- package/lib/tests/integration.test.d.ts.map +1 -0
- package/lib/tests/integration.test.js +302 -0
- package/lib/tests/integrationTests.test.d.ts +2 -0
- package/lib/tests/integrationTests.test.d.ts.map +1 -0
- package/lib/tests/integrationTests.test.js +252 -0
- package/lib/tests/mdx.advanced.test.d.ts +6 -0
- package/lib/tests/mdx.advanced.test.d.ts.map +1 -0
- package/lib/tests/mdx.advanced.test.js +437 -0
- package/lib/tests/objects.improved.test.d.ts +7 -0
- package/lib/tests/objects.improved.test.d.ts.map +1 -0
- package/lib/tests/objects.improved.test.js +302 -0
- package/lib/tests/performance.test.d.ts +6 -0
- package/lib/tests/performance.test.d.ts.map +1 -0
- package/lib/tests/performance.test.js +264 -0
- package/lib/tests/processService.comprehensive.test.d.ts +7 -0
- package/lib/tests/processService.comprehensive.test.d.ts.map +1 -0
- package/lib/tests/processService.comprehensive.test.js +656 -0
- package/lib/tests/processService.test.d.ts +6 -0
- package/lib/tests/processService.test.d.ts.map +1 -0
- package/lib/tests/processService.test.js +322 -0
- package/lib/tests/restService.test.d.ts +6 -0
- package/lib/tests/restService.test.d.ts.map +1 -0
- package/lib/tests/restService.test.js +177 -0
- package/lib/tests/security.advanced.test.d.ts +6 -0
- package/lib/tests/security.advanced.test.d.ts.map +1 -0
- package/lib/tests/security.advanced.test.js +407 -0
- package/lib/tests/security.test.d.ts +6 -0
- package/lib/tests/security.test.d.ts.map +1 -0
- package/lib/tests/security.test.js +204 -0
- package/lib/tests/securityService.comprehensive.test.d.ts +7 -0
- package/lib/tests/securityService.comprehensive.test.d.ts.map +1 -0
- package/lib/tests/securityService.comprehensive.test.js +457 -0
- package/lib/tests/setup.d.ts +4 -0
- package/lib/tests/setup.d.ts.map +1 -0
- package/lib/tests/setup.js +40 -0
- package/lib/tests/simpleCoverage.test.d.ts +6 -0
- package/lib/tests/simpleCoverage.test.d.ts.map +1 -0
- package/lib/tests/simpleCoverage.test.js +236 -0
- package/lib/tests/stress.performance.test.d.ts +6 -0
- package/lib/tests/stress.performance.test.d.ts.map +1 -0
- package/lib/tests/stress.performance.test.js +423 -0
- package/lib/tests/subsetService.test.d.ts +6 -0
- package/lib/tests/subsetService.test.d.ts.map +1 -0
- package/lib/tests/subsetService.test.js +271 -0
- package/lib/tests/testConfig.d.ts +18 -0
- package/lib/tests/testConfig.d.ts.map +1 -0
- package/lib/tests/testConfig.js +38 -0
- package/lib/tests/testUtils.d.ts +9 -0
- package/lib/tests/testUtils.d.ts.map +1 -0
- package/lib/tests/testUtils.js +100 -0
- package/lib/tests/tm1Service.test.d.ts +7 -0
- package/lib/tests/tm1Service.test.d.ts.map +1 -0
- package/lib/tests/tm1Service.test.js +290 -0
- package/lib/tests/viewService.test.d.ts +6 -0
- package/lib/tests/viewService.test.d.ts.map +1 -0
- package/lib/tests/viewService.test.js +240 -0
- package/lib/utils/Utils.d.ts +90 -0
- package/lib/utils/Utils.d.ts.map +1 -0
- package/lib/utils/Utils.js +379 -0
- package/package.json +81 -0
- package/run-all-tests.js +296 -0
- package/src/exceptions/TM1Exception.ts +38 -0
- package/src/exceptions/TM1RestException.ts +17 -0
- package/src/exceptions/TM1TimeoutException.ts +15 -0
- package/src/index.ts +94 -0
- package/src/objects/Annotation.ts +194 -0
- package/src/objects/Application.ts +146 -0
- package/src/objects/Axis.ts +149 -0
- package/src/objects/Chore.ts +174 -0
- package/src/objects/ChoreFrequency.ts +83 -0
- package/src/objects/ChoreStartTime.ts +111 -0
- package/src/objects/ChoreTask.ts +92 -0
- package/src/objects/Cube.ts +125 -0
- package/src/objects/Dimension.ts +107 -0
- package/src/objects/Element.ts +153 -0
- package/src/objects/ElementAttribute.ts +115 -0
- package/src/objects/Git.ts +86 -0
- package/src/objects/GitCommit.ts +31 -0
- package/src/objects/GitPlan.ts +121 -0
- package/src/objects/GitRemote.ts +31 -0
- package/src/objects/Hierarchy.ts +229 -0
- package/src/objects/MDXView.ts +91 -0
- package/src/objects/NativeView.ts +268 -0
- package/src/objects/Process.ts +320 -0
- package/src/objects/ProcessDebugBreakpoint.ts +239 -0
- package/src/objects/ProcessParameter.ts +76 -0
- package/src/objects/ProcessVariable.ts +89 -0
- package/src/objects/Rules.ts +117 -0
- package/src/objects/Sandbox.ts +90 -0
- package/src/objects/Server.ts +45 -0
- package/src/objects/Subset.ts +323 -0
- package/src/objects/TM1Object.ts +17 -0
- package/src/objects/TM1Project.ts +587 -0
- package/src/objects/User.ts +198 -0
- package/src/objects/View.ts +43 -0
- package/src/objects/index.ts +36 -0
- package/src/services/AnnotationService.ts +107 -0
- package/src/services/ApplicationService.ts +279 -0
- package/src/services/AuditLogService.ts +172 -0
- package/src/services/CellService.ts +814 -0
- package/src/services/ChoreService.ts +219 -0
- package/src/services/ConfigurationService.ts +69 -0
- package/src/services/CubeService.ts +338 -0
- package/src/services/DimensionService.ts +168 -0
- package/src/services/ElementService.ts +966 -0
- package/src/services/FileService.ts +67 -0
- package/src/services/GitService.ts +324 -0
- package/src/services/HierarchyService.ts +284 -0
- package/src/services/JobService.ts +59 -0
- package/src/services/LoggerService.ts +118 -0
- package/src/services/ManageService.ts +322 -0
- package/src/services/MessageLogService.ts +211 -0
- package/src/services/MonitoringService.ts +105 -0
- package/src/services/ObjectService.ts +21 -0
- package/src/services/PowerBiService.ts +85 -0
- package/src/services/ProcessService.ts +589 -0
- package/src/services/RestService.ts +224 -0
- package/src/services/SandboxService.ts +217 -0
- package/src/services/SecurityService.ts +284 -0
- package/src/services/ServerService.ts +313 -0
- package/src/services/SessionService.ts +81 -0
- package/src/services/SubsetService.ts +52 -0
- package/src/services/TM1Service.ts +133 -0
- package/src/services/ThreadService.ts +83 -0
- package/src/services/TransactionLogService.ts +148 -0
- package/src/services/UserService.ts +77 -0
- package/src/services/ViewService.ts +398 -0
- package/src/services/index.ts +28 -0
- package/src/tests/100PercentParityCheck.test.ts +166 -0
- package/src/tests/basic.test.ts +59 -0
- package/src/tests/cellService.test.ts +405 -0
- package/src/tests/ciSetup.ts +26 -0
- package/src/tests/comprehensive.service.test.ts +653 -0
- package/src/tests/config.ini.template +23 -0
- package/src/tests/connection.test.ts +90 -0
- package/src/tests/cubeService.test.ts +458 -0
- package/src/tests/dimensionService.comprehensive.test.ts +786 -0
- package/src/tests/dimensionService.test.ts +373 -0
- package/src/tests/edgeCases.test.ts +358 -0
- package/src/tests/elementService.comprehensive.test.ts +1190 -0
- package/src/tests/elementService.test.ts +472 -0
- package/src/tests/enhancedCellService.test.ts +237 -0
- package/src/tests/enhancedCubeService.test.ts +384 -0
- package/src/tests/enhancedElementService.test.ts +301 -0
- package/src/tests/enhancedViewService.test.ts +373 -0
- package/src/tests/errorHandling.test.ts +264 -0
- package/src/tests/exceptions.test.ts +313 -0
- package/src/tests/hierarchyService.test.ts +386 -0
- package/src/tests/index.test.ts +376 -0
- package/src/tests/integration.test.ts +333 -0
- package/src/tests/integrationTests.test.ts +302 -0
- package/src/tests/mdx.advanced.test.ts +513 -0
- package/src/tests/objects.improved.test.ts +385 -0
- package/src/tests/performance.test.ts +314 -0
- package/src/tests/processService.comprehensive.test.ts +933 -0
- package/src/tests/processService.test.ts +409 -0
- package/src/tests/restService.test.ts +218 -0
- package/src/tests/security.advanced.test.ts +464 -0
- package/src/tests/security.test.ts +233 -0
- package/src/tests/securityService.comprehensive.test.ts +582 -0
- package/src/tests/setup.ts +42 -0
- package/src/tests/simpleCoverage.test.ts +287 -0
- package/src/tests/stress.performance.test.ts +531 -0
- package/src/tests/subsetService.test.ts +350 -0
- package/src/tests/testConfig.ts +53 -0
- package/src/tests/testUtils.ts +94 -0
- package/src/tests/tm1Service.test.ts +361 -0
- package/src/tests/viewService.test.ts +324 -0
- package/src/utils/Utils.ts +395 -0
- package/tests/README.md +57 -0
- package/tests/connection/test-connection.ts +86 -0
- package/tests/edge-cases/edge-cases-test.ts +244 -0
- package/tests/integration/working-test.ts +193 -0
- package/tests/performance/performance-test.ts +133 -0
- package/tests/run-all-tests.sh +106 -0
- package/tests/security/security-test.ts +103 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,786 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comprehensive DimensionService Tests
|
|
3
|
+
* Target: Achieve 80%+ coverage for DimensionService (currently 45%)
|
|
4
|
+
* Testing all dimension operations including CRUD, hierarchy management, and service integration
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { DimensionService } from '../services/DimensionService';
|
|
8
|
+
import { RestService } from '../services/RestService';
|
|
9
|
+
import { HierarchyService } from '../services/HierarchyService';
|
|
10
|
+
import { SubsetService } from '../services/SubsetService';
|
|
11
|
+
import { Dimension } from '../objects/Dimension';
|
|
12
|
+
import { Hierarchy } from '../objects/Hierarchy';
|
|
13
|
+
import { TM1RestException } from '../exceptions/TM1Exception';
|
|
14
|
+
|
|
15
|
+
// Mock dependencies
|
|
16
|
+
jest.mock('../services/HierarchyService');
|
|
17
|
+
jest.mock('../services/SubsetService');
|
|
18
|
+
jest.mock('../objects/Dimension');
|
|
19
|
+
jest.mock('../objects/Hierarchy');
|
|
20
|
+
|
|
21
|
+
describe('DimensionService - Comprehensive Tests', () => {
|
|
22
|
+
let dimensionService: DimensionService;
|
|
23
|
+
let mockRestService: jest.Mocked<RestService>;
|
|
24
|
+
let mockHierarchyService: jest.Mocked<HierarchyService>;
|
|
25
|
+
let mockSubsetService: jest.Mocked<SubsetService>;
|
|
26
|
+
|
|
27
|
+
const mockResponse = (data: any) => ({
|
|
28
|
+
data: data,
|
|
29
|
+
status: 200,
|
|
30
|
+
statusText: 'OK',
|
|
31
|
+
headers: {},
|
|
32
|
+
config: { headers: {} }
|
|
33
|
+
} as any);
|
|
34
|
+
|
|
35
|
+
const mockDimension = {
|
|
36
|
+
name: 'TestDimension',
|
|
37
|
+
hierarchies: [
|
|
38
|
+
{ name: 'TestDimension', dimensionName: 'TestDimension' },
|
|
39
|
+
{ name: 'AltHierarchy', dimensionName: 'TestDimension' }
|
|
40
|
+
],
|
|
41
|
+
hierarchyNames: ['TestDimension', 'AltHierarchy'],
|
|
42
|
+
defaultHierarchy: { name: 'TestDimension', dimensionName: 'TestDimension' },
|
|
43
|
+
body: {
|
|
44
|
+
Name: 'TestDimension',
|
|
45
|
+
Hierarchies: [
|
|
46
|
+
{ Name: 'TestDimension' },
|
|
47
|
+
{ Name: 'AltHierarchy' }
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
addHierarchy: jest.fn(),
|
|
51
|
+
[Symbol.iterator]: function* () {
|
|
52
|
+
yield* this.hierarchies;
|
|
53
|
+
}
|
|
54
|
+
} as any;
|
|
55
|
+
|
|
56
|
+
const mockHierarchy = {
|
|
57
|
+
name: 'TestHierarchy',
|
|
58
|
+
dimensionName: 'TestDimension'
|
|
59
|
+
} as any;
|
|
60
|
+
|
|
61
|
+
beforeEach(() => {
|
|
62
|
+
mockRestService = {
|
|
63
|
+
get: jest.fn(),
|
|
64
|
+
post: jest.fn(),
|
|
65
|
+
patch: jest.fn(),
|
|
66
|
+
put: jest.fn(),
|
|
67
|
+
delete: jest.fn()
|
|
68
|
+
} as any;
|
|
69
|
+
|
|
70
|
+
// Mock the constructor-injected services
|
|
71
|
+
mockHierarchyService = {
|
|
72
|
+
getAllNames: jest.fn(),
|
|
73
|
+
exists: jest.fn(),
|
|
74
|
+
update: jest.fn(),
|
|
75
|
+
create: jest.fn(),
|
|
76
|
+
delete: jest.fn(),
|
|
77
|
+
updateElementAttributes: jest.fn()
|
|
78
|
+
} as any;
|
|
79
|
+
|
|
80
|
+
mockSubsetService = {} as any;
|
|
81
|
+
|
|
82
|
+
// Mock the service constructors to return our mocks
|
|
83
|
+
(HierarchyService as jest.MockedClass<typeof HierarchyService>).mockImplementation(() => mockHierarchyService);
|
|
84
|
+
(SubsetService as jest.MockedClass<typeof SubsetService>).mockImplementation(() => mockSubsetService);
|
|
85
|
+
|
|
86
|
+
dimensionService = new DimensionService(mockRestService);
|
|
87
|
+
|
|
88
|
+
// Mock Dimension.fromJSON and fromDict
|
|
89
|
+
(Dimension as any).fromJSON = jest.fn().mockReturnValue(mockDimension);
|
|
90
|
+
(Dimension as any).fromDict = jest.fn().mockReturnValue(mockDimension);
|
|
91
|
+
|
|
92
|
+
// Note: formatUrl and caseAndSpaceInsensitiveEquals are inherited from ObjectService
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
afterEach(() => {
|
|
96
|
+
jest.clearAllMocks();
|
|
97
|
+
jest.restoreAllMocks();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('Constructor and Initialization', () => {
|
|
101
|
+
test('should initialize DimensionService with sub-services', () => {
|
|
102
|
+
expect(dimensionService).toBeDefined();
|
|
103
|
+
expect(dimensionService).toBeInstanceOf(DimensionService);
|
|
104
|
+
expect(HierarchyService).toHaveBeenCalledWith(mockRestService);
|
|
105
|
+
expect(SubsetService).toHaveBeenCalledWith(mockRestService);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('should extend ObjectService', () => {
|
|
109
|
+
expect(dimensionService).toBeInstanceOf(DimensionService);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('Dimension CRUD Operations', () => {
|
|
114
|
+
test('should create dimension successfully', async () => {
|
|
115
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(false);
|
|
116
|
+
mockRestService.post.mockResolvedValue(mockResponse({}));
|
|
117
|
+
mockHierarchyService.updateElementAttributes.mockResolvedValue();
|
|
118
|
+
|
|
119
|
+
const result = await dimensionService.create(mockDimension);
|
|
120
|
+
|
|
121
|
+
expect(dimensionService.exists).toHaveBeenCalledWith('TestDimension');
|
|
122
|
+
expect(mockRestService.post).toHaveBeenCalledWith('/Dimensions', mockDimension.body);
|
|
123
|
+
expect(mockHierarchyService.updateElementAttributes).toHaveBeenCalledTimes(2); // For non-Leaves hierarchies
|
|
124
|
+
expect(result).toBeDefined();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('should throw error when creating existing dimension', async () => {
|
|
128
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(true);
|
|
129
|
+
|
|
130
|
+
await expect(dimensionService.create(mockDimension))
|
|
131
|
+
.rejects.toThrow("Dimension 'TestDimension' already exists");
|
|
132
|
+
|
|
133
|
+
expect(mockRestService.post).not.toHaveBeenCalled();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('should handle creation failure and cleanup', async () => {
|
|
137
|
+
jest.spyOn(dimensionService, 'exists')
|
|
138
|
+
.mockResolvedValueOnce(false) // Initial check
|
|
139
|
+
.mockResolvedValueOnce(true); // Check during cleanup
|
|
140
|
+
jest.spyOn(dimensionService, 'delete').mockResolvedValue(mockResponse({}));
|
|
141
|
+
|
|
142
|
+
const error = new Error('Creation failed');
|
|
143
|
+
mockRestService.post.mockRejectedValue(error);
|
|
144
|
+
|
|
145
|
+
await expect(dimensionService.create(mockDimension)).rejects.toThrow('Creation failed');
|
|
146
|
+
|
|
147
|
+
expect(dimensionService.delete).toHaveBeenCalledWith('TestDimension');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('should skip Leaves hierarchy during creation', async () => {
|
|
151
|
+
const dimensionWithLeaves = {
|
|
152
|
+
...mockDimension,
|
|
153
|
+
hierarchies: [
|
|
154
|
+
{ name: 'TestDimension', dimensionName: 'TestDimension' },
|
|
155
|
+
{ name: 'Leaves', dimensionName: 'TestDimension' },
|
|
156
|
+
{ name: 'AltHierarchy', dimensionName: 'TestDimension' }
|
|
157
|
+
],
|
|
158
|
+
[Symbol.iterator]: function* () {
|
|
159
|
+
yield* this.hierarchies;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(false);
|
|
164
|
+
mockRestService.post.mockResolvedValue(mockResponse({}));
|
|
165
|
+
mockHierarchyService.updateElementAttributes.mockResolvedValue();
|
|
166
|
+
|
|
167
|
+
await dimensionService.create(dimensionWithLeaves);
|
|
168
|
+
|
|
169
|
+
// Should skip 'Leaves' hierarchy, so only 2 calls instead of 3
|
|
170
|
+
expect(mockHierarchyService.updateElementAttributes).toHaveBeenCalledTimes(2);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('should get dimension by name', async () => {
|
|
174
|
+
const dimensionData = {
|
|
175
|
+
Name: 'TestDimension',
|
|
176
|
+
Hierarchies: [{ Name: 'TestDimension' }]
|
|
177
|
+
};
|
|
178
|
+
mockRestService.get.mockResolvedValue(mockResponse(dimensionData));
|
|
179
|
+
|
|
180
|
+
const result = await dimensionService.get('TestDimension');
|
|
181
|
+
|
|
182
|
+
expect(mockRestService.get).toHaveBeenCalledWith("/Dimensions('TestDimension')?$expand=Hierarchies($expand=*)");
|
|
183
|
+
expect(Dimension.fromJSON).toHaveBeenCalledWith(JSON.stringify(dimensionData));
|
|
184
|
+
expect(result).toEqual(mockDimension);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test('should update dimension with existing hierarchies', async () => {
|
|
188
|
+
mockHierarchyService.getAllNames.mockResolvedValue(['TestDimension', 'OldHierarchy', 'AltHierarchy']);
|
|
189
|
+
mockHierarchyService.exists.mockResolvedValue(true);
|
|
190
|
+
mockHierarchyService.update.mockResolvedValue();
|
|
191
|
+
mockHierarchyService.delete.mockResolvedValue(mockResponse({}));
|
|
192
|
+
|
|
193
|
+
await dimensionService.update(mockDimension);
|
|
194
|
+
|
|
195
|
+
expect(mockHierarchyService.getAllNames).toHaveBeenCalledWith('TestDimension');
|
|
196
|
+
expect(mockHierarchyService.update).toHaveBeenCalledTimes(2); // For TestDimension and AltHierarchy
|
|
197
|
+
expect(mockHierarchyService.delete).toHaveBeenCalledWith('TestDimension', 'OldHierarchy'); // Remove old hierarchy
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('should update dimension and create new hierarchies', async () => {
|
|
201
|
+
mockHierarchyService.getAllNames.mockResolvedValue(['TestDimension']);
|
|
202
|
+
mockHierarchyService.exists
|
|
203
|
+
.mockResolvedValueOnce(true) // TestDimension exists
|
|
204
|
+
.mockResolvedValueOnce(false); // AltHierarchy doesn't exist
|
|
205
|
+
mockHierarchyService.update.mockResolvedValue();
|
|
206
|
+
mockHierarchyService.create.mockResolvedValue(mockResponse({}));
|
|
207
|
+
|
|
208
|
+
await dimensionService.update(mockDimension);
|
|
209
|
+
|
|
210
|
+
expect(mockHierarchyService.update).toHaveBeenCalledTimes(1); // For existing TestDimension
|
|
211
|
+
expect(mockHierarchyService.create).toHaveBeenCalledTimes(1); // For new AltHierarchy
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test('should update dimension with keepExistingAttributes flag', async () => {
|
|
215
|
+
mockHierarchyService.getAllNames.mockResolvedValue(['TestDimension']);
|
|
216
|
+
mockHierarchyService.exists.mockResolvedValue(true);
|
|
217
|
+
mockHierarchyService.update.mockResolvedValue();
|
|
218
|
+
|
|
219
|
+
await dimensionService.update(mockDimension, true);
|
|
220
|
+
|
|
221
|
+
expect(mockHierarchyService.update).toHaveBeenCalledWith(
|
|
222
|
+
mockDimension.hierarchies[0],
|
|
223
|
+
true // keepExistingAttributes
|
|
224
|
+
);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test('should skip Leaves hierarchy during update', async () => {
|
|
228
|
+
const dimensionWithLeaves = {
|
|
229
|
+
...mockDimension,
|
|
230
|
+
hierarchies: [
|
|
231
|
+
{ name: 'TestDimension', dimensionName: 'TestDimension' },
|
|
232
|
+
{ name: 'Leaves', dimensionName: 'TestDimension' }
|
|
233
|
+
],
|
|
234
|
+
hierarchyNames: ['TestDimension', 'Leaves'],
|
|
235
|
+
[Symbol.iterator]: function* () {
|
|
236
|
+
yield* this.hierarchies;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
mockHierarchyService.getAllNames.mockResolvedValue(['TestDimension', 'Leaves']);
|
|
241
|
+
mockHierarchyService.exists.mockResolvedValue(true);
|
|
242
|
+
mockHierarchyService.update.mockResolvedValue();
|
|
243
|
+
|
|
244
|
+
await dimensionService.update(dimensionWithLeaves);
|
|
245
|
+
|
|
246
|
+
// Should only update TestDimension, skip Leaves
|
|
247
|
+
expect(mockHierarchyService.update).toHaveBeenCalledTimes(1);
|
|
248
|
+
expect(mockHierarchyService.delete).not.toHaveBeenCalledWith('TestDimension', 'Leaves');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test('should delete dimension', async () => {
|
|
252
|
+
mockRestService.delete.mockResolvedValue(mockResponse({}));
|
|
253
|
+
|
|
254
|
+
const result = await dimensionService.delete('TestDimension');
|
|
255
|
+
|
|
256
|
+
expect(mockRestService.delete).toHaveBeenCalledWith("/Dimensions('TestDimension')");
|
|
257
|
+
expect(result).toBeDefined();
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test('should check if dimension exists', async () => {
|
|
261
|
+
mockRestService.get.mockResolvedValue(mockResponse({}));
|
|
262
|
+
|
|
263
|
+
const result = await dimensionService.exists('TestDimension');
|
|
264
|
+
|
|
265
|
+
expect(result).toBe(true);
|
|
266
|
+
expect(mockRestService.get).toHaveBeenCalledWith("/Dimensions('TestDimension')");
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test('should return false when dimension does not exist', async () => {
|
|
270
|
+
const error = new TM1RestException('Not found', 404);
|
|
271
|
+
error.statusCode = 404; // Set the statusCode property that DimensionService checks
|
|
272
|
+
mockRestService.get.mockRejectedValue(error);
|
|
273
|
+
|
|
274
|
+
const result = await dimensionService.exists('NonExistent');
|
|
275
|
+
|
|
276
|
+
expect(result).toBe(false);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test('should throw error for non-404 errors in exists check', async () => {
|
|
280
|
+
const error = new TM1RestException('Server error', 500);
|
|
281
|
+
mockRestService.get.mockRejectedValue(error);
|
|
282
|
+
|
|
283
|
+
await expect(dimensionService.exists('TestDimension')).rejects.toThrow('Server error');
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
describe('Dimension Retrieval Operations', () => {
|
|
288
|
+
test('should get all dimension names', async () => {
|
|
289
|
+
const dimensionsData = {
|
|
290
|
+
value: [
|
|
291
|
+
{ Name: 'Dimension1' },
|
|
292
|
+
{ Name: 'Dimension2' },
|
|
293
|
+
{ Name: '}Stats' }
|
|
294
|
+
]
|
|
295
|
+
};
|
|
296
|
+
mockRestService.get.mockResolvedValue(mockResponse(dimensionsData));
|
|
297
|
+
|
|
298
|
+
const result = await dimensionService.getAllNames();
|
|
299
|
+
|
|
300
|
+
expect(result).toEqual(['Dimension1', 'Dimension2', '}Stats']);
|
|
301
|
+
expect(mockRestService.get).toHaveBeenCalledWith('/Dimensions?$select=Name');
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test('should get all dimension names excluding control dimensions', async () => {
|
|
305
|
+
const dimensionsData = {
|
|
306
|
+
value: [
|
|
307
|
+
{ Name: 'Dimension1' },
|
|
308
|
+
{ Name: 'Dimension2' }
|
|
309
|
+
]
|
|
310
|
+
};
|
|
311
|
+
mockRestService.get.mockResolvedValue(mockResponse(dimensionsData));
|
|
312
|
+
|
|
313
|
+
const result = await dimensionService.getAllNames(true);
|
|
314
|
+
|
|
315
|
+
expect(result).toEqual(['Dimension1', 'Dimension2']);
|
|
316
|
+
expect(mockRestService.get).toHaveBeenCalledWith("/Dimensions?$select=Name&$filter=not startswith(Name,'}')");
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
test('should get all dimensions', async () => {
|
|
320
|
+
const dimensionsData = {
|
|
321
|
+
value: [
|
|
322
|
+
{ Name: 'Dimension1', Hierarchies: [{ Name: 'Dimension1' }] },
|
|
323
|
+
{ Name: 'Dimension2', Hierarchies: [{ Name: 'Dimension2' }] }
|
|
324
|
+
]
|
|
325
|
+
};
|
|
326
|
+
mockRestService.get.mockResolvedValue(mockResponse(dimensionsData));
|
|
327
|
+
|
|
328
|
+
const result = await dimensionService.getAll();
|
|
329
|
+
|
|
330
|
+
expect(result).toHaveLength(2);
|
|
331
|
+
expect(Dimension.fromDict).toHaveBeenCalledTimes(2);
|
|
332
|
+
expect(mockRestService.get).toHaveBeenCalledWith('/Dimensions?$expand=Hierarchies($expand=*)');
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test('should get all dimensions excluding control dimensions', async () => {
|
|
336
|
+
const dimensionsData = {
|
|
337
|
+
value: [
|
|
338
|
+
{ Name: 'Dimension1', Hierarchies: [{ Name: 'Dimension1' }] }
|
|
339
|
+
]
|
|
340
|
+
};
|
|
341
|
+
mockRestService.get.mockResolvedValue(mockResponse(dimensionsData));
|
|
342
|
+
|
|
343
|
+
const result = await dimensionService.getAll(true);
|
|
344
|
+
|
|
345
|
+
expect(result).toHaveLength(1);
|
|
346
|
+
expect(mockRestService.get).toHaveBeenCalledWith("/Dimensions?$expand=Hierarchies($expand=*)&$filter=not startswith(Name,'}')");
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
test('should get dimension names from cube', async () => {
|
|
350
|
+
const cubeData = {
|
|
351
|
+
Dimensions: [
|
|
352
|
+
{ Name: 'Time' },
|
|
353
|
+
{ Name: 'Account' },
|
|
354
|
+
{ Name: 'Version' }
|
|
355
|
+
]
|
|
356
|
+
};
|
|
357
|
+
mockRestService.get.mockResolvedValue(mockResponse(cubeData));
|
|
358
|
+
|
|
359
|
+
const result = await dimensionService.getDimensionNames('SalesCube');
|
|
360
|
+
|
|
361
|
+
expect(result).toEqual(['Time', 'Account', 'Version']);
|
|
362
|
+
expect(mockRestService.get).toHaveBeenCalledWith("/Cubes('SalesCube')?$select=Dimensions");
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
describe('Dimension Cloning Operations', () => {
|
|
367
|
+
test('should clone dimension with all hierarchies', async () => {
|
|
368
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(false);
|
|
369
|
+
jest.spyOn(dimensionService, 'get').mockResolvedValue(mockDimension);
|
|
370
|
+
jest.spyOn(dimensionService, 'create').mockResolvedValue(mockResponse({}));
|
|
371
|
+
|
|
372
|
+
const result = await dimensionService.clone('SourceDim', 'TargetDim', true);
|
|
373
|
+
|
|
374
|
+
expect(dimensionService.exists).toHaveBeenCalledWith('TargetDim');
|
|
375
|
+
expect(dimensionService.get).toHaveBeenCalledWith('SourceDim');
|
|
376
|
+
expect(dimensionService.create).toHaveBeenCalled();
|
|
377
|
+
expect(result).toBeDefined();
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
test('should clone dimension without additional hierarchies', async () => {
|
|
381
|
+
const sourceDimensionWithMultipleHierarchies = {
|
|
382
|
+
...mockDimension,
|
|
383
|
+
hierarchies: [
|
|
384
|
+
{ name: 'SourceDim', dimensionName: 'SourceDim' },
|
|
385
|
+
{ name: 'AltHierarchy', dimensionName: 'SourceDim' },
|
|
386
|
+
{ name: 'AnotherHierarchy', dimensionName: 'SourceDim' }
|
|
387
|
+
],
|
|
388
|
+
defaultHierarchy: { name: 'SourceDim', dimensionName: 'SourceDim' },
|
|
389
|
+
addHierarchy: jest.fn()
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(false);
|
|
393
|
+
jest.spyOn(dimensionService, 'get').mockResolvedValue(sourceDimensionWithMultipleHierarchies);
|
|
394
|
+
jest.spyOn(dimensionService, 'create').mockResolvedValue(mockResponse({}));
|
|
395
|
+
|
|
396
|
+
await dimensionService.clone('SourceDim', 'TargetDim', false);
|
|
397
|
+
|
|
398
|
+
expect(sourceDimensionWithMultipleHierarchies.hierarchies.length).toBe(0);
|
|
399
|
+
expect(sourceDimensionWithMultipleHierarchies.addHierarchy).toHaveBeenCalledWith(
|
|
400
|
+
expect.objectContaining({ name: 'TargetDim' })
|
|
401
|
+
);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
test('should rename hierarchies to match target dimension name', async () => {
|
|
405
|
+
const sourceDimension = {
|
|
406
|
+
name: 'SourceDim',
|
|
407
|
+
hierarchies: [
|
|
408
|
+
{ name: 'SourceDim', dimensionName: 'SourceDim' }, // Should be renamed
|
|
409
|
+
{ name: 'CustomHierarchy', dimensionName: 'SourceDim' } // Should not be renamed
|
|
410
|
+
],
|
|
411
|
+
hierarchyNames: ['SourceDim', 'CustomHierarchy'],
|
|
412
|
+
defaultHierarchy: { name: 'SourceDim', dimensionName: 'SourceDim' },
|
|
413
|
+
body: {},
|
|
414
|
+
addHierarchy: jest.fn(),
|
|
415
|
+
[Symbol.iterator]: function* () {
|
|
416
|
+
yield* this.hierarchies;
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(false);
|
|
421
|
+
jest.spyOn(dimensionService, 'get').mockResolvedValue(sourceDimension as any);
|
|
422
|
+
jest.spyOn(dimensionService, 'create').mockResolvedValue(mockResponse({}));
|
|
423
|
+
|
|
424
|
+
await dimensionService.clone('SourceDim', 'TargetDim', true);
|
|
425
|
+
|
|
426
|
+
expect(sourceDimension.hierarchies[0].name).toBe('TargetDim'); // Renamed
|
|
427
|
+
expect(sourceDimension.hierarchies[1].name).toBe('CustomHierarchy'); // Not renamed
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
test('should throw error when cloning to existing dimension', async () => {
|
|
431
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(true);
|
|
432
|
+
|
|
433
|
+
await expect(dimensionService.clone('SourceDim', 'ExistingDim'))
|
|
434
|
+
.rejects.toThrow("Dimension 'ExistingDim' already exists");
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
test('should handle cloning when default hierarchy is null', async () => {
|
|
438
|
+
const sourceDimensionNoDefault = {
|
|
439
|
+
...mockDimension,
|
|
440
|
+
defaultHierarchy: null
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(false);
|
|
444
|
+
jest.spyOn(dimensionService, 'get').mockResolvedValue(sourceDimensionNoDefault);
|
|
445
|
+
jest.spyOn(dimensionService, 'create').mockResolvedValue(mockResponse({}));
|
|
446
|
+
|
|
447
|
+
await dimensionService.clone('SourceDim', 'TargetDim', false);
|
|
448
|
+
|
|
449
|
+
expect(dimensionService.create).toHaveBeenCalled();
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
describe('Dimension Statistics Operations', () => {
|
|
454
|
+
test('should get elements count for dimension', async () => {
|
|
455
|
+
mockRestService.get.mockResolvedValue(mockResponse('150'));
|
|
456
|
+
|
|
457
|
+
const result = await dimensionService.getElementsCount('TestDimension');
|
|
458
|
+
|
|
459
|
+
expect(result).toBe(150);
|
|
460
|
+
expect(mockRestService.get).toHaveBeenCalledWith("/Dimensions('TestDimension')/Hierarchies('TestDimension')/Elements/$count");
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
test('should get elements count for specific hierarchy', async () => {
|
|
464
|
+
mockRestService.get.mockResolvedValue(mockResponse('75'));
|
|
465
|
+
|
|
466
|
+
const result = await dimensionService.getElementsCount('TestDimension', 'CustomHierarchy');
|
|
467
|
+
|
|
468
|
+
expect(result).toBe(75);
|
|
469
|
+
expect(mockRestService.get).toHaveBeenCalledWith("/Dimensions('TestDimension')/Hierarchies('CustomHierarchy')/Elements/$count");
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
test('should get hierarchies count for dimension', async () => {
|
|
473
|
+
mockRestService.get.mockResolvedValue(mockResponse('3'));
|
|
474
|
+
|
|
475
|
+
const result = await dimensionService.getHierarchiesCount('TestDimension');
|
|
476
|
+
|
|
477
|
+
expect(result).toBe(3);
|
|
478
|
+
expect(mockRestService.get).toHaveBeenCalledWith("/Dimensions('TestDimension')/Hierarchies/$count");
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test('should handle non-numeric count responses', async () => {
|
|
482
|
+
mockRestService.get.mockResolvedValue(mockResponse('invalid'));
|
|
483
|
+
|
|
484
|
+
const result = await dimensionService.getElementsCount('TestDimension');
|
|
485
|
+
|
|
486
|
+
expect(isNaN(result)).toBe(true);
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
describe('Error Handling', () => {
|
|
491
|
+
test('should handle dimension retrieval errors', async () => {
|
|
492
|
+
const error = new Error('Dimension not found');
|
|
493
|
+
mockRestService.get.mockRejectedValue(error);
|
|
494
|
+
|
|
495
|
+
await expect(dimensionService.get('NonExistent')).rejects.toThrow('Dimension not found');
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
test('should handle dimension creation errors', async () => {
|
|
499
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(false);
|
|
500
|
+
const error = new Error('Creation failed');
|
|
501
|
+
mockRestService.post.mockRejectedValue(error);
|
|
502
|
+
|
|
503
|
+
await expect(dimensionService.create(mockDimension)).rejects.toThrow('Creation failed');
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
test('should handle dimension deletion errors', async () => {
|
|
507
|
+
const error = new Error('Deletion failed');
|
|
508
|
+
mockRestService.delete.mockRejectedValue(error);
|
|
509
|
+
|
|
510
|
+
await expect(dimensionService.delete('TestDimension')).rejects.toThrow('Deletion failed');
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
test('should handle hierarchy service errors during creation', async () => {
|
|
514
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(false);
|
|
515
|
+
mockRestService.post.mockResolvedValue(mockResponse({}));
|
|
516
|
+
mockHierarchyService.updateElementAttributes.mockRejectedValue(new Error('Hierarchy error'));
|
|
517
|
+
|
|
518
|
+
await expect(dimensionService.create(mockDimension)).rejects.toThrow('Hierarchy error');
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
test('should handle hierarchy service errors during update', async () => {
|
|
522
|
+
mockHierarchyService.getAllNames.mockRejectedValue(new Error('Hierarchy access failed'));
|
|
523
|
+
|
|
524
|
+
await expect(dimensionService.update(mockDimension)).rejects.toThrow('Hierarchy access failed');
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
test('should handle cube dimension retrieval errors', async () => {
|
|
528
|
+
const error = new Error('Cube not found');
|
|
529
|
+
mockRestService.get.mockRejectedValue(error);
|
|
530
|
+
|
|
531
|
+
await expect(dimensionService.getDimensionNames('NonExistentCube')).rejects.toThrow('Cube not found');
|
|
532
|
+
});
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
describe('Edge Cases and Special Scenarios', () => {
|
|
536
|
+
test('should handle empty dimension lists', async () => {
|
|
537
|
+
mockRestService.get.mockResolvedValue(mockResponse({ value: [] }));
|
|
538
|
+
|
|
539
|
+
const names = await dimensionService.getAllNames();
|
|
540
|
+
const dimensions = await dimensionService.getAll();
|
|
541
|
+
|
|
542
|
+
expect(names).toEqual([]);
|
|
543
|
+
expect(dimensions).toEqual([]);
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
test('should handle special characters in dimension names', async () => {
|
|
547
|
+
const specialName = "Dimension's & \"Special\" Name";
|
|
548
|
+
mockRestService.get.mockResolvedValue(mockResponse({}));
|
|
549
|
+
|
|
550
|
+
await dimensionService.exists(specialName);
|
|
551
|
+
|
|
552
|
+
// The formatUrl method encodes special characters
|
|
553
|
+
expect(mockRestService.get).toHaveBeenCalledWith(
|
|
554
|
+
expect.stringContaining("Dimension's%20%26%20%22Special%22%20Name")
|
|
555
|
+
);
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
test('should handle dimension with no hierarchies', async () => {
|
|
559
|
+
const emptyDimension = {
|
|
560
|
+
name: 'EmptyDimension',
|
|
561
|
+
hierarchies: [],
|
|
562
|
+
hierarchyNames: [],
|
|
563
|
+
body: { Name: 'EmptyDimension', Hierarchies: [] },
|
|
564
|
+
[Symbol.iterator]: function* () {
|
|
565
|
+
yield* this.hierarchies;
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(false);
|
|
570
|
+
mockRestService.post.mockResolvedValue(mockResponse({}));
|
|
571
|
+
|
|
572
|
+
await dimensionService.create(emptyDimension as any);
|
|
573
|
+
|
|
574
|
+
expect(mockHierarchyService.updateElementAttributes).not.toHaveBeenCalled();
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
test('should handle dimension update with no hierarchy changes', async () => {
|
|
578
|
+
mockHierarchyService.getAllNames.mockResolvedValue(['TestDimension', 'AltHierarchy']);
|
|
579
|
+
mockHierarchyService.exists.mockResolvedValue(true);
|
|
580
|
+
mockHierarchyService.update.mockResolvedValue();
|
|
581
|
+
|
|
582
|
+
await dimensionService.update(mockDimension);
|
|
583
|
+
|
|
584
|
+
expect(mockHierarchyService.delete).not.toHaveBeenCalled(); // No hierarchies to remove
|
|
585
|
+
expect(mockHierarchyService.create).not.toHaveBeenCalled(); // No new hierarchies
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
test('should handle large dimension lists efficiently', async () => {
|
|
589
|
+
const largeDimensionList = Array.from({ length: 1000 }, (_, i) => ({
|
|
590
|
+
Name: `Dimension${i}`
|
|
591
|
+
}));
|
|
592
|
+
|
|
593
|
+
mockRestService.get.mockResolvedValue(mockResponse({ value: largeDimensionList }));
|
|
594
|
+
|
|
595
|
+
const result = await dimensionService.getAllNames();
|
|
596
|
+
|
|
597
|
+
expect(result).toHaveLength(1000);
|
|
598
|
+
expect(result[0]).toBe('Dimension0');
|
|
599
|
+
expect(result[999]).toBe('Dimension999');
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
test('should handle cube with no dimensions', async () => {
|
|
603
|
+
mockRestService.get.mockResolvedValue(mockResponse({ Dimensions: [] }));
|
|
604
|
+
|
|
605
|
+
const result = await dimensionService.getDimensionNames('EmptyCube');
|
|
606
|
+
|
|
607
|
+
expect(result).toEqual([]);
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
test('should handle null/undefined values gracefully', async () => {
|
|
611
|
+
const malformedResponse = {
|
|
612
|
+
value: [
|
|
613
|
+
{ Name: 'ValidDimension' },
|
|
614
|
+
{ Name: null },
|
|
615
|
+
{ Name: undefined },
|
|
616
|
+
{} // No Name property
|
|
617
|
+
]
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
mockRestService.get.mockResolvedValue(mockResponse(malformedResponse));
|
|
621
|
+
|
|
622
|
+
const result = await dimensionService.getAllNames();
|
|
623
|
+
|
|
624
|
+
// Should handle malformed data gracefully
|
|
625
|
+
expect(result).toContain('ValidDimension');
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
describe('Service Integration', () => {
|
|
630
|
+
test('should integrate with HierarchyService for dimension operations', async () => {
|
|
631
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(false);
|
|
632
|
+
mockRestService.post.mockResolvedValue(mockResponse({}));
|
|
633
|
+
mockHierarchyService.updateElementAttributes.mockResolvedValue();
|
|
634
|
+
|
|
635
|
+
await dimensionService.create(mockDimension);
|
|
636
|
+
|
|
637
|
+
expect(mockHierarchyService.updateElementAttributes).toHaveBeenCalledWith(
|
|
638
|
+
mockDimension.hierarchies[0]
|
|
639
|
+
);
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
test('should coordinate hierarchy updates during dimension update', async () => {
|
|
643
|
+
// Create a fresh dimension object for this test
|
|
644
|
+
const testDimension = {
|
|
645
|
+
name: 'TestDimension',
|
|
646
|
+
hierarchies: [
|
|
647
|
+
{ name: 'TestDimension', dimensionName: 'TestDimension' },
|
|
648
|
+
{ name: 'AltHierarchy', dimensionName: 'TestDimension' }
|
|
649
|
+
],
|
|
650
|
+
hierarchyNames: ['TestDimension', 'AltHierarchy'],
|
|
651
|
+
body: {},
|
|
652
|
+
[Symbol.iterator]: function* () {
|
|
653
|
+
yield* this.hierarchies;
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
// Clear any previous calls first
|
|
658
|
+
mockHierarchyService.getAllNames.mockClear();
|
|
659
|
+
mockHierarchyService.exists.mockClear();
|
|
660
|
+
mockHierarchyService.create.mockClear();
|
|
661
|
+
mockHierarchyService.delete.mockClear();
|
|
662
|
+
|
|
663
|
+
mockHierarchyService.getAllNames.mockResolvedValue(['OldHierarchy']);
|
|
664
|
+
mockHierarchyService.exists.mockResolvedValue(false);
|
|
665
|
+
mockHierarchyService.create.mockResolvedValue(mockResponse({}));
|
|
666
|
+
mockHierarchyService.delete.mockResolvedValue(mockResponse({}));
|
|
667
|
+
|
|
668
|
+
await dimensionService.update(testDimension as any);
|
|
669
|
+
|
|
670
|
+
expect(mockHierarchyService.create).toHaveBeenCalledTimes(2); // Create new hierarchies
|
|
671
|
+
expect(mockHierarchyService.delete).toHaveBeenLastCalledWith('TestDimension', 'OldHierarchy'); // Remove old
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
test('should handle hierarchy service initialization', () => {
|
|
675
|
+
const newService = new DimensionService(mockRestService);
|
|
676
|
+
|
|
677
|
+
expect(HierarchyService).toHaveBeenCalledWith(mockRestService);
|
|
678
|
+
expect(SubsetService).toHaveBeenCalledWith(mockRestService);
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
test('should maintain service state across operations', async () => {
|
|
682
|
+
// Test that the service maintains its internal state properly
|
|
683
|
+
jest.spyOn(dimensionService, 'exists').mockResolvedValue(true);
|
|
684
|
+
|
|
685
|
+
const exists1 = await dimensionService.exists('Dimension1');
|
|
686
|
+
const exists2 = await dimensionService.exists('Dimension2');
|
|
687
|
+
|
|
688
|
+
expect(exists1).toBe(true);
|
|
689
|
+
expect(exists2).toBe(true);
|
|
690
|
+
expect(dimensionService.exists).toHaveBeenCalledTimes(2);
|
|
691
|
+
});
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
describe('Complex Workflow Scenarios', () => {
|
|
695
|
+
test('should support complete dimension lifecycle', async () => {
|
|
696
|
+
// Create, update, clone, delete workflow
|
|
697
|
+
jest.spyOn(dimensionService, 'exists')
|
|
698
|
+
.mockResolvedValueOnce(false) // Create check
|
|
699
|
+
.mockResolvedValueOnce(false) // Clone target check
|
|
700
|
+
.mockResolvedValue(true); // Other operations
|
|
701
|
+
|
|
702
|
+
jest.spyOn(dimensionService, 'get').mockResolvedValue(mockDimension);
|
|
703
|
+
jest.spyOn(dimensionService, 'create').mockResolvedValue(mockResponse({}));
|
|
704
|
+
mockRestService.post.mockResolvedValue(mockResponse({}));
|
|
705
|
+
mockRestService.delete.mockResolvedValue(mockResponse({}));
|
|
706
|
+
mockHierarchyService.updateElementAttributes.mockResolvedValue();
|
|
707
|
+
mockHierarchyService.getAllNames.mockResolvedValue(['TestDimension']);
|
|
708
|
+
mockHierarchyService.exists.mockResolvedValue(true);
|
|
709
|
+
mockHierarchyService.update.mockResolvedValue();
|
|
710
|
+
|
|
711
|
+
// Full lifecycle
|
|
712
|
+
await dimensionService.create(mockDimension);
|
|
713
|
+
await dimensionService.update(mockDimension);
|
|
714
|
+
await dimensionService.clone('TestDimension', 'ClonedDimension');
|
|
715
|
+
await dimensionService.delete('TestDimension');
|
|
716
|
+
|
|
717
|
+
expect(dimensionService.create).toHaveBeenCalledTimes(2); // Original + clone
|
|
718
|
+
expect(mockHierarchyService.update).toHaveBeenCalled();
|
|
719
|
+
expect(mockRestService.delete).toHaveBeenCalled();
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
test('should handle complex hierarchy management scenario', async () => {
|
|
723
|
+
const complexDimension = {
|
|
724
|
+
name: 'ComplexDim',
|
|
725
|
+
hierarchies: [
|
|
726
|
+
{ name: 'ComplexDim', dimensionName: 'ComplexDim' },
|
|
727
|
+
{ name: 'NewHierarchy', dimensionName: 'ComplexDim' },
|
|
728
|
+
{ name: 'Leaves', dimensionName: 'ComplexDim' } // Should be skipped
|
|
729
|
+
],
|
|
730
|
+
hierarchyNames: ['ComplexDim', 'NewHierarchy', 'Leaves'],
|
|
731
|
+
body: {},
|
|
732
|
+
[Symbol.iterator]: function* () {
|
|
733
|
+
yield* this.hierarchies;
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
mockHierarchyService.getAllNames.mockResolvedValue(['ComplexDim', 'OldHierarchy', 'Leaves']);
|
|
738
|
+
mockHierarchyService.exists
|
|
739
|
+
.mockResolvedValueOnce(true) // ComplexDim exists
|
|
740
|
+
.mockResolvedValueOnce(false); // NewHierarchy doesn't exist
|
|
741
|
+
mockHierarchyService.update.mockResolvedValue();
|
|
742
|
+
mockHierarchyService.create.mockResolvedValue(mockResponse({}));
|
|
743
|
+
mockHierarchyService.delete.mockResolvedValue(mockResponse({}));
|
|
744
|
+
|
|
745
|
+
await dimensionService.update(complexDimension as any);
|
|
746
|
+
|
|
747
|
+
expect(mockHierarchyService.update).toHaveBeenCalledTimes(1); // ComplexDim updated
|
|
748
|
+
expect(mockHierarchyService.create).toHaveBeenCalledTimes(1); // NewHierarchy created
|
|
749
|
+
expect(mockHierarchyService.delete).toHaveBeenCalledWith('ComplexDim', 'OldHierarchy'); // Remove old
|
|
750
|
+
expect(mockHierarchyService.delete).not.toHaveBeenCalledWith('ComplexDim', 'Leaves'); // Skip Leaves
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
test('should handle error recovery during complex operations', async () => {
|
|
754
|
+
// Create a fresh dimension object for this test
|
|
755
|
+
const testDimension = {
|
|
756
|
+
name: 'TestDimension',
|
|
757
|
+
hierarchies: [
|
|
758
|
+
{ name: 'TestDimension', dimensionName: 'TestDimension' }
|
|
759
|
+
],
|
|
760
|
+
hierarchyNames: ['TestDimension'],
|
|
761
|
+
body: {},
|
|
762
|
+
[Symbol.iterator]: function* () {
|
|
763
|
+
yield* this.hierarchies;
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
// Create fresh spies for this test to avoid interference
|
|
768
|
+
const existsSpy = jest.spyOn(dimensionService, 'exists')
|
|
769
|
+
.mockResolvedValueOnce(false) // Initial check passes
|
|
770
|
+
.mockResolvedValueOnce(true); // Cleanup check - dimension was created
|
|
771
|
+
|
|
772
|
+
const deleteSpy = jest.spyOn(dimensionService, 'delete').mockResolvedValue(mockResponse({}));
|
|
773
|
+
|
|
774
|
+
mockRestService.post.mockClear().mockResolvedValue(mockResponse({})); // Creation succeeds
|
|
775
|
+
mockHierarchyService.updateElementAttributes.mockClear().mockRejectedValue(new Error('Hierarchy update failed')); // But hierarchy update fails
|
|
776
|
+
|
|
777
|
+
await expect(dimensionService.create(testDimension as any)).rejects.toThrow('Hierarchy update failed');
|
|
778
|
+
|
|
779
|
+
expect(deleteSpy).toHaveBeenLastCalledWith('TestDimension'); // Cleanup performed
|
|
780
|
+
|
|
781
|
+
// Clean up spies
|
|
782
|
+
existsSpy.mockRestore();
|
|
783
|
+
deleteSpy.mockRestore();
|
|
784
|
+
});
|
|
785
|
+
});
|
|
786
|
+
});
|