ftmocks-utils 1.4.3 → 1.4.4
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 +1 -1
- package/src/event-run-utils.js +120 -33
package/package.json
CHANGED
package/src/event-run-utils.js
CHANGED
|
@@ -4,19 +4,35 @@ const { getMockDir, nameToFolder } = require("./common-utils");
|
|
|
4
4
|
|
|
5
5
|
const getLocator = async (page, event) => {
|
|
6
6
|
// Check if the event.target exists on the page before returning it.
|
|
7
|
+
console.log("➡ Getting locator for event", event);
|
|
7
8
|
if (event && event.target && typeof page !== "undefined" && page.locator) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const count = await page.locator(
|
|
9
|
+
let locator = null;
|
|
10
|
+
while (!locator) {
|
|
11
|
+
const selector = event.target.startsWith("/")
|
|
12
|
+
? `xpath=${event.target}`
|
|
13
|
+
: event.target;
|
|
14
|
+
try {
|
|
15
|
+
const count = await page.locator(selector).count();
|
|
15
16
|
if (count === 1) {
|
|
16
|
-
|
|
17
|
+
locator = selector;
|
|
18
|
+
} else {
|
|
19
|
+
for (let i = 0; i < event.selectors.length; i++) {
|
|
20
|
+
const selector = event.selectors[i].value.startsWith("/")
|
|
21
|
+
? `xpath=${event.selectors[i].value}`
|
|
22
|
+
: event.selectors[i].value;
|
|
23
|
+
const count = await page.locator(selector).count();
|
|
24
|
+
if (count === 1) {
|
|
25
|
+
locator = selector;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
17
28
|
}
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error("Error getting locator", error, selector);
|
|
18
31
|
}
|
|
32
|
+
console.log("➡ Waiting for locator", event);
|
|
33
|
+
await page.waitForTimeout(500);
|
|
19
34
|
}
|
|
35
|
+
return locator;
|
|
20
36
|
}
|
|
21
37
|
return event.target;
|
|
22
38
|
};
|
|
@@ -83,8 +99,6 @@ const isValidEvent = (event) => {
|
|
|
83
99
|
try {
|
|
84
100
|
console.log("➡ Validating event", event);
|
|
85
101
|
switch (event?.type) {
|
|
86
|
-
case "url":
|
|
87
|
-
return true;
|
|
88
102
|
case "click":
|
|
89
103
|
return true;
|
|
90
104
|
case "input":
|
|
@@ -152,7 +166,7 @@ const runEventsInPresentationMode = async (page, ftmocksConifg, testName) => {
|
|
|
152
166
|
console.log("➡ Next event triggered!");
|
|
153
167
|
if (currentEventIndex === events.length) {
|
|
154
168
|
console.log("➡ No more events to run!");
|
|
155
|
-
return;
|
|
169
|
+
return false;
|
|
156
170
|
}
|
|
157
171
|
let result = await runEvent(page, events[currentEventIndex]);
|
|
158
172
|
while (result === "Unsupported event type") {
|
|
@@ -160,12 +174,17 @@ const runEventsInPresentationMode = async (page, ftmocksConifg, testName) => {
|
|
|
160
174
|
result = await runEvent(page, events[currentEventIndex]);
|
|
161
175
|
}
|
|
162
176
|
currentEventIndex = currentEventIndex + 1;
|
|
177
|
+
return true;
|
|
163
178
|
});
|
|
164
179
|
|
|
165
180
|
await page.exposeFunction("focusOnBodyForPresentationMode", async () => {
|
|
166
181
|
await page.bringToFront();
|
|
167
182
|
});
|
|
168
183
|
|
|
184
|
+
await page.exposeFunction("playwrightPageClose", async () => {
|
|
185
|
+
await page.close();
|
|
186
|
+
});
|
|
187
|
+
|
|
169
188
|
// Inject keyboard listener into browser
|
|
170
189
|
await page.addInitScript(() => {
|
|
171
190
|
window.addEventListener("load", async () => {
|
|
@@ -174,11 +193,15 @@ const runEventsInPresentationMode = async (page, ftmocksConifg, testName) => {
|
|
|
174
193
|
window.focus();
|
|
175
194
|
document.body.focus();
|
|
176
195
|
});
|
|
177
|
-
window.addEventListener("keydown", (e) => {
|
|
196
|
+
window.addEventListener("keydown", async (e) => {
|
|
178
197
|
console.log("➡ keydown event triggered!", e);
|
|
179
198
|
if (e.key === "Shift" && !e.repeat) {
|
|
180
199
|
e.preventDefault();
|
|
181
|
-
window.nextEvent();
|
|
200
|
+
const result = await window.nextEvent();
|
|
201
|
+
if (!result) {
|
|
202
|
+
console.log("➡ No more events to run!");
|
|
203
|
+
await window.playwrightPageClose();
|
|
204
|
+
}
|
|
182
205
|
}
|
|
183
206
|
});
|
|
184
207
|
});
|
|
@@ -187,7 +210,7 @@ const runEventsInPresentationMode = async (page, ftmocksConifg, testName) => {
|
|
|
187
210
|
};
|
|
188
211
|
|
|
189
212
|
const runEventsInTrainingMode = async (page, ftmocksConifg, testName) => {
|
|
190
|
-
|
|
213
|
+
const executedEvents = [];
|
|
191
214
|
const eventsFile = path.join(
|
|
192
215
|
getMockDir(ftmocksConifg),
|
|
193
216
|
`test_${nameToFolder(testName)}`,
|
|
@@ -198,20 +221,31 @@ const runEventsInTrainingMode = async (page, ftmocksConifg, testName) => {
|
|
|
198
221
|
// Expose Node function
|
|
199
222
|
await page.exposeFunction("getNextEvent", async () => {
|
|
200
223
|
let result = false;
|
|
224
|
+
let nonExecutedEvents = events.filter(
|
|
225
|
+
(event) => !executedEvents.includes(event?.id)
|
|
226
|
+
);
|
|
227
|
+
let currentEventIndex = -1;
|
|
201
228
|
while (!result) {
|
|
202
229
|
currentEventIndex = currentEventIndex + 1;
|
|
203
|
-
if (currentEventIndex ===
|
|
230
|
+
if (currentEventIndex === nonExecutedEvents.length) {
|
|
204
231
|
console.log("➡ No more events to validate!");
|
|
205
232
|
return;
|
|
206
233
|
}
|
|
207
|
-
result = isValidEvent(
|
|
234
|
+
result = isValidEvent(nonExecutedEvents[currentEventIndex]);
|
|
208
235
|
}
|
|
209
|
-
if (
|
|
210
|
-
|
|
236
|
+
if (nonExecutedEvents[currentEventIndex]) {
|
|
237
|
+
console.log(
|
|
238
|
+
"➡ Getting locator for event",
|
|
239
|
+
nonExecutedEvents[currentEventIndex]
|
|
240
|
+
);
|
|
241
|
+
const selector = await getLocator(
|
|
242
|
+
page,
|
|
243
|
+
nonExecutedEvents[currentEventIndex]
|
|
244
|
+
);
|
|
211
245
|
const position = await getSelectorPosition(page, selector);
|
|
212
246
|
const element = await page.locator(selector).elementHandle();
|
|
213
247
|
return {
|
|
214
|
-
event:
|
|
248
|
+
event: nonExecutedEvents[currentEventIndex],
|
|
215
249
|
selector,
|
|
216
250
|
position,
|
|
217
251
|
element,
|
|
@@ -220,6 +254,14 @@ const runEventsInTrainingMode = async (page, ftmocksConifg, testName) => {
|
|
|
220
254
|
return null;
|
|
221
255
|
});
|
|
222
256
|
|
|
257
|
+
await page.exposeFunction("addExecutedEvent", (eventId) => {
|
|
258
|
+
executedEvents.push(eventId);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
await page.exposeFunction("playwrightPageClose", async () => {
|
|
262
|
+
await page.close();
|
|
263
|
+
});
|
|
264
|
+
|
|
223
265
|
// Inject keyboard listener into browser
|
|
224
266
|
await page.addInitScript(async () => {
|
|
225
267
|
let currentEventInfo = null;
|
|
@@ -243,6 +285,44 @@ const runEventsInTrainingMode = async (page, ftmocksConifg, testName) => {
|
|
|
243
285
|
popover.style.borderRadius = "8px";
|
|
244
286
|
popover.style.boxShadow = "0 2px 12px rgba(0,0,0,0.25)";
|
|
245
287
|
|
|
288
|
+
// Success Training Popover
|
|
289
|
+
const successPopover = document.createElement("div");
|
|
290
|
+
successPopover.id = "ftmocks-success-popover-training-mode";
|
|
291
|
+
successPopover.style.position = "fixed";
|
|
292
|
+
successPopover.style.top = "32px";
|
|
293
|
+
successPopover.style.left = "50%";
|
|
294
|
+
successPopover.style.transform = "translateX(-50%)";
|
|
295
|
+
successPopover.style.minWidth = "120px";
|
|
296
|
+
successPopover.style.height = "46px";
|
|
297
|
+
successPopover.style.background = "rgba(60,180,75,0.98)";
|
|
298
|
+
successPopover.style.color = "#fff";
|
|
299
|
+
successPopover.style.display = "none";
|
|
300
|
+
successPopover.style.zIndex = "100000";
|
|
301
|
+
successPopover.style.fontFamily = "sans-serif";
|
|
302
|
+
successPopover.style.fontSize = "16px";
|
|
303
|
+
successPopover.style.textAlign = "center";
|
|
304
|
+
successPopover.style.lineHeight = "1.4";
|
|
305
|
+
successPopover.style.padding = "12px 32px";
|
|
306
|
+
successPopover.style.borderRadius = "8px";
|
|
307
|
+
successPopover.style.boxShadow = "0 2px 12px rgba(0,0,0,0.20)";
|
|
308
|
+
successPopover.textContent = "✅ Training Success!";
|
|
309
|
+
|
|
310
|
+
// Utility to show the success popover for a short period
|
|
311
|
+
function showSuccessPopover(message = "✅ Training Success!") {
|
|
312
|
+
successPopover.textContent = message;
|
|
313
|
+
if (!document.getElementById("ftmocks-success-popover-training-mode")) {
|
|
314
|
+
document.body.appendChild(successPopover);
|
|
315
|
+
}
|
|
316
|
+
successPopover.style.display = "block";
|
|
317
|
+
setTimeout(() => {
|
|
318
|
+
successPopover.style.display = "none";
|
|
319
|
+
document
|
|
320
|
+
.getElementById("ftmocks-success-popover-training-mode")
|
|
321
|
+
?.remove();
|
|
322
|
+
window.playwrightPageClose();
|
|
323
|
+
}, 3000);
|
|
324
|
+
}
|
|
325
|
+
|
|
246
326
|
const highlighter = document.createElement("div");
|
|
247
327
|
highlighter.id = "ftmocks-highlighter-training-mode";
|
|
248
328
|
highlighter.style.position = "absolute";
|
|
@@ -254,8 +334,11 @@ const runEventsInTrainingMode = async (page, ftmocksConifg, testName) => {
|
|
|
254
334
|
highlighter.style.border = "2px solid #3fa9f5";
|
|
255
335
|
highlighter.style.display = "none";
|
|
256
336
|
highlighter.style.pointerEvents = "none";
|
|
337
|
+
highlighter.style.zIndex = "99999";
|
|
257
338
|
|
|
258
339
|
function showPopover(eventInfo) {
|
|
340
|
+
console.log("➡ Showing popover", eventInfo);
|
|
341
|
+
window.addExecutedEvent(eventInfo.event.id);
|
|
259
342
|
if (!document.getElementById("ftmocks-popover-training-mode")) {
|
|
260
343
|
document.body.appendChild(popover);
|
|
261
344
|
}
|
|
@@ -279,6 +362,10 @@ const runEventsInTrainingMode = async (page, ftmocksConifg, testName) => {
|
|
|
279
362
|
|
|
280
363
|
function hidePopover() {
|
|
281
364
|
popover.style.display = "none";
|
|
365
|
+
highlighter.style.display = "none";
|
|
366
|
+
document.getElementById("ftmocks-popover-training-mode")?.remove();
|
|
367
|
+
document.getElementById("ftmocks-highlighter-training-mode")?.remove();
|
|
368
|
+
showSuccessPopover("✅ Training Success!");
|
|
282
369
|
}
|
|
283
370
|
|
|
284
371
|
const initialEventRun = async () => {
|
|
@@ -289,15 +376,18 @@ const runEventsInTrainingMode = async (page, ftmocksConifg, testName) => {
|
|
|
289
376
|
};
|
|
290
377
|
|
|
291
378
|
const matchElement = (event, currentEventInfo) => {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
379
|
+
const inBoudingBox =
|
|
380
|
+
currentEventInfo?.position?.x <= event.clientX &&
|
|
381
|
+
currentEventInfo?.position?.x + currentEventInfo?.position?.width >=
|
|
382
|
+
event.clientX &&
|
|
383
|
+
currentEventInfo?.position?.y <= event.clientY &&
|
|
384
|
+
currentEventInfo?.position?.y + currentEventInfo?.position?.height >=
|
|
385
|
+
event.clientY;
|
|
386
|
+
console.log("➡ In bounding box?", inBoudingBox);
|
|
387
|
+
const matchingElement =
|
|
388
|
+
currentEventInfo?.element?.isEqualNode(event.target) ||
|
|
389
|
+
currentEventInfo?.element?.contains(event.target);
|
|
390
|
+
return inBoudingBox || matchingElement;
|
|
301
391
|
};
|
|
302
392
|
|
|
303
393
|
window.addEventListener("load", async () => {
|
|
@@ -305,16 +395,13 @@ const runEventsInTrainingMode = async (page, ftmocksConifg, testName) => {
|
|
|
305
395
|
});
|
|
306
396
|
|
|
307
397
|
window.addEventListener("click", async (event) => {
|
|
308
|
-
console.log(
|
|
309
|
-
"➡ Click event triggered!",
|
|
310
|
-
event.target.isEqualNode(currentEventInfo?.element),
|
|
311
|
-
currentEventInfo?.element?.contains(event.target)
|
|
312
|
-
);
|
|
313
398
|
if (
|
|
314
399
|
currentEventInfo?.event?.type === "click" &&
|
|
315
400
|
matchElement(event, currentEventInfo)
|
|
316
401
|
) {
|
|
402
|
+
console.log("➡ Click event triggered!", event);
|
|
317
403
|
currentEventInfo = await window.getNextEvent();
|
|
404
|
+
console.log("➡ Next event", currentEventInfo);
|
|
318
405
|
if (currentEventInfo) {
|
|
319
406
|
showPopover(currentEventInfo);
|
|
320
407
|
} else {
|