Best JavaScript code snippet using puppeteer
MDBuilder.js
Source: MDBuilder.js
...36 const classes = [];37 const errors = [];38 const headers = document.body.querySelectorAll('h3');39 for (let i = 0; i < headers.length; i++) {40 const fragment = extractSiblingsIntoFragment(41 headers[i],42 headers[i + 1]43 );44 classes.push(parseClass(fragment));45 }46 return { classes, errors };47 /**48 * @param {HTMLLIElement} element49 */50 function parseProperty(element) {51 const clone = element.cloneNode(true);52 const ul = clone.querySelector(':scope > ul');53 const str = parseComment(54 extractSiblingsIntoFragment(clone.firstChild, ul)55 );56 const name = str57 .substring(0, str.indexOf('<'))58 .replace(/\`/g, '')59 .trim();60 const type = findType(str);61 const properties = [];62 const comment = str63 .substring(str.indexOf('<') + type.length + 2)64 .trim();65 // Strings have enum values instead of properties66 if (!type.includes('string')) {67 for (const childElement of element.querySelectorAll(68 ':scope > ul > li'69 )) {70 const property = parseProperty(childElement);71 property.required = property.comment.includes('***required***');72 properties.push(property);73 }74 }75 return {76 name,77 type,78 comment,79 properties,80 };81 }82 /**83 * @param {string} str84 * @returns {string}85 */86 function findType(str) {87 const start = str.indexOf('<') + 1;88 let count = 1;89 for (let i = start; i < str.length; i++) {90 if (str[i] === '<') count++;91 if (str[i] === '>') count--;92 if (!count) return str.substring(start, i);93 }94 return 'unknown';95 }96 /**97 * @param {DocumentFragment} content98 */99 function parseClass(content) {100 const members = [];101 const headers = content.querySelectorAll('h4');102 const name = content.firstChild.textContent;103 let extendsName = null;104 let commentStart = content.firstChild.nextSibling;105 const extendsElement = content.querySelector('ul');106 if (107 extendsElement &&108 extendsElement.textContent.trim().startsWith('extends:')109 ) {110 commentStart = extendsElement.nextSibling;111 extendsName = extendsElement.querySelector('a').textContent;112 }113 const comment = parseComment(114 extractSiblingsIntoFragment(commentStart, headers[0])115 );116 for (let i = 0; i < headers.length; i++) {117 const fragment = extractSiblingsIntoFragment(118 headers[i],119 headers[i + 1]120 );121 members.push(parseMember(fragment));122 }123 return {124 name,125 comment,126 extendsName,127 members,128 };129 }130 /**131 * @param {Node} content132 */133 function parseComment(content) {134 for (const code of content.querySelectorAll('pre > code'))135 code.replaceWith(136 '```' +137 code.className.substring('language-'.length) +138 '\n' +139 code.textContent +140 '```'141 );142 for (const code of content.querySelectorAll('code'))143 code.replaceWith('`' + code.textContent + '`');144 for (const strong of content.querySelectorAll('strong'))145 strong.replaceWith('**' + parseComment(strong) + '**');146 return content.textContent.trim();147 }148 /**149 * @param {string} name150 * @param {DocumentFragment} content151 */152 function parseMember(content) {153 const name = content.firstChild.textContent;154 const args = [];155 let returnType = null;156 const paramRegex = /^\w+\.[\w$]+\((.*)\)$/;157 const matches = paramRegex.exec(name) || ['', ''];158 const parameters = matches[1];159 const optionalStartIndex = parameters.indexOf('[');160 const optinalParamsStr =161 optionalStartIndex !== -1162 ? parameters.substring(optionalStartIndex).replace(/[\[\]]/g, '')163 : '';164 const optionalparams = new Set(165 optinalParamsStr166 .split(',')167 .filter((x) => x)168 .map((x) => x.trim())169 );170 const ul = content.querySelector('ul');171 for (const element of content.querySelectorAll('h4 + ul > li')) {172 if (173 element.matches('li') &&174 element.textContent.trim().startsWith('<')175 ) {176 returnType = parseProperty(element);177 } else if (178 element.matches('li') &&179 element.firstChild.matches &&180 element.firstChild.matches('code')181 ) {182 const property = parseProperty(element);183 property.required = !optionalparams.has(property.name);184 args.push(property);185 } else if (186 element.matches('li') &&187 element.firstChild.nodeType === Element.TEXT_NODE &&188 element.firstChild.textContent.toLowerCase().startsWith('return')189 ) {190 returnType = parseProperty(element);191 const expectedText = 'returns: ';192 let actualText = element.firstChild.textContent;193 let angleIndex = actualText.indexOf('<');194 let spaceIndex = actualText.indexOf(' ');195 angleIndex = angleIndex === -1 ? actualText.length : angleIndex;196 spaceIndex = spaceIndex === -1 ? actualText.length : spaceIndex + 1;197 actualText = actualText.substring(198 0,199 Math.min(angleIndex, spaceIndex)200 );201 if (actualText !== expectedText)202 errors.push(203 `${name} has mistyped 'return' type declaration: expected exactly '${expectedText}', found '${actualText}'.`204 );205 }206 }207 const comment = parseComment(208 extractSiblingsIntoFragment(ul ? ul.nextSibling : content)209 );210 return {211 name,212 args,213 returnType,214 comment,215 };216 }217 /**218 * @param {!Node} fromInclusive219 * @param {!Node} toExclusive220 * @returns {!DocumentFragment}221 */222 function extractSiblingsIntoFragment(fromInclusive, toExclusive) {223 const fragment = document.createDocumentFragment();224 let node = fromInclusive;225 while (node && node !== toExclusive) {226 const next = node.nextSibling;227 fragment.appendChild(node);228 node = next;229 }230 return fragment;231 }232 });233 return new MDOutline(classes, errors);234 }235 constructor(classes, errors) {236 this.classes = [];...
Puppeteer iterate table cells and click specific cells
Interact with browser JavaScript via command line or local script?
How to get all links from the DOM?
how do I set a proxy server in my headless chrome request using Node JS Puppeteer
Clicking a selector with Puppeteer
Puppeteer get all option's value
Puppeteer element selection returning null or timing out
puppeteer how to return page.on response values
Puppeteer wait until page is completely loaded
puppeteer how to return page.on response values
While you haven't provided the live page (so I can't verify that arbitrary JS, visibility and timing won't make this fail), I'll take a stab at it and see if the following works, assuming your HTML is pretty much static:
const puppeteer = require("puppeteer"); // ^16.2.0
let browser;
(async () => {
const html = `
<body>
<table class="calendar">
<tr class="days">
<td class="day">
<div class="day_num">7</div>
<div class="day_content"></div>
</td>
<td class="day">
<div class="day_num">8</div>
<div class="day_content"></div>
</td>
<td class="day">
<div class="day_num">9</div>
<div class="day_content">AWAY</div>
</td>
</tr>
</table>
<script>
[...document.querySelectorAll(".day_content")][1]
.addEventListener("click", e => {
e.target.textContent = "CLICKED";
})
;
</script>
</body>
`;
browser = await puppeteer.launch({headless: true});
const [page] = await browser.pages();
await page.setContent(html);
const xp = '//div[contains(@class, "day_num") and text()="8"]';
const [dayEl] = await page.$x(xp);
const dayContent = await dayEl.evaluate(el => {
const dayContent = el.closest(".day").querySelector(".day_content");
dayContent.click();
return dayContent.textContent;
});
console.log(dayContent); // => CLICKED
})()
.catch(err => console.error(err))
.finally(() => browser?.close())
;
The approach is to find the .day_num
element you're interested in using an XPath on the class and text, then pop up the tree to the .day
element and down again to the associated .day_content
element to click it. I added a listener to change the text upon click to verify that it was indeed clicked.
You could also use nextElementSibling
on the .day_num
rather than the closest
/querySelector
combo, but this assumes more about the relationship between the .day_num
and .day_content
elements and would probably be more brittle.
Also, if the text content "8"
might have whitespace, you can loosen it up a bit with substring contains in your XPath. '//div[contains(@class, "day_num") and contains(text(), "8")]'
, at the risk of false positives and selecting, say, "18"
and "28"
. In that case, a regex or tree walk and trim
might be more appropriate. It's hard to make a recommendation based on this excerpt of the HTML out of context.
Taking a step further, it sounds like you need to click multiple elements in a loop and are struggling to do that. Here's an attempt that works on a mocked-up version of the site:
const puppeteer = require("puppeteer"); // ^16.2.0
let browser;
(async () => {
const html = `
<body>
<table class="calendar">
<tr class="days"></tr>
</table>
<script>
for (let i = 0; i < 30; i++) {
document.querySelector(".days").innerHTML +=
\`<td class="day">
<div class="day_num">\${i + 1}</div>
<div class="day_content"></div>
</td>\`
;
}
[...document.querySelectorAll(".day_content")].forEach(e =>
e.addEventListener("click", e => {
e.target.textContent = "AWAY";
})
);
</script>
</body>
`;
browser = await puppeteer.launch({headless: true});
const [page] = await browser.pages();
await page.setContent(html);
const awayDatesInMonth = [5, 12, 18, 20];
for (const day of awayDatesInMonth) {
const xp = `//div[contains(@class, "day_num") and text()="${day}"]`;
const [dayEl] = await page.$x(xp);
const dayContent = await dayEl.evaluate(el =>
el.closest(".day").querySelector(".day_content").click()
);
}
/* or if you can assume the elements are correctly indexed */
const days = await page.$$(".day_content");
for (const day of awayDatesInMonth) {
await days[day-1].evaluate(el => el.click());
}
/* --- */
console.log(await page.content());
})()
.catch(err => console.error(err))
.finally(() => browser?.close())
;
If this doesn't work, please provide your own mock-up that better represents the original site you're working with so I can be sure I'm solving the relevant problem.
Note that I'm using native DOM clicks which are untrusted and work differently than the trusted Puppeteer page.click()
/ElementHandle.click()
methods. If the native DOM click doesn't trigger a response, try the Puppeteer click.
Check out the latest blogs from LambdaTest on this topic:
As technology keeps evolving, organizations need to realign their business strategies. It is always good to improve the overall efficiency and end-user experience to stay ahead of the competition. Automated tasks and creating customized workflows add tremendous value. This is the primary goal of the ServiceNow platform.
Web applications continue to evolve at an unbelievable pace, and the architecture surrounding web apps get more complicated all of the time. With the growth in complexity of the web application and the development process, web application testing also needs to keep pace with the ever-changing demands.
Staying competitive in today’s corporate world necessitates a continual delivery of client satisfaction. Accelerating release cycles has emerged as a key distinction for businesses wanting to grow their client base. Enterprise tests and releases are built on the foundation of code-level acceleration. It allows teams to write tests at the appropriate level of abstraction to run sooner in the pipeline, iterate faster and at scale, and release higher-quality code faster than ever before.
Organizations build their digital presence by developing websites or web applications to reach a wider audience. This, in turn, leads to competition with the existing players in the market. As the new web applications roll into the market, they try to grab their share of the audience. However, to stay competitive, the existing web applications must also add new features to enhance their user experience.
May this May month bring you a lot of success and happiness! In April, we had a couple of fun events along with sponsoring virtual events like “Techwell STAREAST”, “Unicom EMEA”, “Codeless Conf 2022”, and conducting webinars like How Does Enterprise Accelerate Test And Release Velocity?Last month was quite remarkable, with a handful of jubilant memories to cherish forever and a learning experience to carry forward for the next month.
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!