@thinkwise/testwise 0.0.2-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/.ci/azure-pipelines.yaml +80 -0
  2. package/.eslintcache +1 -0
  3. package/.gitattributes +3 -0
  4. package/.gitconfig +2 -0
  5. package/.vscode/settings.json +18 -0
  6. package/Testwise.ts +22 -0
  7. package/components/BaseComponent.ts +95 -0
  8. package/components/BaseComponentObjects.ts +10 -0
  9. package/components/IComponentObjects.ts +5 -0
  10. package/components/Splitter.ts +11 -0
  11. package/components/TSFComponent.ts +8 -0
  12. package/components/actionbar/Actionbar.ts +57 -0
  13. package/components/actionbar/ActionbarObjects.ts +67 -0
  14. package/components/export/ExportComponent.ts +70 -0
  15. package/components/export/ExportComponentObjects.ts +23 -0
  16. package/components/filter/FilterForm.ts +11 -0
  17. package/components/filter/FindForm.ts +11 -0
  18. package/components/form/Form.ts +31 -0
  19. package/components/grid/Grid.ts +221 -0
  20. package/components/grid/GridObjects.ts +45 -0
  21. package/components/index.ts +6 -0
  22. package/components/pop-up/PopUpComponent.ts +14 -0
  23. package/components/pop-up/PopUpComponentModels.ts +13 -0
  24. package/components/tab/Tab.ts +29 -0
  25. package/components/task/TaskBar.ts +11 -0
  26. package/components/task/TaskTiles.ts +11 -0
  27. package/config.json +10 -0
  28. package/dist/Testwise.d.ts +2 -0
  29. package/dist/Testwise.js +14 -0
  30. package/dist/Testwise.js.map +1 -0
  31. package/dist/components/BaseComponent.d.ts +29 -0
  32. package/dist/components/BaseComponent.js +67 -0
  33. package/dist/components/BaseComponent.js.map +1 -0
  34. package/dist/components/BaseComponentObjects.d.ts +6 -0
  35. package/dist/components/BaseComponentObjects.js +6 -0
  36. package/dist/components/BaseComponentObjects.js.map +1 -0
  37. package/dist/components/IComponentObjects.d.ts +4 -0
  38. package/dist/components/IComponentObjects.js +2 -0
  39. package/dist/components/IComponentObjects.js.map +1 -0
  40. package/dist/components/Splitter.d.ts +5 -0
  41. package/dist/components/Splitter.js +10 -0
  42. package/dist/components/Splitter.js.map +1 -0
  43. package/dist/components/TSFComponent.d.ts +6 -0
  44. package/dist/components/TSFComponent.js +2 -0
  45. package/dist/components/TSFComponent.js.map +1 -0
  46. package/dist/components/actionbar/Actionbar.d.ts +27 -0
  47. package/dist/components/actionbar/Actionbar.js +35 -0
  48. package/dist/components/actionbar/Actionbar.js.map +1 -0
  49. package/dist/components/actionbar/ActionbarObjects.d.ts +24 -0
  50. package/dist/components/actionbar/ActionbarObjects.js +30 -0
  51. package/dist/components/actionbar/ActionbarObjects.js.map +1 -0
  52. package/dist/components/export/ExportComponent.d.ts +12 -0
  53. package/dist/components/export/ExportComponent.js +55 -0
  54. package/dist/components/export/ExportComponent.js.map +1 -0
  55. package/dist/components/export/ExportComponentObjects.d.ts +11 -0
  56. package/dist/components/export/ExportComponentObjects.js +12 -0
  57. package/dist/components/export/ExportComponentObjects.js.map +1 -0
  58. package/dist/components/form/Form.d.ts +7 -0
  59. package/dist/components/form/Form.js +31 -0
  60. package/dist/components/form/Form.js.map +1 -0
  61. package/dist/components/grid/Grid.d.ts +93 -0
  62. package/dist/components/grid/Grid.js +183 -0
  63. package/dist/components/grid/Grid.js.map +1 -0
  64. package/dist/components/grid/GridObjects.d.ts +20 -0
  65. package/dist/components/grid/GridObjects.js +25 -0
  66. package/dist/components/grid/GridObjects.js.map +1 -0
  67. package/dist/components/index.d.ts +6 -0
  68. package/dist/components/index.js +7 -0
  69. package/dist/components/index.js.map +1 -0
  70. package/dist/components/pop-up/PopUpComponent.d.ts +7 -0
  71. package/dist/components/pop-up/PopUpComponent.js +9 -0
  72. package/dist/components/pop-up/PopUpComponent.js.map +1 -0
  73. package/dist/components/pop-up/PopUpComponentModels.d.ts +7 -0
  74. package/dist/components/pop-up/PopUpComponentModels.js +8 -0
  75. package/dist/components/pop-up/PopUpComponentModels.js.map +1 -0
  76. package/dist/config.json +10 -0
  77. package/dist/enums/ActionbarRegions.d.ts +5 -0
  78. package/dist/enums/ActionbarRegions.js +7 -0
  79. package/dist/enums/ActionbarRegions.js.map +1 -0
  80. package/dist/enums/ButtonEnums.d.ts +24 -0
  81. package/dist/enums/ButtonEnums.js +29 -0
  82. package/dist/enums/ButtonEnums.js.map +1 -0
  83. package/dist/enums/ExportFormat.d.ts +5 -0
  84. package/dist/enums/ExportFormat.js +7 -0
  85. package/dist/enums/ExportFormat.js.map +1 -0
  86. package/dist/enums/LogLevel.d.ts +8 -0
  87. package/dist/enums/LogLevel.js +11 -0
  88. package/dist/enums/LogLevel.js.map +1 -0
  89. package/dist/example-code/TestifyService.d.ts +22 -0
  90. package/dist/example-code/TestifyService.js +191 -0
  91. package/dist/example-code/TestifyService.js.map +1 -0
  92. package/dist/helpers/InflightRequestTracker.d.ts +10 -0
  93. package/dist/helpers/InflightRequestTracker.js +26 -0
  94. package/dist/helpers/InflightRequestTracker.js.map +1 -0
  95. package/dist/helpers/LoginHelper.d.ts +38 -0
  96. package/dist/helpers/LoginHelper.js +112 -0
  97. package/dist/helpers/LoginHelper.js.map +1 -0
  98. package/dist/helpers/UserSimulationHelper.d.ts +20 -0
  99. package/dist/helpers/UserSimulationHelper.js +62 -0
  100. package/dist/helpers/UserSimulationHelper.js.map +1 -0
  101. package/dist/index.d.ts +34 -0
  102. package/dist/index.js +26 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/page-extensions/GoToDeepLink.d.ts +11 -0
  105. package/dist/page-extensions/GoToDeepLink.js +17 -0
  106. package/dist/page-extensions/GoToDeepLink.js.map +1 -0
  107. package/dist/page-extensions/LoginFeatures.d.ts +16 -0
  108. package/dist/page-extensions/LoginFeatures.js +30 -0
  109. package/dist/page-extensions/LoginFeatures.js.map +1 -0
  110. package/dist/page-extensions/UserSimulation.d.ts +15 -0
  111. package/dist/page-extensions/UserSimulation.js +30 -0
  112. package/dist/page-extensions/UserSimulation.js.map +1 -0
  113. package/dist/page-overrides/ClickOverride.d.ts +6 -0
  114. package/dist/page-overrides/ClickOverride.js +73 -0
  115. package/dist/page-overrides/ClickOverride.js.map +1 -0
  116. package/dist/services/ConfigBuilder.d.ts +12 -0
  117. package/dist/services/ConfigBuilder.js +30 -0
  118. package/dist/services/ConfigBuilder.js.map +1 -0
  119. package/dist/services/Logger.d.ts +8 -0
  120. package/dist/services/Logger.js +106 -0
  121. package/dist/services/Logger.js.map +1 -0
  122. package/dist/services/ReportingService.d.ts +8 -0
  123. package/dist/services/ReportingService.js +29 -0
  124. package/dist/services/ReportingService.js.map +1 -0
  125. package/dist/types/CoreTypes.d.ts +2 -0
  126. package/dist/types/CoreTypes.js +2 -0
  127. package/dist/types/CoreTypes.js.map +1 -0
  128. package/dist/types/universal.d.ts +25 -0
  129. package/dist/types/universal.js +2 -0
  130. package/dist/types/universal.js.map +1 -0
  131. package/enums/ActionbarRegions.ts +5 -0
  132. package/enums/ButtonEnums.ts +28 -0
  133. package/enums/ExportFormat.ts +5 -0
  134. package/enums/LogLevel.ts +9 -0
  135. package/example-code/TestifyService.ts +201 -0
  136. package/helpers/InflightRequestTracker.ts +33 -0
  137. package/helpers/LoginHelper.ts +140 -0
  138. package/helpers/UserSimulationHelper.ts +72 -0
  139. package/index.ts +28 -0
  140. package/package.json +40 -0
  141. package/page-extensions/GoToDeepLink.ts +29 -0
  142. package/page-extensions/LoginFeatures.ts +50 -0
  143. package/page-extensions/UserSimulation.ts +49 -0
  144. package/page-overrides/ClickOverride.ts +89 -0
  145. package/promptCredentials.js +113 -0
  146. package/scripts/Testwise.template.json +19 -0
  147. package/scripts/add-config.js +23 -0
  148. package/services/ConfigBuilder.ts +40 -0
  149. package/services/Logger.ts +125 -0
  150. package/services/ReportingService.ts +41 -0
  151. package/types/CoreTypes.ts +9 -0
  152. package/types/universal.ts +26 -0
@@ -0,0 +1,5 @@
1
+ export declare enum ActionbarRegion {
2
+ Near = "near",
3
+ Far = "far",
4
+ Overflow = "overflow"
5
+ }
@@ -0,0 +1,7 @@
1
+ export var ActionbarRegion;
2
+ (function (ActionbarRegion) {
3
+ ActionbarRegion["Near"] = "near";
4
+ ActionbarRegion["Far"] = "far";
5
+ ActionbarRegion["Overflow"] = "overflow";
6
+ })(ActionbarRegion || (ActionbarRegion = {}));
7
+ //# sourceMappingURL=ActionbarRegions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActionbarRegions.js","sourceRoot":"","sources":["../../enums/ActionbarRegions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,eAIX;AAJD,WAAY,eAAe;IACzB,gCAAa,CAAA;IACb,8BAAW,CAAA;IACX,wCAAqB,CAAA;AACvB,CAAC,EAJW,eAAe,KAAf,eAAe,QAI1B"}
@@ -0,0 +1,24 @@
1
+ export declare enum ButtonType {
2
+ ADD = "actionbar__add",
3
+ SAVE = "actionbar__save",
4
+ CANCEL = "actionbar__cancel",
5
+ COPY = "actionbar__copy",
6
+ UPDATE = "actionbar__update",
7
+ DELETE = "actionbar__delete",
8
+ REFRESH = "actionbar__refresh",
9
+ QuickFilter = "actionbar__quick-filter",
10
+ Filter = "actionbar__filter",
11
+ ClearAllFilters = "actionbar__clear-filters",
12
+ Sort = "actionbar__sort",
13
+ RestoreSortOrder = "actionbar__restore-sort",
14
+ Import = "actionbar__import",
15
+ Export = "actionbar__export",
16
+ ExportImmediately = "actionbar__export-immediately",
17
+ MassUpdate = "actionbar__mass-update"
18
+ }
19
+ export declare enum ButtonState {
20
+ ENABLED = "enabled",
21
+ DISABLED = "disabled",
22
+ HIDDEN = "hidden",
23
+ NON_EXISTENT = "nonExistent"
24
+ }
@@ -0,0 +1,29 @@
1
+ export var ButtonType;
2
+ (function (ButtonType) {
3
+ // --- CRUD buttons ---
4
+ ButtonType["ADD"] = "actionbar__add";
5
+ ButtonType["SAVE"] = "actionbar__save";
6
+ ButtonType["CANCEL"] = "actionbar__cancel";
7
+ ButtonType["COPY"] = "actionbar__copy";
8
+ ButtonType["UPDATE"] = "actionbar__update";
9
+ ButtonType["DELETE"] = "actionbar__delete";
10
+ ButtonType["REFRESH"] = "actionbar__refresh";
11
+ // --- Overflow menu buttons
12
+ ButtonType["QuickFilter"] = "actionbar__quick-filter";
13
+ ButtonType["Filter"] = "actionbar__filter";
14
+ ButtonType["ClearAllFilters"] = "actionbar__clear-filters";
15
+ ButtonType["Sort"] = "actionbar__sort";
16
+ ButtonType["RestoreSortOrder"] = "actionbar__restore-sort";
17
+ ButtonType["Import"] = "actionbar__import";
18
+ ButtonType["Export"] = "actionbar__export";
19
+ ButtonType["ExportImmediately"] = "actionbar__export-immediately";
20
+ ButtonType["MassUpdate"] = "actionbar__mass-update";
21
+ })(ButtonType || (ButtonType = {}));
22
+ export var ButtonState;
23
+ (function (ButtonState) {
24
+ ButtonState["ENABLED"] = "enabled";
25
+ ButtonState["DISABLED"] = "disabled";
26
+ ButtonState["HIDDEN"] = "hidden";
27
+ ButtonState["NON_EXISTENT"] = "nonExistent";
28
+ })(ButtonState || (ButtonState = {}));
29
+ //# sourceMappingURL=ButtonEnums.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ButtonEnums.js","sourceRoot":"","sources":["../../enums/ButtonEnums.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,UAoBX;AApBD,WAAY,UAAU;IACpB,uBAAuB;IACvB,oCAAsB,CAAA;IACtB,sCAAwB,CAAA;IACxB,0CAA4B,CAAA;IAC5B,sCAAwB,CAAA;IACxB,0CAA4B,CAAA;IAC5B,0CAA4B,CAAA;IAC5B,4CAA8B,CAAA;IAE9B,4BAA4B;IAC5B,qDAAuC,CAAA;IACvC,0CAA4B,CAAA;IAC5B,0DAA4C,CAAA;IAC5C,sCAAwB,CAAA;IACxB,0DAA4C,CAAA;IAC5C,0CAA4B,CAAA;IAC5B,0CAA4B,CAAA;IAC5B,iEAAmD,CAAA;IACnD,mDAAqC,CAAA;AACvC,CAAC,EApBW,UAAU,KAAV,UAAU,QAoBrB;AAED,MAAM,CAAN,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,kCAAmB,CAAA;IACnB,oCAAqB,CAAA;IACrB,gCAAiB,CAAA;IACjB,2CAA4B,CAAA;AAC9B,CAAC,EALW,WAAW,KAAX,WAAW,QAKtB"}
@@ -0,0 +1,5 @@
1
+ export declare enum ExportFormat {
2
+ CSV = "csv",
3
+ XLSX = "xlsx",
4
+ XLS = "xls"
5
+ }
@@ -0,0 +1,7 @@
1
+ export var ExportFormat;
2
+ (function (ExportFormat) {
3
+ ExportFormat["CSV"] = "csv";
4
+ ExportFormat["XLSX"] = "xlsx";
5
+ ExportFormat["XLS"] = "xls";
6
+ })(ExportFormat || (ExportFormat = {}));
7
+ //# sourceMappingURL=ExportFormat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExportFormat.js","sourceRoot":"","sources":["../../enums/ExportFormat.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,YAIX;AAJD,WAAY,YAAY;IACtB,2BAAW,CAAA;IACX,6BAAa,CAAA;IACb,2BAAW,CAAA;AACb,CAAC,EAJW,YAAY,KAAZ,YAAY,QAIvB"}
@@ -0,0 +1,8 @@
1
+ export declare enum LogLevel {
2
+ FATAL = "FATAL",
3
+ ERROR = "ERROR",
4
+ WARN = "WARN",
5
+ INFO = "INFO",
6
+ STEP = "STEP",
7
+ DEBUG = "DEBUG"
8
+ }
@@ -0,0 +1,11 @@
1
+ export var LogLevel;
2
+ (function (LogLevel) {
3
+ // Order by severity
4
+ LogLevel["FATAL"] = "FATAL";
5
+ LogLevel["ERROR"] = "ERROR";
6
+ LogLevel["WARN"] = "WARN";
7
+ LogLevel["INFO"] = "INFO";
8
+ LogLevel["STEP"] = "STEP";
9
+ LogLevel["DEBUG"] = "DEBUG";
10
+ })(LogLevel || (LogLevel = {}));
11
+ //# sourceMappingURL=LogLevel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LogLevel.js","sourceRoot":"","sources":["../../enums/LogLevel.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,QAQX;AARD,WAAY,QAAQ;IAClB,oBAAoB;IACpB,2BAAe,CAAA;IACf,2BAAe,CAAA;IACf,yBAAa,CAAA;IACb,yBAAa,CAAA;IACb,yBAAa,CAAA;IACb,2BAAe,CAAA;AACjB,CAAC,EARW,QAAQ,KAAR,QAAQ,QAQnB"}
@@ -0,0 +1,22 @@
1
+ export declare class TestifyService {
2
+ private token;
3
+ private projectId;
4
+ private baseUrl;
5
+ private axiosInstance;
6
+ testRunId: string;
7
+ constructor();
8
+ createTestRun(): Promise<void>;
9
+ private getTestRunId;
10
+ private createTestRunRequest;
11
+ private getProjectName;
12
+ reportTestResult(testName: string, passed: boolean): Promise<void>;
13
+ private updateResult;
14
+ private getTestResultId;
15
+ private getTestCaseId;
16
+ private addTestCaseToTestRun;
17
+ private createTestCase;
18
+ private testCaseExists;
19
+ private getTestCases;
20
+ closeTestRun(): Promise<void>;
21
+ private headers;
22
+ }
@@ -0,0 +1,191 @@
1
+ /* Ignore this file for reviewing, it is used for Testify integration and only serves as an example*/
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ import axios from 'axios';
4
+ export class TestifyService {
5
+ constructor() {
6
+ this.testRunId = '';
7
+ this.token = `Bearer ${process.env.TESTIFY_TOKEN}`;
8
+ this.projectId = process.env.TESTIFY_PROJECT_ID || '';
9
+ // biome-ignore lint/style/noNonNullAssertion: <explanation>
10
+ this.baseUrl = process.env.TESTIFY_BASE_URL.replace(/\/$/, '');
11
+ this.axiosInstance = axios.create({
12
+ baseURL: this.baseUrl,
13
+ headers: {
14
+ Authorization: this.token,
15
+ accept: '*/*'
16
+ }
17
+ });
18
+ }
19
+ async createTestRun() {
20
+ try {
21
+ const projectName = await this.getProjectName();
22
+ const testRunName = `${projectName} ${new Date().toISOString()}`;
23
+ if (!this.testRunId) {
24
+ await this.createTestRunRequest(testRunName);
25
+ this.testRunId = await this.getTestRunId(testRunName);
26
+ }
27
+ await new Promise((res) => setTimeout(res, 1000));
28
+ }
29
+ catch (err) {
30
+ console.error('createTestRun failed:', err);
31
+ }
32
+ }
33
+ async getTestRunId(testRunName) {
34
+ try {
35
+ const url = `/api/v1/TestRun?projectId=${this.projectId}`;
36
+ const response = await this.axiosInstance.get(url, { headers: this.headers('text/plain') });
37
+ const testRunList = response.data;
38
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
39
+ const found = testRunList.find((tr) => tr.name?.toLowerCase() === testRunName.toLowerCase());
40
+ return found?.id?.toString() ?? '';
41
+ }
42
+ catch (err) {
43
+ console.error('getTestRunId failed:', err);
44
+ return '';
45
+ }
46
+ }
47
+ async createTestRunRequest(testRunName) {
48
+ try {
49
+ const encodedName = encodeURIComponent(testRunName);
50
+ const url = `/api/v1/TestRun/Create?testRunName=${encodedName}&projectId=${this.projectId}`;
51
+ await this.axiosInstance.post(url, null, { headers: this.headers() });
52
+ }
53
+ catch (err) {
54
+ console.error('createTestRunRequest failed:', err);
55
+ }
56
+ }
57
+ async getProjectName() {
58
+ try {
59
+ const url = `/api/v1/Project/${this.projectId}`;
60
+ const response = await this.axiosInstance.get(url, { headers: this.headers('text/plain') });
61
+ const project = response.data;
62
+ return project.name;
63
+ }
64
+ catch (err) {
65
+ console.error('getProjectName failed:', err);
66
+ return '';
67
+ }
68
+ }
69
+ async reportTestResult(testName, passed) {
70
+ try {
71
+ const testCases = await this.getTestCases();
72
+ if (!this.testCaseExists(testCases, testName)) {
73
+ await this.createTestCase(testName);
74
+ }
75
+ const testCaseId = await this.getTestCaseId(testName);
76
+ if (!testCaseId) {
77
+ console.error(`Could not find or create test case ID for "${testName}"`);
78
+ return;
79
+ }
80
+ await this.addTestCaseToTestRun(testCaseId);
81
+ const testResultId = await this.getTestResultId(testCaseId);
82
+ if (!testResultId) {
83
+ console.error(`Could not find test result ID for test case "${testName}"`);
84
+ return;
85
+ }
86
+ await this.updateResult(testResultId, passed);
87
+ await new Promise((res) => setTimeout(res, 200));
88
+ }
89
+ catch (err) {
90
+ console.error('reportTestResult failed:', err);
91
+ }
92
+ }
93
+ async updateResult(testResultId, passed) {
94
+ try {
95
+ const status = passed ? '1' : '2';
96
+ const url = `/api/v1/Result/${testResultId}/UpdateStatus?newStatus=${status}`;
97
+ await this.axiosInstance.put(url, null, { headers: this.headers() });
98
+ }
99
+ catch (err) {
100
+ console.error('updateResult failed:', err);
101
+ }
102
+ }
103
+ async getTestResultId(testCaseId) {
104
+ try {
105
+ const url = `/api/v1/Result?testRunId=${this.testRunId}`;
106
+ const response = await this.axiosInstance.get(url, { headers: this.headers('text/plain') });
107
+ const results = response.data;
108
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
109
+ const found = results.find((r) => r.testCaseId?.toString() === testCaseId);
110
+ return found?.id?.toString() ?? '';
111
+ }
112
+ catch (err) {
113
+ console.error('getTestResultId failed:', err);
114
+ return '';
115
+ }
116
+ }
117
+ async getTestCaseId(testCaseName) {
118
+ try {
119
+ const testCases = await this.getTestCases();
120
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
121
+ const found = testCases.find((tc) => tc.name === testCaseName);
122
+ return found?.id?.toString() ?? '';
123
+ }
124
+ catch (err) {
125
+ console.error('getTestCaseId failed:', err);
126
+ return '';
127
+ }
128
+ }
129
+ async addTestCaseToTestRun(testCaseId) {
130
+ try {
131
+ const url = `/api/v1/Result/Create?caseId=${testCaseId}&testRunId=${this.testRunId}`;
132
+ await this.axiosInstance.post(url, null, { headers: this.headers() });
133
+ }
134
+ catch (err) {
135
+ console.error('addTestCaseToTestRun failed:', err);
136
+ }
137
+ }
138
+ async createTestCase(testCaseName) {
139
+ try {
140
+ const encodedName = encodeURIComponent(testCaseName);
141
+ const url = `/api/v1/TestCase/Create?testCaseName=${encodedName}&projectId=${this.projectId}`;
142
+ await this.axiosInstance.post(url, null, { headers: this.headers() });
143
+ }
144
+ catch (err) {
145
+ console.error('createTestCase failed:', err);
146
+ }
147
+ }
148
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
149
+ testCaseExists(testCases, testName) {
150
+ try {
151
+ return testCases.some((tc) => tc.name?.toLowerCase() === testName.toLowerCase());
152
+ }
153
+ catch (err) {
154
+ console.error('testCaseExists failed:', err);
155
+ return false;
156
+ }
157
+ }
158
+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
159
+ async getTestCases() {
160
+ try {
161
+ const url = `/api/v1/TestCase?projectId=${this.projectId}`;
162
+ const response = await this.axiosInstance.get(url, { headers: this.headers('text/plain') });
163
+ return response.data;
164
+ }
165
+ catch (err) {
166
+ console.error('getTestCases failed:', err);
167
+ return [];
168
+ }
169
+ }
170
+ async closeTestRun() {
171
+ if (!this.testRunId) {
172
+ console.error('closeTestRun failed: testRunId is not set.');
173
+ return;
174
+ }
175
+ try {
176
+ const url = `/api/v1/TestRun/${this.testRunId}/Close`;
177
+ await this.axiosInstance.put(url, null, { headers: this.headers() });
178
+ console.info(`Test run ${this.testRunId} closed successfully.`);
179
+ }
180
+ catch (err) {
181
+ console.error('closeTestRun failed:', err);
182
+ }
183
+ }
184
+ headers(accept = '*/*') {
185
+ return {
186
+ accept,
187
+ Authorization: this.token
188
+ };
189
+ }
190
+ }
191
+ //# sourceMappingURL=TestifyService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestifyService.js","sourceRoot":"","sources":["../../example-code/TestifyService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { Page, Request } from '@playwright/test';
2
+ export declare class InflightRequestsTracker {
3
+ private _page;
4
+ private _requests;
5
+ constructor(page: Page);
6
+ _onStarted(request: Request): void;
7
+ _onFinished(request: Request): void;
8
+ inflightRequests(): Request[];
9
+ dispose(): void;
10
+ }
@@ -0,0 +1,26 @@
1
+ export class InflightRequestsTracker {
2
+ constructor(page) {
3
+ this._page = page;
4
+ this._requests = new Set();
5
+ this._onStarted = this._onStarted.bind(this);
6
+ this._onFinished = this._onFinished.bind(this);
7
+ this._page.on('request', this._onStarted);
8
+ this._page.on('requestfinished', this._onFinished);
9
+ this._page.on('requestfailed', this._onFinished);
10
+ }
11
+ _onStarted(request) {
12
+ this._requests.add(request);
13
+ }
14
+ _onFinished(request) {
15
+ this._requests.delete(request);
16
+ }
17
+ inflightRequests() {
18
+ return Array.from(this._requests);
19
+ }
20
+ dispose() {
21
+ this._page.removeListener('request', this._onStarted);
22
+ this._page.removeListener('requestfinished', this._onFinished);
23
+ this._page.removeListener('requestfailed', this._onFinished);
24
+ }
25
+ }
26
+ //# sourceMappingURL=InflightRequestTracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InflightRequestTracker.js","sourceRoot":"","sources":["../../helpers/InflightRequestTracker.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,uBAAuB;IAIlC,YAAY,IAAU;QACpB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC;IAED,UAAU,CAAC,OAAgB;QACzB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IACD,WAAW,CAAC,OAAgB;QAC1B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,gBAAgB;QACd,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC;IAED,OAAO;QACL,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACtD,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,iBAAiB,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAC/D,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAC/D,CAAC;CACF"}
@@ -0,0 +1,38 @@
1
+ import { type Page } from '@playwright/test';
2
+ import type { UniversalLoginOptions } from '../types/universal.js';
3
+ export declare class LoginHelper {
4
+ private _page;
5
+ private _serviceUrl;
6
+ private _metaEndpoint;
7
+ constructor(page: Page);
8
+ /**
9
+ * Log in and go to a specified application
10
+ * @param applicationName - Application name to launch
11
+ */
12
+ logIn(applicationName?: string): Promise<void>;
13
+ /**
14
+ * Log in with credentials
15
+ * @param username - The username to log in with
16
+ * @param password - The password to log in with
17
+ */
18
+ logInWithCredentials(username: string, password: string): Promise<void>;
19
+ /**
20
+ * Log in with options
21
+ * @param options - The login options
22
+ */
23
+ logInWithOptions(options: UniversalLoginOptions): Promise<void>;
24
+ /**
25
+ * Navigate to the home page and wait for the menu to load
26
+ */
27
+ private navigateHomeAndWaitForMenuToLoad;
28
+ /**
29
+ * Log in and configure the application
30
+ * @param options - The login options
31
+ */
32
+ private logInAndConfigureApplication;
33
+ /**
34
+ * Configure the application
35
+ * @param options - The configuration options
36
+ */
37
+ private configureApplication;
38
+ }
@@ -0,0 +1,112 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { expect } from '@playwright/test';
5
+ import { testwiseConfig } from '../services/ConfigBuilder.js';
6
+ const _dirname = path.dirname(fileURLToPath(import.meta.url));
7
+ const configFixture = JSON.parse(fs.readFileSync(path.resolve(_dirname, '../config.json'), 'utf-8'));
8
+ export class LoginHelper {
9
+ constructor(page) {
10
+ this._page = page;
11
+ const serviceUrl = testwiseConfig().get('environmentSettings.serviceUrl');
12
+ const metaEndpoint = testwiseConfig().get('environmentSettings.metaEndpoint');
13
+ if (!serviceUrl || !metaEndpoint)
14
+ throw new Error('Either environmentSettings.serviceUrl or environmentSettings.metaEndpoint is not defined in the configuration.');
15
+ this._serviceUrl = serviceUrl;
16
+ this._metaEndpoint = metaEndpoint;
17
+ }
18
+ /**
19
+ * Log in and go to a specified application
20
+ * @param applicationName - Application name to launch
21
+ */
22
+ async logIn(applicationName = configFixture.defaultApplication) {
23
+ await this.logInAndConfigureApplication({
24
+ config: {
25
+ defaultApplication: applicationName
26
+ }
27
+ });
28
+ }
29
+ /**
30
+ * Log in with credentials
31
+ * @param username - The username to log in with
32
+ * @param password - The password to log in with
33
+ */
34
+ async logInWithCredentials(username, password) {
35
+ const options = {
36
+ username: username,
37
+ password: password
38
+ };
39
+ await this.logInWithOptions(options);
40
+ }
41
+ /**
42
+ * Log in with options
43
+ * @param options - The login options
44
+ */
45
+ async logInWithOptions(options) {
46
+ await this.logInAndConfigureApplication(options);
47
+ }
48
+ /**
49
+ * Navigate to the home page and wait for the menu to load
50
+ */
51
+ async navigateHomeAndWaitForMenuToLoad() {
52
+ await this._page.goto('/');
53
+ await this._page.route('**/i_ui_menu?**', (route) => {
54
+ route.continue();
55
+ });
56
+ await expect.poll(async () => await this._page.url()).toContain('#application=');
57
+ }
58
+ /**
59
+ * Log in and configure the application
60
+ * @param options - The login options
61
+ */
62
+ async logInAndConfigureApplication(options = {}) {
63
+ const { serviceUrl, metaEndpoint, config } = options;
64
+ const username = options.username ?? process.env.SF_TEST_USERNAME;
65
+ const password = options.password ?? process.env.SF_TEST_PASSWORD;
66
+ if (!username || !password) {
67
+ throw new Error('Username and password are required for login.');
68
+ }
69
+ if (serviceUrl && metaEndpoint) {
70
+ this._serviceUrl = serviceUrl;
71
+ this._metaEndpoint = metaEndpoint;
72
+ }
73
+ const response = await this._page.request.post(`${this._serviceUrl}/account/api/login`, {
74
+ form: {
75
+ UserName: username,
76
+ Password: password
77
+ }
78
+ });
79
+ if (response.status() !== 204) {
80
+ console.error('Login failed', await response.status());
81
+ }
82
+ // Set the navigator.language property
83
+ await this._page.route('**/*', (route, request) => {
84
+ route.continue({
85
+ headers: {
86
+ ...request.headers(),
87
+ 'Accept-Language': 'en-US'
88
+ }
89
+ });
90
+ });
91
+ await this.configureApplication(config ?? {});
92
+ await this.navigateHomeAndWaitForMenuToLoad();
93
+ }
94
+ /**
95
+ * Configure the application
96
+ * @param options - The configuration options
97
+ */
98
+ async configureApplication(options) {
99
+ await this._page.route('**/config.json', (route) => {
100
+ route.fulfill({
101
+ status: 200,
102
+ contentType: 'application/json',
103
+ body: JSON.stringify({
104
+ ...configFixture,
105
+ serviceUrl: `${this._serviceUrl}/iam/${this._metaEndpoint}`,
106
+ ...options
107
+ })
108
+ });
109
+ });
110
+ }
111
+ }
112
+ //# sourceMappingURL=LoginHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoginHelper.js","sourceRoot":"","sources":["../../helpers/LoginHelper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type Page } from '@playwright/test';
2
+ export declare class UserSimulationHelper {
3
+ private _page;
4
+ private _serviceUrl;
5
+ constructor(page: Page);
6
+ /**
7
+ * Get the simulated user
8
+ * @returns The simulated user name
9
+ */
10
+ getSimulatedUser(): Promise<string>;
11
+ /**
12
+ * Stop the user simulation
13
+ */
14
+ stopSimulation(): Promise<void>;
15
+ /**
16
+ * Simulate a user
17
+ * @param userName - The name of the user to simulate
18
+ */
19
+ simulateUser(userName: string): Promise<void>;
20
+ }
@@ -0,0 +1,62 @@
1
+ import { expect } from '@playwright/test';
2
+ import { testwiseConfig } from '../services/ConfigBuilder.js';
3
+ export class UserSimulationHelper {
4
+ constructor(page) {
5
+ this._page = page;
6
+ const serviceUrl = testwiseConfig().get('environmentSettings.serviceUrl');
7
+ if (!serviceUrl)
8
+ throw new Error('environmentSettings.serviceUrl is not defined in the configuration.');
9
+ this._serviceUrl = serviceUrl;
10
+ }
11
+ /**
12
+ * Get the simulated user
13
+ * @returns The simulated user name
14
+ */
15
+ async getSimulatedUser() {
16
+ const response = await this._page.request.get(`${this._serviceUrl}/account/api/usersimulation`);
17
+ switch (response.status()) {
18
+ case 204:
19
+ console.error('User simulation not active', await response.status());
20
+ return '';
21
+ case 200:
22
+ return (await response.json()).simulated_user;
23
+ default:
24
+ throw new Error(`Get simulated user request failed with status: ${await response.status()}`);
25
+ }
26
+ }
27
+ /**
28
+ * Stop the user simulation
29
+ */
30
+ async stopSimulation() {
31
+ const response = await this._page.request.delete(`${this._serviceUrl}/account/api/usersimulation`);
32
+ if (response.status() === 204) {
33
+ console.info('STOP User simulation request is successful', await response.status());
34
+ }
35
+ else {
36
+ throw new Error(`STOP User simulation has unexpected status: ${await response.status()}`);
37
+ }
38
+ await expect.poll(async () => await this.getSimulatedUser()).toBe('');
39
+ }
40
+ /**
41
+ * Simulate a user
42
+ * @param userName - The name of the user to simulate
43
+ */
44
+ async simulateUser(userName) {
45
+ const response = await this._page.request.patch(`${this._serviceUrl}/account/api/usersimulation`, {
46
+ headers: {
47
+ 'Content-Type': 'application/json',
48
+ Accept: 'application/json'
49
+ },
50
+ data: JSON.stringify({
51
+ simulated_user: userName
52
+ })
53
+ });
54
+ if (response.status() === 200) {
55
+ console.info('User simulation request is successful', await response.status());
56
+ }
57
+ else {
58
+ throw new Error(`User simulation has unexpected status: ${await response.status()}`);
59
+ }
60
+ }
61
+ }
62
+ //# sourceMappingURL=UserSimulationHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserSimulationHelper.js","sourceRoot":"","sources":["../../helpers/UserSimulationHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9D,MAAM,OAAO,oBAAoB;IAI/B,YAAY,IAAU;QACpB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAElB,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC,GAAG,CAAS,gCAAgC,CAAC,CAAC;QAElF,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;QAExG,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;IAChC,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,gBAAgB;QAC3B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW,6BAA6B,CAAC,CAAC;QAEhG,QAAQ,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,KAAK,GAAG;gBACN,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;gBACrE,OAAO,EAAE,CAAC;YACZ,KAAK,GAAG;gBACN,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,cAAc,CAAC;YAChD;gBACE,MAAM,IAAI,KAAK,CAAC,kDAAkD,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACjG,CAAC;IACH,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,cAAc;QACzB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,6BAA6B,CAAC,CAAC;QAEnG,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,4CAA4C,EAAE,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACtF,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,+CAA+C,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC5F,CAAC;QAED,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,YAAY,CAAC,QAAgB;QACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,6BAA6B,EAAE;YAChG,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,MAAM,EAAE,kBAAkB;aAC3B;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,cAAc,EAAE,QAAQ;aACzB,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,uCAAuC,EAAE,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACjF,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,0CAA0C,MAAM,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;CACF"}