Last active
February 14, 2022 21:48
-
-
Save alexcmgit/6f2adc8a73e27fef73f99f42258d7912 to your computer and use it in GitHub Desktop.
Too lazy do find JS selectors and implement testing code, so lets make the browser my friend
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Generate unique CSS selector from document [HTMLElement] | |
*/ | |
function generateCssSelector(element) { | |
let path = [], | |
parent; | |
while ((parent = element.parentNode)) { | |
path.unshift( | |
`${element.tagName}:nth-child(${ | |
[].indexOf.call(parent.children, element) + 1 | |
})` | |
); | |
element = parent; | |
} | |
return `${path.join(" > ")}`.toLowerCase(); | |
} | |
/* | |
* Start and end record by typing these commands on the console | |
* | |
* Also I can see myself putting these commands in a separated extension | |
* to don't even need to type it, just click on buttons | |
*/ | |
let recording = false; | |
window.stoprecording = () => (recording = false); | |
window.startrecording = () => (recording = true); | |
let pressed = []; | |
/** | |
* Add global click and input event listener to find the test "path" | |
* I mean, the E2E is just a bot trying to use the app in | |
* a deterministic and linear path, but you need to provide | |
* the selectors to cypress in order to do that | |
* so here I'll "record" every click that I'll do in the browser | |
* to generate a linear path about what the bot needs to click and type | |
*/ | |
let path = []; | |
function combine(e, code, f, o) { | |
if (e.code === code) f(e); | |
else o(); | |
} | |
function addGlobalEventListeners() { | |
document.onkeydown = (e) => { | |
if (e.code === "Backspace") { | |
const last = path[path.length - 1]; | |
if (last && last.event === "input") { | |
const entry = { | |
...last, | |
value: last.value.substring(0, last.value.length - 1), | |
}; | |
console.log( | |
`Deleting a current INPUT entry: ${obj(entry)} at index: ${ | |
path.length - 1 | |
}` | |
); | |
path[path.length - 1] = entry; | |
} | |
return; | |
} | |
const control = pressed.some((p) => p.code === "ControlLeft"); | |
if (e.code === "ShiftLeft" && control) { | |
console.log( | |
`Now, ${ | |
(recording = !recording) | |
? "we are recording" | |
: "we aren NOT recording" | |
}` | |
); | |
return; | |
} | |
if (e.code === "AltLeft" && control && !recording) { | |
genCode(); | |
clearpath(); | |
return; | |
} | |
pressed.push(e); | |
}; | |
document.onkeyup = (e) => | |
(pressed = pressed.filter((p) => p.code !== e.code)); | |
document.onclick = function (e) { | |
if (!recording) return; | |
const entry = { | |
event: "click", | |
element: e.target, | |
selector: generateCssSelector(e.target), | |
}; | |
console.log(`Pushing a new CLICK entry: ${obj(entry)}`); | |
path.push(entry); | |
}; | |
document.oninput = function (e) { | |
if (!recording || !e.data) return; | |
let last = path[path.length - 1]; | |
if (last && last.event === "input" && !!e.data) { | |
const entry = { ...last, value: e.target.value }; | |
console.log( | |
`Editing a current INPUT entry: ${obj(entry)} at index: ${ | |
path.length - 1 | |
}` | |
); | |
path[path.length - 1] = entry; | |
} else { | |
const entry = { | |
event: "input", | |
element: e.target, | |
selector: generateCssSelector(e.target), | |
value: e.target.value, | |
}; | |
console.log(`Pushing a new INPUT entry: ${obj(entry)}`); | |
path.push(entry); | |
} | |
}; | |
} | |
function obj(e) { | |
return JSON.stringify({ event: e.event, value: e.value }, null, 2); | |
} | |
function printPath() { | |
console.log(JSON.stringify(path, null, 2)); | |
} | |
function clearpath() { | |
path = []; | |
} | |
function genCode() { | |
const code = []; | |
for (let i = 0; !!path[i]; i += 2) { | |
const [e, n] = [path[i], path[i + 1]]; | |
if (!!e && !!n) { | |
if (e.event === "click" && n.event === "input") { | |
code.push(`cy.get("${e.selector}").type("${n.value}");`); | |
} | |
} else { | |
const t = e ?? n; | |
if (t?.event === "click") { | |
code.push(`cy.get("${e.selector}").click();`); | |
} else if (t.event === "input") { | |
/// ... | |
} | |
} | |
} | |
console.log(code.join("\n\n")); | |
} | |
addGlobalEventListeners(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment