The findElements
function uses the Chrome debugger API to find elements on a webpage based on an input selector, and is called by two express routes to handle POST requests. The function and express router are exported as part of the module, allowing it to be used in other applications.
var express = require('express');
var router = express.Router();
function findElements(selector) {
return promisifyChrome('debugger.sendCommand', {
tabId: getTab()
}, 'Runtime.evaluate', {
expression: `new window.BackupPromise(resolve => setTimeout(() => {
resolve([].slice.call(window.document.querySelectorAll(${JSON.stringify(selector)}), 0)[0])
}, 500))`,
awaitPromise: true
})
.then(r => {
return promisifyChrome('debugger.sendCommand', {
tabId: getTab()
}, 'DOM.requestNode', {
objectId: r.result.objectId
})
})
.then(r => ({value: {ELEMENT: r.nodeId}}))
.catch(e => console.log(e))
}
router.post('/session/:sessionId/element', (req, res) =>
response(res, findElements(req.body.value)));
router.post('/session/:sessionId/elements', (req, res) =>
response(res, findElements(req.body.value)));
module.exports = {
findElements,
router
}
const express = require('express');
const router = express.Router();
const { promisifyChrome } = require('./promisifyChrome'); // Assuming promisifyChrome is in a separate file
// Helper function to get the current tab ID
const getTab = () => {
// Assuming getTab is implemented elsewhere
};
// Helper function to send a response
const response = (res, data) => {
res.json(data);
};
// Helper function to handle Chrome DevTools commands
const handleChromeCommand = (method, params) => {
try {
return promisifyChrome(method, params);
} catch (error) {
console.error('Error handling Chrome DevTools command:', error);
return Promise.reject(error);
}
};
// Helper function to get elements using the given selector
const findElements = async (selector) => {
/**
* Finds elements on the current page using the given selector.
*
* @param {string} selector - A CSS selector to find elements.
* @returns {object[]} An array of element objects.
*/
const tabId = getTab();
const chromeMethod = 'Runtime.evaluate';
const evaluateParams = {
expression: `new window.BackupPromise(resolve => setTimeout(() => {
resolve([].slice.call(window.document.querySelectorAll(${JSON.stringify(selector)}), 0)[0])
}, 500))`,
awaitPromise: true,
};
try {
const evaluateResult = await handleChromeCommand('debugger.sendCommand', {
tabId,
}, chromeMethod, evaluateParams);
const nodeId = evaluateResult.result.objectId;
const domMethod = 'DOM.requestNode';
const requestParams = { objectId: nodeId };
const nodeResult = await handleChromeCommand('debugger.sendCommand', {
tabId,
}, domMethod, requestParams);
return { value: { ELEMENT: nodeResult.nodeId } };
} catch (error) {
console.error('Error finding elements:', error);
return Promise.reject(error);
}
};
// Routes for finding a single element or multiple elements
router.post('/session/:sessionId/element', (req, res) =>
response(res, findElements(req.body.value))
);
router.post('/session/:sessionId/elements', (req, res) =>
response(res, findElements(req.body.value))
);
module.exports = { findElements, router };
Code Breakdown
express
is required and an instance of an express router is created.findElements(selector)
selector
as input, which is a string representing an HTML or CSS selector.promisifyChrome
to send a command to the Chrome debugger to evaluate an expression.window.BackupPromise
to resolve a promise that returns an array of elements matching the selector./session/:sessionId/element
: Handles a POST request to find a single element./session/:sessionId/elements
: Handles a POST request to find multiple elements.findElements
function with the request body as an argument, and call the response
function to send the result back to the client.findElements
function and the express router are exported as part of the module.