@eclipse-che/che-e2e 7.74.0-dev-1d09cb7 → 7.74.0-dev-aace77a

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 (229) hide show
  1. package/.eslintignore +10 -0
  2. package/.eslintrc.js +197 -0
  3. package/.prettierignore +10 -0
  4. package/.prettierrc.json +10 -0
  5. package/CODE_STYLE.md +144 -0
  6. package/README.md +47 -47
  7. package/configs/inversify.config.ts +39 -14
  8. package/configs/inversify.types.ts +44 -30
  9. package/configs/mocharc.ts +21 -24
  10. package/constants/API_TEST_CONSTANTS.ts +67 -0
  11. package/constants/BASE_TEST_CONSTANTS.ts +80 -0
  12. package/constants/CHROME_DRIVER_CONSTANTS.ts +42 -0
  13. package/constants/FACTORY_TEST_CONSTANTS.ts +61 -0
  14. package/constants/MONACO_CONSTANTS.ts +25 -0
  15. package/constants/OAUTH_CONSTANTS.ts +67 -0
  16. package/constants/PLUGIN_TEST_CONSTANTS.ts +15 -0
  17. package/constants/REPORTER_CONSTANTS.ts +53 -0
  18. package/constants/TIMEOUT_CONSTANTS.ts +131 -0
  19. package/dist/configs/inversify.config.js +36 -9
  20. package/dist/configs/inversify.config.js.map +1 -1
  21. package/dist/configs/inversify.types.js +19 -5
  22. package/dist/configs/inversify.types.js.map +1 -1
  23. package/dist/configs/mocharc.js +13 -16
  24. package/dist/configs/mocharc.js.map +1 -1
  25. package/dist/constants/{APITestConstants.js → API_TEST_CONSTANTS.js} +12 -12
  26. package/dist/constants/API_TEST_CONSTANTS.js.map +1 -0
  27. package/dist/constants/{BaseTestConstants.js → BASE_TEST_CONSTANTS.js} +16 -16
  28. package/dist/constants/BASE_TEST_CONSTANTS.js.map +1 -0
  29. package/dist/constants/CHROME_DRIVER_CONSTANTS.js +36 -0
  30. package/dist/constants/CHROME_DRIVER_CONSTANTS.js.map +1 -0
  31. package/dist/constants/{FactoryTestConstants.js → FACTORY_TEST_CONSTANTS.js} +14 -13
  32. package/dist/constants/FACTORY_TEST_CONSTANTS.js.map +1 -0
  33. package/dist/constants/{MonacoConstants.js → MONACO_CONSTANTS.js} +7 -7
  34. package/dist/constants/MONACO_CONSTANTS.js.map +1 -0
  35. package/dist/constants/{OAuthConstants.js → OAUTH_CONSTANTS.js} +14 -14
  36. package/dist/constants/OAUTH_CONSTANTS.js.map +1 -0
  37. package/dist/constants/{PluginsTestConstants.js → PLUGIN_TEST_CONSTANTS.js} +7 -7
  38. package/dist/constants/PLUGIN_TEST_CONSTANTS.js.map +1 -0
  39. package/dist/constants/{ReporterConstants.js → REPORTER_CONSTANTS.js} +12 -12
  40. package/dist/constants/REPORTER_CONSTANTS.js.map +1 -0
  41. package/dist/constants/{TimeoutConstants.js → TIMEOUT_CONSTANTS.js} +24 -24
  42. package/dist/constants/TIMEOUT_CONSTANTS.js.map +1 -0
  43. package/dist/driver/ChromeDriver.js +12 -22
  44. package/dist/driver/ChromeDriver.js.map +1 -1
  45. package/dist/index.js +18 -12
  46. package/dist/index.js.map +1 -1
  47. package/dist/pageobjects/dashboard/CreateWorkspace.js +15 -15
  48. package/dist/pageobjects/dashboard/CreateWorkspace.js.map +1 -1
  49. package/dist/pageobjects/dashboard/Dashboard.js +20 -21
  50. package/dist/pageobjects/dashboard/Dashboard.js.map +1 -1
  51. package/dist/pageobjects/dashboard/Workspaces.js +55 -60
  52. package/dist/pageobjects/dashboard/Workspaces.js.map +1 -1
  53. package/dist/pageobjects/dashboard/workspace-details/WorkspaceDetails.js +58 -48
  54. package/dist/pageobjects/dashboard/workspace-details/WorkspaceDetails.js.map +1 -1
  55. package/dist/pageobjects/git-providers/OauthPage.js +22 -20
  56. package/dist/pageobjects/git-providers/OauthPage.js.map +1 -1
  57. package/dist/pageobjects/ide/CheCodeLocatorLoader.js +26 -12
  58. package/dist/pageobjects/ide/CheCodeLocatorLoader.js.map +1 -1
  59. package/dist/pageobjects/login/interfaces/ICheLoginPage.js +2 -2
  60. package/dist/pageobjects/login/interfaces/IOcpLoginPage.js +2 -2
  61. package/dist/pageobjects/login/kubernetes/DexLoginPage.js +14 -14
  62. package/dist/pageobjects/login/kubernetes/DexLoginPage.js.map +1 -1
  63. package/dist/pageobjects/login/kubernetes/KubernetesLoginPage.js +7 -7
  64. package/dist/pageobjects/login/kubernetes/KubernetesLoginPage.js.map +1 -1
  65. package/dist/pageobjects/login/openshift/OcpLoginPage.js +24 -28
  66. package/dist/pageobjects/login/openshift/OcpLoginPage.js.map +1 -1
  67. package/dist/pageobjects/login/openshift/OcpRedHatLoginPage.js +13 -16
  68. package/dist/pageobjects/login/openshift/OcpRedHatLoginPage.js.map +1 -1
  69. package/dist/pageobjects/login/openshift/OcpUserLoginPage.js +9 -9
  70. package/dist/pageobjects/login/openshift/OcpUserLoginPage.js.map +1 -1
  71. package/dist/pageobjects/login/openshift/RedHatLoginPage.js +19 -23
  72. package/dist/pageobjects/login/openshift/RedHatLoginPage.js.map +1 -1
  73. package/dist/pageobjects/login/openshift/RegularUserOcpCheLoginPage.js +20 -19
  74. package/dist/pageobjects/login/openshift/RegularUserOcpCheLoginPage.js.map +1 -1
  75. package/dist/pageobjects/openshift/OcpApplicationPage.js +11 -11
  76. package/dist/pageobjects/openshift/OcpApplicationPage.js.map +1 -1
  77. package/dist/pageobjects/openshift/OcpImportFromGitPage.js +24 -24
  78. package/dist/pageobjects/openshift/OcpImportFromGitPage.js.map +1 -1
  79. package/dist/pageobjects/openshift/OcpMainPage.js +30 -30
  80. package/dist/pageobjects/openshift/OcpMainPage.js.map +1 -1
  81. package/dist/specs/MochaHooks.js +33 -27
  82. package/dist/specs/MochaHooks.js.map +1 -1
  83. package/dist/specs/SmokeTest.spec.js +17 -17
  84. package/dist/specs/SmokeTest.spec.js.map +1 -1
  85. package/dist/specs/api/ContainerOverridesAPI.spec.js +8 -6
  86. package/dist/specs/api/ContainerOverridesAPI.spec.js.map +1 -1
  87. package/dist/specs/api/DevfileAcceptanceTestAPI.spec.js +27 -24
  88. package/dist/specs/api/DevfileAcceptanceTestAPI.spec.js.map +1 -1
  89. package/dist/specs/api/EmptyWorkspaceAPI.spec.js +17 -17
  90. package/dist/specs/api/EmptyWorkspaceAPI.spec.js.map +1 -1
  91. package/dist/specs/api/PodOverridesAPI.spec.js +10 -8
  92. package/dist/specs/api/PodOverridesAPI.spec.js.map +1 -1
  93. package/dist/specs/dashboard-samples/EmptyWorkspace.spec.js +10 -10
  94. package/dist/specs/dashboard-samples/EmptyWorkspace.spec.js.map +1 -1
  95. package/dist/specs/dashboard-samples/Quarkus.spec.js +13 -13
  96. package/dist/specs/dashboard-samples/Quarkus.spec.js.map +1 -1
  97. package/dist/specs/dashboard-samples/RecommendedExtensions.spec.js +52 -52
  98. package/dist/specs/dashboard-samples/RecommendedExtensions.spec.js.map +1 -1
  99. package/dist/specs/devconsole-intergration/DevConsoleIntegration.spec.js +23 -19
  100. package/dist/specs/devconsole-intergration/DevConsoleIntegration.spec.js.map +1 -1
  101. package/dist/specs/factory/Factory.spec.js +38 -41
  102. package/dist/specs/factory/Factory.spec.js.map +1 -1
  103. package/dist/specs/factory/NoSetupRepoFactory.spec.js +52 -50
  104. package/dist/specs/factory/NoSetupRepoFactory.spec.js.map +1 -1
  105. package/dist/specs/factory/RefusedOAuthFactory.spec.js +49 -51
  106. package/dist/specs/factory/RefusedOAuthFactory.spec.js.map +1 -1
  107. package/dist/specs/miscellaneous/PredefinedNamespace.spec.js +45 -42
  108. package/dist/specs/miscellaneous/PredefinedNamespace.spec.js.map +1 -1
  109. package/dist/tests-library/LoginTests.js +13 -13
  110. package/dist/tests-library/LoginTests.js.map +1 -1
  111. package/dist/tests-library/ProjectAndFileTests.js +9 -7
  112. package/dist/tests-library/ProjectAndFileTests.js.map +1 -1
  113. package/dist/tests-library/WorkspaceHandlingTests.js +22 -19
  114. package/dist/tests-library/WorkspaceHandlingTests.js.map +1 -1
  115. package/dist/utils/BrowserTabsUtil.js +21 -21
  116. package/dist/utils/BrowserTabsUtil.js.map +1 -1
  117. package/dist/utils/CheReporter.js +91 -65
  118. package/dist/utils/CheReporter.js.map +1 -1
  119. package/dist/utils/DevWorkspaceConfigurationHelper.js +34 -15
  120. package/dist/utils/DevWorkspaceConfigurationHelper.js.map +1 -1
  121. package/dist/utils/DevfilesRegistryHelper.js +34 -18
  122. package/dist/utils/DevfilesRegistryHelper.js.map +1 -1
  123. package/dist/utils/DriverHelper.js +73 -68
  124. package/dist/utils/DriverHelper.js.map +1 -1
  125. package/dist/utils/IContextParams.js +12 -0
  126. package/dist/utils/IContextParams.js.map +1 -0
  127. package/dist/utils/IKubernetesCommandLineToolsExecutor.js +3 -0
  128. package/dist/utils/IKubernetesCommandLineToolsExecutor.js.map +1 -0
  129. package/dist/utils/KubernetesCommandLineToolsExecutor.js +146 -107
  130. package/dist/utils/KubernetesCommandLineToolsExecutor.js.map +1 -1
  131. package/dist/utils/Logger.js +18 -19
  132. package/dist/utils/Logger.js.map +1 -1
  133. package/dist/utils/ScreenCatcher.js +26 -16
  134. package/dist/utils/ScreenCatcher.js.map +1 -1
  135. package/dist/utils/ShellExecutor.js +29 -9
  136. package/dist/utils/ShellExecutor.js.map +1 -1
  137. package/dist/utils/StringUtil.js +19 -9
  138. package/dist/utils/StringUtil.js.map +1 -1
  139. package/dist/utils/request-handlers/CheApiRequestHandler.js +29 -29
  140. package/dist/utils/request-handlers/CheApiRequestHandler.js.map +1 -1
  141. package/dist/utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler.js +12 -8
  142. package/dist/utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler.js.map +1 -1
  143. package/dist/utils/request-handlers/headers/IAuthorizationHeaderHandler.js +2 -2
  144. package/dist/utils/workspace/ApiUrlResolver.js +5 -5
  145. package/dist/utils/workspace/ApiUrlResolver.js.map +1 -1
  146. package/dist/utils/workspace/ITestWorkspaceUtil.js +2 -2
  147. package/dist/utils/workspace/TestWorkspaceUtil.js +25 -23
  148. package/dist/utils/workspace/TestWorkspaceUtil.js.map +1 -1
  149. package/dist/utils/workspace/WorkspaceStatus.js +2 -2
  150. package/dist/utils/workspace/WorkspaceStatus.js.map +1 -1
  151. package/driver/ChromeDriver.ts +45 -58
  152. package/driver/IDriver.ts +3 -3
  153. package/index.ts +11 -9
  154. package/package.json +59 -49
  155. package/pageobjects/dashboard/CreateWorkspace.ts +65 -55
  156. package/pageobjects/dashboard/Dashboard.ts +100 -100
  157. package/pageobjects/dashboard/Workspaces.ts +210 -186
  158. package/pageobjects/dashboard/workspace-details/WorkspaceDetails.ts +153 -131
  159. package/pageobjects/git-providers/OauthPage.ts +177 -166
  160. package/pageobjects/ide/CheCodeLocatorLoader.ts +51 -46
  161. package/pageobjects/login/interfaces/ICheLoginPage.ts +3 -3
  162. package/pageobjects/login/interfaces/IOcpLoginPage.ts +3 -3
  163. package/pageobjects/login/kubernetes/DexLoginPage.ts +31 -30
  164. package/pageobjects/login/kubernetes/KubernetesLoginPage.ts +15 -14
  165. package/pageobjects/login/openshift/OcpLoginPage.ts +51 -56
  166. package/pageobjects/login/openshift/OcpRedHatLoginPage.ts +27 -27
  167. package/pageobjects/login/openshift/OcpUserLoginPage.ts +15 -18
  168. package/pageobjects/login/openshift/RedHatLoginPage.ts +49 -46
  169. package/pageobjects/login/openshift/RegularUserOcpCheLoginPage.ts +43 -34
  170. package/pageobjects/openshift/OcpApplicationPage.ts +21 -19
  171. package/pageobjects/openshift/OcpImportFromGitPage.ts +68 -68
  172. package/pageobjects/openshift/OcpMainPage.ts +69 -69
  173. package/specs/MochaHooks.ts +59 -52
  174. package/specs/SmokeTest.spec.ts +47 -45
  175. package/specs/api/ContainerOverridesAPI.spec.ts +39 -26
  176. package/specs/api/DevfileAcceptanceTestAPI.spec.ts +110 -97
  177. package/specs/api/EmptyWorkspaceAPI.spec.ts +67 -58
  178. package/specs/api/PodOverridesAPI.spec.ts +48 -34
  179. package/specs/dashboard-samples/EmptyWorkspace.spec.ts +36 -36
  180. package/specs/dashboard-samples/Quarkus.spec.ts +41 -40
  181. package/specs/dashboard-samples/RecommendedExtensions.spec.ts +202 -183
  182. package/specs/devconsole-intergration/DevConsoleIntegration.spec.ts +85 -75
  183. package/specs/factory/Factory.spec.ts +184 -178
  184. package/specs/factory/NoSetupRepoFactory.spec.ts +233 -219
  185. package/specs/factory/RefusedOAuthFactory.spec.ts +223 -211
  186. package/specs/miscellaneous/PredefinedNamespace.spec.ts +70 -64
  187. package/tests-library/LoginTests.ts +34 -32
  188. package/tests-library/ProjectAndFileTests.ts +21 -18
  189. package/tests-library/WorkspaceHandlingTests.ts +98 -89
  190. package/tsconfig.json +15 -15
  191. package/utils/BrowserTabsUtil.ts +78 -74
  192. package/utils/CheReporter.ts +159 -157
  193. package/utils/DevWorkspaceConfigurationHelper.ts +63 -69
  194. package/utils/DevfilesRegistryHelper.ts +71 -57
  195. package/utils/DriverHelper.ts +728 -700
  196. package/utils/IContextParams.ts +26 -0
  197. package/utils/IKubernetesCommandLineToolsExecutor.ts +42 -0
  198. package/utils/KubernetesCommandLineToolsExecutor.ts +231 -183
  199. package/utils/Logger.ts +102 -125
  200. package/utils/ScreenCatcher.ts +57 -46
  201. package/utils/ShellExecutor.ts +23 -12
  202. package/utils/StringUtil.ts +49 -36
  203. package/utils/request-handlers/CheApiRequestHandler.ts +91 -88
  204. package/utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler.ts +32 -21
  205. package/utils/request-handlers/headers/IAuthorizationHeaderHandler.ts +3 -3
  206. package/utils/workspace/ApiUrlResolver.ts +31 -26
  207. package/utils/workspace/ITestWorkspaceUtil.ts +31 -31
  208. package/utils/workspace/TestWorkspaceUtil.ts +152 -145
  209. package/utils/workspace/WorkspaceStatus.ts +5 -5
  210. package/constants/APITestConstants.ts +0 -57
  211. package/constants/BaseTestConstants.ts +0 -68
  212. package/constants/ChromeDriverConstants.ts +0 -46
  213. package/constants/FactoryTestConstants.ts +0 -51
  214. package/constants/MonacoConstants.ts +0 -22
  215. package/constants/OAuthConstants.ts +0 -57
  216. package/constants/PluginsTestConstants.ts +0 -15
  217. package/constants/ReporterConstants.ts +0 -45
  218. package/constants/TimeoutConstants.ts +0 -113
  219. package/dist/constants/APITestConstants.js.map +0 -1
  220. package/dist/constants/BaseTestConstants.js.map +0 -1
  221. package/dist/constants/ChromeDriverConstants.js +0 -44
  222. package/dist/constants/ChromeDriverConstants.js.map +0 -1
  223. package/dist/constants/FactoryTestConstants.js.map +0 -1
  224. package/dist/constants/MonacoConstants.js.map +0 -1
  225. package/dist/constants/OAuthConstants.js.map +0 -1
  226. package/dist/constants/PluginsTestConstants.js.map +0 -1
  227. package/dist/constants/ReporterConstants.js.map +0 -1
  228. package/dist/constants/TimeoutConstants.js.map +0 -1
  229. package/tslint.json +0 -126
@@ -1,5 +1,5 @@
1
- /*********************************************************************
2
- * Copyright (c) 2019-2023 Red Hat, Inc.
1
+ /** *******************************************************************
2
+ * copyright (c) 2019-2023 Red Hat, Inc.
3
3
  *
4
4
  * This program and the accompanying materials are made
5
5
  * available under the terms of the Eclipse Public License 2.0
@@ -19,150 +19,157 @@ import { Logger } from '../Logger';
19
19
  import axios, { AxiosResponse } from 'axios';
20
20
  import { ITestWorkspaceUtil } from './ITestWorkspaceUtil';
21
21
  import { ApiUrlResolver } from './ApiUrlResolver';
22
- import { TimeoutConstants } from '../../constants/TimeoutConstants';
22
+ import { TIMEOUT_CONSTANTS } from '../../constants/TIMEOUT_CONSTANTS';
23
23
 
24
24
  @injectable()
25
25
  export class TestWorkspaceUtil implements ITestWorkspaceUtil {
26
- readonly polling: number = TimeoutConstants.TS_SELENIUM_DEFAULT_POLLING;
27
- readonly attempts: number = TimeoutConstants.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT / this.polling;
28
-
29
- constructor(
30
- @inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper,
31
- @inject(CLASSES.CheApiRequestHandler) private readonly processRequestHandler: CheApiRequestHandler,
32
- @inject(CLASSES.ApiUrlResolver) private readonly apiUrlResolver: ApiUrlResolver
33
- ) { }
34
-
35
- async waitWorkspaceStatus(workspaceName: string, expectedWorkspaceStatus: WorkspaceStatus): Promise<void> {
36
- Logger.debug();
37
-
38
- let workspaceStatus: string = '';
39
- let expectedStatus: boolean = false;
40
- for (let i: number = 0; i < this.attempts; i++) {
41
- const response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName));
42
-
43
- if (response.status !== 200) {
44
- throw new Error(`Can not get status of a workspace. Code: ${response.status} Data: ${response.data}`);
45
- }
46
-
47
- workspaceStatus = await response.data.status.phase;
48
-
49
- if (workspaceStatus === expectedWorkspaceStatus) {
50
- expectedStatus = true;
51
- break;
52
- }
53
-
54
- await this.driverHelper.wait(this.polling);
55
- }
56
-
57
- if (!expectedStatus) {
58
- let waitTime: number = this.attempts * this.polling;
59
- throw new error.TimeoutError(`The workspace was not stopped in ${waitTime} ms. Current status is: ${workspaceStatus}`);
60
- }
61
- }
62
-
63
- async stopWorkspaceByName(workspaceName: string): Promise<void> {
64
- Logger.debug(`${workspaceName}`);
65
-
66
- const stopWorkspaceApiUrl: string = await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName);
67
- let stopWorkspaceResponse: AxiosResponse;
68
-
69
- try {
70
- stopWorkspaceResponse = await this.processRequestHandler.patch(stopWorkspaceApiUrl, [{
71
- 'op': 'replace',
72
- 'path': '/spec/started',
73
- 'value': false
74
- }]);
75
- } catch (err) {
76
- Logger.error(`stop workspace call failed. URL used: ${stopWorkspaceApiUrl}`);
77
- throw err;
78
- }
79
-
80
- if (stopWorkspaceResponse.status !== 200) {
81
- throw new Error(`Cannot stop workspace. Code: ${stopWorkspaceResponse.status} Data: ${stopWorkspaceResponse.data}`);
82
- }
83
-
84
- await this.waitWorkspaceStatus(workspaceName, WorkspaceStatus.STOPPED);
85
- Logger.debug(`${workspaceName} stopped successfully`);
86
- }
87
-
88
- // delete a workspace without stopping phase (similar with force deleting)
89
- async deleteWorkspaceByName(workspaceName: string): Promise<void> {
90
- Logger.debug(`${workspaceName}`);
91
-
92
- const deleteWorkspaceApiUrl: string = await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName);
93
- let deleteWorkspaceResponse: AxiosResponse;
94
- let deleteWorkspaceStatus: boolean = false;
95
- try {
96
- deleteWorkspaceResponse = await this.processRequestHandler.delete(deleteWorkspaceApiUrl);
97
- } catch (error) {
98
- if (axios.isAxiosError(error) && error.response?.status === 404) {
99
- Logger.error(`the workspace :${workspaceName} not found`);
100
- throw error;
101
- }
102
- Logger.error(`delete workspace call failed. URL used: ${deleteWorkspaceStatus}`);
103
- throw error;
104
- }
105
-
106
- if (deleteWorkspaceResponse.status !== 204) {
107
- throw new Error(`Can not delete workspace. Code: ${deleteWorkspaceResponse.status} Data: ${deleteWorkspaceResponse.data}`);
108
- }
109
-
110
- for (let i: number = 0; i < this.attempts; i++) {
111
- try {
112
- deleteWorkspaceResponse = await this.processRequestHandler.get(deleteWorkspaceApiUrl);
113
- } catch (error) {
114
- if (axios.isAxiosError(error) && error.response?.status === 404) {
115
- deleteWorkspaceStatus = true;
116
- Logger.debug(`${workspaceName} deleted successfully`);
117
- break;
118
- }
119
- }
120
- }
121
-
122
- if (!deleteWorkspaceStatus) {
123
- let waitTime: number = this.attempts * this.polling;
124
- throw new error.TimeoutError(`The workspace was not deleted in ${waitTime} ms.`);
125
- }
126
- }
127
-
128
- // stop workspace before deleting with checking stopping phase
129
- async stopAndDeleteWorkspaceByName(workspaceName: string): Promise<void> {
130
- Logger.debug();
131
-
132
- await this.stopWorkspaceByName(workspaceName);
133
- await this.deleteWorkspaceByName(workspaceName);
134
- }
135
-
136
- // stop all run workspaces in the namespace
137
- async stopAllRunningWorkspaces(namespace: string): Promise<void> {
138
- Logger.debug();
139
- let response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl());
140
- for (let i: number = 0; i < response.data.items.length; i++) {
141
- Logger.info('the project is being stopped: ' + response.data.items[i].metadata.name);
142
- await this.stopWorkspaceByName(response.data.items[i].metadata.name);
143
- }
144
- }
145
-
146
- // stop all run workspaces, check statuses and remove the workspaces
147
- async stopAndDeleteAllRunningWorkspaces(namespace: string): Promise<void> {
148
- Logger.debug();
149
- let response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl());
150
- await this.stopAllRunningWorkspaces(namespace);
151
- for (let i: number = 0; i < response.data.items.length; i++) {
152
- Logger.info('the project is being deleted: ' + response.data.items[i].metadata.name);
153
- await this.deleteWorkspaceByName(response.data.items[i].metadata.name);
154
- }
155
- }
156
-
157
- // stop all run workspaces without stopping and waiting for of 'Stopped' phase
158
- // similar with 'force' deleting
159
- async deleteAllWorkspaces(namespace: string): Promise<void> {
160
- Logger.debug();
161
- let response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl());
162
-
163
- for (let i: number = 0; i < response.data.items.length; i++) {
164
- Logger.info('the project is being deleted .......: ' + response.data.items[i].metadata.name);
165
- await this.deleteWorkspaceByName(response.data.items[i].metadata.name);
166
- }
167
- }
26
+ readonly polling: number = TIMEOUT_CONSTANTS.TS_SELENIUM_DEFAULT_POLLING;
27
+ readonly attempts: number = TIMEOUT_CONSTANTS.TS_DASHBOARD_WORKSPACE_STOP_TIMEOUT / this.polling;
28
+
29
+ constructor(
30
+ @inject(CLASSES.DriverHelper)
31
+ private readonly driverHelper: DriverHelper,
32
+ @inject(CLASSES.CheApiRequestHandler)
33
+ private readonly processRequestHandler: CheApiRequestHandler,
34
+ @inject(CLASSES.ApiUrlResolver)
35
+ private readonly apiUrlResolver: ApiUrlResolver
36
+ ) {}
37
+
38
+ async waitWorkspaceStatus(workspaceName: string, expectedWorkspaceStatus: WorkspaceStatus): Promise<void> {
39
+ Logger.debug();
40
+
41
+ let workspaceStatus: string = '';
42
+ let expectedStatus: boolean = false;
43
+ for (let i: number = 0; i < this.attempts; i++) {
44
+ const response: AxiosResponse = await this.processRequestHandler.get(
45
+ await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName)
46
+ );
47
+
48
+ if (response.status !== 200) {
49
+ throw new Error(`Can not get status of a workspace. Code: ${response.status} Data: ${response.data}`);
50
+ }
51
+
52
+ workspaceStatus = await response.data.status.phase;
53
+
54
+ if (workspaceStatus === expectedWorkspaceStatus) {
55
+ expectedStatus = true;
56
+ break;
57
+ }
58
+
59
+ await this.driverHelper.wait(this.polling);
60
+ }
61
+
62
+ if (!expectedStatus) {
63
+ const waitTime: number = this.attempts * this.polling;
64
+ throw new error.TimeoutError(`The workspace was not stopped in ${waitTime} ms. Current status is: ${workspaceStatus}`);
65
+ }
66
+ }
67
+
68
+ async stopWorkspaceByName(workspaceName: string): Promise<void> {
69
+ Logger.debug(`${workspaceName}`);
70
+
71
+ const stopWorkspaceApiUrl: string = await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName);
72
+ let stopWorkspaceResponse: AxiosResponse;
73
+
74
+ try {
75
+ stopWorkspaceResponse = await this.processRequestHandler.patch(stopWorkspaceApiUrl, [
76
+ {
77
+ op: 'replace',
78
+ path: '/spec/started',
79
+ value: false
80
+ }
81
+ ]);
82
+ } catch (err) {
83
+ Logger.error(`stop workspace call failed. URL used: ${stopWorkspaceApiUrl}`);
84
+ throw err;
85
+ }
86
+
87
+ if (stopWorkspaceResponse.status !== 200) {
88
+ throw new Error(`Cannot stop workspace. Code: ${stopWorkspaceResponse.status} Data: ${stopWorkspaceResponse.data}`);
89
+ }
90
+
91
+ await this.waitWorkspaceStatus(workspaceName, WorkspaceStatus.STOPPED);
92
+ Logger.debug(`${workspaceName} stopped successfully`);
93
+ }
94
+
95
+ // delete a workspace without stopping phase (similar with force deleting)
96
+ async deleteWorkspaceByName(workspaceName: string): Promise<void> {
97
+ Logger.debug(`${workspaceName}`);
98
+
99
+ const deleteWorkspaceApiUrl: string = await this.apiUrlResolver.getWorkspaceApiUrl(workspaceName);
100
+ let deleteWorkspaceResponse: AxiosResponse;
101
+ let deleteWorkspaceStatus: boolean = false;
102
+ try {
103
+ deleteWorkspaceResponse = await this.processRequestHandler.delete(deleteWorkspaceApiUrl);
104
+ } catch (error) {
105
+ if (axios.isAxiosError(error) && error.response?.status === 404) {
106
+ Logger.error(`the workspace :${workspaceName} not found`);
107
+ throw error;
108
+ }
109
+ Logger.error(`delete workspace call failed. URL used: ${deleteWorkspaceStatus}`);
110
+ throw error;
111
+ }
112
+
113
+ if (deleteWorkspaceResponse.status !== 204) {
114
+ throw new Error(`Can not delete workspace. Code: ${deleteWorkspaceResponse.status} Data: ${deleteWorkspaceResponse.data}`);
115
+ }
116
+
117
+ for (let i: number = 0; i < this.attempts; i++) {
118
+ try {
119
+ deleteWorkspaceResponse = await this.processRequestHandler.get(deleteWorkspaceApiUrl);
120
+ } catch (error) {
121
+ if (axios.isAxiosError(error) && error.response?.status === 404) {
122
+ deleteWorkspaceStatus = true;
123
+ Logger.debug(`${workspaceName} deleted successfully`);
124
+ break;
125
+ }
126
+ }
127
+ }
128
+
129
+ if (!deleteWorkspaceStatus) {
130
+ const waitTime: number = this.attempts * this.polling;
131
+ throw new error.TimeoutError(`The workspace was not deleted in ${waitTime} ms.`);
132
+ }
133
+ }
134
+
135
+ // stop workspace before deleting with checking stopping phase
136
+ async stopAndDeleteWorkspaceByName(workspaceName: string): Promise<void> {
137
+ Logger.debug();
138
+
139
+ await this.stopWorkspaceByName(workspaceName);
140
+ await this.deleteWorkspaceByName(workspaceName);
141
+ }
142
+
143
+ // stop all run workspaces in the namespace
144
+ async stopAllRunningWorkspaces(): Promise<void> {
145
+ Logger.debug();
146
+ const response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl());
147
+ for (let i: number = 0; i < response.data.items.length; i++) {
148
+ Logger.info('the project is being stopped: ' + response.data.items[i].metadata.name);
149
+ await this.stopWorkspaceByName(response.data.items[i].metadata.name);
150
+ }
151
+ }
152
+
153
+ // stop all run workspaces, check statuses and remove the workspaces
154
+ async stopAndDeleteAllRunningWorkspaces(): Promise<void> {
155
+ Logger.debug();
156
+ const response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl());
157
+ await this.stopAllRunningWorkspaces();
158
+ for (let i: number = 0; i < response.data.items.length; i++) {
159
+ Logger.info('the project is being deleted: ' + response.data.items[i].metadata.name);
160
+ await this.deleteWorkspaceByName(response.data.items[i].metadata.name);
161
+ }
162
+ }
163
+
164
+ // stop all run workspaces without stopping and waiting for of 'Stopped' phase
165
+ // similar with 'force' deleting
166
+ async deleteAllWorkspaces(): Promise<void> {
167
+ Logger.debug();
168
+ const response: AxiosResponse = await this.processRequestHandler.get(await this.apiUrlResolver.getWorkspacesApiUrl());
169
+
170
+ for (let i: number = 0; i < response.data.items.length; i++) {
171
+ Logger.info('the project is being deleted .......: ' + response.data.items[i].metadata.name);
172
+ await this.deleteWorkspaceByName(response.data.items[i].metadata.name);
173
+ }
174
+ }
168
175
  }
@@ -1,5 +1,5 @@
1
- /*********************************************************************
2
- * Copyright (c) 2019-2023 Red Hat, Inc.
1
+ /** *******************************************************************
2
+ * copyright (c) 2019-2023 Red Hat, Inc.
3
3
  *
4
4
  * This program and the accompanying materials are made
5
5
  * available under the terms of the Eclipse Public License 2.0
@@ -9,7 +9,7 @@
9
9
  **********************************************************************/
10
10
 
11
11
  export enum WorkspaceStatus {
12
- RUNNING = 'Running',
13
- STOPPED = 'Stopped',
14
- STARTING = 'Starting'
12
+ RUNNING = 'Running',
13
+ STOPPED = 'Stopped',
14
+ STARTING = 'Starting'
15
15
  }
@@ -1,57 +0,0 @@
1
- /*********************************************************************
2
- * Copyright (c) 2020-2023 Red Hat, Inc.
3
- *
4
- * This program and the accompanying materials are made
5
- * available under the terms of the Eclipse Public License 2.0
6
- * which is available at https://www.eclipse.org/legal/epl-2.0/
7
- *
8
- * SPDX-License-Identifier: EPL-2.0
9
- **********************************************************************/
10
-
11
- import { BaseTestConstants } from './BaseTestConstants';
12
-
13
- export enum KubernetesCommandLineTool {
14
- OC = 'oc',
15
- KUBECTL = 'kubectl',
16
- }
17
-
18
- export const SupportedDevfilesRegistries: any = {
19
- INBUILT_APPLICATION_DEVFILE_REGISTRY_URL: () => `${BaseTestConstants.TS_SELENIUM_BASE_URL}/devfile-registry/devfiles/`,
20
- GIT_HUB_CHE_DEVFILE_REGISTRY_URL: `https://api.github.com/repos/eclipse-che/che-devfile-registry/contents/devfiles/`
21
- };
22
- export const APITestConstants: any = {
23
- /**
24
- * Possible values "oc" or "kubectl"
25
- */
26
- TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL: process.env.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL || KubernetesCommandLineTool.OC,
27
-
28
- /**
29
- * 'quay.io/devfile/universal-developer-image:latest'
30
- * is default assigned by DevWorkspaceConfigurationHelper.generateDevfileContext() using @eclipse-che/che-devworkspace-generator
31
- */
32
- TS_API_TEST_UDI_IMAGE: process.env.TS_API_TEST_UDI_IMAGE || undefined,
33
-
34
- /**
35
- * https://eclipse-che.github.io/che-plugin-registry/main/v3/plugins/che-incubator/che-code/latest/devfile.yaml
36
- * is default assigned by DevWorkspaceConfigurationHelper.generateDevfileContext() using @eclipse-che/che-devworkspace-generator
37
- */
38
- TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI: process.env.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI || undefined,
39
-
40
- /**
41
- * https://eclipse-che.github.io/che-plugin-registry/main/v3
42
- * is default assigned by DevWorkspaceConfigurationHelper.generateDevfileContext() using @eclipse-che/che-devworkspace-generator
43
- */
44
- TS_API_TEST_PLUGIN_REGISTRY_URL: process.env.TS_API_TEST_PLUGIN_REGISTRY_URL || undefined,
45
-
46
- /**
47
- * Namespace on openshift platform
48
- */
49
- TS_API_TEST_NAMESPACE: process.env.TS_API_TEST_NAMESPACE || undefined,
50
-
51
- /**
52
- * to run all devfile from registry. used in DevfileAcceptanceTestAPI.suite.ts
53
- */
54
- TS_API_ACCEPTANCE_TEST_REGISTRY_URL(): string {
55
- return process.env.TS_API_ACCEPTANCE_TEST_REGISTRY_URL || SupportedDevfilesRegistries.INBUILT_APPLICATION_DEVFILE_REGISTRY_URL();
56
- }
57
- };
@@ -1,68 +0,0 @@
1
- /*********************************************************************
2
- * Copyright (c) 2020-2023 Red Hat, Inc.
3
- *
4
- * This program and the accompanying materials are made
5
- * available under the terms of the Eclipse Public License 2.0
6
- * which is available at https://www.eclipse.org/legal/epl-2.0/
7
- *
8
- * SPDX-License-Identifier: EPL-2.0
9
- **********************************************************************/
10
- export enum Platform {
11
- OPENSHIFT = 'openshift',
12
- KUBERNETES = 'kubernetes',
13
- }
14
-
15
- export const BaseTestConstants: any = {
16
- /**
17
- * Base URL of the application which should be checked
18
- */
19
- TS_SELENIUM_BASE_URL: !process.env.TS_SELENIUM_BASE_URL ? 'http://sample-url' : process.env.TS_SELENIUM_BASE_URL.replace(/\/$/, ''),
20
-
21
- IS_CLUSTER_DISCONNECTED: () => BaseTestConstants.TS_SELENIUM_BASE_URL.includes('airgap'),
22
-
23
- /**
24
- * Choose the platform where "che" application deployed, "openshift" by default.
25
- */
26
- TS_PLATFORM: process.env.TS_PLATFORM || Platform.OPENSHIFT,
27
-
28
- /**
29
- * Editor the tests are running against, "code" by default.
30
- * Possible values: "che-code"
31
- */
32
- TS_SELENIUM_EDITOR: process.env.TS_SELENIUM_EDITOR || 'che-code',
33
-
34
- /**
35
- * File name to check if project was imported
36
- */
37
- TS_SELENIUM_PROJECT_ROOT_FILE_NAME: process.env.TS_SELENIUM_PROJECT_ROOT_FILE_NAME || 'devfile.yaml',
38
-
39
- /**
40
- * Name of workspace created for 'Happy Path' scenario validation.
41
- */
42
- TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME: process.env.TS_SELENIUM_HAPPY_PATH_WORKSPACE_NAME || 'EmptyWorkspace',
43
-
44
- /**
45
- * This variable specifies that run test is used for load testing and that all artifacts will be sent to ftp client.
46
- */
47
- TS_LOAD_TESTS: process.env.TS_LOAD_TESTS || 'false',
48
-
49
- /**
50
- * Enable Axios request interceptor, false by default
51
- */
52
- TS_SELENIUM_REQUEST_INTERCEPTOR: process.env.TS_SELENIUM_REQUEST_INTERCEPTOR === 'true',
53
-
54
- /**
55
- * Enable Axios response interceptor, false by default
56
- */
57
- TS_SELENIUM_RESPONSE_INTERCEPTOR: process.env.TS_SELENIUM_RESPONSE_INTERCEPTOR === 'true',
58
-
59
- /**
60
- * Stop and remove workspace if a test fails.
61
- */
62
- DELETE_WORKSPACE_ON_FAILED_TEST: process.env.DELETE_WORKSPACE_ON_FAILED_TEST === 'true',
63
-
64
- /**
65
- * Constant, which prolong timeout constants for local debug.
66
- */
67
- TS_DEBUG_MODE: process.env.TS_DEBUG_MODE === 'true'
68
- };
@@ -1,46 +0,0 @@
1
- /*********************************************************************
2
- * Copyright (c) 2020-2023 Red Hat, Inc.
3
- *
4
- * This program and the accompanying materials are made
5
- * available under the terms of the Eclipse Public License 2.0
6
- * which is available at https://www.eclipse.org/legal/epl-2.0/
7
- *
8
- * SPDX-License-Identifier: EPL-2.0
9
- **********************************************************************/
10
- export const ChromeDriverConstants: any = {
11
- /**
12
- * Remote driver URL.
13
- */
14
- TS_SELENIUM_REMOTE_DRIVER_URL: process.env.TS_SELENIUM_REMOTE_DRIVER_URL || '',
15
-
16
- /**
17
- * Run browser in "Headless" (hidden) mode, "false" by default.
18
- */
19
- TS_SELENIUM_HEADLESS: process.env.TS_SELENIUM_HEADLESS === 'true',
20
-
21
- /**
22
- * Create instance of chromedriver, "true" by default. Should be "false" to run only API tests.
23
- */
24
- TS_USE_WEB_DRIVER_FOR_TEST: process.env.TS_USE_WEB_DRIVER_FOR_TEST !== 'false',
25
-
26
- /**
27
- * Run browser in "Fullscreen" (kiosk) mode.
28
- * Default to true if undefined
29
- */
30
- TS_SELENIUM_LAUNCH_FULLSCREEN: (process.env.TS_SELENIUM_LAUNCH_FULLSCREEN !== 'false'),
31
-
32
- /**
33
- * Run browser with an enabled or disabled W3C protocol (on Chrome 76 and upper, it is enabled by default), "true" by default.
34
- */
35
- TS_SELENIUM_W3C_CHROME_OPTION: process.env.TS_SELENIUM_W3C_CHROME_OPTION !== 'false',
36
-
37
- /**
38
- * Browser width resolution, "1920" by default.
39
- */
40
- TS_SELENIUM_RESOLUTION_WIDTH: Number(process.env.TS_SELENIUM_RESOLUTION_WIDTH) || 1920,
41
-
42
- /**
43
- * Browser height resolution, "1080" by default.
44
- */
45
- TS_SELENIUM_RESOLUTION_HEIGHT: Number(process.env.TS_SELENIUM_RESOLUTION_HEIGHT) || 1080
46
- };
@@ -1,51 +0,0 @@
1
- /*********************************************************************
2
- * Copyright (c) 2020-2023 Red Hat, Inc.
3
- *
4
- * This program and the accompanying materials are made
5
- * available under the terms of the Eclipse Public License 2.0
6
- * which is available at https://www.eclipse.org/legal/epl-2.0/
7
- *
8
- * SPDX-License-Identifier: EPL-2.0
9
- **********************************************************************/
10
- import { BaseTestConstants } from './BaseTestConstants';
11
-
12
- export enum GitProviderType {
13
- GITHUB = 'github',
14
- GITLAB = 'gitlab',
15
- BITBUCKET = 'bitbucket',
16
- AZURE_DEVOPS = 'azure-devops'
17
- }
18
-
19
- export const FactoryTestConstants: any = {
20
- /**
21
- * Git provider to check in factory tests
22
- */
23
- TS_SELENIUM_FACTORY_GIT_PROVIDER: process.env.TS_SELENIUM_FACTORY_GIT_PROVIDER || GitProviderType.GITHUB,
24
-
25
- /**
26
- * URL to create factory
27
- */
28
- TS_SELENIUM_FACTORY_GIT_REPO_URL: process.env.TS_SELENIUM_FACTORY_GIT_REPO_URL || '',
29
-
30
- /**
31
- * Git repository name
32
- */
33
- TS_SELENIUM_PROJECT_NAME: process.env.TS_SELENIUM_PROJECT_NAME || '',
34
-
35
- /**
36
- * Is factory repository URL private or no
37
- */
38
- TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO: process.env.TS_SELENIUM_IS_PRIVATE_FACTORY_GIT_REPO === 'true',
39
-
40
- /**
41
- * Git repository main branch name (main or master)
42
- */
43
- TS_SELENIUM_FACTORY_GIT_REPO_BRANCH: process.env.TS_SELENIUM_FACTORY_GIT_REPO_BRANCH || 'master',
44
-
45
- /**
46
- * Full factory URL
47
- */
48
- TS_SELENIUM_FACTORY_URL(): string {
49
- return process.env.TS_SELENIUM_FACTORY_URL || BaseTestConstants.TS_SELENIUM_BASE_URL + '/dashboard/#/' + this.TS_SELENIUM_FACTORY_GIT_REPO_URL;
50
- }
51
- };
@@ -1,22 +0,0 @@
1
- /*********************************************************************
2
- * Copyright (c) 2020-2023 Red Hat, Inc.
3
- *
4
- * This program and the accompanying materials are made
5
- * available under the terms of the Eclipse Public License 2.0
6
- * which is available at https://www.eclipse.org/legal/epl-2.0/
7
- *
8
- * SPDX-License-Identifier: EPL-2.0
9
- **********************************************************************/
10
- export const MonacoConstants: any = {
11
- /**
12
- * Base version of VSCode editor for monaco-page-objects, "1.37.0" by default.
13
- */
14
- TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION: process.env.TS_SELENIUM_MONACO_PAGE_OBJECTS_BASE_VERSION || '1.37.0',
15
-
16
- /**
17
- * Latest compatible version to be used, based on versions available in
18
- * https://github.com/redhat-developer/vscode-extension-tester/tree/master/locators/lib ,
19
- * "1.73.0" by default.
20
- */
21
- TS_SELENIUM_MONACO_PAGE_OBJECTS_USE_VERSION: process.env.TS_SELENIUM_MONACO_PAGE_OBJECTS_USE_VERSION || '1.73.0'
22
- };
@@ -1,57 +0,0 @@
1
- /*********************************************************************
2
- * Copyright (c) 2020-2023 Red Hat, Inc.
3
- *
4
- * This program and the accompanying materials are made
5
- * available under the terms of the Eclipse Public License 2.0
6
- * which is available at https://www.eclipse.org/legal/epl-2.0/
7
- *
8
- * SPDX-License-Identifier: EPL-2.0
9
- **********************************************************************/
10
- export const OAuthConstants: any = {
11
- /**
12
- * Value of OpenShift oAuth property determines how to login in installed application,
13
- * if 'false' as an user of application, if 'true' as a regular user of OCP.
14
- */
15
- TS_SELENIUM_VALUE_OPENSHIFT_OAUTH: process.env.TS_SELENIUM_VALUE_OPENSHIFT_OAUTH === 'true',
16
-
17
- /**
18
- * Log into OCP by using appropriate provider title.
19
- */
20
- TS_OCP_LOGIN_PAGE_PROVIDER_TITLE: process.env.TS_OCP_LOGIN_PAGE_PROVIDER_TITLE || '',
21
-
22
- /**
23
- * Regular username used to login in OCP.
24
- */
25
- TS_SELENIUM_OCP_USERNAME: process.env.TS_SELENIUM_OCP_USERNAME || '',
26
-
27
- /**
28
- * Password regular user used to login in OCP.
29
- */
30
- TS_SELENIUM_OCP_PASSWORD: process.env.TS_SELENIUM_OCP_PASSWORD || '',
31
-
32
- /**
33
- * Regular username used to login in Kubernetes.
34
- */
35
- TS_SELENIUM_K8S_USERNAME: process.env.TS_SELENIUM_K8S_USERNAME || '',
36
-
37
- /**
38
- * Password regular user used to login in Kubernetes.
39
- */
40
- TS_SELENIUM_K8S_PASSWORD: process.env.TS_SELENIUM_K8S_PASSWORD || '',
41
-
42
- /**
43
- * For login via github for example on https://che-dogfooding.apps.che-dev.x6e0.p1.openshiftapps.com
44
- * For factory tests
45
- */
46
- TS_SELENIUM_GIT_PROVIDER_OAUTH: process.env.TS_SELENIUM_GIT_PROVIDER_OAUTH === 'true',
47
-
48
- /**
49
- * Git repository username
50
- */
51
- TS_SELENIUM_GIT_PROVIDER_USERNAME: process.env.TS_SELENIUM_GIT_PROVIDER_USERNAME || '',
52
-
53
- /**
54
- * Git repository password
55
- */
56
- TS_SELENIUM_GIT_PROVIDER_PASSWORD: process.env.TS_SELENIUM_GIT_PROVIDER_PASSWORD || ''
57
- };
@@ -1,15 +0,0 @@
1
- /*********************************************************************
2
- * Copyright (c) 2020-2023 Red Hat, Inc.
3
- *
4
- * This program and the accompanying materials are made
5
- * available under the terms of the Eclipse Public License 2.0
6
- * which is available at https://www.eclipse.org/legal/epl-2.0/
7
- *
8
- * SPDX-License-Identifier: EPL-2.0
9
- **********************************************************************/
10
- export const PluginsTestConstants: any = {
11
- /**
12
- * Dashboard samples to check in RecommendedExtensions.spec.ts
13
- */
14
- TS_SAMPLE_LIST: process.env.TS_SAMPLE_LIST || 'Node.js MongoDB,Node.js Express',
15
- };