ftmocks-utils 1.4.0 → 1.4.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ftmocks-utils",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "Util functions for FtMocks",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -79,6 +79,42 @@ const runEvent = async (page, event, delay = 0) => {
79
79
  }
80
80
  };
81
81
 
82
+ const isValidEvent = (event) => {
83
+ try {
84
+ console.log("➡ Validating event", event);
85
+ switch (event?.type) {
86
+ case "url":
87
+ return true;
88
+ case "click":
89
+ return true;
90
+ case "input":
91
+ return true;
92
+ case "keypress":
93
+ return true;
94
+ case "change":
95
+ return true;
96
+ case "dblclick":
97
+ return true;
98
+ case "contextmenu":
99
+ return true;
100
+ case "hover":
101
+ return true;
102
+ case "keydown":
103
+ return true;
104
+ case "keyup":
105
+ return true;
106
+ default:
107
+ return false;
108
+ }
109
+ } catch (error) {
110
+ console.error("Error running event", {
111
+ error: error.message,
112
+ stack: error.stack,
113
+ });
114
+ }
115
+ return false;
116
+ };
117
+
82
118
  const runEvents = async (page, events, delay = 1000) => {
83
119
  for (const event of events) {
84
120
  await runEvent(page, event, delay);
@@ -95,6 +131,13 @@ const runEventsForTest = async (page, ftmocksConifg, testName) => {
95
131
  await runEvents(page, events, ftmocksConifg.delay || 1000);
96
132
  };
97
133
 
134
+ const getSelectorPosition = async (page, selector) => {
135
+ const element = await page.locator(selector).elementHandle();
136
+ const position = await element.boundingBox();
137
+ console.log("position", position);
138
+ return position;
139
+ };
140
+
98
141
  const runEventsInPresentationMode = async (page, ftmocksConifg, testName) => {
99
142
  let currentEventIndex = 1;
100
143
  const eventsFile = path.join(
@@ -119,8 +162,18 @@ const runEventsInPresentationMode = async (page, ftmocksConifg, testName) => {
119
162
  currentEventIndex = currentEventIndex + 1;
120
163
  });
121
164
 
165
+ await page.exposeFunction("focusOnBodyForPresentationMode", async () => {
166
+ await page.bringToFront();
167
+ });
168
+
122
169
  // Inject keyboard listener into browser
123
170
  await page.addInitScript(() => {
171
+ window.addEventListener("load", async () => {
172
+ console.log("➡ focus on body for presentation mode");
173
+ await window.focusOnBodyForPresentationMode();
174
+ window.focus();
175
+ document.body.focus();
176
+ });
124
177
  window.addEventListener("keydown", (e) => {
125
178
  if (e.key === "ArrowRight") {
126
179
  console.log("➡ ArrowRight key pressed!");
@@ -132,9 +185,199 @@ const runEventsInPresentationMode = async (page, ftmocksConifg, testName) => {
132
185
  await runEvent(page, events[0]);
133
186
  };
134
187
 
188
+ const runEventsInTrainingMode = async (page, ftmocksConifg, testName) => {
189
+ let currentEventIndex = 0;
190
+ const eventsFile = path.join(
191
+ getMockDir(ftmocksConifg),
192
+ `test_${nameToFolder(testName)}`,
193
+ `_events.json`
194
+ );
195
+ const events = JSON.parse(fs.readFileSync(eventsFile, "utf8"));
196
+
197
+ // Expose Node function
198
+ await page.exposeFunction("getNextEvent", async () => {
199
+ let result = false;
200
+ while (!result) {
201
+ currentEventIndex = currentEventIndex + 1;
202
+ if (currentEventIndex === events.length) {
203
+ console.log("➡ No more events to validate!");
204
+ return;
205
+ }
206
+ result = isValidEvent(events[currentEventIndex]);
207
+ }
208
+ if (events[currentEventIndex]) {
209
+ const selector = await getLocator(page, events[currentEventIndex]);
210
+ const position = await getSelectorPosition(page, selector);
211
+ const element = await page.locator(selector).elementHandle();
212
+ return {
213
+ event: events[currentEventIndex],
214
+ selector,
215
+ position,
216
+ element,
217
+ };
218
+ }
219
+ return null;
220
+ });
221
+
222
+ // Inject keyboard listener into browser
223
+ await page.addInitScript(async () => {
224
+ let currentEventInfo = null;
225
+ // Create and style the popover
226
+ const popover = document.createElement("div");
227
+ popover.id = "ftmocks-popover-training-mode";
228
+ popover.style.position = "absolute";
229
+ popover.style.top = "0";
230
+ popover.style.left = "0";
231
+ popover.style.minWidth = "100px";
232
+ popover.style.height = "58px";
233
+ popover.style.background = "rgba(40,40,40,0.97)";
234
+ popover.style.color = "#fff";
235
+ popover.style.display = "none";
236
+ popover.style.zIndex = "99999";
237
+ popover.style.fontFamily = "sans-serif";
238
+ popover.style.fontSize = "16px";
239
+ popover.style.textAlign = "center";
240
+ popover.style.lineHeight = "1.5";
241
+ popover.style.padding = "16px 24px";
242
+ popover.style.borderRadius = "8px";
243
+ popover.style.boxShadow = "0 2px 12px rgba(0,0,0,0.25)";
244
+
245
+ const highlighter = document.createElement("div");
246
+ highlighter.id = "ftmocks-highlighter-training-mode";
247
+ highlighter.style.position = "absolute";
248
+ highlighter.style.top = "0";
249
+ highlighter.style.left = "0";
250
+ highlighter.style.width = "100%";
251
+ highlighter.style.height = "100%";
252
+ highlighter.style.background = "rgba(0,0,0,0.5)";
253
+ highlighter.style.border = "2px solid #3fa9f5";
254
+ highlighter.style.display = "none";
255
+ highlighter.style.pointerEvents = "none";
256
+
257
+ function showPopover(eventInfo) {
258
+ if (!document.getElementById("ftmocks-popover-training-mode")) {
259
+ document.body.appendChild(popover);
260
+ }
261
+ popover.textContent = eventInfo.event.type;
262
+ popover.style.display = "block";
263
+ popover.style.left =
264
+ eventInfo.position.x + eventInfo.position.width / 2 + "px";
265
+ popover.style.top =
266
+ eventInfo.position.y + eventInfo.position.height + "px";
267
+
268
+ // Show highlighter
269
+ if (!document.getElementById("ftmocks-highlighter-training-mode")) {
270
+ document.body.appendChild(highlighter);
271
+ }
272
+ highlighter.style.display = "block";
273
+ highlighter.style.left = eventInfo.position.x + "px";
274
+ highlighter.style.top = eventInfo.position.y + "px";
275
+ highlighter.style.width = eventInfo.position.width + "px";
276
+ highlighter.style.height = eventInfo.position.height + "px";
277
+ }
278
+
279
+ function hidePopover() {
280
+ popover.style.display = "none";
281
+ }
282
+
283
+ const initialEventRun = async () => {
284
+ currentEventInfo = await window.getNextEvent();
285
+ if (currentEventInfo) {
286
+ showPopover(currentEventInfo);
287
+ }
288
+ };
289
+
290
+ const matchElement = (event, currentEventInfo) => {
291
+ console.log(
292
+ "➡ Matching element!",
293
+ event.target.isEqualNode(currentEventInfo?.element),
294
+ currentEventInfo?.element?.contains(event.target)
295
+ );
296
+ return (
297
+ event.target.isEqualNode(currentEventInfo?.element) ||
298
+ currentEventInfo?.element?.contains(event.target)
299
+ );
300
+ };
301
+
302
+ window.addEventListener("load", async () => {
303
+ await initialEventRun();
304
+ });
305
+
306
+ window.addEventListener("click", async (event) => {
307
+ console.log(
308
+ "➡ Click event triggered!",
309
+ event.target.isEqualNode(currentEventInfo?.element),
310
+ currentEventInfo?.element?.contains(event.target)
311
+ );
312
+ if (
313
+ currentEventInfo?.event?.type === "click" &&
314
+ matchElement(event, currentEventInfo)
315
+ ) {
316
+ currentEventInfo = await window.getNextEvent();
317
+ if (currentEventInfo) {
318
+ showPopover(currentEventInfo);
319
+ } else {
320
+ hidePopover();
321
+ }
322
+ }
323
+ });
324
+ window.addEventListener("dblclick", async (event) => {
325
+ if (
326
+ currentEventInfo?.event?.type === "dblclick" &&
327
+ matchElement(event, currentEventInfo)
328
+ ) {
329
+ currentEventInfo = await window.getNextEvent();
330
+ if (currentEventInfo) {
331
+ showPopover(currentEventInfo);
332
+ } else {
333
+ hidePopover();
334
+ }
335
+ }
336
+ });
337
+ window.addEventListener("contextmenu", async (event) => {
338
+ if (
339
+ currentEventInfo?.event?.type === "contextmenu" &&
340
+ matchElement(event, currentEventInfo)
341
+ ) {
342
+ currentEventInfo = await window.getNextEvent();
343
+ if (currentEventInfo) {
344
+ showPopover(currentEventInfo);
345
+ } else {
346
+ hidePopover();
347
+ }
348
+ }
349
+ });
350
+ window.addEventListener("input", async (event) => {
351
+ if (
352
+ currentEventInfo?.event?.type === "input" &&
353
+ matchElement(event, currentEventInfo)
354
+ ) {
355
+ currentEventInfo = await window.getNextEvent();
356
+ if (currentEventInfo) {
357
+ showPopover(currentEventInfo);
358
+ }
359
+ }
360
+ });
361
+ window.addEventListener("keypress", async (event) => {
362
+ if (
363
+ currentEventInfo?.event?.type === "keypress" &&
364
+ matchElement(event, currentEventInfo)
365
+ ) {
366
+ currentEventInfo = await window.getNextEvent();
367
+ if (currentEventInfo) {
368
+ showPopover(currentEventInfo);
369
+ }
370
+ }
371
+ });
372
+ });
373
+
374
+ await runEvent(page, events[0]);
375
+ };
376
+
135
377
  module.exports = {
136
378
  runEvents,
137
379
  runEventsForTest,
138
380
  runEventsInPresentationMode,
381
+ runEventsInTrainingMode,
139
382
  runEvent,
140
383
  };
package/src/index.js CHANGED
@@ -26,6 +26,7 @@ const {
26
26
  runEventsForTest,
27
27
  runEvent,
28
28
  runEventsInPresentationMode,
29
+ runEventsInTrainingMode,
29
30
  } = require("./event-run-utils");
30
31
 
31
32
  // Export functions as a module
@@ -52,4 +53,5 @@ module.exports = {
52
53
  runEventsForTest,
53
54
  runEvent,
54
55
  runEventsInPresentationMode,
56
+ runEventsInTrainingMode,
55
57
  };