@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
package/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # @playq/core (Alpha)
2
+
3
+ Unified Playwright + Cucumber test runner and engine registry.
4
+
5
+ ## Quick Start
6
+ ```bash
7
+ npm install @playq/core @playwright/test @cucumber/cucumber --save-dev
8
+ npx playq util versions
9
+ npx playq test # runs Playwright specs by default
10
+ npx playq test --cucumber # runs Cucumber features
11
+ ```
12
+
13
+ ## Config Resolution
14
+ Looks for `playq.config.(js|cjs|mjs|json)` in project root, merges with internal defaults, then applies env overrides like:
15
+ ```
16
+ PLAYQ__browser__browserType=firefox
17
+ PLAYQ__testExecution__parallel=true
18
+ ```
19
+
20
+ ## CLI Commands
21
+ - `playq test [--cucumber] [--parallel N] [--grep pattern] [--tags expr]`
22
+ - `playq util versions`
23
+ - `playq report allure --open` (placeholder)
24
+ - `playq init` (placeholder)
25
+
26
+ ## Engine API
27
+ ```ts
28
+ import { registerEngine } from '@playq/core';
29
+ registerEngine({ id: 'myEngine', init: async () => {/*...*/} });
30
+ ```
31
+
32
+ ## Environment Overrides
33
+ Prefixed with `PLAYQ__` and mapped by `__` segments to nested config keys.
34
+
35
+ ## Roadmap
36
+ - Implement real init scaffolder
37
+ - Add allure integration
38
+ - External engine auto-discovery
39
+ - Hook system exposure
40
+
41
+ Alpha: APIs may change.
package/bin/playq.js ADDED
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env node
2
+ // Lightweight CLI wrapper: maps flags to PLAYQ_* env vars and invokes compiled runner.js
3
+
4
+
5
+ const minimist = require('minimist');
6
+ const path = require('path');
7
+ const fs = require('fs');
8
+
9
+ // Version flag support
10
+ if (process.argv.includes('--version') || process.argv.includes('-v')) {
11
+ const pkgPath = path.join(__dirname, '../package.json');
12
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
13
+ console.log(pkg.version);
14
+ process.exit(0);
15
+ }
16
+
17
+
18
+ // If first argument is 'util' and -h/--help/help is present, print help and exit
19
+ if (process.argv[2] === 'util' && (process.argv.includes('--help') || process.argv.includes('-h') || process.argv.includes('help'))) {
20
+ console.log(`PlayQ CLI - util
21
+ Usage: playq util [options]
22
+
23
+ Description:
24
+ Interactive utility for various PlayQ operations including encryption,
25
+ decryption, key generation, TOTP codes, and API schema generation.
26
+
27
+ Options:
28
+ --help | -h Show help
29
+
30
+ Available Utilities:
31
+ 1. Password Encryption - Encrypt passwords using strong encryption
32
+ 2. Text Encryption - Encrypt any text using strong encryption
33
+ 3. Decryption - Decrypt previously encrypted values
34
+ 4. Generate 32bit Key - Generate cryptographic keys for encryption
35
+ 5. Generate TOTP Code - Generate time-based one-time passwords
36
+ 6. Generate API Schema - Generate TypeScript schemas from OpenAPI specs
37
+
38
+ Examples:
39
+ npx playq util # Launch interactive utility menu
40
+ npx playq util --help # Show this help message
41
+ `);
42
+ process.exit(0);
43
+ }
44
+
45
+ // If first argument is 'util', run the util script and exit
46
+ if (process.argv[2] === 'util') {
47
+ const { spawnSync } = require('child_process');
48
+ const utilScript = path.join(__dirname, '../dist/scripts/util.js');
49
+ const result = spawnSync(process.execPath, [utilScript], { stdio: 'inherit' });
50
+ process.exit(result.status || 0);
51
+ }
52
+
53
+
54
+ // If first argument is 'generate' and -h/--help/help is present, print help and exit
55
+ if (process.argv[2] === 'generate' && (process.argv.includes('--help') || process.argv.includes('-h') || process.argv.includes('help'))) {
56
+ console.log(`PlayQ CLI - generate
57
+ Usage: playq generate [options]
58
+
59
+ Options:
60
+ --stepgroup | -sg Generate step group cache and step defs
61
+ --help | -h Show help
62
+
63
+ Examples:
64
+ npx playq generate --stepgroup
65
+ npx playq generate -sg
66
+ `);
67
+ process.exit(0);
68
+ }
69
+
70
+ // If first argument is 'generate' and --stepgroup or -sg is present, run the sgGenerator script and exit
71
+ if (process.argv[2] === 'generate' && (process.argv.includes('--stepgroup') || process.argv.includes('-sg'))) {
72
+ const { spawnSync } = require('child_process');
73
+ const sgGenScript = path.join(__dirname, '../dist/exec/sgGenerator.js');
74
+ const result = spawnSync(process.execPath, [sgGenScript], { stdio: 'inherit' });
75
+ process.exit(result.status || 0);
76
+ }
77
+
78
+
79
+ // Only run test runner if 'test' subcommand is provided
80
+ if (process.argv[2] === 'test') {
81
+
82
+ const args = minimist(process.argv.slice(3), {
83
+ string: ['grep', 'tags', 'runner', 'project', 'env', 'filter', 'key'],
84
+ alias: { g: 'grep', t: 'tags', r: 'runner', p: 'project', e: 'env', f: 'filter', k: 'key' }
85
+ });
86
+
87
+ // Support --key or -k for PLAYQ_SECRET_KEY
88
+ if (args.key) process.env.PLAYQ_SECRET_KEY = args.key;
89
+
90
+ if (args.grep) process.env.PLAYQ_GREP = args.grep;
91
+ if (args.tags) process.env.PLAYQ_TAGS = args.tags;
92
+ if (args.runner) process.env.PLAYQ_RUNNER = args.runner;
93
+ // Mirror to legacy TEST_RUNNER flag used by action helpers
94
+ if (args.runner) process.env.TEST_RUNNER = args.runner;
95
+ if (args.project) process.env.PLAYQ_PROJECT = args.project;
96
+ if (args.env) process.env.PLAYQ_ENV = args.env;
97
+
98
+ // --filter support: map to grep/tags based on runner
99
+ if (args.filter) {
100
+ const runner = args.runner || process.env.PLAYQ_RUNNER || 'playwright';
101
+ if (runner === 'cucumber') {
102
+ process.env.PLAYQ_TAGS = args.filter;
103
+ } else {
104
+ process.env.PLAYQ_GREP = args.filter;
105
+ }
106
+ }
107
+
108
+ // Provide defaults if not set
109
+ if (!process.env.PLAYQ_ENV) process.env.PLAYQ_ENV = 'default';
110
+ if (!process.env.PLAYQ_RUNNER) process.env.PLAYQ_RUNNER = 'playwright';
111
+ if (!process.env.TEST_RUNNER) process.env.TEST_RUNNER = process.env.PLAYQ_RUNNER;
112
+ // Core & project root hints for helpers
113
+ process.env.PLAYQ_CORE_ROOT = path.join(__dirname, '../dist');
114
+ process.env.PLAYQ_PROJECT_ROOT = process.cwd();
115
+
116
+ // Do NOT register ts-node or tsconfig-paths here; the test runner handles TypeScript via project config.
117
+
118
+ // Provide basic help for test subcommand
119
+ if (args.help || args.h) {
120
+ console.log(`PlayQ CLI (Phase 1)
121
+ Usage: playq test [options]
122
+ --grep | -g Playwright grep filter
123
+ --tags | -t Cucumber tag expression
124
+ --filter | -f Universal filter (maps to grep/tags by runner)
125
+ --runner | -r playwright | cucumber (default playwright)
126
+ --project| -p Playwright project name
127
+ --env | -e Environment name (mapped to PLAYQ_ENV)
128
+ --key | -k Secret key for crypto (sets PLAYQ_SECRET_KEY)
129
+
130
+ --help | -h Show help
131
+ --version| -v Show PlayQ CLI version
132
+
133
+ Examples:
134
+ npx playq test --filter "Registration001"
135
+ npx playq test --filter "@smoke" --runner cucumber
136
+ npx playq test --grep "Registration001"
137
+ npx playq test --tags "@smoke" --runner cucumber
138
+ npx playq test --key "mysecret" --grep "Registration001"
139
+ `);
140
+ process.exit(0);
141
+ }
142
+
143
+ const runnerJs = path.join(__dirname, '../dist/exec/runner.js');
144
+ require(runnerJs);
145
+ }
146
+
147
+ // Top-level help for all commands
148
+ if (process.argv[2] === 'help' || process.argv[2] === '--help' || process.argv[2] === '-h' || !process.argv[2]) {
149
+ console.log(`PlayQ CLI (Phase 1)
150
+
151
+ Usage: playq <command> [options]
152
+ --help | -h Show help
153
+ --version| -v Show PlayQ CLI version
154
+
155
+ Commands:
156
+ test Run PlayQ tests (Playwright or Cucumber)
157
+ util Run the PlayQ utility
158
+ generate --stepgroup | -sg Generate step group cache and step defs
159
+
160
+ For test options, run: npx playq test --help
161
+ For util options, run: npx playq util --help
162
+ For version, run: npx playq --version or npx playq -v
163
+
164
+ Examples:
165
+ npx playq test --filter "Registration001"
166
+ npx playq test --filter "@smoke" --runner cucumber
167
+ npx playq test --grep "Registration001"
168
+ npx playq test --tags "@smoke" --runner cucumber
169
+ npx playq util
170
+ npx playq util --help
171
+ npx playq generate --stepgroup
172
+ npx playq generate -sg
173
+ `);
174
+ process.exit(0);
175
+ }
package/cucumber.js ADDED
@@ -0,0 +1,10 @@
1
+ module.exports = {
2
+ default: {
3
+ formatOptions: { snippetInterface: 'async-await' },
4
+ paths: [ './test/features/**/*.feature' ],
5
+ dryRun: false,
6
+ require: [ './test/steps/**/*.js' ],
7
+ format: [ 'progress-bar' ],
8
+ parallel: 1
9
+ }
10
+ };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Returns the path to the cached feature file inside _Temp/execution/
3
+ */
4
+ export declare function getCachedFeatureFilePath(originalPath: string): string;
5
+ /**
6
+ * Determines if the cached feature should be used.
7
+ * Checks:
8
+ * - config.cucumber.featureFileCache is enabled
9
+ * - cached file and metadata exist
10
+ * - cached timestamp is newer than original file
11
+ */
12
+ export declare function shouldUseCachedFeature(originalPath: string, cachedPath: string): boolean;
13
+ /**
14
+ * Updates the feature cache metadata file.
15
+ * Ensures _Temp/.cache/featureMeta.json exists, and writes { filePath, updatedAt }.
16
+ */
17
+ export declare function updateFeatureCacheMeta(originalPath: string, cachedPath: string): void;
18
+ /**
19
+ * Writes feature content to cache if valid.
20
+ */
21
+ export declare function writeFeatureToCache(cachedPath: string, content: string): void;
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.getCachedFeatureFilePath = getCachedFeatureFilePath;
40
+ exports.shouldUseCachedFeature = shouldUseCachedFeature;
41
+ exports.updateFeatureCacheMeta = updateFeatureCacheMeta;
42
+ exports.writeFeatureToCache = writeFeatureToCache;
43
+ const fs_1 = __importDefault(require("fs"));
44
+ const path_1 = __importDefault(require("path"));
45
+ const vars = __importStar(require("../helper/bundle/vars"));
46
+ const config = {};
47
+ const FEATURE_META_PATH = path_1.default.resolve('_Temp/.cache/featureMeta.json');
48
+ /**
49
+ * Returns the path to the cached feature file inside _Temp/execution/
50
+ */
51
+ function getCachedFeatureFilePath(originalPath) {
52
+ const filename = path_1.default.basename(originalPath);
53
+ return path_1.default.resolve('_Temp/execution', filename);
54
+ }
55
+ /**
56
+ * Determines if the cached feature should be used.
57
+ * Checks:
58
+ * - config.cucumber.featureFileCache is enabled
59
+ * - cached file and metadata exist
60
+ * - cached timestamp is newer than original file
61
+ */
62
+ function shouldUseCachedFeature(originalPath, cachedPath) {
63
+ var _a;
64
+ // Logging for cache check
65
+ console.log(`🔍 Cache check started for: ${originalPath}`);
66
+ if (!((_a = config === null || config === void 0 ? void 0 : config.cucumber) === null || _a === void 0 ? void 0 : _a.featureFileCache) || vars.getConfigValue('cucumber.featureFileCache'))
67
+ return false;
68
+ if (!fs_1.default.existsSync(cachedPath))
69
+ return false;
70
+ if (!fs_1.default.existsSync(FEATURE_META_PATH))
71
+ return false;
72
+ try {
73
+ const meta = JSON.parse(fs_1.default.readFileSync(FEATURE_META_PATH, 'utf-8'));
74
+ const originalStats = fs_1.default.statSync(originalPath);
75
+ const cachedMeta = meta[originalPath];
76
+ console.log(`📄 Cached Meta:`, cachedMeta);
77
+ if (!cachedMeta)
78
+ return false;
79
+ const originalTime = originalStats.mtimeMs;
80
+ const metaTime = new Date(cachedMeta.updatedAt).getTime();
81
+ console.log(`📆 Original mtime: ${originalTime} | Cached updatedAt: ${metaTime}`);
82
+ console.log(`✅ Should use cache: ${metaTime >= originalTime}`);
83
+ return metaTime >= originalTime;
84
+ }
85
+ catch (err) {
86
+ console.warn(`⚠️ Cache check failed. Proceeding without cache.`, err);
87
+ return false;
88
+ }
89
+ }
90
+ /**
91
+ * Updates the feature cache metadata file.
92
+ * Ensures _Temp/.cache/featureMeta.json exists, and writes { filePath, updatedAt }.
93
+ */
94
+ function updateFeatureCacheMeta(originalPath, cachedPath) {
95
+ const dir = path_1.default.dirname(FEATURE_META_PATH);
96
+ if (!fs_1.default.existsSync(dir)) {
97
+ fs_1.default.mkdirSync(dir, { recursive: true });
98
+ }
99
+ let meta = {};
100
+ if (fs_1.default.existsSync(FEATURE_META_PATH)) {
101
+ try {
102
+ meta = JSON.parse(fs_1.default.readFileSync(FEATURE_META_PATH, 'utf-8'));
103
+ }
104
+ catch {
105
+ console.warn('⚠️ Failed to parse featureMeta.json. Overwriting.');
106
+ }
107
+ }
108
+ meta[originalPath] = {
109
+ filePath: cachedPath,
110
+ updatedAt: new Date().toISOString()
111
+ };
112
+ fs_1.default.writeFileSync(FEATURE_META_PATH, JSON.stringify(meta, null, 2), 'utf-8');
113
+ console.log(`💾 Feature cache metadata updated for: ${originalPath}`);
114
+ }
115
+ /**
116
+ * Writes feature content to cache if valid.
117
+ */
118
+ function writeFeatureToCache(cachedPath, content) {
119
+ if (!content.trim().startsWith('Feature')) {
120
+ console.warn(`❌ Skipping cache write: Content does not start with "Feature". Content preview:\n${content.substring(0, 100)}`);
121
+ return;
122
+ }
123
+ fs_1.default.writeFileSync(cachedPath, content, 'utf8');
124
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Preprocesses a feature file using all transformation steps:
3
+ * - Variable replacement
4
+ * - Step group expansion
5
+ * - SmartIQ data injection
6
+ * - Tag injection
7
+ *
8
+ * @param srcFeaturePath Path to the source .feature file
9
+ * @returns Path to the preprocessed file (under _Temp/execution)
10
+ */
11
+ export declare function preprocessFeatureFile(srcFeaturePath: string): string | undefined;
12
+ export declare function expandStepGroups(featureText: string): string;
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.preprocessFeatureFile = preprocessFeatureFile;
7
+ exports.expandStepGroups = expandStepGroups;
8
+ // Replace legacy '@playq' alias with local global exports
9
+ const global_1 = require("../global");
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const xlsx_1 = __importDefault(require("@e965/xlsx"));
13
+ /**
14
+ * Preprocesses a feature file using all transformation steps:
15
+ * - Variable replacement
16
+ * - Step group expansion
17
+ * - SmartIQ data injection
18
+ * - Tag injection
19
+ *
20
+ * @param srcFeaturePath Path to the source .feature file
21
+ * @returns Path to the preprocessed file (under _Temp/execution)
22
+ */
23
+ function preprocessFeatureFile(srcFeaturePath) {
24
+ var _a;
25
+ try {
26
+ const rawContent = fs_1.default.readFileSync(srcFeaturePath, "utf-8");
27
+ // Step 1: Replace variables like ${url}, ${user}
28
+ let processedContent = replaceVariablesInString(rawContent);
29
+ // Step 2: Replacing examples with data file and filter
30
+ processedContent = processExamplesWithFilter(processedContent); // <-- Add this
31
+ // Step 3: Expand Step Groups
32
+ processedContent = expandStepGroups(processedContent);
33
+ // Step 4: Inject SmartIQ data or resolve special steps
34
+ processedContent = processSmartData(processedContent);
35
+ // Step 5: Inject scenario-level tags if needed
36
+ processedContent = injectScenarioTag(processedContent, srcFeaturePath);
37
+ // Write processed file
38
+ const outputDir = path_1.default.join("_Temp/execution");
39
+ const relativePath = path_1.default.relative("tests/bdd/scenarios", srcFeaturePath);
40
+ const outputPath = path_1.default.join(outputDir, relativePath);
41
+ fs_1.default.mkdirSync(path_1.default.dirname(outputPath), { recursive: true });
42
+ fs_1.default.writeFileSync(outputPath, processedContent, "utf-8");
43
+ if (((_a = global_1.config === null || global_1.config === void 0 ? void 0 : global_1.config.cucumber) === null || _a === void 0 ? void 0 : _a.featureFileCache) || global_1.vars.getConfigValue('cucumber.featureFileCache')) {
44
+ const { updateFeatureCacheMeta } = require("./featureFileCache");
45
+ updateFeatureCacheMeta(srcFeaturePath, outputPath);
46
+ }
47
+ return outputPath;
48
+ }
49
+ catch (err) {
50
+ console.error(`❌ Error preprocessing feature file: ${err}`);
51
+ return undefined;
52
+ }
53
+ }
54
+ // 🔁 Placeholder replacement
55
+ function replaceVariablesInString(content) {
56
+ return content.replace(/Examples\s*:\s*({[^}]*})/g, (match, jsonPart) => {
57
+ const replaced = jsonPart.replace(/\${env\.([\w]+)}/g, (_, key) => {
58
+ const val = process.env[key] || "";
59
+ console.log(`🔄 Replacing variable env.${key} -> ${val}`);
60
+ return val;
61
+ });
62
+ return `Examples:${replaced}`;
63
+ });
64
+ }
65
+ // 🔁 Expand Step Groups
66
+ function expandStepGroups(featureText) {
67
+ const cachePath = path_1.default.join("_Temp", ".cache", "stepGroup_cache.json");
68
+ if (!fs_1.default.existsSync(cachePath)) {
69
+ console.warn(`⚠️ Step group cache not found at ${cachePath}`);
70
+ return featureText;
71
+ }
72
+ const stepGroupCache = JSON.parse(fs_1.default.readFileSync(cachePath, "utf8"));
73
+ const stepGroupRegex = /^\s*\*\s*Step\s*Group:\s*-(.+?)-\s*-(.+?)-\s*$/gm;
74
+ const updatedText = featureText.replace(stepGroupRegex, (_match, groupIdRaw, groupDescRaw) => {
75
+ const groupId = groupIdRaw.trim();
76
+ const groupDesc = groupDescRaw.trim();
77
+ const cachedGroup = stepGroupCache[groupId];
78
+ if (!cachedGroup || !Array.isArray(cachedGroup.steps)) {
79
+ console.warn(`❌ Step group "${groupId}" not found or steps invalid`);
80
+ return _match;
81
+ }
82
+ const steps = cachedGroup.steps.join("\n");
83
+ const replacement = [
84
+ `\n* - Step Group - START: "${groupId}" Desc: "${groupDesc}"`,
85
+ steps,
86
+ `* - Step Group - END: "${groupId}"`,
87
+ ].join("\n");
88
+ return replacement;
89
+ });
90
+ return updatedText;
91
+ }
92
+ // 🔁 Process Smart Data (e.g., inject data-driven values or SmartIQ rules)
93
+ function processSmartData(content) {
94
+ // Example: Replace [[SMART:...]] with resolved steps
95
+ return content.replace(/\[\[SMART:(.*?)\]\]/g, (_, expr) => {
96
+ console.log(`🧠 Processing SMART: ${expr}`);
97
+ return `# Processed SMART step: ${expr}`;
98
+ });
99
+ }
100
+ // 🔁 Inject scenario-level tags
101
+ function injectScenarioTag(content, filePath) {
102
+ const tag = `@file(${path_1.default.basename(filePath)})`;
103
+ const lines = content.split("\n");
104
+ const processedLines = lines.map((line, i) => {
105
+ if (line.trim().startsWith("Scenario") &&
106
+ (i === 0 || !lines[i - 1].trim().startsWith("@"))) {
107
+ return `${tag}\n${line}`;
108
+ }
109
+ return line;
110
+ });
111
+ return processedLines.join("\n");
112
+ }
113
+ function processExamplesWithFilter(content, dataDir = "test-data") {
114
+ return content.replace(/(^|\n)\s*Examples\s*:?\s*({[^}]*})/g, (match, prefix, jsonStr) => {
115
+ console.log(`🔄 FOUND Examples block: [${jsonStr}]`);
116
+ console.log(`🔄 Preprocessing feature == MATCH == file: ${match}`);
117
+ console.log(`🔄 Preprocessing feature == MATCH END == file:`);
118
+ console.log(`🔄 Preprocessing feature == PREFIX == file: ${prefix}`);
119
+ console.log(`🔄 Preprocessing feature == jsonStr == file: ${jsonStr}`);
120
+ const obj = JSON.parse(jsonStr.replace(/'/g, '"'));
121
+ const normalized = {};
122
+ for (const [k, v] of Object.entries(obj)) {
123
+ normalized[k.toLowerCase()] = v;
124
+ }
125
+ const dataFile = normalized["datafile"];
126
+ const filter = normalized["filter"];
127
+ const sheetName = normalized["sheetname"];
128
+ console.log(`🔄 Preprocessing feature == dataFile == file: ${dataFile}`);
129
+ console.log(`🔄 Preprocessing feature == filter == file: ${filter}`);
130
+ console.log(`🔄 Preprocessing feature == sheetName == file: ${sheetName}`);
131
+ const fullPath = path_1.default.join(dataDir, path_1.default.basename(dataFile || ""));
132
+ const ext = path_1.default.extname(fullPath).toLowerCase();
133
+ console.log(`🔄 Preprocessing feature == FULL PATH == file: ${fullPath}`);
134
+ console.log(`🔄 Preprocessing feature == EXT == file: ${ext}`);
135
+ if (!fs_1.default.existsSync(fullPath))
136
+ return match;
137
+ const isNumeric = (val) => typeof val === "string" && val.trim() !== "" && !isNaN(Number(val));
138
+ const substituteFilter = (filter, row) => filter.replace(/\b[_a-zA-Z][_a-zA-Z0-9]*\b/g, (key) => {
139
+ var _a;
140
+ const raw = (_a = row[key]) !== null && _a !== void 0 ? _a : row[`_${key}`];
141
+ if (raw === undefined)
142
+ return key;
143
+ return isNumeric(raw) ? raw.trim() : JSON.stringify(raw);
144
+ });
145
+ let rows = [];
146
+ console.log(`🔍 Checking file existence: fullPath='${fullPath}'`);
147
+ if (!fs_1.default.existsSync(fullPath)) {
148
+ console.error(`❌ File not found: ${fullPath}`);
149
+ return match;
150
+ }
151
+ if (ext === ".xlsx") {
152
+ console.log(`✔️ File found: ${fullPath}, now reading with xlsx`);
153
+ const workbook = xlsx_1.default.readFile(fullPath);
154
+ console.log(`📄 Workbook sheets: ${workbook.SheetNames.join(", ")}`);
155
+ const sheet = sheetName || workbook.SheetNames[0];
156
+ console.log(`📋 Using sheet: ${sheet}`);
157
+ const sheetData = xlsx_1.default.utils.sheet_to_json(workbook.Sheets[sheet]);
158
+ console.log(`🔢 Read ${sheetData.length} rows from sheet`);
159
+ rows = sheetData.filter((row) => {
160
+ try {
161
+ console.log("🔍 Row raw:", row);
162
+ return eval(substituteFilter(filter, row));
163
+ }
164
+ catch {
165
+ console.warn("⚠️ Row filter error, skipping.");
166
+ return false;
167
+ }
168
+ });
169
+ }
170
+ else if (ext === ".csv") {
171
+ console.log(`📋 ENTER CSV:`);
172
+ const csvData = fs_1.default.readFileSync(fullPath, "utf-8").split("\n");
173
+ console.log(`📋 Using csvData: ${csvData}`);
174
+ const headers = csvData[0].split(",").map((h) => h.trim());
175
+ console.log(`📋 Using headers: ${headers}`);
176
+ for (let i = 1; i < csvData.length; i++) {
177
+ const values = csvData[i].split(",");
178
+ if (values.length !== headers.length)
179
+ continue;
180
+ const row = {};
181
+ headers.forEach((h, j) => {
182
+ var _a;
183
+ row[h] = (_a = values[j]) === null || _a === void 0 ? void 0 : _a.trim();
184
+ });
185
+ try {
186
+ if (eval(substituteFilter(filter, row)))
187
+ rows.push(row);
188
+ }
189
+ catch { }
190
+ }
191
+ }
192
+ else {
193
+ return match; // unsupported file
194
+ }
195
+ console.log(`🔍 Filtered row count: ${rows.length}`);
196
+ if (!rows.length) {
197
+ console.error(`❌ No matching rows found. Returning fallback Examples block.`);
198
+ throw new Error(`❌ No matching rows found. Returning fallback Examples block.`);
199
+ }
200
+ const headers = Object.keys(rows[0]);
201
+ const lines = ["\n\nExamples:", ` | ${headers.join(" | ")} |`];
202
+ for (const r of rows) {
203
+ const rowLine = ` | ${headers.map((h) => r[h] || "").join(" | ")} |`;
204
+ lines.push(rowLine);
205
+ }
206
+ return lines.join("\n");
207
+ });
208
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ // // Replaced legacy '@playq' alias import with direct relative import from public globals
3
+ // import { config, vars } from "../global";
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ var _a;
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ // // Loading D365 CRM pattern
10
+ // const d365CrmEnable = config?.addons?.d365Crm?.enable || vars.getConfigValue('addons.d365Crm.enable').toLowerCase().trim() === 'true';
11
+ // const d365CrmVersion = config?.addons?.d365Crm?.version || vars.getConfigValue('addons.d365Crm.version').toLowerCase().trim();
12
+ // // Updated: Look for D365 pattern in playq/addons/d365Crm/pattern/ (new path)
13
+ // if (d365CrmEnable && d365CrmVersion.startsWith("v")) vars.loadFileEntries(`playq/addons/d365Crm/pattern/d365CrmPattern_${d365CrmVersion}.ts`, "d365CrmLocPatterns", "pattern.d365crm");
14
+ const global_1 = require("../global");
15
+ const path_1 = __importDefault(require("path"));
16
+ const fs_1 = __importDefault(require("fs"));
17
+ // Use minimal addons.json for discovery, config for logic
18
+ const projectRoot = process.env.PLAYQ_PROJECT_ROOT || process.cwd();
19
+ const addonsJsonPath = path_1.default.join(projectRoot, "playq", "addons", "addons.json");
20
+ let addonList = [];
21
+ try {
22
+ const raw = fs_1.default.readFileSync(addonsJsonPath, "utf-8");
23
+ addonList = JSON.parse(raw);
24
+ }
25
+ catch (e) {
26
+ console.warn("No addons.json found or failed to load:", e);
27
+ }
28
+ for (const addon of addonList) {
29
+ console.log("[PLAYQ DEBUG] Processing addon:", addon.name);
30
+ const addonKey = addon.name;
31
+ let configEntry = (_a = global_1.config === null || global_1.config === void 0 ? void 0 : global_1.config.addons) === null || _a === void 0 ? void 0 : _a[addonKey];
32
+ let enabled = false;
33
+ let version = "";
34
+ // Debug: print configEntry and its type
35
+ console.log(`[PLAYQ DEBUG] configEntry for ${addonKey}:`, configEntry, 'type:', typeof configEntry);
36
+ console.log("[PLAYQ DEBUG] config object:", global_1.config);
37
+ if (configEntry && typeof configEntry === 'object') {
38
+ enabled = configEntry.enable === true || String(configEntry.enable).toLowerCase() === "true";
39
+ version = configEntry.version || "";
40
+ console.log(`[PLAYQ DEBUG] (object) enabled:`, enabled, 'version:', version);
41
+ }
42
+ else {
43
+ // Use vars.getConfigValue for enable/version as string
44
+ const enableStr = String(global_1.vars.getConfigValue(`addons.${addonKey}.enable`)).toLowerCase().trim();
45
+ const versionStr = String(global_1.vars.getConfigValue(`addons.${addonKey}.version`)).toLowerCase().trim();
46
+ enabled = enableStr === 'true';
47
+ version = versionStr;
48
+ console.log(`[PLAYQ DEBUG] (vars) enableStr:`, enableStr, 'versionStr:', versionStr);
49
+ }
50
+ console.log("[PLAYQ DEBUG] Before if condition addon:", enabled, " >> ", version);
51
+ if (enabled && version.startsWith("v")) {
52
+ console.log("[PLAYQ DEBUG] After if condition addon:", enabled, " >> ", version);
53
+ try {
54
+ global_1.vars.loadFileEntries(`playq/addons/${addonKey}/pattern/${addonKey}Pattern_${version}.ts`, `${addonKey}LocPatterns`, `pattern.${addonKey.toLowerCase()}`);
55
+ }
56
+ catch (e) {
57
+ console.warn(`Pattern file for ${addonKey} not found or failed to load:`, e);
58
+ }
59
+ // Prefer .js if exists, else .ts
60
+ // const basePatternPath = path.join(projectRoot, "playq", "addons", addonKey, "pattern", `${addonKey}Pattern_${version}`);
61
+ // let patternPath = basePatternPath + ".js";
62
+ // if (!fs.existsSync(patternPath)) {
63
+ // patternPath = basePatternPath + ".ts";
64
+ // }
65
+ // try {
66
+ // vars.loadFileEntries(patternPath, `${addonKey}LocPatterns`, `pattern.${addonKey.toLowerCase()}`);
67
+ // } catch (e) {
68
+ // console.warn(`Pattern file for ${addonKey} not found or failed to load:`, e);
69
+ // }
70
+ // Optionally, perform other addon-specific initialization here
71
+ }
72
+ }
@@ -0,0 +1 @@
1
+ export {};