@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,57 @@
1
+ import { Logger, createLogger } from 'winston';
2
+ import { options } from '../util/logger';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+
6
+ let logger: Logger;
7
+
8
+ export const logFixture = {
9
+ init(scenarioName: string): void {
10
+ logger = createLogger(options(scenarioName));
11
+ },
12
+ get(): Logger {
13
+ if (!logger) throw new Error("Logger not initialized!");
14
+ return logger;
15
+ },
16
+ setLogger(log: Logger) {
17
+ logger = log;
18
+ },
19
+ getLogger(): Logger {
20
+ return logger;
21
+ },
22
+ async attach(name: string, data: Buffer, type: string = 'application/octet-stream') {
23
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
24
+ const ext = type.includes('png') ? 'png' : type.includes('jpg') ? 'jpg' : 'txt';
25
+ const filename = `${timestamp}-${name.replace(/\s+/g, '_')}.${ext}`;
26
+ const attachmentDir = path.resolve('logs', 'attachments');
27
+ const filePath = path.join(attachmentDir, filename);
28
+
29
+ fs.mkdirSync(attachmentDir, { recursive: true });
30
+ fs.writeFileSync(filePath, data);
31
+
32
+ logger.info(`๐Ÿ“Ž Attached file: ${filePath}`);
33
+ }
34
+ };
35
+
36
+
37
+ // // src/hooks/logFixture.ts
38
+ // import { Logger, createLogger, format, transports } from 'winston';
39
+
40
+ // let logger: Logger;
41
+
42
+ // export const logFixture = {
43
+ // init(scenarioName: string): void {
44
+ // logger = createLogger({
45
+ // level: 'info',
46
+ // format: format.combine(
47
+ // format.timestamp(),
48
+ // format.printf(({ timestamp, level, message }) => `[${timestamp}] ${level}: ${message}`)
49
+ // ),
50
+ // transports: [new transports.Console()]
51
+ // });
52
+ // },
53
+ // get(): Logger {
54
+ // if (!logger) throw new Error("Logger not initialized!");
55
+ // return logger;
56
+ // }
57
+ // };
@@ -0,0 +1,206 @@
1
+ import type { Browser, BrowserContext, Page, Frame } from "playwright";
2
+ import { Logger } from "winston";
3
+ import { invokeBrowser } from "../browsers/browserManager";
4
+ // Inline runner detection to avoid external alias dependency
5
+ function isPlaywrightRunner() { return process.env.TEST_RUNNER === 'playwright'; }
6
+
7
+
8
+ const pages = new Map<string, Page>();
9
+ const frames = new Map<string, Frame>();
10
+ let currentPage: Page | undefined;
11
+ let currentFrame: Frame | undefined;
12
+ let logger: Logger;
13
+ let currentPageName = "main";
14
+ let browser: Browser;
15
+ let context: BrowserContext;
16
+ let _world: any = null;
17
+ let smartIQData: any[] = [];
18
+
19
+
20
+ export const webFixture = {
21
+ pages,
22
+ frames,
23
+ async launchBrowser() {
24
+ browser = await invokeBrowser();
25
+ },
26
+ async newContext(options?: Parameters<Browser["newContext"]>[0]) {
27
+ if (!options) {
28
+ options = {
29
+ recordVideo: {
30
+ dir: "test-results/videos",
31
+ },
32
+ };
33
+ }
34
+ context = await browser.newContext(options);
35
+ return context;
36
+ },
37
+ async newPage(name = "main") {
38
+ const page = await context.newPage();
39
+ pages.set(name, page);
40
+ currentPage = page;
41
+ currentPageName = name;
42
+ return page;
43
+ },
44
+ getBrowser() {
45
+ return browser;
46
+ },
47
+ getContext() {
48
+ return context;
49
+ },
50
+ getCurrentPage(): Page | undefined {
51
+ return currentPage;
52
+ },
53
+ setCurrentPage(name: string) {
54
+ currentPage = pages.get(name);
55
+ currentPageName = name;
56
+ },
57
+ async closeContext() {
58
+ if (context) {
59
+ await context.close();
60
+ }
61
+ },
62
+ async closeAll() {
63
+ try {
64
+ if (context) {
65
+ // Close all pages explicitly
66
+ const allPages = context.pages();
67
+ for (const page of allPages) {
68
+ try {
69
+ // If tracing is on, stop and save
70
+ if (context.tracing && context.tracing.stop) {
71
+ await context.tracing.stop({ path: `test-results/trace/trace.zip` });
72
+ }
73
+ await page.close();
74
+ } catch (err) {
75
+ // Swallow errors silently
76
+ }
77
+ }
78
+ await context.close();
79
+ }
80
+ if (browser) {
81
+ await browser.close();
82
+ }
83
+ } catch (err) {
84
+ // Swallow errors silently
85
+ }
86
+ },
87
+ setWorld(world: any) {
88
+ _world = world;
89
+ },
90
+ getWorld(): any {
91
+ if (isPlaywrightRunner()) {
92
+ console.warn('โš ๏ธ Skipping getWorld() in Playwright Runner');
93
+ return null;
94
+ }
95
+ if (!_world) {
96
+ throw new Error("โŒ Cucumber World context not set. Did you forget to call webFixture.setWorld(this) in your step?");
97
+ }
98
+ return _world;
99
+ },
100
+ // other frame helpers remain the same
101
+ setPlaywrightPage(page: Page) { // โœ… Added this method!
102
+ console.log('โœ… Playwright page set in webFixture');
103
+ currentPage = page;
104
+ },
105
+ // SmartIQ Imeplementation
106
+ getSmartIQData(): any[] {
107
+ return smartIQData;
108
+ },
109
+
110
+ setSmartIQData(data: any[]) {
111
+ smartIQData = data;
112
+ }
113
+ };
114
+
115
+
116
+ async function createContextWithDefaults(scenarioName: string): Promise<BrowserContext> {
117
+ const ctx = await browser.newContext({
118
+ recordVideo: {
119
+ dir: "test-results/videos",
120
+ },
121
+ });
122
+
123
+ await ctx.tracing.start({
124
+ name: scenarioName,
125
+ title: scenarioName,
126
+ sources: true,
127
+ screenshots: true,
128
+ snapshots: true,
129
+ });
130
+
131
+ return ctx;
132
+ }
133
+
134
+ // import { Page, Frame } from "@playwright/test";
135
+ // import { Logger } from "winston";
136
+ // import { invokeBrowser } from "@helper/browsers/browserManager";
137
+
138
+
139
+ // const pages = new Map<string, Page>();
140
+ // const frames = new Map<string, Frame>();
141
+ // let currentPage: Page | undefined;
142
+ // let currentFrame: Frame | undefined;
143
+ // let logger: Logger;
144
+ // let currentPageName: string = "main";
145
+
146
+ // export const uiFixture = {
147
+ // pages,
148
+ // frames,
149
+ // setPage(page: Page) {
150
+ // pages.set(currentPageName, page);
151
+ // },
152
+ // setPageWithName(name: string, page: Page) {
153
+ // pages.set(name, page);
154
+ // currentPage = page;
155
+ // currentPageName = name;
156
+ // },
157
+ // getPage(name: string): Page | undefined {
158
+ // return pages.get(name);
159
+ // },
160
+ // setCurrentPage(name: string) {
161
+ // currentPage = pages.get(name);
162
+ // currentPageName = name;
163
+ // },
164
+ // getCurrentPage(): Page | undefined {
165
+ // return currentPage;
166
+ // },
167
+ // getCurrentPageName(): string {
168
+ // return currentPageName;
169
+ // },
170
+ // setFrame(name: string, frame: Frame) {
171
+ // frames.set(name, frame);
172
+ // currentFrame = frame;
173
+ // },
174
+ // getFrame(name: string): Frame | undefined {
175
+ // return frames.get(name);
176
+ // },
177
+ // setCurrentFrame(name: string) {
178
+ // currentFrame = frames.get(name);
179
+ // },
180
+ // getCurrentFrame(): Frame | undefined {
181
+ // return currentFrame;
182
+ // },
183
+ // setLogger(log: Logger) {
184
+ // logger = log;
185
+ // },
186
+ // getLogger(): Logger {
187
+ // return logger;
188
+ // }
189
+ // };
190
+
191
+
192
+
193
+
194
+
195
+
196
+
197
+
198
+
199
+ // import { Page } from "@playwright/test";
200
+ // import { Logger } from "winston";
201
+
202
+ // export const fixture = {
203
+ // // @ts-ignore
204
+ // page: undefined as Page,
205
+ // logger: undefined as Logger
206
+ // }
@@ -0,0 +1,143 @@
1
+ // src/helper/loc/locatorResolver.ts
2
+ import type { Page, Locator } from "playwright";
3
+ import * as vars from "../bundle/vars";
4
+ // Access project-provided engines dynamically at call time to avoid module init ordering issues
5
+ function getEngines(): any { return (globalThis as any).engines || {}; }
6
+ // import { smartAI} from "@project/engines/smartAi/smartAiEngine";
7
+
8
+
9
+
10
+
11
+ export async function webLocResolver(
12
+ type: string,
13
+ selector: string,
14
+ pageArg: Page,
15
+ overridePattern?: string,
16
+ timeout?: number,
17
+ smartAiRefresh: 'before' | 'after' | '' = ''
18
+ ): Promise<Locator> {
19
+ console.log(`๐Ÿ” Resolving locator: ${selector}`);
20
+ const page = pageArg
21
+ const isPlaywrightPrefixed = selector.startsWith("xpath=") || selector.startsWith("xpath =") || selector.startsWith("css=") || selector.startsWith("css =");
22
+ if (isPlaywrightPrefixed) {
23
+ // const rawSelector = selector.replace(/^xpath=|^css=|^xpath =|^xpath=\\|^xpath =\\|^css =/, "");
24
+ // Normalize escaped forward slashes first, then remove prefix
25
+ const rawSelector = selector
26
+ .replace(/^xpath=\\|^xpath =\\/, "xpath=") // normalize `xpath=\` to `xpath=`
27
+ .replace(/^xpath=|^xpath =|^css=|^css =/, "") // remove the actual prefix
28
+ .replace(/\\\//g, "/"); // replace escaped slashes with normal ones
29
+ console.log("๐Ÿ“ Detected Playwright-prefixed selector. Returning raw locator.");
30
+ return page.locator(rawSelector);
31
+ }
32
+
33
+ const isPlaywrightChainedPrefixed = selector.startsWith("chain=") || selector.startsWith("chain =");
34
+ if (isPlaywrightChainedPrefixed) {
35
+ const rawSelector = selector.replace(/^chain=|^chain =/, "");
36
+ console.log("๐Ÿ“ Detected Playwright-prefixed chained selector. Returning raw locator.");
37
+ return page.locator(rawSelector);
38
+ }
39
+
40
+ const isXPath =
41
+ selector.trim().startsWith("//") || selector.trim().startsWith("(");
42
+ const isCSS =
43
+ selector.includes(">") ||
44
+ selector.startsWith(".") ||
45
+ selector.includes("#");
46
+ const isChained = selector.includes(">>");
47
+ const isResourceLocator = selector.startsWith("loc.");
48
+
49
+ if ((isXPath || isCSS || isChained) && !isResourceLocator) {
50
+ console.log("๐Ÿ“ Detected XPath/CSS/Chained. Returning locator directly.");
51
+ return page.locator(selector);
52
+ }
53
+
54
+ if (isResourceLocator) {
55
+ const parts = selector.split(".");
56
+ if (parts.length < 3) {
57
+ throw new Error(
58
+ `โŒ Invalid locator format: "${selector}". Expected format: loc.(ts|json).<page>.<field>`
59
+ );
60
+ }
61
+
62
+ const [, locType, pageName, fieldName] = parts;
63
+ if (selector.startsWith("loc.json.")) {
64
+ const [, , fileName, pageName, fieldName] = selector.split(".");
65
+ const jsonLocatorMap = await import(
66
+ `@resources/locators/json/${fileName}.json`
67
+ );
68
+ const pageObj = jsonLocatorMap?.[pageName];
69
+ if (!pageObj)
70
+ throw new Error(
71
+ `โŒ Page "${pageName}" not found in ${fileName}.json`
72
+ );
73
+ const locatorString = pageObj[fieldName];
74
+ if (!locatorString)
75
+ throw new Error(
76
+ `โŒ Field "${fieldName}" not found in ${fileName}.json[${pageName}]`
77
+ );
78
+ console.log(
79
+ `๐Ÿงฉ Resolved locator string from loc.json.${fileName}.${pageName}.${fieldName} -> ${locatorString}`
80
+ );
81
+ return page.locator(await vars.replaceVariables(locatorString));
82
+ }
83
+
84
+ if (selector.startsWith("loc.ts.")) {
85
+ const [, , fileName, pageName, fieldName] = selector.split(".");
86
+ // First try globalThis.loc if available
87
+ const globalLoc = (globalThis as any).loc;
88
+ if (globalLoc?.[fileName]?.[pageName]?.[fieldName]) {
89
+ // console.log(`โœ… Found locator in globalThis.loc for loc.ts.${fileName}.${pageName}.${fieldName}`);
90
+ return globalLoc[fileName][pageName][fieldName](page);
91
+ }
92
+ }
93
+
94
+ if (selector.startsWith("loc.")) {
95
+ const [, fileName, pageName, fieldName] = selector.split(".");
96
+
97
+ // First try globalThis.loc if available
98
+ const globalLoc = (globalThis as any).loc;
99
+ if (globalLoc?.[fileName]?.[pageName]?.[fieldName]) {
100
+ // console.log(`โœ… Found locator in globalThis.loc for loc.ts.${fileName}.${pageName}.${fieldName}`);
101
+ return globalLoc[fileName][pageName][fieldName](page);
102
+ }
103
+ }
104
+
105
+
106
+ throw new Error(
107
+ `โŒ Unknown locator source type "${locType}". Use loc. or locator.`
108
+ );
109
+ }
110
+ if (overridePattern && overridePattern.toLowerCase() === '-no-check-') {
111
+ console.log("๐Ÿ“ '-no-check-' detected. Skipping locator resolution.");
112
+ return undefined as any; // or even better, throw a custom signal or null to trigger fallback
113
+ }
114
+
115
+ // SmartAI (guard if engine missing)
116
+ const isSmartAiEnabled = String(vars.getConfigValue('smartAi.enable')).toLowerCase().trim() === 'true';
117
+ if (isSmartAiEnabled) {
118
+ const smartAiEngine = getEngines()?.smartAi;
119
+ if (typeof smartAiEngine === 'function') {
120
+ return await smartAiEngine(page, type, selector, smartAiRefresh);
121
+ } else {
122
+ console.warn('โš ๏ธ SmartAI enabled but engines.smartAi not available/function. Falling back.');
123
+ }
124
+ }
125
+
126
+ // Fallback to locatorPattern (locPattern)
127
+ const isPatternEnabled = String(vars.getConfigValue('patternIq.enable')).toLowerCase().trim() === 'true';
128
+ console.log('PatternIQ enabled?', isPatternEnabled);
129
+ if (isPatternEnabled) {
130
+ const eng = getEngines();
131
+ try { console.log('PatternIQ engines keys:', Object.keys(eng || {})); } catch {}
132
+ const patternEngine = eng?.patternIq || (eng && (eng as any).engines && (eng as any).engines.patternIq);
133
+ if (typeof patternEngine === 'function') {
134
+ return await patternEngine(page, type, selector, overridePattern, timeout);
135
+ } else {
136
+ console.warn('โš ๏ธ PatternIQ enabled but engines.patternIq not available/function. Falling back to default locator.');
137
+ }
138
+ }
139
+
140
+ // Fallback to default locator
141
+ return page.locator(selector);
142
+ }
143
+
@@ -0,0 +1,26 @@
1
+ // src/helper/report/allureStepLogger.ts
2
+ // import { step, attachment, owner, issue } from 'allure-js-commons';
3
+ // import { isCucumberRunner } from '@config/runner';
4
+ // import { webFixture } from '@helper/fixtures/webFixture';
5
+
6
+ // /**
7
+ // * Logs a step to Allure or attaches it in Cucumber world.
8
+ // *
9
+ // * @param stepName Description of the step
10
+ // * @param stepFn Function to execute within the step
11
+ // */
12
+ // export async function logStep(stepName: string, stepFn: () => Promise<void>) {
13
+ // if (isCucumberRunner()) {
14
+ // const world = webFixture.getWorld();
15
+ // try {
16
+ // await world.attach(`๐ŸŸก Step: ${stepName}`, 'text/plain');
17
+ // await stepFn();
18
+ // await world.attach(`โœ… Passed: ${stepName}`, 'text/plain');
19
+ // } catch (err: any) {
20
+ // await world.attach(`โŒ Failed: ${stepName} - ${err.message}`, 'text/plain');
21
+ // throw err;
22
+ // }
23
+ // } else {
24
+ // await allure.step(stepName, stepFn);
25
+ // }
26
+ // }
@@ -0,0 +1,61 @@
1
+ import fs from 'fs';
2
+
3
+ const inputPath = 'test-results/cucumber-report.json';
4
+ const outputPath = 'test-results/cucumber-report-custom.json';
5
+
6
+ function extractReplacements(embeddings: any[]): Record<string, string> {
7
+ const replacements: Record<string, string> = {};
8
+ embeddings?.forEach(embed => {
9
+ const data = embed?.data;
10
+ const match = data?.match(/Replaced: \|\\?"(.*?)\\?"\|-with-\|(.*?)\|/);
11
+ if (match) {
12
+ const original = match[1];
13
+ const replaced = match[2];
14
+ replacements[original] = replaced;
15
+ }
16
+ });
17
+ return replacements;
18
+ }
19
+
20
+ function updateStepName(step: any) {
21
+ const replacements = extractReplacements(step.embeddings || []);
22
+ for (const [original, replaced] of Object.entries(replacements)) {
23
+ const quotedOriginal = `"${original}"`;
24
+ const quotedReplaced = `"${replaced}"`;
25
+ step.name = step.name.replace(quotedOriginal, quotedReplaced);
26
+ }
27
+ }
28
+
29
+ function processReport() {
30
+ const raw = fs.readFileSync(inputPath, 'utf-8');
31
+ if (!raw || !raw.trim()) {
32
+ console.warn("โš ๏ธ customiseReport: Empty or invalid JSON input. Skipping processing.");
33
+ return;
34
+ }
35
+ const report = JSON.parse(raw);
36
+
37
+ for (const feature of report) {
38
+ for (const scenario of feature.elements || []) {
39
+ for (const step of scenario.steps || []) {
40
+ updateStepName(step);
41
+ // Check for soft assertion failures in embeddings
42
+ if (
43
+ Array.isArray(step.embeddings) &&
44
+ step.embeddings.some(
45
+ (embed) =>
46
+ typeof embed.data === "string" &&
47
+ embed.data.includes("Soft Assertion: [Failed]")
48
+ )
49
+ ) {
50
+ if (!step.result) step.result = {};
51
+ step.result.status = "failed";
52
+ }
53
+ }
54
+ }
55
+ }
56
+
57
+ fs.writeFileSync(outputPath, JSON.stringify(report, null, 2), 'utf-8');
58
+ console.log(`โœ… Updated report written to ${outputPath}`);
59
+ }
60
+
61
+ processReport();
@@ -0,0 +1,18 @@
1
+
2
+ const fs = require("fs-extra");
3
+
4
+ try {
5
+ fs.ensureDirSync("test-results/screenshots");
6
+ fs.emptyDirSync("test-results/screenshots");
7
+
8
+ fs.ensureDirSync("test-results/videos");
9
+ fs.emptyDirSync("test-results/videos");
10
+
11
+ fs.ensureDirSync("test-results/trace");
12
+ fs.emptyDirSync("test-results/trace");
13
+
14
+ // Do NOT clean the whole test-results folder!
15
+ // fs.emptyDirSync("test-results");
16
+ } catch (error) {
17
+ console.log("โš ๏ธ Folder setup failed! " + error);
18
+ }
@@ -0,0 +1,72 @@
1
+ const report = require("multiple-cucumber-html-reporter");
2
+ import * as fs from "fs";
3
+ import * as os from "os";
4
+
5
+
6
+ const jsonPath = "test-results/cucumber-report.json";
7
+ if (!fs.existsSync(jsonPath)) {
8
+ console.warn("โš ๏ธ cucumber-report.json not found.");
9
+ const files = fs.readdirSync("test-results");
10
+ console.warn("๐Ÿ“ test-results folder contains:", files);
11
+ } else {
12
+ // ๐Ÿ’ก Load JSON, patch paths, save back
13
+ const raw = fs.readFileSync(jsonPath, "utf-8");
14
+ const data = JSON.parse(raw);
15
+ data.forEach((feature: any) => {
16
+ if (feature.uri?.startsWith("_TEMP/execution/")) {
17
+ feature.uri = feature.uri.replace("_TEMP/execution/", "");
18
+ }
19
+ });
20
+ fs.writeFileSync(jsonPath, JSON.stringify(data, null, 2)); // Save the cleaned version
21
+ }
22
+
23
+ // Removing "_TEMP/execution/" from cucumber-report.html
24
+ const htmlReportPath = "test-results/cucumber-report.html";
25
+ if (fs.existsSync(htmlReportPath)) {
26
+ let html = fs.readFileSync(htmlReportPath, "utf-8");
27
+ // Use split/join for wide Node compatibility (avoid String.replaceAll requirement)
28
+ const updatedHtml = html.split("_TEMP/execution/").join("");
29
+
30
+ fs.writeFileSync(htmlReportPath, updatedHtml, "utf-8");
31
+ console.log("๐Ÿงผ Cleaned cucumber-report.html by removing '_TEMP/execution/'");
32
+ } else {
33
+ console.warn("โš ๏ธ cucumber-report.html not found.");
34
+ }
35
+
36
+ if (fs.existsSync(jsonPath)) {
37
+ fs.unlinkSync(jsonPath);
38
+ console.log(`๐Ÿ—‘๏ธ Removed existing ${jsonPath}`);
39
+ }
40
+
41
+
42
+ // Fetching the system details
43
+ const platformName = os.platform();
44
+ const platformVersion = os.release();
45
+ const deviceName = os.hostname();
46
+
47
+ report.generate({
48
+ jsonDir: "test-results",
49
+ reportPath: "test-results/reports/",
50
+ reportName: "Playwright Automation Report",
51
+ pageTitle: "BookCart App test report",
52
+ displayDuration: false,
53
+ metadata: {
54
+ browser: {
55
+ name: "chrome",
56
+ version: "112",
57
+ },
58
+ device: deviceName,
59
+ platform: {
60
+ name: platformName,
61
+ version: platformVersion,
62
+ },
63
+ },
64
+ customData: {
65
+ title: "Test Info",
66
+ data: [
67
+ { label: "Project", value: "Book Cart Application" },
68
+ { label: "Release", value: "1.2.3" },
69
+ { label: "Cycle", value: "Smoke-1" },
70
+ ],
71
+ },
72
+ });
@@ -0,0 +1,42 @@
1
+
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import * as XLSX from '@e965/xlsx';
5
+
6
+ type DataFormat = 'json' | 'excel' | 'csv';
7
+
8
+ /**
9
+ * Reads test data from .json, .xlsx, or .csv
10
+ *
11
+ * @param file - Filename (without extension), e.g., "login"
12
+ * @param format - File format: "json" | "excel" | "csv"
13
+ * @param sheetName - (optional) Sheet name for Excel files
14
+ */
15
+ export function getTestData(file: string, format: DataFormat = 'json', sheetName?: string): any[] {
16
+ const basePath = path.resolve(`resources/test-data`);
17
+
18
+ switch (format) {
19
+ case 'json': {
20
+ const jsonPath = path.join(basePath, `${file}.json`);
21
+ const raw = fs.readFileSync(jsonPath, 'utf-8');
22
+ return JSON.parse(raw);
23
+ }
24
+
25
+ case 'excel': {
26
+ const xlsxPath = path.join(basePath, `${file}.xlsx`);
27
+ const workbook = XLSX.readFile(xlsxPath);
28
+ const sheet = workbook.Sheets[sheetName || workbook.SheetNames[0]];
29
+ return XLSX.utils.sheet_to_json(sheet);
30
+ }
31
+
32
+ case 'csv': {
33
+ const csvPath = path.join(basePath, `${file}.csv`);
34
+ const fileData = fs.readFileSync(csvPath, 'utf-8');
35
+ const worksheet = XLSX.read(fileData, { type: 'string' }).Sheets['Sheet1'];
36
+ return XLSX.utils.sheet_to_json(worksheet);
37
+ }
38
+
39
+ default:
40
+ throw new Error(`Unsupported format: ${format}`);
41
+ }
42
+ }
@@ -0,0 +1,32 @@
1
+ import { transports, format } from "winston";
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+
5
+ // โœ… Replace invalid characters for Windows file/folder names
6
+ function sanitiseFileName(name: string): string {
7
+ return name.replace(/[<>:"/\\|?*\x00-\x1F]/g, '_').slice(0, 100);
8
+ }
9
+
10
+ export function options(scenarioName: string) {
11
+ const sanitised = sanitiseFileName(scenarioName);
12
+ const logDir = path.join("test-results", "logs", sanitised);
13
+
14
+ // โœ… Ensure directory exists
15
+ if (!fs.existsSync(logDir)) {
16
+ fs.mkdirSync(logDir, { recursive: true });
17
+ }
18
+
19
+ return {
20
+ transports: [
21
+ new transports.File({
22
+ filename: path.join(logDir, "log.log"),
23
+ level: 'info',
24
+ format: format.combine(
25
+ format.timestamp({ format: 'MMM-DD-YYYY HH:mm:ss' }),
26
+ format.align(),
27
+ format.printf(info => `${info.level}: ${[info.timestamp]}: ${info.message}`)
28
+ )
29
+ }),
30
+ ]
31
+ }
32
+ };