Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Chrome DevTools User Flow Recording for GitHub Search
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
async function waitForSelectors(selectors, frame) {
for (const selector of selectors) {
try {
return await waitForSelector(selector, frame);
} catch (err) {
console.error(err);
}
}
throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors));
}
async function waitForSelector(selector, frame) {
if (selector instanceof Array) {
let element = null;
for (const part of selector) {
if (!element) {
element = await frame.waitForSelector(part);
} else {
element = await element.$(part);
}
if (!element) {
throw new Error('Could not find element: ' + part);
}
element = (await element.evaluateHandle(el => el.shadowRoot ? el.shadowRoot : el)).asElement();
}
if (!element) {
throw new Error('Could not find element: ' + selector.join('|'));
}
return element;
}
const element = await frame.waitForSelector(selector);
if (!element) {
throw new Error('Could not find element: ' + selector);
}
return element;
}
async function waitForElement(step, frame) {
const count = step.count || 1;
const operator = step.operator || '>=';
const comp = {
'==': (a, b) => a === b,
'>=': (a, b) => a >= b,
'<=': (a, b) => a <= b,
};
const compFn = comp[operator];
await waitForFunction(async () => {
const elements = await querySelectorsAll(step.selectors, frame);
return compFn(elements.length, count);
});
}
async function querySelectorsAll(selectors, frame) {
for (const selector of selectors) {
const result = await querySelectorAll(selector, frame);
if (result.length) {
return result;
}
}
return [];
}
async function querySelectorAll(selector, frame) {
if (selector instanceof Array) {
let elements = [];
let i = 0;
for (const part of selector) {
if (i === 0) {
elements = await frame.$$(part);
} else {
const tmpElements = elements;
elements = [];
for (const el of tmpElements) {
elements.push(...(await el.$$(part)));
}
}
if (elements.length === 0) {
return [];
}
const tmpElements = [];
for (const el of elements) {
const newEl = (await el.evaluateHandle(el => el.shadowRoot ? el.shadowRoot : el)).asElement();
if (newEl) {
tmpElements.push(newEl);
}
}
elements = tmpElements;
i++;
}
return elements;
}
const element = await frame.$$(selector);
if (!element) {
throw new Error('Could not find element: ' + selector);
}
return element;
}
async function waitForFunction(fn) {
let isActive = true;
setTimeout(() => {
isActive = false;
}, 5000);
while (isActive) {
const result = await fn();
if (result) {
return;
}
await new Promise(resolve => setTimeout(resolve, 100));
}
throw new Error('Timed out');
}
{
const targetPage = page;
await targetPage.setViewport({"width":1135,"height":338})
}
{
const targetPage = page;
const promises = [];
promises.push(targetPage.waitForNavigation());
await targetPage.goto('https://github.com/');
await Promise.all(promises);
}
{
const targetPage = page;
const element = await waitForSelectors([["aria/Search GitHub"],["body > div.position-relative.js-header-wrapper > header > div > div.HeaderMenu.HeaderMenu--logged-out.position-fixed.top-0.right-0.bottom-0.height-fit.position-lg-relative.d-lg-flex.flex-justify-between.flex-items-center.flex-auto > div.d-lg-flex.flex-items-center.px-3.px-lg-0.text-center.text-lg-left > div.d-lg-flex.min-width-0.mb-3.mb-lg-0 > div > div > form > label > input.form-control.input-sm.header-search-input.jump-to-field.js-jump-to-field.js-site-search-focus.js-navigation-enable.jump-to-field-active.jump-to-dropdown-visible"]], targetPage);
await element.click({ offset: { x: 74.5, y: 24} });
}
{
const targetPage = page;
const element = await waitForSelectors([["aria/Search GitHub"],["body > div.position-relative.js-header-wrapper > header > div > div.HeaderMenu.HeaderMenu--logged-out.position-fixed.top-0.right-0.bottom-0.height-fit.position-lg-relative.d-lg-flex.flex-justify-between.flex-items-center.flex-auto > div.d-lg-flex.flex-items-center.px-3.px-lg-0.text-center.text-lg-left > div.d-lg-flex.min-width-0.mb-3.mb-lg-0 > div > div > form > label > input.form-control.input-sm.header-search-input.jump-to-field.js-jump-to-field.js-site-search-focus.js-navigation-enable.jump-to-field-active.jump-to-dropdown-visible"]], targetPage);
const type = await element.evaluate(el => el.type);
if (["textarea","select-one","text","url","tel","search","password","number","email"].includes(type)) {
await element.type('react');
} else {
await element.focus();
await element.evaluate((el, value) => {
el.value = value;
el.dispatchEvent(new Event('input', { bubbles: true }));
el.dispatchEvent(new Event('change', { bubbles: true }));
}, "react");
}
}
{
const targetPage = page;
const promises = [];
promises.push(targetPage.waitForNavigation());
const element = await waitForSelectors([["aria/react"],["#jump-to-suggestion-search-global > a > div.jump-to-suggestion-name.js-jump-to-suggestion-name.flex-auto.overflow-hidden.text-left.no-wrap.css-truncate.css-truncate-target"]], targetPage);
await element.click({ offset: { x: 41.5, y: 4} });
await Promise.all(promises);
}
{
const targetPage = page;
const promises = [];
promises.push(targetPage.waitForNavigation());
const element = await waitForSelectors([["aria/facebook/react"],["#js-pjax-container > div > div.col-12.col-md-9.float-left.px-2.pt-3.pt-md-0.codesearch-results > div > ul > li:nth-child(1) > div.mt-n1.flex-auto > div.d-flex > div > a"]], targetPage);
await element.click({ offset: { x: 62.5, y: 12.21875} });
await Promise.all(promises);
}
await browser.close();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment