@playq/core 0.2.77

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 (225) hide show
  1. package/README.md +41 -0
  2. package/bin/playq.js +175 -0
  3. package/cucumber.js +10 -0
  4. package/dist/exec/featureFileCache.d.ts +21 -0
  5. package/dist/exec/featureFileCache.js +124 -0
  6. package/dist/exec/featureFilePreProcess.d.ts +12 -0
  7. package/dist/exec/featureFilePreProcess.js +208 -0
  8. package/dist/exec/preLoader.d.ts +1 -0
  9. package/dist/exec/preLoader.js +72 -0
  10. package/dist/exec/preProcessEntry.d.ts +1 -0
  11. package/dist/exec/preProcessEntry.js +83 -0
  12. package/dist/exec/preProcess_old_todelete.d.ts +1 -0
  13. package/dist/exec/preProcess_old_todelete.js +258 -0
  14. package/dist/exec/runner.d.ts +1 -0
  15. package/dist/exec/runner.js +221 -0
  16. package/dist/exec/runner_orchestrator.d.ts +1 -0
  17. package/dist/exec/runner_orchestrator.js +85 -0
  18. package/dist/exec/sgGenerator.d.ts +11 -0
  19. package/dist/exec/sgGenerator.js +310 -0
  20. package/dist/global.d.ts +15 -0
  21. package/dist/global.js +185 -0
  22. package/dist/helper/actions/api/apiRequestActions.d.ts +117 -0
  23. package/dist/helper/actions/api/apiRequestActions.js +374 -0
  24. package/dist/helper/actions/api/apiValidationActions.d.ts +119 -0
  25. package/dist/helper/actions/api/apiValidationActions.js +615 -0
  26. package/dist/helper/actions/apiActions.d.ts +18 -0
  27. package/dist/helper/actions/apiActions.js +34 -0
  28. package/dist/helper/actions/apiStepDefs.d.ts +1 -0
  29. package/dist/helper/actions/apiStepDefs.js +64 -0
  30. package/dist/helper/actions/comm/commonActions.d.ts +58 -0
  31. package/dist/helper/actions/comm/commonActions.js +198 -0
  32. package/dist/helper/actions/comm/utilityActions.d.ts +131 -0
  33. package/dist/helper/actions/comm/utilityActions.js +351 -0
  34. package/dist/helper/actions/commActions.d.ts +18 -0
  35. package/dist/helper/actions/commActions.js +34 -0
  36. package/dist/helper/actions/commStepDefs.d.ts +1 -0
  37. package/dist/helper/actions/commStepDefs.js +57 -0
  38. package/dist/helper/actions/stepGroupStepDefs.d.ts +1 -0
  39. package/dist/helper/actions/stepGroupStepDefs.js +15 -0
  40. package/dist/helper/actions/web/alertActions.d.ts +61 -0
  41. package/dist/helper/actions/web/alertActions.js +224 -0
  42. package/dist/helper/actions/web/cookieActions.d.ts +45 -0
  43. package/dist/helper/actions/web/cookieActions.js +186 -0
  44. package/dist/helper/actions/web/downloadActions.d.ts +40 -0
  45. package/dist/helper/actions/web/downloadActions.js +153 -0
  46. package/dist/helper/actions/web/elementReaderActions.d.ts +95 -0
  47. package/dist/helper/actions/web/elementReaderActions.js +326 -0
  48. package/dist/helper/actions/web/formActions.d.ts +122 -0
  49. package/dist/helper/actions/web/formActions.js +423 -0
  50. package/dist/helper/actions/web/iframeActions.d.ts +23 -0
  51. package/dist/helper/actions/web/iframeActions.js +108 -0
  52. package/dist/helper/actions/web/javascriptActions.d.ts +14 -0
  53. package/dist/helper/actions/web/javascriptActions.js +77 -0
  54. package/dist/helper/actions/web/keyboardActions.d.ts +35 -0
  55. package/dist/helper/actions/web/keyboardActions.js +118 -0
  56. package/dist/helper/actions/web/localStorageActions.d.ts +51 -0
  57. package/dist/helper/actions/web/localStorageActions.js +163 -0
  58. package/dist/helper/actions/web/mouseActions.d.ts +240 -0
  59. package/dist/helper/actions/web/mouseActions.js +609 -0
  60. package/dist/helper/actions/web/reportingActions.d.ts +34 -0
  61. package/dist/helper/actions/web/reportingActions.js +58 -0
  62. package/dist/helper/actions/web/screenshotActions.d.ts +34 -0
  63. package/dist/helper/actions/web/screenshotActions.js +151 -0
  64. package/dist/helper/actions/web/testDataActions.d.ts +21 -0
  65. package/dist/helper/actions/web/testDataActions.js +211 -0
  66. package/dist/helper/actions/web/validationActions.d.ts +547 -0
  67. package/dist/helper/actions/web/validationActions.js +1754 -0
  68. package/dist/helper/actions/web/waitActions.d.ts +191 -0
  69. package/dist/helper/actions/web/waitActions.js +589 -0
  70. package/dist/helper/actions/web/webNavigation.d.ts +104 -0
  71. package/dist/helper/actions/web/webNavigation.js +288 -0
  72. package/dist/helper/actions/webActions.d.ts +32 -0
  73. package/dist/helper/actions/webActions.js +48 -0
  74. package/dist/helper/actions/webStepDefs.d.ts +1 -0
  75. package/dist/helper/actions/webStepDefs.js +455 -0
  76. package/dist/helper/browsers/browserManager.d.ts +1 -0
  77. package/dist/helper/browsers/browserManager.js +56 -0
  78. package/dist/helper/bundle/defaultEntries.d.ts +6 -0
  79. package/dist/helper/bundle/defaultEntries.js +200 -0
  80. package/dist/helper/bundle/env.d.ts +1 -0
  81. package/dist/helper/bundle/env.js +157 -0
  82. package/dist/helper/bundle/vars.d.ts +9 -0
  83. package/dist/helper/bundle/vars.js +375 -0
  84. package/dist/helper/faker/customFaker.d.ts +55 -0
  85. package/dist/helper/faker/customFaker.js +45 -0
  86. package/dist/helper/faker/modules/data/postcodes_valid_sg.json +17 -0
  87. package/dist/helper/faker/modules/dateTime.d.ts +18 -0
  88. package/dist/helper/faker/modules/dateTime.js +106 -0
  89. package/dist/helper/faker/modules/mobile.d.ts +4 -0
  90. package/dist/helper/faker/modules/mobile.js +59 -0
  91. package/dist/helper/faker/modules/nric.d.ts +32 -0
  92. package/dist/helper/faker/modules/nric.js +84 -0
  93. package/dist/helper/faker/modules/passport.d.ts +3 -0
  94. package/dist/helper/faker/modules/passport.js +36 -0
  95. package/dist/helper/faker/modules/person.d.ts +14 -0
  96. package/dist/helper/faker/modules/person.js +73 -0
  97. package/dist/helper/faker/modules/postcode.d.ts +6 -0
  98. package/dist/helper/faker/modules/postcode.js +47 -0
  99. package/dist/helper/fixtures/locAggregate.d.ts +7 -0
  100. package/dist/helper/fixtures/locAggregate.js +94 -0
  101. package/dist/helper/fixtures/logFixture.d.ts +8 -0
  102. package/dist/helper/fixtures/logFixture.js +56 -0
  103. package/dist/helper/fixtures/webFixture.d.ts +19 -0
  104. package/dist/helper/fixtures/webFixture.js +186 -0
  105. package/dist/helper/fixtures/webLocFixture.d.ts +2 -0
  106. package/dist/helper/fixtures/webLocFixture.js +144 -0
  107. package/dist/helper/report/allureStepLogger.d.ts +0 -0
  108. package/dist/helper/report/allureStepLogger.js +25 -0
  109. package/dist/helper/report/customiseReport.d.ts +1 -0
  110. package/dist/helper/report/customiseReport.js +55 -0
  111. package/dist/helper/report/init.d.ts +1 -0
  112. package/dist/helper/report/init.js +14 -0
  113. package/dist/helper/report/report.d.ts +1 -0
  114. package/dist/helper/report/report.js +102 -0
  115. package/dist/helper/util/dataLoader.d.ts +10 -0
  116. package/dist/helper/util/dataLoader.js +73 -0
  117. package/dist/helper/util/logger.d.ts +4 -0
  118. package/dist/helper/util/logger.js +61 -0
  119. package/dist/helper/util/session/sessionUtil.d.ts +26 -0
  120. package/dist/helper/util/session/sessionUtil.js +729 -0
  121. package/dist/helper/util/stepHelpers.d.ts +2 -0
  122. package/dist/helper/util/stepHelpers.js +16 -0
  123. package/dist/helper/util/test-data/dataLoader.d.ts +7 -0
  124. package/dist/helper/util/test-data/dataLoader.js +145 -0
  125. package/dist/helper/util/test-data/dataTest.d.ts +10 -0
  126. package/dist/helper/util/test-data/dataTest.js +216 -0
  127. package/dist/helper/util/totp/totpHelper.d.ts +38 -0
  128. package/dist/helper/util/totp/totpHelper.js +117 -0
  129. package/dist/helper/util/utilities/cryptoUtil.d.ts +2 -0
  130. package/dist/helper/util/utilities/cryptoUtil.js +53 -0
  131. package/dist/helper/util/utilities/schemaGeneratorUtil.d.ts +2 -0
  132. package/dist/helper/util/utilities/schemaGeneratorUtil.js +129 -0
  133. package/dist/helper/util/utils.d.ts +2 -0
  134. package/dist/helper/util/utils.js +22 -0
  135. package/dist/helper/wrapper/PlaywrightWrappers.d.ts +8 -0
  136. package/dist/helper/wrapper/PlaywrightWrappers.js +26 -0
  137. package/dist/helper/wrapper/assert.d.ts +9 -0
  138. package/dist/helper/wrapper/assert.js +23 -0
  139. package/dist/index.d.ts +7 -0
  140. package/dist/index.js +57 -0
  141. package/dist/scripts/get-versions.d.ts +1 -0
  142. package/dist/scripts/get-versions.js +98 -0
  143. package/dist/scripts/posttest.d.ts +1 -0
  144. package/dist/scripts/posttest.js +29 -0
  145. package/dist/scripts/pretest.d.ts +1 -0
  146. package/dist/scripts/pretest.js +57 -0
  147. package/dist/scripts/util.d.ts +1 -0
  148. package/dist/scripts/util.js +376 -0
  149. package/package.json +68 -0
  150. package/src/exec/featureFileCache.ts +80 -0
  151. package/src/exec/featureFilePreProcess.ts +239 -0
  152. package/src/exec/preLoader.ts +72 -0
  153. package/src/exec/preProcessEntry.ts +59 -0
  154. package/src/exec/preProcess_old_todelete.ts +289 -0
  155. package/src/exec/runner.ts +241 -0
  156. package/src/exec/runnerCuke.js +90 -0
  157. package/src/exec/runner_orchestrator.ts +91 -0
  158. package/src/exec/sgGenerator.ts +373 -0
  159. package/src/global.ts +130 -0
  160. package/src/helper/actions/api/apiRequestActions.ts +362 -0
  161. package/src/helper/actions/api/apiValidationActions.ts +594 -0
  162. package/src/helper/actions/apiActions.ts +18 -0
  163. package/src/helper/actions/apiStepDefs.ts +80 -0
  164. package/src/helper/actions/comm/commonActions.ts +165 -0
  165. package/src/helper/actions/comm/utilityActions.ts +344 -0
  166. package/src/helper/actions/commActions.ts +18 -0
  167. package/src/helper/actions/commStepDefs.ts +72 -0
  168. package/src/helper/actions/stepGroupStepDefs.ts +17 -0
  169. package/src/helper/actions/web/alertActions.ts +179 -0
  170. package/src/helper/actions/web/cookieActions.ts +124 -0
  171. package/src/helper/actions/web/downloadActions.ts +129 -0
  172. package/src/helper/actions/web/elementReaderActions.ts +323 -0
  173. package/src/helper/actions/web/formActions.ts +469 -0
  174. package/src/helper/actions/web/iframeActions.ts +67 -0
  175. package/src/helper/actions/web/javascriptActions.ts +38 -0
  176. package/src/helper/actions/web/keyboardActions.ts +101 -0
  177. package/src/helper/actions/web/localStorageActions.ts +109 -0
  178. package/src/helper/actions/web/mouseActions.ts +864 -0
  179. package/src/helper/actions/web/reportingActions.ts +53 -0
  180. package/src/helper/actions/web/screenshotActions.ts +124 -0
  181. package/src/helper/actions/web/testDataActions.ts +162 -0
  182. package/src/helper/actions/web/validationActions.ts +2287 -0
  183. package/src/helper/actions/web/waitActions.ts +757 -0
  184. package/src/helper/actions/web/webNavigation.ts +313 -0
  185. package/src/helper/actions/webActions.ts +33 -0
  186. package/src/helper/actions/webStepDefs.ts +505 -0
  187. package/src/helper/browsers/browserManager.ts +23 -0
  188. package/src/helper/bundle/defaultEntries.ts +208 -0
  189. package/src/helper/bundle/env.ts +119 -0
  190. package/src/helper/bundle/vars.ts +368 -0
  191. package/src/helper/faker/customFaker.ts +107 -0
  192. package/src/helper/faker/modules/data/postcodes_valid_sg.json +17 -0
  193. package/src/helper/faker/modules/dateTime.ts +121 -0
  194. package/src/helper/faker/modules/mobile.ts +58 -0
  195. package/src/helper/faker/modules/nric.ts +109 -0
  196. package/src/helper/faker/modules/passport.ts +34 -0
  197. package/src/helper/faker/modules/person.ts +93 -0
  198. package/src/helper/faker/modules/postcode.ts +57 -0
  199. package/src/helper/fixtures/locAggregate.ts +61 -0
  200. package/src/helper/fixtures/logFixture.ts +57 -0
  201. package/src/helper/fixtures/webFixture.ts +206 -0
  202. package/src/helper/fixtures/webLocFixture.ts +143 -0
  203. package/src/helper/report/allureStepLogger.ts +26 -0
  204. package/src/helper/report/customiseReport.ts +61 -0
  205. package/src/helper/report/init.ts +18 -0
  206. package/src/helper/report/report.ts +72 -0
  207. package/src/helper/util/dataLoader.ts +42 -0
  208. package/src/helper/util/logger.ts +32 -0
  209. package/src/helper/util/session/sessionUtil.ts +839 -0
  210. package/src/helper/util/stepHelpers.ts +14 -0
  211. package/src/helper/util/test-data/dataLoader.ts +108 -0
  212. package/src/helper/util/test-data/dataTest.ts +191 -0
  213. package/src/helper/util/test-data/registerUser.json +7 -0
  214. package/src/helper/util/totp/totpHelper.ts +102 -0
  215. package/src/helper/util/utilities/cryptoUtil.ts +53 -0
  216. package/src/helper/util/utilities/schemaGeneratorUtil.ts +143 -0
  217. package/src/helper/util/utils.ts +28 -0
  218. package/src/helper/wrapper/PlaywrightWrappers.ts +28 -0
  219. package/src/helper/wrapper/assert.ts +25 -0
  220. package/src/index.ts +17 -0
  221. package/src/scripts/get-versions.ts +68 -0
  222. package/src/scripts/posttest.ts +32 -0
  223. package/src/scripts/pretest.ts +48 -0
  224. package/src/scripts/util.ts +406 -0
  225. package/tsconfig.json +30 -0
@@ -0,0 +1,208 @@
1
+ export default [
2
+ // baseUrl
3
+ {
4
+ "name": "config.baseUrl",
5
+ "value": "https://your-app.com",
6
+ "description": "Base URL for the application",
7
+ },
8
+
9
+ // cucumber
10
+ {
11
+ "name": "config.cucumber.featureFileCache",
12
+ "value": "false",
13
+ "description": "Cache feature files for faster execution",
14
+ },
15
+ {
16
+ "name": "config.cucumber.stepGroupCache",
17
+ "value": "true",
18
+ "description": "Cache step groups during execution",
19
+ },
20
+
21
+ // browser
22
+ {
23
+ "name": "config.browser.playwrightSession",
24
+ "value": "shared",
25
+ "description": "Playwright browser session control",
26
+ },
27
+ {
28
+ "name": "config.browser.cucumberSession",
29
+ "value": "perScenario",
30
+ "description": "Cucumber browser session control",
31
+ },
32
+ {
33
+ "name": "config.browser.headless",
34
+ "value": "true",
35
+ "description": "Run browser in headless mode",
36
+ },
37
+ {
38
+ "name": "config.browser.browserType",
39
+ "value": "chromium",
40
+ "description": "Browser type: chromium, firefox or webkit",
41
+ },
42
+
43
+ // artifacts
44
+ {
45
+ "name": "config.artifacts.screenshot",
46
+ "value": "true",
47
+ "description": "Capture screenshots",
48
+ },
49
+ {
50
+ "name": "config.artifacts.video",
51
+ "value": "true",
52
+ "description": "Capture videos",
53
+ },
54
+ {
55
+ "name": "config.artifacts.trace",
56
+ "value": "true",
57
+ "description": "Capture Playwright traces",
58
+ },
59
+ {
60
+ "name": "config.artifacts.onFailureOnly",
61
+ "value": "true",
62
+ "description": "Capture artifacts only on failure",
63
+ },
64
+ {
65
+ "name": "config.artifacts.onSuccessOnly",
66
+ "value": "false",
67
+ "description": "Capture artifacts only on success",
68
+ },
69
+ {
70
+ "name": "config.artifacts.cleanUpBeforeRun",
71
+ "value": "true",
72
+ "description": "Clean up artifacts before run",
73
+ },
74
+
75
+ // testExecution
76
+ {
77
+ "name": "config.testExecution.timeout",
78
+ "value": "80000",
79
+ "description": "Test execution timeout",
80
+ },
81
+ {
82
+ "name": "config.testExecution.actionTimeout",
83
+ "value": "10000",
84
+ "description": "Action timeout in milliseconds",
85
+ },
86
+ {
87
+ "name": "config.testExecution.navigationTimeout",
88
+ "value": "20000",
89
+ "description": "Navigation timeout in milliseconds",
90
+ },
91
+ {
92
+ "name": "config.testExecution.retryOnFailure",
93
+ "value": "true",
94
+ "description": "Retry tests on failure",
95
+ },
96
+ {
97
+ "name": "config.testExecution.parallel",
98
+ "value": "true",
99
+ "description": "Run tests in parallel",
100
+ },
101
+ {
102
+ "name": "config.testExecution.maxInstances",
103
+ "value": "5",
104
+ "description": "Maximum parallel test instances",
105
+ },
106
+ {
107
+ "name": "config.testExecution.maxRetries",
108
+ "value": "2",
109
+ "description": "Maximum number of retries",
110
+ },
111
+ {
112
+ "name": "config.testExecution.retryDelay",
113
+ "value": "1000",
114
+ "description": "Delay between retries in milliseconds",
115
+ },
116
+ {
117
+ "name": "config.testExecution.retryInterval",
118
+ "value": "2000",
119
+ "description": "Interval between retries in milliseconds",
120
+ },
121
+ {
122
+ "name": "config.testExecution.retryTimeout",
123
+ "value": "30000",
124
+ "description": "Total retry timeout in milliseconds",
125
+ },
126
+ {
127
+ "name": "config.testExecution.order",
128
+ "value": "sequential",
129
+ "description": "Test execution order",
130
+ },
131
+
132
+ // apiTest
133
+ {
134
+ "name": "config.apiTest.maxUrlRedirects",
135
+ "value": "5",
136
+ "description": "Maximum number of URL redirects",
137
+ },
138
+ {
139
+ "name": "config.apiTest.timeout",
140
+ "value": "10000",
141
+ "description": "API request timeout in milliseconds",
142
+ },
143
+
144
+ // patternIq
145
+ {
146
+ "name": "config.patternIq.enable",
147
+ "value": "false",
148
+ "description": "Enable PatternIQ",
149
+ },
150
+ {
151
+ "name": "config.patternIq.config",
152
+ "value": "default",
153
+ "description": "PatternIQ configuration source",
154
+ },
155
+ {
156
+ "name": "config.patternIq.retryInterval",
157
+ "value": "2000",
158
+ "description": "PatternIQ retry interval in milliseconds",
159
+ },
160
+ {
161
+ "name": "config.patternIq.retryTimeout",
162
+ "value": "30000",
163
+ "description": "PatternIQ total retry timeout in milliseconds",
164
+ },
165
+
166
+ // smartAi
167
+ {
168
+ "name": "config.smartAi.enable",
169
+ "value": "false",
170
+ "description": "Enable SmartAI",
171
+ },
172
+ {
173
+ "name": "config.smartAi.consoleLog",
174
+ "value": "true",
175
+ "description": "Log SmartAI actions to console",
176
+ },
177
+ {
178
+ "name": "config.smartAi.resolve",
179
+ "value": "smart",
180
+ "description": "SmartAI resolution mode",
181
+ },
182
+
183
+
184
+ // report
185
+ {
186
+ "name": "report.allure.singleFile",
187
+ "value": "false",
188
+ "description": "Enable Allure single file report",
189
+ },
190
+ // featureFlags
191
+ {
192
+ "name": "config.featureFlags.enableBetaUI",
193
+ "value": "true",
194
+ "description": "Enable Beta UI",
195
+ },
196
+ {
197
+ "name": "config.featureFlags.useMockBackend",
198
+ "value": "false",
199
+ "description": "Use mock backend",
200
+ },
201
+
202
+ // supportedLanguages
203
+ {
204
+ "name": "config.supportedLanguages",
205
+ "value": "en,fr,es",
206
+ "description": "Supported languages",
207
+ },
208
+ ];
@@ -0,0 +1,119 @@
1
+ import * as dotenv from 'dotenv';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+
5
+ export const loadEnv = (env?: string) => {
6
+ // Setting PlayQ Project Root
7
+ if (!process.env['PLAYQ_PROJECT_ROOT']) {
8
+ process.env['PLAYQ_PROJECT_ROOT'] = findProjectRoot();
9
+ }
10
+ // Setting PlayQ Core Root
11
+ process.env['PLAYQ_CORE_ROOT'] = path.resolve(process.env['PLAYQ_PROJECT_ROOT'], 'src');
12
+ // Setting PlayQ Defaults
13
+ if(!process.env.PLAYQ_REPORT_OPEN) process.env.PLAYQ_REPORT_OPEN = 'true';
14
+
15
+ // Setting PlayQ Runner
16
+ if (process.env.PLAYQ_RUNNER && ['bdd', 'cuke', 'cucumber'].includes(process.env.PLAYQ_RUNNER.trim())) {
17
+ process.env.PLAYQ_RUNNER = 'cucumber';
18
+ } else {
19
+ process.env.PLAYQ_RUNNER = 'playwright';
20
+ }
21
+
22
+ let envPath;
23
+ let playqEnvMem = undefined
24
+ let playqRunnerMem = process.env['PLAYQ_RUNNER']
25
+ if (process.env['PLAYQ_ENV']) playqEnvMem = process.env['PLAYQ_ENV']
26
+
27
+
28
+ if (env) {
29
+ envPath = path.resolve(process.env.PLAYQ_PROJECT_ROOT, 'environments', `${env}.env`);
30
+ dotenv.config({
31
+ override: true,
32
+ path: envPath
33
+ })
34
+ } else {
35
+ if (process.env.PLAYQ_ENV) {
36
+ process.env.PLAYQ_ENV = process.env.PLAYQ_ENV.trim();
37
+ envPath = path.resolve(process.env.PLAYQ_PROJECT_ROOT, 'environments', `${process.env.PLAYQ_ENV}.env`);
38
+ dotenv.config({
39
+ override: true,
40
+ path: envPath
41
+ })
42
+ } else {
43
+ // No explicit env passed. Try to load 'default.env' if it exists.
44
+ // Try several candidate roots to locate default.env. In some cases
45
+ // PLAYQ_PROJECT_ROOT or process.cwd() may differ depending on how
46
+ // Playwright/VSCode started the process, so check a few locations.
47
+ const candidateRoots = [process.env.PLAYQ_PROJECT_ROOT, process.cwd(), findProjectRoot()];
48
+ let loadedDefault = false;
49
+ for (const root of candidateRoots) {
50
+ if (!root) continue;
51
+ const candidatePath = path.resolve(root, 'environments', 'default.env');
52
+ if (fs.existsSync(candidatePath)) {
53
+ dotenv.config({ override: true, path: candidatePath });
54
+ process.env.PLAYQ_ENV = 'default';
55
+ console.log(`ℹ️ Loaded default environment from ${candidatePath}`);
56
+ loadedDefault = true;
57
+ break;
58
+ }
59
+ }
60
+ if (!loadedDefault) {
61
+ // As a last attempt, try walking up from this file's directory to find an 'environments' folder
62
+ let cur = __dirname;
63
+ for (let i = 0; i < 6 && !loadedDefault; i++) {
64
+ const candidatePath = path.resolve(cur, '..'.repeat(i), 'environments', 'default.env');
65
+ if (fs.existsSync(candidatePath)) {
66
+ dotenv.config({ override: true, path: candidatePath });
67
+ process.env.PLAYQ_ENV = 'default';
68
+ console.log(`ℹ️ Loaded default environment from ${candidatePath}`);
69
+ loadedDefault = true;
70
+ break;
71
+ }
72
+ }
73
+ }
74
+ if (!loadedDefault) {
75
+ console.warn("NO ENVIRONMENTS PASSED : default.env not present or --env is undefined!");
76
+ }
77
+ }
78
+ }
79
+ process.env['PLAYQ_RUNNER'] = playqRunnerMem; // Override any environment config for PLAYQ_RUNNER.
80
+ if (playqEnvMem) process.env['PLAYQ_ENV'] = playqEnvMem;
81
+
82
+ // Load variables only when not explicitly disabled and TS loader is present (parent process may not have ts-node)
83
+ try {
84
+ if (process.env.PLAYQ_NO_INIT_VARS === '1') {
85
+ // Parent runner explicitly disables var init; child will handle it.
86
+ } else {
87
+ const canRequireTs = !!require.extensions['.ts'];
88
+ if (!canRequireTs) {
89
+ // Defer var loading to the test subprocess (Playwright/Cucumber), which preloads ts-node.
90
+ } else {
91
+ const { initVars } = require('./vars');
92
+ if (typeof initVars === 'function') {
93
+ initVars();
94
+ }
95
+ }
96
+ }
97
+ } catch (error) {
98
+ console.warn('Warning: Could not initialize vars:', error.message);
99
+ }
100
+ }
101
+
102
+ function findProjectRoot(): string {
103
+ // Method 1: Check for environment variable
104
+ if (process.env.PLAYQ_PROJECT_ROOT) {
105
+ return process.env.PLAYQ_PROJECT_ROOT;
106
+ }
107
+
108
+ // Method 2: Walk up from cwd to find package.json
109
+ let currentDir = process.cwd();
110
+ while (currentDir !== path.dirname(currentDir)) {
111
+ if (fs.existsSync(path.join(currentDir, 'package.json'))) {
112
+ return currentDir;
113
+ }
114
+ currentDir = path.dirname(currentDir);
115
+ }
116
+
117
+ // Method 3: Fallback to cwd
118
+ return process.cwd();
119
+ }
@@ -0,0 +1,368 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+
4
+ let importedVars: Record<string, string> = {};
5
+
6
+ const patternDirs = [
7
+ path.resolve(process.env.PLAYQ_PROJECT_ROOT || process.cwd(), "resources/patterns"),
8
+ path.resolve(process.env.PLAYQ_PROJECT_ROOT || process.cwd(), "extend/addons/pattern"),
9
+ ];
10
+
11
+ const storedVars: Record<string, string> = {};
12
+ const loggedMissingKeys = new Set<string>();
13
+
14
+ function getValue(key: string, ifEmpty?: boolean): string {
15
+ if (!key) {
16
+ console.warn("⚠️ Empty key provided to getValue");
17
+ return ifEmpty ? "" : key;
18
+ }
19
+ key = key.trim();
20
+
21
+ if (key.startsWith("env.")) {
22
+ const envKey = key.slice(4);
23
+ const envValue = process.env[envKey];
24
+ if (!envValue) {
25
+ return ifEmpty ? "" : key;
26
+ }
27
+ return envValue;
28
+ }
29
+
30
+ if (key in storedVars) return (ifEmpty && storedVars[key] === key) ? "" : storedVars[key];
31
+
32
+ // Only log when this is not an existence check
33
+ if (!ifEmpty && !loggedMissingKeys.has(key)) {
34
+ console.warn(`⚠️ Variable not found for key: "${key}"`);
35
+ loggedMissingKeys.add(key);
36
+ }
37
+
38
+ return ifEmpty ? "" : key;
39
+ }
40
+
41
+ function getConfigValue(key: string, ifEmpty?: boolean): string {
42
+ // Support environment variable overrides using PLAYQ__ dotted path mapping.
43
+ // Example: config.browser.browserType -> PLAYQ__browser__browserType
44
+ const rawKey = key.trim();
45
+ const envKey = 'PLAYQ__' + rawKey.replace(/\./g, '__');
46
+ if (process.env[envKey]) return process.env[envKey] as string;
47
+
48
+ const fullKey = 'config.' + rawKey;
49
+ if (fullKey in storedVars) return storedVars[fullKey];
50
+
51
+ if (!loggedMissingKeys.has(fullKey)) {
52
+ loggedMissingKeys.add(fullKey);
53
+ if (ifEmpty) return '';
54
+ }
55
+ return fullKey;
56
+ }
57
+
58
+ function setValue(key: string, value: string): void {
59
+ storedVars[key] = value;
60
+ if (key.startsWith("var.static.")) {
61
+ updateVarStaticJson(key.slice(11), value);
62
+ }
63
+ }
64
+
65
+ function updateVarStaticJson(key: string, value: string): void {
66
+ const jsonFilePath = path.resolve(process.cwd(), "resources/var.static.json");
67
+
68
+ let data: Record<string, string> = {};
69
+
70
+ // Read existing file if it exists
71
+ if (fs.existsSync(jsonFilePath)) {
72
+ try {
73
+ const fileContent = fs.readFileSync(jsonFilePath, "utf-8");
74
+ data = JSON.parse(fileContent);
75
+ console.log(`📖 Existing data:`, data); // Debug log
76
+ } catch (error) {
77
+ console.warn(`Warning: Could not parse existing var.static.json:`, error.message);
78
+ data = {};
79
+ }
80
+ } else {
81
+ console.log(`📝 Creating new var.static.json file`);
82
+ }
83
+
84
+ // Store old value for comparison
85
+ const oldValue = data[key];
86
+
87
+ // Update or add the key-value pair
88
+ data[key] = value;
89
+
90
+ console.log(`🔄 Updating key "${key}": "${oldValue}" → "${value}"`); // Debug log
91
+ console.log(`📦 Final data:`, data); // Debug log
92
+
93
+ // Ensure the directory exists
94
+ const dir = path.dirname(jsonFilePath);
95
+ if (!fs.existsSync(dir)) {
96
+ fs.mkdirSync(dir, { recursive: true });
97
+ }
98
+
99
+ // Write the updated data back to the file
100
+ try {
101
+ fs.writeFileSync(jsonFilePath, JSON.stringify(data, null, 2), "utf-8");
102
+
103
+ if (oldValue !== undefined) {
104
+ console.log(`✅ Updated var.static.json: ${key} = ${value} (was: ${oldValue})`);
105
+ } else {
106
+ console.log(`✅ Added to var.static.json: ${key} = ${value}`);
107
+ }
108
+ } catch (error) {
109
+ console.error(`❌ Failed to write to var.static.json:`, error.message);
110
+ throw error;
111
+ }
112
+ }
113
+
114
+ function replaceVariables(input: any): string {
115
+ if (typeof input !== "string") input = input.toString();
116
+ return input.replace(/\#\{([^}]+)\}/g, (_, varName) => {
117
+ if (varName.startsWith("pwd.")) {
118
+ const encryptedValue = varName.replace(/^pwd\./, "");
119
+ try {
120
+ const crypto = require("../util/utilities/cryptoUtil");
121
+ return crypto.decrypt(encryptedValue);
122
+ } catch (error) {
123
+ console.warn('Warning: Could not decrypt pwd value:', error.message);
124
+ return varName;
125
+ }
126
+ } else if (varName.startsWith("enc.")) {
127
+ const encryptedValue = varName.replace(/^enc\./, "");
128
+ try {
129
+ const crypto = require("../util/utilities/cryptoUtil");
130
+ return crypto.decrypt(encryptedValue);
131
+ } catch (error) {
132
+ console.warn('Warning: Could not decrypt enc value:', error.message);
133
+ return varName;
134
+ }
135
+ }
136
+
137
+ if (varName.endsWith(".(toNumber)")) {
138
+ const baseVar = varName.replace(".(toNumber)", "");
139
+ const value = getValue(baseVar);
140
+ return value !== undefined && value !== null && value !== ""
141
+ ? Number(value)
142
+ : "";
143
+ }
144
+ return getValue(varName);
145
+ });
146
+ }
147
+
148
+ function debugVars() {
149
+ console.log("📦 Static Vars:", storedVars);
150
+ }
151
+
152
+ function flattenConfig(obj: any, prefix = "config"): Record<string, string> {
153
+ const entries: Record<string, string> = {};
154
+ for (const key in obj) {
155
+ const fullKey = `${prefix}.${key}`;
156
+ if (typeof obj[key] === "object" && obj[key] !== null && !Array.isArray(obj[key])) {
157
+ Object.assign(entries, flattenConfig(obj[key], fullKey));
158
+ } else if (Array.isArray(obj[key])) {
159
+ entries[fullKey] = obj[key].join(";");
160
+ } else {
161
+ entries[fullKey] = String(obj[key]);
162
+ }
163
+ }
164
+ return entries;
165
+ }
166
+
167
+ function loadPatternEntries() {
168
+ const files: string[] = [];
169
+ for (const dir of patternDirs) {
170
+ if (fs.existsSync(dir)) {
171
+ try {
172
+ const dirFiles = fs
173
+ .readdirSync(dir)
174
+ .filter((file) => {
175
+ const isTS = file.endsWith(".pattern.ts");
176
+ const isAddonDir = dir.includes("extend/addons/pattern");
177
+ if (!isTS) return false;
178
+ if (isAddonDir) return file.startsWith("_");
179
+ return !file.startsWith("_");
180
+ })
181
+ .map((file) => path.join(dir, file));
182
+ files.push(...dirFiles);
183
+ } catch (error) {
184
+ console.warn(`Warning: Could not read pattern directory ${dir}:`, error.message);
185
+ }
186
+ }
187
+ }
188
+
189
+ for (const file of files) {
190
+ try {
191
+ const fileName = path.basename(file, ".pattern.ts");
192
+ if (!/^[a-zA-Z0-9_]+$/.test(fileName)) {
193
+ console.warn(`❌ Invalid pattern file name "${fileName}". Only alphanumeric characters and underscores are allowed.`);
194
+ continue;
195
+ }
196
+
197
+ delete require.cache[require.resolve(file)];
198
+ const patternModule = require(file);
199
+ const exported = patternModule[fileName] || patternModule.default?.[fileName];
200
+
201
+ if (!exported) {
202
+ console.warn(`❌ Exported const '${fileName}' not found in: ${file}`);
203
+ continue;
204
+ }
205
+
206
+ const flattened = flattenConfig(exported, `pattern.${fileName}`);
207
+ Object.assign(storedVars, flattened);
208
+ } catch (error) {
209
+ console.warn(`Warning: Could not load pattern file ${file}:`, error.message);
210
+ }
211
+ }
212
+ }
213
+
214
+ function loadFileEntries(file: string, constName: string, prefix?: string) {
215
+ console.log(`🔍 Loading file: ${file} with constName: ${constName} and prefix: ${prefix}`);
216
+
217
+ const absPath = path.isAbsolute(file) ? file : path.resolve(process.cwd(), file);
218
+
219
+ if (!fs.existsSync(absPath)) {
220
+ throw new Error(`❌ Load file not found: ${absPath}`);
221
+ }
222
+
223
+ const ext = path.extname(absPath);
224
+ let data: any;
225
+
226
+ if (ext === ".ts" || ext === ".js") {
227
+ delete require.cache[require.resolve(absPath)];
228
+ const module = require(absPath);
229
+ data = module[constName] || (module.default && module.default[constName]) || module.default || module;
230
+
231
+ if (!data) {
232
+ throw new Error(`❌ Exported const '${constName}' not found in: ${file}`);
233
+ }
234
+ } else if (ext === ".json") {
235
+ data = JSON.parse(fs.readFileSync(absPath, "utf-8"));
236
+ } else {
237
+ throw new Error(`❌ Unsupported file extension: ${ext}`);
238
+ }
239
+
240
+ const flat = flattenConfig(data, prefix || "");
241
+ Object.assign(storedVars, flat);
242
+ }
243
+
244
+ function resolveModulePath(basePath: string): string {
245
+ const candidates = [".ts", ".js", ".mjs", ".cjs", ".json"];
246
+ for (const ext of candidates) {
247
+ const candidate = basePath + ext;
248
+ if (fs.existsSync(candidate)) return candidate;
249
+ }
250
+ return basePath; // fall back to base (may still resolve via require paths)
251
+ }
252
+
253
+ function parseLooseJson(str: string): Record<string, any> {
254
+ if (!str || str.trim() === "" || str.trim() === '""') return {};
255
+
256
+ const needsBraces = !str.trim().startsWith("{") || !str.trim().endsWith("}");
257
+ let wrappedStr = needsBraces ? `{${str}}` : str;
258
+
259
+ try {
260
+ const locatorRegex = /(["']?locator["']?\s*:\s*)(xpath=[^,\}\n\r]+|css=[^,\}\n\r]+|chain=[^,\}\n\r]+)/g;
261
+ const locatorPlaceholders: string[] = [];
262
+
263
+ let maskedStr = wrappedStr.replace(locatorRegex, (match, p1, p2) => {
264
+ locatorPlaceholders.push(`"${p2.trim()}"`);
265
+ return `${p1}__LOCATOR_PLACEHOLDER_${locatorPlaceholders.length - 1}__`;
266
+ });
267
+
268
+ maskedStr = maskedStr.replace(/:\s*'((?:[^']|\\')*)'/g, (match, p1) => {
269
+ return `: "${p1}"`;
270
+ });
271
+
272
+ let normalized = maskedStr
273
+ .replace(/([{,]\s*)([a-zA-Z0-9_]+)\s*:/g, '$1"$2":')
274
+ .replace(/:\s*True\b/g, ": true")
275
+ .replace(/:\s*False\b/g, ": false")
276
+ .replace(/:\s*None\b/g, ": null")
277
+ .replace(/,(\s*[}\]])/g, "$1");
278
+
279
+ locatorPlaceholders.forEach((value, index) => {
280
+ normalized = normalized.replace(`__LOCATOR_PLACEHOLDER_${index}__`, value);
281
+ });
282
+
283
+ return JSON.parse(normalized);
284
+ } catch (err) {
285
+ throw new Error(`❌ Failed to parse options string: "${str}". Error: ${err.message}`);
286
+ }
287
+ }
288
+
289
+ function loadDefaults() {
290
+ try {
291
+ // defaultEntries sits next to this file; load it relatively to avoid env/path issues
292
+ const { default: defaultEntries } = require('./defaultEntries');
293
+
294
+ if (Array.isArray(defaultEntries)) {
295
+ defaultEntries.forEach((item) => {
296
+ let value = getValue('env.' + item.name, true) ? getValue('env.' + item.name) : (getValue(item.name, true) ? getValue(item.name) : item.value);
297
+ setValue(item.name, value);
298
+ });
299
+ }
300
+ } catch (error) {
301
+ console.warn('Warning: Could not load default entries:', error.message);
302
+ }
303
+ }
304
+
305
+ function initVars(vars?: Record<string, string>) {
306
+ try {
307
+ // Load config with error handling
308
+ let configEntries = {};
309
+ try {
310
+ const importConfigBase = path.resolve(process.env.PLAYQ_PROJECT_ROOT, 'resources/config');
311
+ const importConfigPath = resolveModulePath(importConfigBase);
312
+ console.log('🔎 [core] Requiring config from:', importConfigPath);
313
+ const configModule = require(importConfigPath);
314
+ configEntries = configModule.config || configModule.default || {};
315
+ } catch (error) {
316
+ console.warn('Warning: Could not load config file, using empty config');
317
+ }
318
+
319
+ // Load static variables preferring resources/var.static.json
320
+ let variablesEntries = {};
321
+ const varStaticPath = path.resolve(process.env.PLAYQ_PROJECT_ROOT, 'resources/var.static.json');
322
+ if (fs.existsSync(varStaticPath)) {
323
+ try {
324
+ console.log('🔎 [core] Loading var.static.json:', varStaticPath);
325
+ const fileContent = fs.readFileSync(varStaticPath, 'utf-8');
326
+ variablesEntries = JSON.parse(fileContent) || {};
327
+ } catch (error) {
328
+ console.warn('Warning: Could not parse var.static.json, using empty variables:', (error as any).message);
329
+ }
330
+ } else {
331
+ // Fallback to legacy resources/variable module if present
332
+ try {
333
+ const importVariableBase = path.resolve(process.env.PLAYQ_PROJECT_ROOT, 'resources/variable');
334
+ const importVariablePath = resolveModulePath(importVariableBase);
335
+ console.log('🔎 [core] Requiring legacy variable module from:', importVariablePath);
336
+ const variableModule = require(importVariablePath);
337
+ variablesEntries = variableModule.var_static || variableModule.default || {};
338
+ } catch (error) {
339
+ console.warn('Warning: Could not load variable file (var.static.json or legacy module), using empty variables');
340
+ }
341
+ }
342
+
343
+ if (vars) {
344
+ Object.assign(storedVars, vars);
345
+ }
346
+
347
+ Object.assign(storedVars, flattenConfig(variablesEntries, "var.static"));
348
+ Object.assign(storedVars, flattenConfig(configEntries, "config"));
349
+ loadPatternEntries();
350
+ loadDefaults();
351
+ } catch (error) {
352
+ console.error('Error initializing vars:', error.message);
353
+ }
354
+ }
355
+
356
+ export {
357
+ getValue,
358
+ getConfigValue,
359
+ setValue,
360
+ replaceVariables,
361
+ debugVars,
362
+ parseLooseJson,
363
+ loadFileEntries,
364
+ initVars
365
+ };
366
+
367
+
368
+