2
\$\begingroup\$

I'm writing a web bot using puppeteer and I'm logging (using winston) every action the bots does and running it inside try/catch blocks.

For automating these processes and avoiding code repetition I created this function:

module.exports = {
 webAction: async function (logger, msg, func, ...args)
 {
 return new Promise(async (resolve) => {
 let actionMessage, actionLevel;
 try
 {
 await func(...args);
 actionMessage = msg;
 actionLevel = 'info';
 }
 catch (error)
 {
 actionMessage = "Error while executing (" + msg + ") function.\n---\n" + error.message + "\n---";
 actionLevel = 'error';
 }
 finally
 {
 logger.log({
 level: actionLevel,
 message: actionMessage
 })
 }
 resolve('Fullfilment value of Promise');
 })
 },

I use the previous function with arrow functions and normal/regular functions as arguments for making it as dynamic as it can be:

const htmlCode = await page.evaluate(() => document.querySelector('*').outerHTML);
await utils.webAction(
 logger, 'Save web code as html file',
 (() => (utils.saveStrAsFile('htmlCodeMP_NewItem.html', htmlCode)))
);
let titleID, priceID;
await utils.webAction(
 logger, 'Find Ids',
 (() => ([titleID, priceID] = utils.findDynamicIdsMP(htmlCode)))
);
await utils.webAction(
 logger, 'Enter item title', utils.webType,
 page, 'FooTitle', `input[id="${titleID}"]` // Arguments of `webType`
);
await utils.webAction(
 logger, 'Enter item price', utils.webType,
 page, '1234', `input[id="${priceID}"]` // Arguments of `webType`
);
await utils.webAction(
 logger, 'Click item category dropdown menu',
 (() => (page.click(constants.cssMpCreateItemCategory))),
); 

Is this a good practice?

I honestly thinks it avoids much repetition of code (at least the try/catch blocks & the logger block).

But on the other hand I'm thinking that there must be a better approach or professional way of doing this.

I'm no professional nor am I skilled in Javascript, I'm an amateur in Javascript.

Any advice is highly appreciated.

Sᴀᴍ Onᴇᴌᴀ
29.5k16 gold badges45 silver badges201 bronze badges
asked Feb 6, 2024 at 3:43
\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

Passing in arguments as a list of arguments into webAction becomes hard to read. My suggestion would be as follows

  1. Make the arguments an object
  2. Make the func a callback that is invoked with no arguments. Don't have webAction know anything about what function it is running
  3. return the func's return value in webAction.
const utils = {
 webAction: async ({ logger, msg, func }) => {
 return new Promise(async (resolve) => {
 let res
 let actionMessage, actionLevel
 try {
 res = await func()
 actionMessage = msg
 actionLevel = 'info'
 }
 catch (error) {
 actionMessage = "Error while executing (" + msg + ") function.\n---\n" + error.message + "\n---"
 actionLevel = 'error'
 }
 finally {
 logger.log({
 level: actionLevel,
 message: actionMessage,
 })
 }
 resolve(res)
 })
 },
}

Notice how func is invoked with no arguments. Then in its usage:

const htmlCode = await page.evaluate(() => document.querySelector('*').outerHTML);
await utils.webAction({
 logger,
 msg: 'Save web code as html file',
 func: () => utils.saveStrAsFile('htmlCodeMP_NewItem.html', htmlCode)
})
const [titleID, priceID] = await utils.webAction({
 func: () => utils.findDynamicIdsMP('htmlCode'),
 logger,
 msg: 'Find Ids',
})
await utils.webAction({
 func: () => utils.webType(page, 'FooTitle', `input[id="${titleID}"]`),
 logger,
 msg: 'Enter item title',
})
answered Feb 9, 2024 at 11:55
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.