@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,469 @@
1
+ /**
2
+ * @file formActions.ts
3
+ *
4
+ * Form interaction helpers for PlayQ web actions.
5
+ * Provides fill/select/upload utilities with runner-aware step wrappers,
6
+ * locator resolution, and screenshot options.
7
+ *
8
+ * Authors: PlayQ Team
9
+ * Version: v1.0.0
10
+ */
11
+ import * as allure from "allure-js-commons";
12
+ import { Page, Locator } from "@playwright/test";
13
+ import { vars } from "../../../global";
14
+ import path from "path";
15
+ import fs from "fs";
16
+ import { webLocResolver } from "../../fixtures/webLocFixture";
17
+ import { waitForEnabled } from "./waitActions";
18
+ import { processScreenshot } from "./screenshotActions";
19
+ import { parseLooseJson } from '../../bundle/vars';
20
+ import { waitInMilliSeconds } from '../commActions';
21
+
22
+ function isPlaywrightRunner() { return process.env.TEST_RUNNER === 'playwright'; }
23
+ const __allureAny_form: any = allure as any;
24
+ if (typeof __allureAny_form.step !== 'function') { __allureAny_form.step = async (_n: string, f: any) => await f(); }
25
+
26
+ /**
27
+ * Web: Fill -field: {param} -value: {param} -options: {param}
28
+ *
29
+ * Fills a form input field (e.g., text box, textarea) with the specified value.
30
+ *
31
+ * @param field - The label, placeholder, id, name, or pattern of the input field (e.g., "Username", "Email", "search").
32
+ * @param value - The text value to fill in the input field (e.g., "JohnDoe", "test@example.com").
33
+ * @param options - Optional JSON string or object:
34
+ * - actionTimeout: [number] Timeout in ms (default: 30000)
35
+ * - pattern: [string] Optional pattern to refine element search. Default: Configured pattern.
36
+ * - screenshot: [boolean] Capture a screenshot after filling the input. Default: false.
37
+ * - screenshotText: [string] Text description for the screenshot. Default: "".
38
+ * - screenshotFullPage: [boolean] Capture a full page screenshot. Default: true.
39
+ * - screenshotField: [boolean] Capture screenshot of the field (input element) only. Overrides fullPage. Default: false.
40
+ *
41
+ * @example
42
+ * Web: Fill -field: "Username" -value: "JohnDoe" -options: "{screenshot: true, screenshotText: 'After filling Username', screenshotField: true}"
43
+ */
44
+ export async function fill(
45
+ page: Page,
46
+ field: string | Locator,
47
+ value: string | number,
48
+ options?: string | Record<string, any>
49
+ ) {
50
+ let resolvedvalue = vars.replaceVariables(value.toString());
51
+ const options_json =
52
+ typeof options === "string" ? parseLooseJson(options) : options || {};
53
+ if (!page) throw new Error("Page not initialized");
54
+ const {
55
+ iframe = "",
56
+ actionTimeout = Number(vars.getConfigValue("testExecution.actionTimeout")),
57
+ pattern,
58
+ screenshot = false,
59
+ screenshotText = "",
60
+ screenshotFullPage = true,
61
+ screenshotField = false,
62
+ smartIQ_refreshLoc = "",
63
+ } = options_json || {};
64
+
65
+ if (isPlaywrightRunner()) {
66
+ await __allureAny_form.step(
67
+ `Web: Fill -field: ${field} -value: ${value} -options: ${JSON.stringify(
68
+ options_json
69
+ )}`,
70
+ async () => {
71
+ await doFill();
72
+ }
73
+ );
74
+ } else {
75
+ await doFill();
76
+ }
77
+ async function doFill() {
78
+ const target =
79
+ typeof field === "string"
80
+ ? await webLocResolver(
81
+ "input",
82
+ field,
83
+ page,
84
+ pattern,
85
+ smartIQ_refreshLoc
86
+ )
87
+ : field;
88
+
89
+ if (iframe) {
90
+ await waitForEnabled(
91
+ page.frameLocator(iframe).locator(target),
92
+ actionTimeout
93
+ );
94
+ await page
95
+ .frameLocator(iframe)
96
+ .locator(target)
97
+ .fill(resolvedvalue, { timeout: actionTimeout });
98
+ } else {
99
+ await waitForEnabled(target, actionTimeout);
100
+ await target.fill(resolvedvalue, { timeout: actionTimeout });
101
+ }
102
+
103
+ const isFieldScreenshot = screenshotField === true;
104
+ await processScreenshot(
105
+ page,
106
+ screenshot,
107
+ screenshotText,
108
+ !isFieldScreenshot,
109
+ isFieldScreenshot ? target : undefined
110
+ );
111
+ }
112
+ }
113
+
114
+ // Friendly aliases
115
+ export const input = fill;
116
+ export const type = fill;
117
+ export const set = fill;
118
+ export const enter = fill;
119
+
120
+ /**
121
+ * Web: Append -field: {param} -value: {param} -options: {param}
122
+ *
123
+ * Appends text to an input or textarea without clearing existing content.
124
+ *
125
+ * @param page - Playwright Page instance
126
+ * @param field - The label, placeholder, id, name, or pattern of the input field
127
+ * @param value - The text value to append
128
+ * @param options - Optional JSON string or object:
129
+ * - actionTimeout: [number] Timeout in ms (default: 30000)
130
+ * - pattern: [string] Optional pattern to refine element search
131
+ * - screenshot: [boolean] Capture a screenshot after appending (default: false)
132
+ * - screenshotText: [string] Text description for the screenshot
133
+ * - screenshotFullPage: [boolean] Capture a full page screenshot (default: true)
134
+ * - screenshotField: [boolean] Capture screenshot of the field (input element) only (default: false)
135
+ */
136
+ export async function append(
137
+ page: Page,
138
+ field: string | Locator,
139
+ value: string | number,
140
+ options?: string | Record<string, any>
141
+ ) {
142
+ let resolvedvalue = vars.replaceVariables(value.toString());
143
+ const options_json =
144
+ typeof options === "string" ? parseLooseJson(options) : options || {};
145
+ if (!page) throw new Error("Page not initialized");
146
+ const {
147
+ iframe = "",
148
+ actionTimeout = Number(vars.getConfigValue("testExecution.actionTimeout")),
149
+ pattern,
150
+ screenshot = false,
151
+ screenshotText = "",
152
+ screenshotFullPage = true,
153
+ screenshotField = false,
154
+ smartIQ_refreshLoc = "",
155
+ } = options_json || {};
156
+
157
+ if (isPlaywrightRunner()) {
158
+ await __allureAny_form.step(
159
+ `Web: Append -field: ${field} -value: ${value} -options: ${JSON.stringify(
160
+ options_json
161
+ )}`,
162
+ async () => {
163
+ await doAppend();
164
+ }
165
+ );
166
+ } else {
167
+ await doAppend();
168
+ }
169
+ async function doAppend() {
170
+ const target =
171
+ typeof field === "string"
172
+ ? await webLocResolver(
173
+ "input",
174
+ field,
175
+ page,
176
+ pattern,
177
+ smartIQ_refreshLoc
178
+ )
179
+ : field;
180
+
181
+ if (iframe) {
182
+ await waitForEnabled(
183
+ page.frameLocator(iframe).locator(target),
184
+ actionTimeout
185
+ );
186
+ await page
187
+ .frameLocator(iframe)
188
+ .locator(target)
189
+ .type(resolvedvalue, { timeout: actionTimeout });
190
+ } else {
191
+ await waitForEnabled(target, actionTimeout);
192
+ await target.type(resolvedvalue, { timeout: actionTimeout });
193
+ }
194
+
195
+ const isFieldScreenshot = screenshotField === true;
196
+ await processScreenshot(
197
+ page,
198
+ screenshot,
199
+ screenshotText,
200
+ !isFieldScreenshot,
201
+ isFieldScreenshot ? target : undefined
202
+ );
203
+ }
204
+ }
205
+
206
+
207
+ /**
208
+ * Web: Select Option -field: {param} -value: {param} -options: {param}
209
+ *
210
+ * Selects an option in a dropdown by label or value.
211
+ * Delegates to core `selectDropdown`.
212
+ *
213
+ * @param page Playwright Page instance
214
+ * @param field Dropdown locator or string selector
215
+ * @param value Option label or value
216
+ * @param options Optional JSON string or object ({ actionTimeout, pattern })
217
+ */
218
+ /**
219
+ * Web: Select Dropdown -field: {param} -value: {param} -options: {param}
220
+ *
221
+ * Selects a dropdown option by visible text or value.
222
+ * Works with both native <select> elements and custom dropdowns.
223
+ *
224
+ * @param page - Playwright Page instance
225
+ * @param field - Locator or label of the dropdown
226
+ * @param value - Value or label of the option to select
227
+ * @param options - Optional string or object containing:
228
+ * - actionTimeout: custom timeout
229
+ * - pattern: extra pattern string for locator resolution
230
+ * - screenshot: boolean (default false)
231
+ * - screenshotText: text for screenshot description
232
+ * - screenshotFullPage: boolean (default true)
233
+ * - smartIQ_refreshLoc: optional override for locator refresh key
234
+ */
235
+ export async function selectOption(page: Page, field: string | Locator, value: string | number, options?: string | Record<string, any>) {
236
+ const resolvedValue = value !== undefined && value !== null ? vars.replaceVariables(value.toString()) : "";
237
+ const options_json = typeof options === "string" ? vars.parseLooseJson(options) : options || {};
238
+ const { actionTimeout = Number(vars.getConfigValue("testExecution.actionTimeout")) || 30000, pattern, screenshot = false, screenshotText = "", screenshotFullPage = true, smartIQ_refreshLoc = "" } = options_json;
239
+ const stepName = `Web: Select Dropdown -field: ${String(field)} -value: ${resolvedValue} -options: ${JSON.stringify(options_json)}`;
240
+ async function run() {
241
+ if (!page) throw new Error("Page not initialized");
242
+ const target = typeof field === "string" ? await webLocResolver("dropdown", field, page, pattern, actionTimeout, smartIQ_refreshLoc) : field;
243
+ const tag = await (target as Locator).evaluate((el) => el.tagName.toLowerCase());
244
+ try {
245
+ if (tag === "select") {
246
+ await (target as Locator).selectOption({ label: resolvedValue }).catch(async () => { await (target as Locator).selectOption({ value: resolvedValue }); });
247
+ } else {
248
+ await waitForEnabled(target as Locator, actionTimeout);
249
+ await (target as Locator).click();
250
+ const dropdownOptions = page.locator(`role=option >> text="${resolvedValue}"`);
251
+ const visibleOption = dropdownOptions.first();
252
+ if (await visibleOption.isVisible()) {
253
+ await visibleOption.click();
254
+ } else {
255
+ await page.locator(`text="${resolvedValue}"`).first().click();
256
+ }
257
+ }
258
+ } catch (e) {
259
+ throw new Error(`❌ Failed to select "${resolvedValue}" from dropdown: ${e}`);
260
+ }
261
+ await processScreenshot(page, screenshot, screenshotText || `Select: ${resolvedValue}`, screenshotFullPage);
262
+ }
263
+ if (isPlaywrightRunner()) { await __allureAny_form.step(stepName, run); } else { await run(); }
264
+ }
265
+
266
+ /**
267
+ * Web: Upload File -field: {param} -file: {param} -options: {param}
268
+ *
269
+ * Uploads a file to an input element.
270
+ * Delegates to core `uploadFile`.
271
+ *
272
+ * @param page Playwright Page instance
273
+ * @param field File input locator or string selector
274
+ * @param file Local file path
275
+ * @param options Optional JSON string or object ({ actionTimeout })
276
+ */
277
+ export async function uploadFile(page: Page, field: string | Locator, file: string, options?: string | Record<string, any>) {
278
+ const projectRoot = process.env['PLAYQ_PROJECT_ROOT'] || process.cwd();
279
+ let filePath = file;
280
+ if (!path.isAbsolute(filePath)) {
281
+ const basePath = path.resolve(projectRoot, 'test-data');
282
+ filePath = path.resolve(basePath, file);
283
+ }
284
+ filePath = path.normalize(filePath);
285
+ if (!fs.existsSync(filePath)) {
286
+ throw new Error(`File not found for upload: ${filePath}`);
287
+ }
288
+ const options_json = typeof options === "string" ? vars.parseLooseJson(options) : options || {};
289
+ const { actionTimeout = Number(vars.getConfigValue("testExecution.actionTimeout")) || 10000, screenshot = false, screenshotText = "", screenshotFullPage = true, pattern } = options_json || {};
290
+ const stepName = `Web: Upload file at -field: ${String(field)} with filename: ${file} -options: ${JSON.stringify(options_json)}`;
291
+ async function run() {
292
+ if (!page) throw new Error("Page not initialized");
293
+ const target = typeof field === "string" ? await webLocResolver("input", field, page, pattern, actionTimeout) : field;
294
+ await (target as Locator).waitFor({ state: "visible", timeout: actionTimeout });
295
+ const tag = await (target as Locator).evaluate((el: any) => ({ tag: el.tagName.toLowerCase(), type: el.getAttribute('type') || '' }));
296
+ if (tag.tag === 'input' && tag.type.toLowerCase() === 'file') {
297
+ await (target as Locator).setInputFiles(filePath, { timeout: actionTimeout });
298
+ } else {
299
+ const fileChooserPromise = page.waitForEvent('filechooser');
300
+ await (target as Locator).click();
301
+ const fileChooser = await fileChooserPromise;
302
+ await fileChooser.setFiles(filePath);
303
+ }
304
+ }
305
+ if (isPlaywrightRunner()) { await __allureAny_form.step(stepName, run); } else { await run(); }
306
+ }
307
+
308
+ /**
309
+ * Web: Select Dropdown by Index -field: {param} -index: {param} -options: {param}
310
+ *
311
+ * Selects a dropdown option by its index (zero-based).
312
+ * Works with both native <select> elements and custom dropdowns.
313
+ *
314
+ * @param page - Playwright Page instance
315
+ * @param field - Locator or label of the dropdown
316
+ * @param index - Index of the option to select (zero-based)
317
+ * @param options - Optional string or object containing:
318
+ * - actionTimeout: custom timeout
319
+ * - pattern: extra pattern string for locator resolution
320
+ * - screenshot: boolean (default false)
321
+ * - screenshotText: text for screenshot description
322
+ * - screenshotFullPage: boolean (default true)
323
+ * - smartIQ_refreshLoc: optional override for locator refresh key
324
+ */
325
+ export async function selectOptionByIndex(page: Page, field: string | Locator, index: number, options?: string | Record<string, any>) {
326
+ const options_json = typeof options === "string" ? vars.parseLooseJson(options) : options || {};
327
+ const { actionTimeout = Number(vars.getConfigValue("testExecution.actionTimeout")) || 30000, pattern, screenshot = false, screenshotText = "", screenshotFullPage = true, smartIQ_refreshLoc = "" } = options_json;
328
+ const stepName = `Web: Select Dropdown by Index -field: ${String(field)} -index: ${index} -options: ${JSON.stringify(options_json)}`;
329
+ async function run() {
330
+ if (!page) throw new Error("Page not initialized");
331
+ const target = typeof field === "string" ? await webLocResolver("dropdown", field, page, pattern, actionTimeout, smartIQ_refreshLoc) : field;
332
+ const tag = await (target as Locator).evaluate((el) => el.tagName.toLowerCase());
333
+ try {
334
+ if (tag === "select") {
335
+ const optionsCount = await (target as Locator).locator("option").count();
336
+ if (index < 0 || index >= optionsCount) { throw new Error(`❌ Index ${index} is out of bounds for dropdown with ${optionsCount} options`); }
337
+ const optionLocator = (target as Locator).locator("option").nth(index);
338
+ const value = await optionLocator.getAttribute("value");
339
+ await (target as Locator).selectOption({ value });
340
+ } else {
341
+ await (target as Locator).click();
342
+ const dropdownOptions = page.locator('role=option');
343
+ const optionCount = await dropdownOptions.count();
344
+ if (index < 0 || index >= optionCount) { throw new Error(`❌ Index ${index} is out of bounds for custom dropdown with ${optionCount} options`); }
345
+ const optionToClick = dropdownOptions.nth(index);
346
+ await optionToClick.click();
347
+ }
348
+ } catch (e) {
349
+ throw new Error(`❌ Failed to select index ${index} from dropdown: ${e}`);
350
+ }
351
+ await processScreenshot(page, screenshot, screenshotText || `Select dropdown index: ${index}`, screenshotFullPage);
352
+ }
353
+ if (isPlaywrightRunner()) { await __allureAny_form.step(stepName, run); } else { await run(); }
354
+ }
355
+
356
+ /**
357
+ * Web: Select Dropdown -field: {param} -value: {param} -options: {param}
358
+ *
359
+ * Selects a dropdown option by visible text or value.
360
+ * Works with both native <select> elements and custom dropdowns.
361
+ *
362
+ * @param page - Playwright Page instance
363
+ * @param field - Locator or label of the dropdown
364
+ * @param value - Value or label of the option to select
365
+ * @param options - Optional string or object containing:
366
+ * - actionTimeout: custom timeout
367
+ * - pattern: extra pattern string for locator resolution
368
+ * - screenshot: boolean (default false)
369
+ * - screenshotText: text for screenshot description
370
+ * - screenshotFullPage: boolean (default true)
371
+ * - smartIQ_refreshLoc: optional override for locator refresh key
372
+ */
373
+ export async function selectDropdown(
374
+ page: Page,
375
+ field: string | Locator,
376
+ value: string | number,
377
+ options?: string | Record<string, any>
378
+ ) {
379
+ const resolvedValue =
380
+ value !== undefined && value !== null
381
+ ? vars.replaceVariables(value.toString())
382
+ : "";
383
+ const options_json =
384
+ typeof options === "string" ? parseLooseJson(options) : options || {};
385
+
386
+ const {
387
+ actionTimeout,
388
+ pattern,
389
+ screenshot = false,
390
+ screenshotText = "",
391
+ screenshotFullPage = true,
392
+ smartIQ_refreshLoc = "",
393
+ } = options_json;
394
+
395
+ if (isPlaywrightRunner()) {
396
+ await __allureAny_form.step(
397
+ `Web: Select Dropdown -field: ${field} -value: ${resolvedValue} -options: ${JSON.stringify(
398
+ options_json
399
+ )}`,
400
+ async () => {
401
+ await doSelectDropdown();
402
+ }
403
+ );
404
+ } else {
405
+ await doSelectDropdown();
406
+ }
407
+ async function doSelectDropdown() {
408
+ if (!page) throw new Error("Page not initialized");
409
+
410
+ // Resolve dropdown element
411
+ const target =
412
+ typeof field === "string"
413
+ ? await webLocResolver(
414
+ "dropdown",
415
+ field,
416
+ page,
417
+ pattern,
418
+ actionTimeout,
419
+ smartIQ_refreshLoc
420
+ )
421
+ : field;
422
+
423
+ // Determine tag
424
+ const tag = await target.evaluate((el) => el.tagName.toLowerCase());
425
+
426
+ try {
427
+ if (tag === "select") {
428
+ // Native select dropdown
429
+ await target.selectOption({ label: resolvedValue }).catch(async () => {
430
+ await target.selectOption({ value: resolvedValue });
431
+ });
432
+ } else {
433
+ await waitInMilliSeconds(2000);
434
+ // Custom dropdown: aria-haspopup or role-based
435
+ await target.click();
436
+
437
+ const dropdownOptions = page.locator(
438
+ `role=option >> text="${resolvedValue}"`
439
+ );
440
+ const visibleOption = dropdownOptions.first();
441
+
442
+ if (await visibleOption.isVisible()) {
443
+ await visibleOption.click();
444
+ } else {
445
+ // Fallback to plain text match
446
+ await page.locator(`text="${resolvedValue}"`).first().click();
447
+ }
448
+ }
449
+ } catch (e) {
450
+ throw new Error(
451
+ `❌ Failed to select "${resolvedValue}" from dropdown: ${e}`
452
+ );
453
+ }
454
+
455
+ await processScreenshot(
456
+ page,
457
+ screenshot,
458
+ screenshotText || `Select: ${resolvedValue}`,
459
+ screenshotFullPage
460
+ );
461
+ }
462
+ }
463
+
464
+ /**
465
+ * Alias: Select Dropdown by Index (wrapper to selectOptionByIndex)
466
+ */
467
+ export async function selectDropdownByIndex(page: Page, field: string | Locator, index: number, options?: string | Record<string, any>) {
468
+ return selectOptionByIndex(page, field, index, options);
469
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @file iframeActions.ts
3
+ *
4
+ * Frame switching helpers for PlayQ web actions.
5
+ * Provides utilities to switch to a specific iframe and back to main content
6
+ * with runner-aware step wrappers and robust error handling.
7
+ *
8
+ * Authors: PlayQ Team
9
+ * Version: v1.0.0
10
+ */
11
+ import * as allure from "allure-js-commons";
12
+ import type { Page, Frame, Locator } from "playwright";
13
+ import { vars, webLocResolver } from "../../../global";
14
+
15
+ function isPlaywrightRunner() { return process.env.TEST_RUNNER === 'playwright'; }
16
+ const __allureAny_iframe: any = allure as any;
17
+ if (typeof __allureAny_iframe.step !== 'function') { __allureAny_iframe.step = async (_n: string, f: any) => await f(); }
18
+
19
+ /**
20
+ * Web: Switch To Frame -selector: {param} -options: {param}
21
+ *
22
+ * Switches execution context to the specified iframe.
23
+ *
24
+ * @param page - Playwright Page instance
25
+ * @param frameSelector - Frame locator or string selector
26
+ * @param options - Optional JSON string or object ({ pattern, actionTimeout })
27
+ * @returns The resolved `Frame`
28
+ * @throws Error if page is not initialized or frame not found
29
+ */
30
+ export async function switchToFrame(page: Page, frameSelector: string | Locator, options?: string | Record<string, any>): Promise<Frame> {
31
+ if (!page) throw new Error("Page not initialized");
32
+ const options_json = typeof options === 'string' ? vars.parseLooseJson(options) : options || {};
33
+ const locator = typeof frameSelector === 'string'
34
+ ? await webLocResolver(options_json?.fieldType || '', frameSelector, page, options_json?.pattern, typeof options_json?.actionTimeout === 'number' ? options_json.actionTimeout : undefined, options_json?.smartAiRefresh || '')
35
+ : frameSelector;
36
+ let frame: Frame | null = null;
37
+ const stepName = `Web: Switch To Frame -selector: ${typeof frameSelector === 'string' ? frameSelector : '<locator>'}`;
38
+ if (isPlaywrightRunner()) {
39
+ await __allureAny_iframe.step(stepName, async () => {
40
+ frame = await locator.elementHandle().then(h => h?.contentFrame() || null);
41
+ if (!frame) throw new Error('Frame not found');
42
+ });
43
+ } else {
44
+ frame = await locator.elementHandle().then(h => h?.contentFrame() || null);
45
+ if (!frame) throw new Error('Frame not found');
46
+ }
47
+ return frame as Frame;
48
+ }
49
+
50
+ /**
51
+ * Web: Switch To Main Content -options: {param}
52
+ *
53
+ * Returns to the main document context.
54
+ *
55
+ * @param page - Playwright Page instance
56
+ * @param options - Optional JSON string or object (reserved)
57
+ * @throws Error if page is not initialized
58
+ */
59
+ export async function switchToMainContent(page: Page, options?: string | Record<string, any>) {
60
+ if (!page) throw new Error("Page not initialized");
61
+ const stepName = `Web: Switch To Main Content`;
62
+ if (isPlaywrightRunner()) {
63
+ await __allureAny_iframe.step(stepName, async () => { /* No-op: page operates on main frame */ });
64
+ } else {
65
+ /* No-op */
66
+ }
67
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @file javascriptActions.ts
3
+ *
4
+ * Execute custom JavaScript in the page context with PlayQ.
5
+ * Wraps page.evaluate with reporting-friendly step wrappers.
6
+ *
7
+ * Authors: PlayQ Team
8
+ * Version: v1.0.0
9
+ */
10
+ import * as allure from "allure-js-commons";
11
+ import type { Page } from "playwright";
12
+
13
+ function isPlaywrightRunner() { return process.env.TEST_RUNNER === 'playwright'; }
14
+ const __allureAny_js: any = allure as any;
15
+ if (typeof __allureAny_js.step !== 'function') { __allureAny_js.step = async (_n: string, f: any) => await f(); }
16
+
17
+ /**
18
+ * Web: Execute Script -options: {param}
19
+ *
20
+ * Executes a function in the browser context via `page.evaluate`.
21
+ *
22
+ * @param page - Playwright Page instance
23
+ * @param fn - Function to execute in the page context
24
+ * @param args - Optional array passed as a single argument to the function
25
+ * @returns The function result
26
+ * @throws Error if page is not initialized or `fn` is not a function
27
+ */
28
+ export async function execute<T>(page: Page, fn: (...args: any[]) => any, args?: any[]) {
29
+ if (!page) throw new Error("Page not initialized");
30
+ if (typeof fn !== 'function') throw new Error("javascript.execute: 'fn' must be a function");
31
+ const stepName = `Web: Execute Script`;
32
+ const run = async () => page.evaluate(fn, ...(args ? [args] : []));
33
+ if (isPlaywrightRunner()) { return __allureAny_js.step(stepName, run); }
34
+ return run();
35
+ }
36
+
37
+ // Friendly aliases
38
+ export const executeScript = execute;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * @file keyboardActions.ts
3
+ *
4
+ * Keyboard interaction utilities for PlayQ web actions.
5
+ * Provides typing and key press helpers with screenshot options and
6
+ * runner-aware step wrappers.
7
+ *
8
+ * Authors: PlayQ Team
9
+ * Version: v1.0.0
10
+ */
11
+ import * as allure from "allure-js-commons";
12
+ import { Page } from "@playwright/test";
13
+ import { waitForPageToLoad } from "./waitActions";
14
+ import { processScreenshot } from "./screenshotActions";
15
+ import { parseLooseJson } from '../../bundle/vars';
16
+
17
+ function isPlaywrightRunner() { return process.env.TEST_RUNNER === 'playwright'; }
18
+ const __allureAny_keys: any = allure as any;
19
+ if (typeof __allureAny_keys.step !== 'function') { __allureAny_keys.step = async (_n: string, f: any) => await f(); }
20
+ // Allure compatibility shim: if step is unavailable, just run the body
21
+ const __allureAny_web: any = allure as any;
22
+ if (typeof __allureAny_web.step !== 'function') {
23
+ __allureAny_web.step = async (_name: string, fn: any) => await fn();
24
+ }
25
+
26
+ /**
27
+ * Web: Press Key -key: {param} -options: {param}
28
+ *
29
+ * Presses a keyboard key on the page or a specific element.
30
+ *
31
+ * @param page - Playwright Page instance
32
+ * @param key - The key to press (e.g., "Enter", "Tab", "ArrowDown", "a", etc.)
33
+ * @param options - Optional string or object:
34
+ * - screenshot: [boolean] Capture screenshot after pressing the key. Default: false.
35
+ * - screenshotText: [string] Description for the screenshot. Default: "".
36
+ * - screenshotFullPage: [boolean] Full page screenshot. Default: true.
37
+ *
38
+ * @example
39
+ * await pressKey(page, 'Enter', { field: 'Username', screenshot: true });
40
+ */
41
+ export async function pressKey(
42
+ page: Page,
43
+ key: string,
44
+ options?: string | Record<string, any>
45
+ ) {
46
+ const options_json =
47
+ typeof options === "string" ? parseLooseJson(options) : options || {};
48
+ const {
49
+ screenshot = false,
50
+ screenshotText = "",
51
+ screenshotFullPage = true,
52
+ } = options_json;
53
+
54
+ if (!page) throw new Error("Page not initialized");
55
+
56
+ if (isPlaywrightRunner()) {
57
+ await __allureAny_keys.step(
58
+ `Web: Press Key -key: ${key} -options: ${JSON.stringify(options_json)}`,
59
+ async () => {
60
+ await doPressKey();
61
+ }
62
+ );
63
+ } else {
64
+ await doPressKey();
65
+ }
66
+
67
+ async function doPressKey() {
68
+ await waitForPageToLoad(page);
69
+ await page.keyboard.press(key, { delay: 0 });
70
+ await processScreenshot(
71
+ page,
72
+ screenshot,
73
+ screenshotText || `Pressed key: ${key}`,
74
+ screenshotFullPage
75
+ );
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Web: Press Enter -options: {param}
81
+ *
82
+ * Convenience wrapper to press the Enter key.
83
+ *
84
+ * @param page Playwright Page instance
85
+ * @param options Optional JSON string or object ({ delay })
86
+ */
87
+ export async function pressEnter(page: Page, options?: string | Record<string, any>) {
88
+ return pressKey(page, "Enter", options);
89
+ }
90
+
91
+ /**
92
+ * Web: Press Tab -options: {param}
93
+ *
94
+ * Convenience wrapper to press the Tab key.
95
+ *
96
+ * @param page Playwright Page instance
97
+ * @param options Optional JSON string or object ({ delay })
98
+ */
99
+ export async function pressTab(page: Page, options?: string | Record<string, any>) {
100
+ return pressKey(page, "Tab", options);
101
+ }