SlideShare a Scribd company logo
possibly
Puppeteer can
automate that!
with the help of minions
Önder Ceylan
@onderceylan
Sharing knowledge on #javascript, #typescript, #angular, #ionic and #pwa
JS Squad Lead @LINKIT
Speaker, Organiser @ITNEXT
Speaker, Organiser @GDG NL
Chrome
Chrome
canarychromiumchrome
Headless Chrome
Headless Chrome
chrome —-headless —-remote-debugging-port=9222
Puppeteer
Puppeteer
npm i puppeteer
–Puppeteer docs
“Most things that you can do
manually in the browser can be
done using Puppeteer! ”
Examples to get you started
• Generate screenshots and PDFs of pages
• Crawl a SPA and generate pre-rendered
content
• Automate form submission, UI testing,
keyboard input, etc
• Capture a timeline trace of your site to
help diagnose performance issues
puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  await page.goto('https://www.linkit.nl');
  await page.screenshot({path: 'screenshot.png'});
  await browser.close();
});
pptr.dev
try-puppeteer.appspot.com
github.com/transitive-bullshit/awesome-puppeteer
Puppeteer Recorder Extension
DEMOS
Alex ! "
Xander # $
Ellen % &
Yelda ' (
Text to speech!
Alex ! "
Text to speech!
Xander # $
Text to speech!
Ellen % &
Text to speech!
Yelda ' (
speechSynthesis.getVoices()
Whatsapp messages every day!
const browser = await puppeteer.launch(({
userDataDir: ".tmp",
}));
const page = await browser.newPage();
await page.goto('https://web.whatsapp.com/', {waitUntil: 'networkidle2'});

await page.waitForSelector('#side input[type=text]');

await page.type('#side input[type=text]', groupName);

await page.waitForSelector(`#pane-side span[title=“${groupName}"]`,
{visible: true});

await page.click(`span[title="${groupName}"`);

await page.waitForSelector('footer .copyable-text', {visible: true});

await page.type('footer .copyable-text', getTodaysMessage());

await page.keyboard.press('Enter');

await browser.close();
Whatsapp messages every day!
Emulating color scheme NEW

in v2
await page.goto('https://googlechromelabs.github.io/dark-mode-toggle/demo/index.html');

await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'light' }]);

await page.screenshot({ path: 'light.jpg', type: 'jpeg', omitBackground: true });

await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }]);
await page.screenshot({ path: 'dark.jpg', type: 'jpeg', omitBackground: true });
Emulating color scheme NEW

in v2
Side by side page load
const devices = require('puppeteer/DeviceDescriptors');
const nexus5X = devices['Nexus 5X'];



const browser = await puppeteer.launch({
headless: false,
args: [
`--window-size=${DEFAULT_VIEWPORT.width},${DEFAULT_VIEWPORT.height}`,
CENTER_WINDOWS_ON_SCREEN ? `--window-position=${x},${y}` : `--window-position=${dx},0`,
],
});
const page = await browser.newPage();
await page.emulate(nexus5X);


const session = await page.target().createCDPSession();
// Emulate "Slow 3G" according to WebPageTest
await session.send('Network.emulateNetworkConditions', {
offline: false,
latency: 400,
downloadThroughput: Math.floor(400 * 1024 / 8), // 400 Kbps
uploadThroughput: Math.floor(400 * 1024 / 8) // 400 Kbps
});
await session.send('Emulation.setCPUThrottlingRate', {rate: 4});
Side by side page load
Element to PDF
const overlay = await page.$('.tweet.permalink-tweet');



await page.evaluate(tweet => {
const width = getComputedStyle(tweet).width;
tweet = tweet.cloneNode(true);
tweet.style.width = width;
document.body.innerHTML = `
<div style="display:flex;justify-content:center;align-items:center;height:100vh;">;
${tweet.outerHTML}
</div>
`;
}, overlay);


await page.pdf({path: 'tweet.pdf', printBackground: true});
Element to PDF
Accessibility test
await page.goto('https://frontmania.com');
await page.addScriptTag(
{ url: 'https://cdnjs.cloudflare.com/ajax/libs/axe-core/3.3.2/axe.min.js' }
);
const results = await page.evaluate(() => axe.run(document));


expect(results.violations.length).toBe(0);
Accessibility test
Code coverage test
const pti = require('puppeteer-to-istanbul');


const page = await browser.newPage();
await page.coverage.startJSCoverage();
await page.goto('https://www.linkit.nl/');
const jsCoverage = await page.coverage.stopJSCoverage();


pti.write(jsCoverage);
await page.close();
Code coverage test
Chrome DevTools
throttle network
track memory usage
emulate devices
run audits
github.com/ChromeDevTools/devtools-frontend
Protocol Monitor
chrome://flags/#enable-devtools-experiments
chrome —-remote-debugging-port=9222
Chrome DevTools
Protocol
127.0.0.1:9222/json/version
chromedevtools.github.io/devtools-protocol
github.com/ChromeDevTools/awesome-chrome-devtools
puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  await page.goto('https://www.linkit.nl');
  await page.screenshot({path: 'screenshot.png'});
  await browser.close();
});
Using DevTools
Protocol with PPTR
puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  await page.goto('https://www.linkit.nl');
const session = await page.target().createCDPSession();
  session.on('Animation.animationCreated', () => {
    console.log('Animation created!');
  });
  await session.send('Animation.enable');
  await session.send('Animation.setPlaybackRate', {
    playbackRate: 10,
  });
  await browser.close();
});
Puppeteer Core
npm i puppeteer-core
Puppeteer Core
browser = await puppeteer.connect({
  browserWSEndpoint: 'ws://127.0.0.1:9222/.../...'
});
// or 
browser = await puppeteer.launch({
  executablePath: '/Applications/Google Chrome.app
/Contents/MacOS/Google Chrome'
});
Chrome Launcher
npm i chrome-launcher
const chromeLauncher = require('chrome-launcher');
// Launches a debugging instance of Chrome
function launchChrome(headless=true) {
  return chromeLauncher.launch({
    // port: 9222,
    chromeFlags: [
      '--window-size=412,732',
      '--disable-gpu',
      headless ? '--headless' : ''
    ]
  });
}
launchChrome().then(chrome => {
  console.log(`Chrome debuggable on port: ${chrome.port}`);
  // chrome.kill();
});
const chromeLauncher = require('chrome-launcher');
// Launches a debugging instance of Chrome
function launchChrome(headless=true) {
  return chromeLauncher.launch({
    // port: 9222,
    chromeFlags: [
      '--window-size=412,732',
      '--disable-gpu',
      headless ? '--headless' : ''
    ]
  });
}
launchChrome().then(chrome => {
  console.log(`Chrome debuggable on port: ${chrome.port}`);
  // chrome.kill();
});
chrome instance
Puppeteer Light
npm i puppeteer-core
npm i chrome-launcher
const chromeLauncher = require('chrome-launcher');
const puppeteer = require('puppeteer-core');
const util = require('util');
(async() => {
const URL = 'https://www.linkit.nl';
// Chrome executable launch arguments
const opts = {
  chromeFlags: ['--headless'],
  logLevel: 'info',
  output: 'json'
};
// Launching chrome using chrome-launcher
const chrome = await chromeLauncher.launch(opts);
opts.port = chrome.port;
// Connecting to WS using puppeteer.connect()
const resp = await util.promisify(request)(`http://localhost:${opts.port}/json/version`);
const chromeVersion = JSON.parse(resp.body);
const browser = await puppeteer.connect({
  browserWSEndpoint: chromeVersion.webSocketDebuggerUrl
});
// Cleanup of resources
await browser.disconnect();
await chrome.kill();
})();
const chromeLauncher = require('chrome-launcher');
const puppeteer = require(‘puppeteer-core');
const util = require('util');
(async() => {
const URL = 'https://www.linkit.nl';
// Chrome executable launch arguments
const opts = {
  chromeFlags: ['--headless'],
  logLevel: 'info',
  output: 'json'
};
// Launching chrome using chrome-launcher
const chrome = await chromeLauncher.launch(opts);
opts.port = chrome.port;
// Connecting to WS using puppeteer.connect()
const resp = await util.promisify(request)(`http://localhost:${opts.port}/json/version`);
const chromeVersion = JSON.parse(resp.body);
const browser = await puppeteer.connect({
  browserWSEndpoint: chromeVersion.webSocketDebuggerUrl
});
// Cleanup of resources
await browser.disconnect();
await chrome.kill();
})();
const chromeLauncher = require('chrome-launcher');
const puppeteer = require(‘puppeteer-core');
const util = require('util');
(async() => {
const URL = 'https://www.linkit.nl';
// Chrome executable launch arguments
const opts = {
  chromeFlags: ['--headless'],
  logLevel: 'info',
  output: 'json'
};
// Launching chrome using chrome-launcher
const chrome = await chromeLauncher.launch(opts);
opts.port = chrome.port;
// Connecting to WS using puppeteer.connect()
const resp = await util.promisify(request)(`http://localhost:${opts.port}/json/version`);
const chromeVersion = JSON.parse(resp.body);
const browser = await puppeteer.connect({
  browserWSEndpoint: chromeVersion.webSocketDebuggerUrl
});
// Cleanup of resources
await browser.disconnect();
await chrome.kill();
})();
const chromeLauncher = require('chrome-launcher');
const puppeteer = require(‘puppeteer-core');
const util = require('util');
(async() => {
const URL = 'https://www.linkit.nl';
// Chrome executable launch arguments
const opts = {
  chromeFlags: ['--headless'],
  logLevel: 'info',
  output: 'json'
};
// Launching chrome using chrome-launcher
const chrome = await chromeLauncher.launch(opts);
opts.port = chrome.port;
// Connecting to WS using puppeteer.connect()
const resp = await util.promisify(request)(`http://localhost:${opts.port}/json/version`);
const chromeVersion = JSON.parse(resp.body);
const browser = await puppeteer.connect({
  browserWSEndpoint: chromeVersion.webSocketDebuggerUrl
});
// Cleanup of resources
await browser.disconnect();
await chrome.kill();
})();
const chromeLauncher = require('chrome-launcher');
const puppeteer = require(‘puppeteer-core');
const util = require('util');
(async() => {
const URL = 'https://www.linkit.nl';
// Chrome executable launch arguments
const opts = {
  chromeFlags: ['--headless'],
  logLevel: 'info',
  output: 'json'
};
// Launching chrome using chrome-launcher
const chrome = await chromeLauncher.launch(opts);
opts.port = chrome.port;
// Connecting to WS using puppeteer.connect()
const resp = await util.promisify(request)(`http://localhost:${opts.port}/json/version`);
const chromeVersion = JSON.parse(resp.body);
const browser = await puppeteer.connect({
  browserWSEndpoint: chromeVersion.webSocketDebuggerUrl
});
// Cleanup of resources
await browser.disconnect();
await chrome.kill();
})();
DEMOS
even more
github.com/onderceylan/pwa-asset-generator
PptrGram
await Promise.all(filters.map(async (filter) => {
const page = await browser.newPage();
await page.setContent(`
<style>/* Page styles here */</style>
<figure class="${filter}">
<img src="${getImageBase64Url('./sample.jpg')}">
<span>@onderceylan</span>
</figure>
`, { waitUntil: 'networkidle2' });
await page.addStyleTag({
url: 'https://cdnjs.cloudflare.com/ajax/libs/cssgram/0.1.10/cssgram.min.css'
});
// Get original image dimensions
const { width, height } = await page.evaluate(() => {
return (({naturalWidth: width, naturalHeight: height}) =>
({width, height}))(document.querySelector('img'));
});
await page.setViewport({ width, height });
await page.screenshot({
path: `pptgram/pptrgram-${filter}.jpeg`,
type: 'jpeg',
quality: 70,
fullPage: true,
});
});
PptrGram
PptrFlow
PptrFlow
PptrFlow
await page.goto(`http://localhost:8002/tensorflow.html`);
const result = await page.evaluate(() => {
const img = document.getElementById('img');
// Load the model
return cocoSsd.load().then(model => model.detect(img))
});
console.log(result);
PptrFlow
Monitoring
Visual Regression Testing
const takeScreenshot = async (page, title) => {
if (!fs.existsSync('./.screenshots')) {
fs.mkdirSync('./.screenshots');
}
const filePath = `./.screenshots/${title}.png`;
if (fs.existsSync(filePath)) {
const newFilePath = `./.screenshots/${title}-new.png`;

await page.screenshot({
path: newFilePath,
fullPage: true
});

const result = await new Promise(resolve =>
looksSame(filePath, newFilePath, (err, equal) => resolve(equal)));


fs.unlinkSync(newFilePath);
return result;
} else {
await page.screenshot({
path: filePath,
fullPage: true
});
return true;
}
};


await page.goto('https://www.linkit.nl');
expect(await takeScreenshot(page, 'main-page.1')).toBeTruthy();
Visual Regression Testing
DOM Snapshot Testing
const page = await browser.newPage();
await page.goto('https://www.linkit.nl/');
expect(await page.content()).toMatchSnapshot();
DOM Snapshot Testing
Timeline Trace Monitoring
await page.tracing.start({ path: 'trace.json' });

await page.goto('https://www.google.com');

await page.tracing.stop();
Timeline Trace Monitoring
FPS Monitoring
const protocol = await page.target().createCDPSession();

await protocol.send('Overlay.setShowFPSCounter', { show: true });

await page.goto('https://www.linkit.nl');
// Do graphical regressions here by interacting with the page
await protocol.send('Input.synthesizeScrollGesture', {
x: 100,
y: 100,
yDistance: -400,
repeatCount: 3
});
await page.screenshot({
path: 'fps.jpeg',
type: 'jpeg',
clip: {
x:0,
y:0,
width: 370,
height: 370
}
});
FPS Monitoring
Memory leak by Heap
const protocol = await page.target().createCDPSession();
await protocol.send('HeapProfiler.enable');
await protocol.send('HeapProfiler.collectGarbage');
const startMetrics = await page.metrics();
// Do memory regressions here by interacting with the page
await protocol.send('Input.synthesizeScrollGesture', {
x: 100,
y: 100,
yDistance: -400,
repeatCount: 3
});
await protocol.send('HeapProfiler.collectGarbage');
const endMetrics = await page.metrics();
expect(endMetrics.JSHeapUsedSize < startMetrics.JSHeapUsedSize * 1.1)
.toBeTruthy();
Memory leak by Heap
Memory leak by Prototype
// Get a handle to the Map object prototype
const mapPrototype = await page.evaluateHandle(() => Map.prototype);
// Query all map instances into an array
const mapInstances = await page.queryObjects(mapPrototype);
// Count amount of map objects in heap
const count = await page.evaluate(maps => maps.length, mapInstances);
// Idea here is to test object instances on the page
// where it's expected to be invalidated
expect(count).toBe(0);
Memory leak by Prototype
Monitor change on security state
const protocol = await page.target().createCDPSession();

await protocol.send('Security.enable');
protocol.on('Security.securityStateChanged', console.log);
Monitor change on security state
Monitor SSL certificate expiration
const page = await browser.newPage();
page.on('response', (resp) => {
const url = resp.url();

if (url === siteUrl) {
const secDetails = resp.securityDetails();
const now = Math.floor((new Date()).getTime() / 1000);

console.log((Math.floor((secDetails.validTo() - now) / 86400)),
'days to expire');
}
});
await page.goto(siteUrl, { waitUntil: 'networkidle0' });
Monitor SSL certificate expiration
Puppeteer on Cloud
const launchChrome = require('@serverless-chrome/lambda');
const request = require('superagent');
module.exports.getChrome = async () => {
const chrome = await launchChrome();
const response = await request
.get(`${chrome.url}/json/version`)
.set('Content-Type', 'application/json');
const endpoint = response.body.webSocketDebuggerUrl;
return {
endpoint,
instance: chrome,
};
};
Ppptr on AWS Lambda via Serverless Framework
const puppeteer = require('puppeteer');
const { getChrome } = require('./chrome-script');
module.exports.hello = async (event) => {
const { url } = event.queryStringParameters;
const chrome = await getChrome();
const browser = await puppeteer.connect({
browserWSEndpoint: chrome.endpoint,
});
const page = await browser.newPage();

await page.goto(url, { waitUntil: 'networkidle0' });

const content = await page.evaluate(() => document.body.innerHTML);

return {
statusCode: 200,
body: JSON.stringify({
content,
}),
};
};
Ppptr on AWS Lambda via Serverless Framework
PaaS
Puppeteer as a Service
browserless.io
checklyhq.com
Main Takeaways
• Chrome can be instrumented with a WS connection over
Chrome DevTools Protocol — CDP
• You might not need to download chromium revision every time
—puppeteer-core + chrome-launcher
• Headless chrome can be executed on servers— cloud, and CI
pipelines
• You can automate anything you do on DevTools, by using raw
protocol of CDP on puppeteer—CDPSession
Thank you!
@onderceylan
https://github.com/onderceylan/puppeteer-demos

More Related Content

What's hot

Node.js Express
Node.js  ExpressNode.js  Express
Node.js ExpressEyal Vardi
 
PHP Cookies and Sessions
PHP Cookies and SessionsPHP Cookies and Sessions
PHP Cookies and SessionsNisa Soomro
 
Cypress-vs-Playwright: Let the Code Speak
Cypress-vs-Playwright: Let the Code SpeakCypress-vs-Playwright: Let the Code Speak
Cypress-vs-Playwright: Let the Code SpeakApplitools
 
[131]chromium binging 기술을 node.js에 적용해보자
[131]chromium binging 기술을 node.js에 적용해보자[131]chromium binging 기술을 node.js에 적용해보자
[131]chromium binging 기술을 node.js에 적용해보자NAVER D2
 
Async Tasks with Django Channels
Async Tasks with Django ChannelsAsync Tasks with Django Channels
Async Tasks with Django ChannelsAlbert O'Connor
 
Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017Roman Elizarov
 
A Basic Django Introduction
A Basic Django IntroductionA Basic Django Introduction
A Basic Django IntroductionGanga Ram
 
Functional Reactive Programming with RxJS
Functional Reactive Programming with RxJSFunctional Reactive Programming with RxJS
Functional Reactive Programming with RxJSstefanmayer13
 
Rust Programming Language
Rust Programming LanguageRust Programming Language
Rust Programming LanguageJaeju Kim
 
Asynchronous JavaScript & XML (AJAX)
Asynchronous JavaScript & XML (AJAX)Asynchronous JavaScript & XML (AJAX)
Asynchronous JavaScript & XML (AJAX)Adnan Sohail
 
Build RESTful API Using Express JS
Build RESTful API Using Express JSBuild RESTful API Using Express JS
Build RESTful API Using Express JSCakra Danu Sedayu
 
Node.js File system & Streams
Node.js File system & StreamsNode.js File system & Streams
Node.js File system & StreamsEyal Vardi
 
Writing native Linux desktop apps with JavaScript
Writing native Linux desktop apps with JavaScriptWriting native Linux desktop apps with JavaScript
Writing native Linux desktop apps with JavaScriptIgalia
 
Le Wagon - UI components design
Le Wagon - UI components designLe Wagon - UI components design
Le Wagon - UI components designBoris Paillard
 
RESTful API In Node Js using Express
RESTful API In Node Js using Express RESTful API In Node Js using Express
RESTful API In Node Js using Express Jeetendra singh
 

What's hot (20)

Node.js Express
Node.js  ExpressNode.js  Express
Node.js Express
 
Android Networking
Android NetworkingAndroid Networking
Android Networking
 
PHP Cookies and Sessions
PHP Cookies and SessionsPHP Cookies and Sessions
PHP Cookies and Sessions
 
Cypress-vs-Playwright: Let the Code Speak
Cypress-vs-Playwright: Let the Code SpeakCypress-vs-Playwright: Let the Code Speak
Cypress-vs-Playwright: Let the Code Speak
 
[131]chromium binging 기술을 node.js에 적용해보자
[131]chromium binging 기술을 node.js에 적용해보자[131]chromium binging 기술을 node.js에 적용해보자
[131]chromium binging 기술을 node.js에 적용해보자
 
Async Tasks with Django Channels
Async Tasks with Django ChannelsAsync Tasks with Django Channels
Async Tasks with Django Channels
 
Express js
Express jsExpress js
Express js
 
Socket.IO
Socket.IOSocket.IO
Socket.IO
 
Rest in flask
Rest in flaskRest in flask
Rest in flask
 
Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017
 
A Basic Django Introduction
A Basic Django IntroductionA Basic Django Introduction
A Basic Django Introduction
 
Functional Reactive Programming with RxJS
Functional Reactive Programming with RxJSFunctional Reactive Programming with RxJS
Functional Reactive Programming with RxJS
 
Rust Programming Language
Rust Programming LanguageRust Programming Language
Rust Programming Language
 
Asynchronous JavaScript & XML (AJAX)
Asynchronous JavaScript & XML (AJAX)Asynchronous JavaScript & XML (AJAX)
Asynchronous JavaScript & XML (AJAX)
 
Build RESTful API Using Express JS
Build RESTful API Using Express JSBuild RESTful API Using Express JS
Build RESTful API Using Express JS
 
JavaScript Promises
JavaScript PromisesJavaScript Promises
JavaScript Promises
 
Node.js File system & Streams
Node.js File system & StreamsNode.js File system & Streams
Node.js File system & Streams
 
Writing native Linux desktop apps with JavaScript
Writing native Linux desktop apps with JavaScriptWriting native Linux desktop apps with JavaScript
Writing native Linux desktop apps with JavaScript
 
Le Wagon - UI components design
Le Wagon - UI components designLe Wagon - UI components design
Le Wagon - UI components design
 
RESTful API In Node Js using Express
RESTful API In Node Js using Express RESTful API In Node Js using Express
RESTful API In Node Js using Express
 

Similar to Puppeteer can automate that! - Frontmania

Puppeteer can automate that! - HolyJS Piter 2020
Puppeteer can automate that! - HolyJS Piter 2020Puppeteer can automate that! - HolyJS Piter 2020
Puppeteer can automate that! - HolyJS Piter 2020Önder Ceylan
 
Introducing perf budgets on CI with puppeteer - perf.now()
Introducing perf budgets on CI with puppeteer - perf.now()Introducing perf budgets on CI with puppeteer - perf.now()
Introducing perf budgets on CI with puppeteer - perf.now()Önder Ceylan
 
Bruce Lawson, Web Development 2.0, SparkUp! Poznan Poland
Bruce Lawson, Web Development 2.0, SparkUp! Poznan PolandBruce Lawson, Web Development 2.0, SparkUp! Poznan Poland
Bruce Lawson, Web Development 2.0, SparkUp! Poznan Polandbrucelawson
 
[convergese] Adaptive Images in Responsive Web Design
[convergese] Adaptive Images in Responsive Web Design[convergese] Adaptive Images in Responsive Web Design
[convergese] Adaptive Images in Responsive Web DesignChristopher Schmitt
 
[refreshaustin] Adaptive Images in Responsive Web Design
[refreshaustin] Adaptive Images in Responsive Web Design[refreshaustin] Adaptive Images in Responsive Web Design
[refreshaustin] Adaptive Images in Responsive Web DesignChristopher Schmitt
 
Pinkoi Mobile Web
Pinkoi Mobile WebPinkoi Mobile Web
Pinkoi Mobile Webmikeleeme
 
Backend, app e internet das coisas com NodeJS no Google Cloud Platform
Backend, app e internet das coisas com NodeJS no Google Cloud PlatformBackend, app e internet das coisas com NodeJS no Google Cloud Platform
Backend, app e internet das coisas com NodeJS no Google Cloud PlatformAlvaro Viebrantz
 
Backend, app e internet das coisas com NodeJS no Google Cloud Platform
Backend, app e internet das coisas com NodeJS no Google Cloud PlatformBackend, app e internet das coisas com NodeJS no Google Cloud Platform
Backend, app e internet das coisas com NodeJS no Google Cloud PlatformDevMT
 
Google Compute Engine Starter Guide
Google Compute Engine Starter GuideGoogle Compute Engine Starter Guide
Google Compute Engine Starter GuideSimon Su
 
vodQA Pune (2019) - Browser automation using dev tools
vodQA Pune (2019) - Browser automation using dev toolsvodQA Pune (2019) - Browser automation using dev tools
vodQA Pune (2019) - Browser automation using dev toolsvodQA
 
Drive chrome(headless) with puppeteer
Drive chrome(headless) with puppeteerDrive chrome(headless) with puppeteer
Drive chrome(headless) with puppeteerVodqaBLR
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch
 
FINHTML5 - Breaking the mobile web
FINHTML5 - Breaking the mobile webFINHTML5 - Breaking the mobile web
FINHTML5 - Breaking the mobile webMaximiliano Firtman
 
Electron - cross platform desktop applications made easy
Electron - cross platform desktop applications made easyElectron - cross platform desktop applications made easy
Electron - cross platform desktop applications made easyUlrich Krause
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"Provectus
 
AFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack EncoreAFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack EncoreEngineor
 

Similar to Puppeteer can automate that! - Frontmania (20)

Puppeteer can automate that! - HolyJS Piter 2020
Puppeteer can automate that! - HolyJS Piter 2020Puppeteer can automate that! - HolyJS Piter 2020
Puppeteer can automate that! - HolyJS Piter 2020
 
Introducing perf budgets on CI with puppeteer - perf.now()
Introducing perf budgets on CI with puppeteer - perf.now()Introducing perf budgets on CI with puppeteer - perf.now()
Introducing perf budgets on CI with puppeteer - perf.now()
 
JavaScript on the Desktop
JavaScript on the DesktopJavaScript on the Desktop
JavaScript on the Desktop
 
Node azure
Node azureNode azure
Node azure
 
Bruce Lawson, Web Development 2.0, SparkUp! Poznan Poland
Bruce Lawson, Web Development 2.0, SparkUp! Poznan PolandBruce Lawson, Web Development 2.0, SparkUp! Poznan Poland
Bruce Lawson, Web Development 2.0, SparkUp! Poznan Poland
 
[convergese] Adaptive Images in Responsive Web Design
[convergese] Adaptive Images in Responsive Web Design[convergese] Adaptive Images in Responsive Web Design
[convergese] Adaptive Images in Responsive Web Design
 
[refreshaustin] Adaptive Images in Responsive Web Design
[refreshaustin] Adaptive Images in Responsive Web Design[refreshaustin] Adaptive Images in Responsive Web Design
[refreshaustin] Adaptive Images in Responsive Web Design
 
Always on! Or not?
Always on! Or not?Always on! Or not?
Always on! Or not?
 
Pinkoi Mobile Web
Pinkoi Mobile WebPinkoi Mobile Web
Pinkoi Mobile Web
 
Backend, app e internet das coisas com NodeJS no Google Cloud Platform
Backend, app e internet das coisas com NodeJS no Google Cloud PlatformBackend, app e internet das coisas com NodeJS no Google Cloud Platform
Backend, app e internet das coisas com NodeJS no Google Cloud Platform
 
Backend, app e internet das coisas com NodeJS no Google Cloud Platform
Backend, app e internet das coisas com NodeJS no Google Cloud PlatformBackend, app e internet das coisas com NodeJS no Google Cloud Platform
Backend, app e internet das coisas com NodeJS no Google Cloud Platform
 
Google Compute Engine Starter Guide
Google Compute Engine Starter GuideGoogle Compute Engine Starter Guide
Google Compute Engine Starter Guide
 
vodQA Pune (2019) - Browser automation using dev tools
vodQA Pune (2019) - Browser automation using dev toolsvodQA Pune (2019) - Browser automation using dev tools
vodQA Pune (2019) - Browser automation using dev tools
 
Drive chrome(headless) with puppeteer
Drive chrome(headless) with puppeteerDrive chrome(headless) with puppeteer
Drive chrome(headless) with puppeteer
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.js
 
FINHTML5 - Breaking the mobile web
FINHTML5 - Breaking the mobile webFINHTML5 - Breaking the mobile web
FINHTML5 - Breaking the mobile web
 
Electron - cross platform desktop applications made easy
Electron - cross platform desktop applications made easyElectron - cross platform desktop applications made easy
Electron - cross platform desktop applications made easy
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
 
AFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack EncoreAFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack Encore
 

More from Önder Ceylan

Make your PWA feel more like an app
Make your PWA feel more like an appMake your PWA feel more like an app
Make your PWA feel more like an appÖnder Ceylan
 
Build a production ready PWA - LINKIT & KLM Digital Studio Meetup
Build a production ready PWA - LINKIT & KLM Digital Studio MeetupBuild a production ready PWA - LINKIT & KLM Digital Studio Meetup
Build a production ready PWA - LINKIT & KLM Digital Studio MeetupÖnder Ceylan
 
Build a production ready PWA with Angular and Firebase
Build a production ready PWA with Angular and FirebaseBuild a production ready PWA with Angular and Firebase
Build a production ready PWA with Angular and FirebaseÖnder Ceylan
 
Level up your NgRx game
Level up your NgRx gameLevel up your NgRx game
Level up your NgRx gameÖnder Ceylan
 
Building angular apps at scale
Building angular apps at scaleBuilding angular apps at scale
Building angular apps at scaleÖnder Ceylan
 
Progressive Web Apps: Is it a replacement for your mobile app?
Progressive Web Apps: Is it a replacement for your mobile app?Progressive Web Apps: Is it a replacement for your mobile app?
Progressive Web Apps: Is it a replacement for your mobile app?Önder Ceylan
 

More from Önder Ceylan (6)

Make your PWA feel more like an app
Make your PWA feel more like an appMake your PWA feel more like an app
Make your PWA feel more like an app
 
Build a production ready PWA - LINKIT & KLM Digital Studio Meetup
Build a production ready PWA - LINKIT & KLM Digital Studio MeetupBuild a production ready PWA - LINKIT & KLM Digital Studio Meetup
Build a production ready PWA - LINKIT & KLM Digital Studio Meetup
 
Build a production ready PWA with Angular and Firebase
Build a production ready PWA with Angular and FirebaseBuild a production ready PWA with Angular and Firebase
Build a production ready PWA with Angular and Firebase
 
Level up your NgRx game
Level up your NgRx gameLevel up your NgRx game
Level up your NgRx game
 
Building angular apps at scale
Building angular apps at scaleBuilding angular apps at scale
Building angular apps at scale
 
Progressive Web Apps: Is it a replacement for your mobile app?
Progressive Web Apps: Is it a replacement for your mobile app?Progressive Web Apps: Is it a replacement for your mobile app?
Progressive Web Apps: Is it a replacement for your mobile app?
 

Recently uploaded

ER(Entity Relationship) Diagram for online shopping - TAE
ER(Entity Relationship) Diagram for online shopping - TAEER(Entity Relationship) Diagram for online shopping - TAE
ER(Entity Relationship) Diagram for online shopping - TAEHimani415946
 
The+Prospects+of+E-Commerce+in+China.pptx
The+Prospects+of+E-Commerce+in+China.pptxThe+Prospects+of+E-Commerce+in+China.pptx
The+Prospects+of+E-Commerce+in+China.pptxlaozhuseo02
 
Multi-cluster Kubernetes Networking- Patterns, Projects and Guidelines
Multi-cluster Kubernetes Networking- Patterns, Projects and GuidelinesMulti-cluster Kubernetes Networking- Patterns, Projects and Guidelines
Multi-cluster Kubernetes Networking- Patterns, Projects and GuidelinesSanjeev Rampal
 
Article writing on excessive use of internet.pptx
Article writing on excessive use of internet.pptxArticle writing on excessive use of internet.pptx
Article writing on excessive use of internet.pptxabhinandnam9997
 
Pvtaan Social media marketing proposal.pdf
Pvtaan Social media marketing proposal.pdfPvtaan Social media marketing proposal.pdf
Pvtaan Social media marketing proposal.pdfPvtaan
 
The AI Powered Organization-Intro to AI-LAN.pdf
The AI Powered Organization-Intro to AI-LAN.pdfThe AI Powered Organization-Intro to AI-LAN.pdf
The AI Powered Organization-Intro to AI-LAN.pdfSiskaFitrianingrum
 
The Use of AI in Indonesia Election 2024: A Case Study
The Use of AI in Indonesia Election 2024: A Case StudyThe Use of AI in Indonesia Election 2024: A Case Study
The Use of AI in Indonesia Election 2024: A Case StudyDamar Juniarto
 
一比一原版UTS毕业证悉尼科技大学毕业证成绩单如何办理
一比一原版UTS毕业证悉尼科技大学毕业证成绩单如何办理一比一原版UTS毕业证悉尼科技大学毕业证成绩单如何办理
一比一原版UTS毕业证悉尼科技大学毕业证成绩单如何办理aagad
 
How Do I Begin the Linksys Velop Setup Process?
How Do I Begin the Linksys Velop Setup Process?How Do I Begin the Linksys Velop Setup Process?
How Do I Begin the Linksys Velop Setup Process?Linksys Velop Login
 
History+of+E-commerce+Development+in+China-www.cfye-commerce.shop
History+of+E-commerce+Development+in+China-www.cfye-commerce.shopHistory+of+E-commerce+Development+in+China-www.cfye-commerce.shop
History+of+E-commerce+Development+in+China-www.cfye-commerce.shoplaozhuseo02
 
How to Use Contact Form 7 Like a Pro.pptx
How to Use Contact Form 7 Like a Pro.pptxHow to Use Contact Form 7 Like a Pro.pptx
How to Use Contact Form 7 Like a Pro.pptxGal Baras
 

Recently uploaded (12)

ER(Entity Relationship) Diagram for online shopping - TAE
ER(Entity Relationship) Diagram for online shopping - TAEER(Entity Relationship) Diagram for online shopping - TAE
ER(Entity Relationship) Diagram for online shopping - TAE
 
The+Prospects+of+E-Commerce+in+China.pptx
The+Prospects+of+E-Commerce+in+China.pptxThe+Prospects+of+E-Commerce+in+China.pptx
The+Prospects+of+E-Commerce+in+China.pptx
 
Multi-cluster Kubernetes Networking- Patterns, Projects and Guidelines
Multi-cluster Kubernetes Networking- Patterns, Projects and GuidelinesMulti-cluster Kubernetes Networking- Patterns, Projects and Guidelines
Multi-cluster Kubernetes Networking- Patterns, Projects and Guidelines
 
Article writing on excessive use of internet.pptx
Article writing on excessive use of internet.pptxArticle writing on excessive use of internet.pptx
Article writing on excessive use of internet.pptx
 
The Best AI Powered Software - Intellivid AI Studio
The Best AI Powered Software - Intellivid AI StudioThe Best AI Powered Software - Intellivid AI Studio
The Best AI Powered Software - Intellivid AI Studio
 
Pvtaan Social media marketing proposal.pdf
Pvtaan Social media marketing proposal.pdfPvtaan Social media marketing proposal.pdf
Pvtaan Social media marketing proposal.pdf
 
The AI Powered Organization-Intro to AI-LAN.pdf
The AI Powered Organization-Intro to AI-LAN.pdfThe AI Powered Organization-Intro to AI-LAN.pdf
The AI Powered Organization-Intro to AI-LAN.pdf
 
The Use of AI in Indonesia Election 2024: A Case Study
The Use of AI in Indonesia Election 2024: A Case StudyThe Use of AI in Indonesia Election 2024: A Case Study
The Use of AI in Indonesia Election 2024: A Case Study
 
一比一原版UTS毕业证悉尼科技大学毕业证成绩单如何办理
一比一原版UTS毕业证悉尼科技大学毕业证成绩单如何办理一比一原版UTS毕业证悉尼科技大学毕业证成绩单如何办理
一比一原版UTS毕业证悉尼科技大学毕业证成绩单如何办理
 
How Do I Begin the Linksys Velop Setup Process?
How Do I Begin the Linksys Velop Setup Process?How Do I Begin the Linksys Velop Setup Process?
How Do I Begin the Linksys Velop Setup Process?
 
History+of+E-commerce+Development+in+China-www.cfye-commerce.shop
History+of+E-commerce+Development+in+China-www.cfye-commerce.shopHistory+of+E-commerce+Development+in+China-www.cfye-commerce.shop
History+of+E-commerce+Development+in+China-www.cfye-commerce.shop
 
How to Use Contact Form 7 Like a Pro.pptx
How to Use Contact Form 7 Like a Pro.pptxHow to Use Contact Form 7 Like a Pro.pptx
How to Use Contact Form 7 Like a Pro.pptx
 

Puppeteer can automate that! - Frontmania