puppeteer trigger ajax and get response data - node.js

I need to get what comes in response to an ajax request after clicking on a div
Here is my html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Js test</title>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="/index.js"></script>
<script type="text/javascript">
var pt = 'dc37ecab5ca7675be79857f3657b773';
</script>
<style type="text/css">
#button{
cursor: pointer;
border: 1px solid black;
background: yellow;
width: 100px;
text-align: center;
line-height: 2;
}
</style>
</head>
<body>
<h1>Title text</h1>
<div id="button">
<div>get data</div>
<div id="result">*******</div>
</div>
</body>
</html>
index.js
jQuery.noConflict();
jQuery(document).ready(function($) {
$('#button').click(function(){
$.ajax({
url: "ajax.php",
data: {pt: pt},
success: function(data){
$('#button').addClass('activated');
$('#result').text(data);
}
});
});
});
ajax.php
<?php
if(isset($_GET['pt']) && !empty($_GET['pt']) && $_GET['pt'] == 'dc37ecab5ca7675be79857f3657b773'){
echo 'success';
}else{
echo 'error';
}
?>
When a button is pressed, a request is made the result of which is inserted into the result block, and a class 'activated' is added to the button block.
Next, I try to trigger this click through the puppeteer.
const puppeteer = require('puppeteer');
(async() => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
const pageURL = 'http://puppeteer.local';
try {
await page.goto(pageURL);
console.log(`Page open: ${pageURL}`);
} catch (error) {
console.log(`Can not open page: ${pageURL} error: ${error}`);
}
const titleSelector = 'h1';
await page.waitForSelector(titleSelector);
const pageTitle = await page.$eval(
titleSelector, titleSelector => titleSelector.outerHTML
);
console.log('title: ', pageTitle);
const buttonSelector = '#button';
await page.waitForSelector(buttonSelector, { timeout: 0 });
await Promise.all([
//page.waitForNavigation(),
page.click(buttonSelector),
]);
await new Promise((resolve, reject) => setTimeout(resolve, 3000));
const buttonSelectorReuslt = '#button.activated #result';
await page.waitForSelector(buttonSelectorReuslt, { timeout: 5000 });
const buttonResult = await page.$eval(buttonSelectorReuslt,
buttonSelectorReuslt => buttonSelectorReuslt.innerHTML);
console.log('result: ', buttonResult);
await browser.close();
process.exit()
})();
I see in the console
node .\index.js
Page open: http://puppeteer.local
title: <h1>Title text</h1>
result: success
Is it possible to somehow force the puppeteer to initialize the request on his own without pressing a button.
We need to do this GET request to the url with the parameter
http://puppeteer.local/ajax.php?pt=dc37ecab5ca7675be79857f3657b773
and get response.
and second question
How can I perform any action immediately after the end of the ajax request, now I'm just doing a delay of 3 seconds
await new Promise((resolve, reject) => setTimeout(resolve, 3000));
And I would like to somehow find out that the ajax request has been completed and immediately after that do the remaining actions, such as searching for updated tags, or parsing what returned this request
In other words, something like a handler of the received response, rather than doing this delay in the execution of the code for 3 seconds

Related

Chrome Extension: How to communicate with Content.js from a newly opened Window?

I have created a new window in chrome.action.onClicked.addListener as given below.
On clicking of "Check" button in newly opened window I need to connect to content.js and print some message in the console of window. I dont know where it is going wrong! I am using Manifest version 3.
content.js
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
if(msg.color === "#00FF00"){
document.body.style.backgroundColor = "green";
sendResponse({ status: "done" });
}
});
background.js
var urlRegex = /^(https?:\/\/)?[a-z0-9-]*\.?[a-z0-9-]+\.[a-z0-9-]+(\/[^<>]*)?$/;
chrome.action.onClicked.addListener(function(tab) {
/*...check the URL of the active tab against our pattern and... */
if (urlRegex.test(tab.url)) {
/* ...if it matches, send a message specifying a callback too */
chrome.windows.create({
tabId: tab.id,
type:"popup",
url:"popup.html",
focused:true
});
}
});
popup.html
<html>
<head>
<script defer src="popup.js"></script>
</head>
<body>
<h3>Test Extension Page</h3>
<input type="button" id="sendMessage" value="Check"/>
</body>
</html>
popup.js
let sendMessageButton = document.getElementById("sendMessage");
console.log(document.URL);
console.log(sendMessageButton.value);
function getTitle()
{
return document.title;
}
sendMessageButton.onclick = function() {
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs){
var tab = tabs[0];
chrome.scripting.executeScript(
{
target: {tabId:tab.id},
func: getTitle,
},
() => {
// This executes only after your content script executes
chrome.tabs.sendMessage(
tab.id,
{ color: "#00FF00" },
function (response) {
console.log(response.status);
}
);
});
});
};
Error in console of newly opened window.
Unchecked runtime.lastError: Cannot access contents of url "chrome-extension://jjaaoafdfmabdajdckiacompibnnmnlh/popup.html". Extension manifest must request permission to access this host.
Error handling response: TypeError: Cannot read properties of undefined (reading 'status') at chrome-extension://jjaaoafdfmabdajdckiacompibnnmnlh/popup.js:25:34
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
The problem is that the window you create becomes active and hence it becomes the result of chrome.tabs.query in your code, meaning that executeScript runs inside your own extension page, which can't work as this method is only for web sites.
The solution is to pass the tab id as URL parameter.
// background.js
chrome.action.onClicked.addListener(tab => {
chrome.windows.create({
type: 'popup',
url: 'popup.html?' + new URLSearchParams({
tabId: tab.id,
title: tab.title,
}),
});
});
// popup.js
const params = new URLSearchParams(location.search);
const tabId = +params.get('tabId');
let title = params.get('title'); // initial title
document.getElementById('sendMessage').onclick = async function () {
title = (await chrome.tabs.get(tabId)).title;
let res = await chrome.tabs.sendMessage(tabId, { color: "#00FF00" });
};

How to FTP upload a buffer (pdf buffer) using NodeJS?

I converted a HTML to pdf using html-pdf-node, but I am not find a way to store this PDF in my server using FTP.
My Code:
const html_to_pdf = require('html-pdf-node');
const generatePDF = () => {
// The test HTML file
let content = `
<html>
<head>
<title>Test Application</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2>Just a Test</h2>
</div>
</body>
</html>
`;
// generating the PDF
let options = {
format: 'letter',
margin: {
right: '40px',
left: '40px'
}
};
let file = { content };
html_to_pdf.generatePdf(file, options).then((pdfBuffer) => {
console.log(pdfBuffer); // This is the pdfBuffer. It works because if I send this buffer to my email as an attachment, I can open the PDF
// How can I create and store a test.pdf file inside my server using FTP connection?
});
}
Thank you
Using ftp should do it - https://www.npmjs.com/package/ftp
Installation: npm i ftp and usage something like:
const Client = require("ftp");
// snip snip some code here
html_to_pdf.generatePdf(file, options).then((pdfBuffer) => {
const c = new Client();
c.on("ready", function () {
c.put(pdfBuffer, "foo.pdf", function (err) {
if (err) throw err;
c.end();
});
});
const secureOptions = {
host: "localhost",
port: 21,
user: "TheGreatPotatoKingOfEurope",
password: "5uper_5eekrit!"
};
c.connect(secureOptions);
});

Create image NextJS + NodeJS - 404 This page could not be found

I'm creating images using this library https://github.com/frinyvonnick/node-html-to-image
The output folder is public (https://nextjs.org/docs/basic-features/static-file-serving)
Everything works well on Dev, but when I build the app and run in production mode, I can't have access to the image (the image is created) but I receive the message 404 This page could not be found.
const nodeHtmlToImage = require('node-html-to-image')
async function generateImage({ htmlContent }) {
const htmlFile = `<html>
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Roboto+Slab:400,700|Material+Icons"/>
<style>
body {
width: 600px;
height: auto;
}
</style>
</head>
${htmlContent}
</html>`
const image_name = crypto.randomBytes(20).toString('hex')
const relativePath = `output/${image_name}.png`
const output = `${process.env.SERVER_STATIC_URL}/${relativePath}`
return await nodeHtmlToImage({
output: `./public/${relativePath}`,
html: htmlFile,
}).then(() => {
return { image_src: output }
})
.catch((err) => {
console.log('err')
return err
})
}
export { generateImage }
How can I solve it?
Thanks!

How To Send a Message From Popup.js to Content Script in Chrome Extension on Active Tab?

When I click on the toolbar icon from my chrome extension, it brings up the default popup.html along with popup.js. From that popup.js, I want to send a message to the current active tab. I can't figure out how to get the active tab.
My code in the popup.js looks like this:
window.onload = function() {
console.log(`popup.js:window.onload`);
const timeNow = document.getElementById("timeNowId");
timeNow.innerText = new Date().toLocaleTimeString();
var resultsButton = document.getElementById("buttonId");
resultsButton.onclick = () => {
chrome.runtime.sendMessage(
"FromPopupToBackgroundToContent:" + timeNow.innerText,
function(response) {
response === undefined
? alert("popup.js:return from sendMessage:undefined")
: alert("popup.js:return from sendMessage:", response);
}
);
};
};
The full, non-working example is in this github repo at this branch linked to.
https://github.com/pkellner/chrome-extension-message-popup-to-content/tree/feature-popup-to-content-directly-getcurrent
Example:
popup.js
function popup() {
chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
var activeTab = tabs[0];
chrome.tabs.sendMessage(activeTab.id, {"message": "start"});
});
}
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("button1").addEventListener("click", popup);
});
content.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if( request.message === "start" ) {
start();
}
}
);
function start(){
alert("started");
}
popup.html
<!DOCTYPE html>
<html>
<head></head>
<script src="popup.js"></script>
<body>
<input id="button1" type=button value=clickme>
</body>
</html>

Trying to figure a way to read all the files in a directory, re-create and write files programmatically

I'm trying to use node built in file structure module/package in trying to read and write files. I'm looking for a way on how I can read all the files in specific directory, re-create the files and write for any changes.
Basically if I have a file called templates/_template-1.html it would re-create it to a different directory called pages/template-1.html. Instead of having to declare each file manually within the gulpfile.js. The code below is currently a work in progress.
It basically prints tpl files written then re-writes them to basic html.
/*------------------ INDEX -------------------*/
/* Build index file for the final HTML form
*/
gulp.task("build:index", function() {
let templateFiles = glob.sync("templates/**/*.tpl"),
templates = {},
RESPONSIVE_HTML = fs.readFileSync("_responsive.html", "utf8"),
THE_HTML = fs.readFileSync("_design-system.html", "utf8"),
THE_VISUAL_LIBRARY = fs.readFileSync("_visual-library.html", "utf8");
// Discover all templates
for (let file in templateFiles) {
file = templateFiles[file];
let template = /templates\/(.+?)\.tpl/gi.exec(file)[1],
text = fs.readFileSync(file, "utf8");
template = path.basename(file, '.tpl');
templates[template] = text;
}
// --------------------------------------------------------
// Visible templates:
_.each(templates, (partial, name) => {
interpolateTemplate(partial, name, templates);
});
// replace the main HTML file
for (let template in templates) {
RESPONSIVE_HTML = RESPONSIVE_HTML.replace(new RegExp(`{[#$]${template}}`, "g"), templates[template]);
THE_HTML = THE_HTML.replace(new RegExp(`{[#$]${template}}`, "g"), templates[template]);
THE_VISUAL_LIBRARY = THE_VISUAL_LIBRARY.replace(new RegExp(`{[#$]${template}}`, "g"), templates[template]);
}
fs.writeFileSync("design-system.html", beautify(THE_HTML), "utf8");
fs.writeFileSync("responsive.html", beautify(RESPONSIVE_HTML), "utf8");
fs.writeFileSync("visual-library.html", beautify(THE_VISUAL_LIBRARY), "utf8");
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>BDO Components</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify-css.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify-html.js"></script>
<script src="assets/js/libs.js" type="text/javascript"></script>
<link rel="stylesheet" href="assets/css/assets-page.css" />
<link rel="stylesheet" href="assets/css/component-guide.css" />
</head>
<body>
<div class="display-panels">
{$control-bar}
<div class="preview-pane -hide-code">
{$globals}
{$design-references}
{$component-modifiers}
<div class="section-block element-group --show-code --components -component"
data-name="Typesetting">
{$typesetting}
</div>
<div class="section-block element-group --show-code --components -component"
data-name="Elements">
{$elements}
</div>
<div class="section-block element-group --show-code --components -component"
data-name="Low Level Components">
{$low-level-components}
</div>
<div class="section-block element-group --show-code --components -component"
data-name="High Level Components">
{$high-level-components}
</div>
</div>
<div class="index-group">
</div>
</div>
<script src="assets/js/app.js" type="text/javascript"></script>
</body>
</html>
You can use the function called readdir on fs. It will return a list of filenames which you can traverse and do whatever you need to do.
Basically, this will read all files inside dirname, read content of each filename returned, modify it, write it back.
(I wrapped fs functions with promises for better flow)
function readFiles(dirname) {
let fileNames = [];
let fileContents = [];
const results = [];
return readdir(dirname)
.then((_fileNames) => {
fileNames = _fileNames;
// map filenames to array of readFile promises
return Promise.all(fileNames.map((filename) => readFile(filename)))
})
.then((allFilesContent) => {
fileContents = allFilesContent;
// for each file, push an object with name + content to a new array
fileNames.forEach((fileName, index) => {
results.push({
name: fileName, // <-- you can also change the file paths here if needed
content: beautify(fileContents[index]) // <-- modify the content here as you please
});
});
})
// map that array to a writeFile promise array
.then(() => results.map((file) => writeFile(file.name, file.content)))
.then(() => console.log('all files written successfully'))
.catch((err) => console.error(err));
}
// FS FUNCTIONS AS PROMISES:
function readFile(filepath) {
return new Promise((resolve, reject) => {
fs.readFile(filepath, 'utf-8', function(err, content) {
if (err) { return reject(err); }
resolve(content);
});
});
}
function readdir(dirname) {
return new Promise((resolve, reject) => {
fs.readdir(dirname, function(err, filenames) {
if (err) { return reject(err); }
resolve(filenames);
});
});
}
function writeFile(filename, content) {
return new Promise((resolve, reject) => {
fs.writeFile(filename, content, function(err) {
if (err) { return reject(err); }
resolve();
});
});
}
I have a series of modules around slurping whole directories (recursively), and then doing stuff, like making a web page, with the results.
https://github.com/AWinterman/node-fsj and https://github.com/AWinterman/fsj-render
it should be pretty easy for you to add what you want.

Resources