Highcharts with puppeteer - node.js

This below code executes fine but renders a PDF with no series displayed in pdf. Rest all components of a report is displayed in PDF . Please add comments to help the same.
Highcharts and puppeteer. without highchart export server.
/**
* This file creates a highchart,
* no html page is required. The html is crafted
* within this script.
*/
const puppeteer = require('puppeteer')
const fs = require('fs')
async function run() {
const browser = await puppeteer.launch({
headless: true
})
// const browser = await puppeteer.launch({
// headless: false,
// slowMo: 2000,
// devtools: true
// })
const page = await browser.newPage()
const loaded = page.waitForNavigation({
waitUntil: 'load'
})
const html =
`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Highcharts Test 4</title>
</head>
<body>
<div id="container" style="width:100%; height:400px;"></div>
</body>
</html>`
await page.setContent(html)
await loaded
async function loadChart() {
page.evaluate( fs.readFileSync('./lib/highcharts/highcharts.js', 'utf8'));
await page.evaluate(async (fs) => {
console.log('page.evaluate Highcharts.version=' + Highcharts.version)
var myChart = Highcharts.chart('container', {
chart: {
type: 'bar'
},
title: {
text: 'Fruit Consumption'
},
xAxis: {
categories: ['Apples', 'Bananas', 'Oranges']
},
yAxis: {
title: {
text: 'Fruit eaten'
}
},
series: [{
name: 'Jane',
data: [1, 0, 4]
}, {
name: 'John',
data: [5, 7, 3]
}]
});
}, fs)
}
await loadChart()
await browser.close()
}
run()

Related

how to trigger chrome extension function from puppeteer Cluster

I need to trigger a function in background.js in extension from puppeteer Cluster
here is my code :
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
(async () => {
const puppeteer = addExtra(puppeteerStream);
const pathToExtension = "C:/Users/Proj/test-extension";
const extensionId = 'lpnlgnlkloegindjk443sfdbjipo';
const cluster = await Cluster.launch({
concurrency: Cluster.CONCURRENCY_PAGE,
maxConcurrency: 50,
timeout: 86400000,
retryLimit: 10,
retryDelay: 1000,
puppeteer: puppeteer,
executablePath: executablePath(),
puppeteerOptions: {
executablePath: "C:/Program Files/Google/Chrome/Application/chrome.exe",
timeout: 120000,
headless: false,
pipe: true,
defaultViewport:null,
ignoreDefaultArgs: [
],
args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-notifications", "--allow-http-screen-capture", "--autoplay-policy=no-user-gesture-required",
'--disable-gpu',
'--disable-dev-shm-usage',
'--no-first-run',
'--enable-usermedia-screen-capturing',
'--auto-select-desktop-capture-source=pickme',
'--no-zygote',
`--whitelisted-extension-id=${extensionId}`,
'--enable-remote-extensions',
'--start-maximized',
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`,
]
}
});
// setup the function to be executed for each request
cluster.task(async ({ page, data: url }) => {
return start(page, url);
});
app.get('/', async function (req, res) {
res.send("index page");
});
app.get('/start', async function (req, res) { // expects URL to be given by ?url=...
try {
// run the task function for the URL
const resp = cluster.queue(req.query.url);
res.send(resp);
} catch (err) {
res.end('Error: ' + err.message);
}
});
async function start(page, Url) {
const context = page.browser().defaultBrowserContext();
await page.goto(Url);
}
})();
now I can run mt puppeteer and click a button in my extension manually but what I need is call the function (same as button click in extension) from puppeteer cluster automatically after await page.goto(Url);
I can do that when I'm using puppeteer without cluster like :
const browser = await puppeteer.launch({
headless: false,
args: [
`--whitelisted-extension-id=${extensionId}`,
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`,
],
});
const page = await browser.newPage();
await page.goto('https://www.youtube.com/', { waitUntil: 'networkidle2' });
const targets = await browser.targets();
const backgroundPageTarget = targets.find(target => target.type() === 'background_page' && target.url().startsWith(`chrome-extension://${extensionId}/`));
const backgroundPage = await backgroundPageTarget.page();
backgroundPage.on('console', msg => {
for (let i = 0; i < msg.args().length; i++) {
console.log(`${i}: ${msg.args()[i]}`);
}
});
await backgroundPage.evaluate(() => {
startFunction();
return Promise.resolve(42);
});
But I cannot get the targets in cluster any suggestion

Puppeteer not work correctly with handlebars and get only blank page PDF

Hello im working in application that i want to create PDF files using puppeteer and handlbars but it create only blank PDF
Here is my code
File : functions.js
createPDF = async (templateName, data, file_name) => {
const pdfPath = `${process.cwd()}/public/tickets/${file_name}.pdf`;
const filePath = path.join(process.cwd(), "templates", `${templateName}.hbs`);
const html = fs.readFileSync(filePath, "utf-8");
const content = hbs.compile(html);
const htmlContent = content(data);
const options = {
format: "A4",
headerTemplate: "<p></p>",
footerTemplate: "<p></p>",
displayHeaderFooter: false,
margin: {
top: "10px",
bottom: "30px",
},
printBackground: true,
path: pdfPath,
};
const browser = await puppeteer.launch({
args: ["--no-sandbox"],
headless: true,
});
const page = await browser.newPage();
await page.goto(`data:text/html;charset=UTF-8,${htmlContent}`, {
waitUntil: "networkidle0",
});
console.log(await page.content());
await page.pdf(options);
await browser.close();
};
fileContoller.js
exports.myfile = async (req, res, next) => {
const { approved } = req.body;
const getData = await MyTable.findAll({
attributes: [
"id",
"first_name",
"last_name",
"birthday",
"gender",
"address",
"img",
],
where: { approved},
raw: true,
});
for (let i = 0; i < getData.length; i++) {
const createPDFforuser = await functions.createPDF(
"myhbsmockuptemplate",
getData[i],
`${getData[i].id}+${i}`
);
}
}
when i console.log htmlContent it get the html complete and correctly done as i write it
But when i console log awit page.content()
Here i dont get the html as expected it get only few line
<html><head>
<meta charset="utf-8">
<style type="text/css">
.tmp-mockup { font-family: "Staatliches", cursive; color: black;
font-size: 14px; letter-spacing: 0.1em; margin: 25px 0; } .ticket-box {
margin: auto; display: flex; background: </style></head><body></body></html>
Wait for some element in htmlContent after page is loaded.
await page.goto(`data:text/html;charset=UTF-8,${htmlContent}`, {
waitUntil: "networkidle0",
});
await page.waitForSelector('#visible-element')

Is there a problem with dialog.showOpenDialog in Electron on Windows?

I'm working on an example out of a book and can't seem to get past this. When I hit Ctrl-o it shows the dialog to open a file, but it never loads in the file into the markup editor. However, if I run it using the debugger in VSCode it works fine.
I believe the problem is with this section:
dialog.showOpenDialog(window, options, paths => {
if (paths && paths.length > 0) {
const content = fs.readFileSync(paths[0]).toString();
window.webContents.send('load', content);
}
});
This is my menu.js file:
const {
app,
Menu,
shell,
ipcMain,
BrowserWindow,
globalShortcut,
dialog
} = require('electron');
const fs = require('fs');
function saveFile() {
console.log('Saving the file');
const window = BrowserWindow.getFocusedWindow();
window.webContents.send('editor-event', 'save');
}
function loadFile() {
console.log('loadFile confirmation');
const window = BrowserWindow.getFocusedWindow();
const options = {
title: 'Pick a markdown file',
filters: [
{ name: 'Markdown files', extensions: ['md'] },
{ name: 'Text files', extensions: ['txt'] }
]
};
dialog.showOpenDialog(window, options, paths => {
if (paths && paths.length > 0) {
const content = fs.readFileSync(paths[0]).toString();
window.webContents.send('load', content);
}
});
}
app.on('ready', () => {
globalShortcut.register('CommandOrControl+S', () => {
saveFile();
});
globalShortcut.register('CommandorControl+O', () => {
console.log('Ctrl-O received');
loadFile();
});
});
ipcMain.on('save', (event, arg) => {
console.log(`Saving content of the file`);
console.log(arg);
const window = BrowserWindow.getFocusedWindow();
const options = {
title: 'Save markdown file',
filters: [
{
name: 'MyFile',
extensions: ['md']
}
]
};
//Broken code from book apparently: dialog.showSaveDialog(window, options, filename => {
let filename = dialog.showSaveDialogSync(window, options);
console.log(filename);
if (filename) {
console.log(`Saving content to the file: ${filename}`);
fs.writeFileSync(filename, arg);
}
//Broken code from book apparently });
});
ipcMain.on('editor-reply', (event, arg) => {
console.log(`Receieved reply from web page: ${arg}`);
});
const template = [
{
label: 'Format',
submenu: [
{
label: 'Toggle Bold',
click() {
const window = BrowserWindow.getFocusedWindow();
window.webContents.send('editor-event',
'toggle-bold'
);
}
}
]
}
];
if (process.env.DEBUG) {
template.push({
label: 'Debugging',
submenu: [
{
label: 'Dev Tools',
role: 'toggleDevTools'
},
{type: 'separator' },
{
role: 'reload',
accelerator: 'Alt+R'
}
]
});
}
const menu = Menu.buildFromTemplate(template);
module.exports = menu;
My index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta
http-equiv="Content-Security-Policy"
content="script-src 'self' 'unsafe-inline';" />
<style>
html, body {
height: 100%;
display: flex;
flex: 1;
flex-direction: column;
}
.CodeMirror {
flex: 1;
}
</style>
<title>Document</title>
<link rel="stylesheet" href="./node_modules/simplemde/dist/simplemde.min.css">
<script src="./node_modules/simplemde/dist/simplemde.min.js"></script>
</head>
<body>
<textarea id="editor"></textarea>
<script>
var editor = new SimpleMDE({
element: document.getElementById('editor')
});
const { ipcRenderer } = require('electron');
ipcRenderer.on('editor-event', (event, arg) => {
console.log(arg);
event.sender.send('editor-reply', `Received ${arg}`);
if (arg === 'toggle-bold') {
editor.toggleBold();
}
if (arg === 'save') {
event.sender.send('save', editor.value());
}
});
ipcRenderer.on('load', (event, content) => {
if (content) {
editor.value(content);
}
});
ipcRenderer.send('editor-reply', 'Page Loaded');
</script>
</body>
</html>
In recent versions of Electron, as stated in the relevant documentation: dialog.showOpenDialog () is no longer making use of a callback function, but is now returning a promise, so the .then syntax must be used instead:
function loadFile() {
console.log('loadFile confirmation');
const window = BrowserWindow.getFocusedWindow();
const options = {
title: 'Pick a markdown file',
filters: [
{ name: 'Markdown files', extensions: ['md'] },
{ name: 'Text files', extensions: ['txt'] }
]
};
dialog.showOpenDialog(window, options).then
(
result => {
if (!result.canceled)
{
let paths = result.filePaths;
if (paths && paths.length > 0) {
const content = fs.readFileSync(paths[0]).toString();
console.log (content);
// window.webContents.send('load', content);
}
}
}
);
}
loadFile();
Alternatively, you can use the dialog.showOpenDialogSync () function, which directly returns an array of file paths, or undefined if the dialog has been cancelled by the user...
TLDR: change the callback for dialog.showOpenDialog inside loadFile to:
dialog.showOpenDialog(window, options, (canceled, paths) => {
Instead of:
dialog.showOpenDialog(window, options, paths => {
Long version:
The callback for dialog.showOpenDialog passes in 3 arguments:
canceled
filePaths
And only on mac: bookmarks
You wanted the 2nd argument filePaths, although if your callback was just: paths => { expecting only one argument Electron would pass in the canceled argument because it's the first and you only said you wanted one argument.
So this means you need to pass in an argument before paths like: (canceled, paths) => {
See the docs

Puppeteer - PDFPrint but pdf is blank

I have a problem with puppeteer and pdf printing.
Everything looks ok, no error code,... but pdf is blank.
and templateHtml is good ! maybe it's an error in functions call await ?
Please help me !
async function createPDF(quotation, quoteurl, quotname){
var templateHtml = fs.readFileSync(path.join(process.cwd(), './templates/quotation2.html'), 'utf8');
//console.log(templateHtml);
var template = handlebars.compile(templateHtml);
//console.log(template);
var html = template(quotation);
//console.log(html);
var pdfPath = path.join(`${quoteurl}`, `${quotname}.pdf`);
console.log(pdfPath)
var options = {
width: '1230px',
headerTemplate: "<p></p>",
footerTemplate: "<p></p>",
displayHeaderFooter: false,
margin: {
top: "10px",
bottom: "30px"
},
printBackground: true,
path: pdfPath
}
const browser = await puppeteer.launch({
//args: ['--no-sandbox'],
headless: true
});
var page = await browser.newPage();
console.log('OH YES');
await page.goto(`data:text/html;charset=UTF-8,${html}`,{ waitUntil: ['domcontentloaded', 'load'] }).then(function (response) {
// page.emulateMedia('screen')
page.pdf({ path: pdfPath
, format: 'letter' })
.then(function (res) {
browser.close();
}).catch(function (e) {
browser.close();
})
})
}
i don't understand why it's not working.
I Change with this content and it works ! but the logo.png doesn't appear in the pdf (or it's in the same folder than html file.
Is there something to add to puppeteer to include image file in the pdf ? (it's declared in html file)
await page.setContent(html,{ waitUntil: ['domcontentloaded', 'load', "networkidle0"] }).then(function (response) {
// page.emulateMedia('screen')
page.pdf({ path: pdfPath,
format: 'A4',
printBackground: true,
margin: {
top: '20px',
bottom: '20px',
right: '20px',
left: '20px' }})
.then(function (res) {
browser.close();
}).catch(function (e) {
browser.close();
})
})

Pass Custom Parameters from webchat control to bot framework

So, I'm currently using this:
<!DOCTYPE html>
<html>
<body>
<div id="webchat"></div>
<script src="https://cdn.botframework.com/botframework-webchat/preview/botchat.js"></script>
<script>
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ secret: 'YOUR_BOT_SECRET_FROM_AZURE_PORTAL' })
}, document.getElementById('webchat'));
</script>
</body>
</html>
and it works fine, however I have multiple QnA Knowledge base for different client applications. SO I would like to pass custom parameter for 'applicationname' to decide the QNA KB in my BOT frame work(V4) in OnTurnAsync method.
I tried
var d1 = window.WebChat.createDirectLine({ token })
window.WebChat.renderWebChat({
directLine: d1,
styleSet,
postActivity: activity => {
var newActivity = Object.assign({}, activity, {channelData: { "userparam": "test" } });
return dl.postActivity(newActivity);
}
}, document.getElementById('webchat'));
})();
but Context.Activity.ChannelData in bot returning Null
and also tried
var d1 = window.WebChat.createDirectLine({ token })
window.WebChat.renderWebChat({
directLine: d1,
user: { id: 'userid', userparam:'test'},
styleSet
}, document.getElementById('webchat'));
})();
still Context.Activity.From.Properties["userparam"] returns Null
From Cilent Side
var d1 = window.WebChat.createDirectLine({ token })
window.WebChat.renderWebChat({
directLine: Object.assign({}, d1, {
postActivity: activity => {
var newActivity = Object.assign({}, activity, { channelData: { "param1": "test" } });
return d1.postActivity(newActivity);
}
}),
styleSet,
botAvatarInitials: 'CAB',
userAvatarInitials: 'You'
}, document.getElementById('webchat'));
})();
from BOt Framework
var channelObj = turnContext.Activity.ChannelData.ToString();
var channeldata = Newtonsoft.Json.Linq.JObject.Parse(channelObj);
var customdata = channeldata["param1"].ToString();
The other answer provided is helpful but it overwrites channelData. For others finding this answer and just wanting to send custom parameters, this will be helpful:
const originalDirectline = props.webchat.createDirectLine({
token,
})
const directLine = Object.assign({}, originalDirectline, {
postActivity: (activity: any) => {
const newActivity = Object.assign({}, activity)
newActivity.customParam = "custom value"
return originalDirectline.postActivity(newActivity)
}
})

Resources