Skip to content

Instantly share code, notes, and snippets.

@martinschierle
Last active August 6, 2018 09:43
Show Gist options
  • Save martinschierle/a7fb5bf6c8af14f568c111d621b685f2 to your computer and use it in GitHub Desktop.
Save martinschierle/a7fb5bf6c8af14f568c111d621b685f2 to your computer and use it in GitHub Desktop.
const puppeteer = require('puppeteer');
const lighthouse = require('lighthouse');
const devices = require('puppeteer/DeviceDescriptors');
const pixelmatch = require('pixelmatch');
const {URL} = require('url');
var fs = require('fs');
var first = true;
const phone = devices['Nexus 5X'];
async function testPage(url, prefetchList) {
var count = 0;
const browser = await puppeteer.launch();
const page = await browser.newPage();
// make sure we get the logs from the page, comment in&out as needed
//page.on('console', msg => console.log(msg.text()));
page.on('error', err=> {console.log('error happen at the page: ', err);});
page.on('pageerror', pageerr=> {console.log('pageerror occurred: ', pageerr);});
// enable network and cpu throttling
const client = await page.target().createCDPSession();
await client.send('Network.enable');
await client.send('Network.emulateNetworkConditions', {
offline: false,
latency: 120, // ms
downloadThroughput: 4096,
uploadThroughput: 1024,
});
await client.send('Emulation.setCPUThrottlingRate', { rate: 4 });
await page.emulate(phone);
// event handler for network responses. Here we can alter response, what we'll use this as trigger to inject resource hints for now
page.on('response', response => {
count++;
// log out the first 15 loaded resources to see if the resource hints did something
if(count<15) console.log(response.url().substring(0,55));
// we can't inject the links initially, so we do it on second request
if(count === 2) {
if(prefetchList)for(var i = 0; i < prefetchList.length; i++) {
var urlToPreload = prefetchList[i];
page.evaluate((url) => {
var e = document.createElement("LINK");
e.rel = "prefetch";
e.href = url;
document.head.appendChild(e);
//console.log("Injected: " + url);
return true;
}, urlToPreload).catch(e => {});
}
}
});
//}
//load target url
await page.goto(url);
// we'll need to wait a sec, otherwise FMP isn't calculated yet
await page.waitFor(2000);
// collect performance metrics - you can also comment out and use lighthouse below instead
var fmp = (await page._client.send('Performance.getMetrics')).metrics.find(x => x.name === "FirstMeaningfulPaint").value/1000;
const firstPaint = await page.evaluate("window.performance.getEntriesByName('first-paint')[0].startTime;");
const domInteractive = await page.evaluate("window.performance.timing.domInteractive - window.performance.timing.navigationStart");
const loadEventStart = await page.evaluate("window.performance.timing.loadEventStart - window.performance.timing.navigationStart");
console.log(firstPaint + " - " + fmp + " - " + domInteractive + " - " + loadEventStart);
// run lighthouse if needed
// Lighthouse will open URL. Puppeteer observes `targetchanged` and sets up network conditions.
// Possible race condition.
const {lhr} = await lighthouse(url, {
port: (new URL(browser.wsEndpoint())).port,
output: 'json',
logLevel: 'error', // do info for additional details
});
console.log(`Lighthouse scores: ${Object.values(lhr.categories).map(c => c.score).join(', ')}`);
// get a screenshot of result page. Int he long run we wanna have the whole visual loading progress, but that's more tricky to implement without slowing down page load
var filename = "screenshot.png";
if(prefetchList) filename = "screenshot_prefetching.png";
await page.screenshot({path: filename});
await browser.close();
}
// ------------ start test case settings -----------
var filesToPreload = [
"ionlyexistfortestingprefetch.js",
];
var testURL = "INPUT_TEST_URL_HERE";
// ------------- end test case -------------------
// run test
testPage(testURL).then(function() {
testPage(testURL, filesToPreload).then(function() {
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment