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.
1 Answer 1
Passing in arguments as a list of arguments into webAction
becomes hard to read. My suggestion would be as follows
- Make the arguments an object
- Make the
func
a callback that is invoked with no arguments. Don't havewebAction
know anything about what function it is running return
thefunc
'sreturn
value inwebAction
.
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',
})