Code used to evaluate Recommendation banner appearance speed

  • popup.js
javascript
const fs = require('fs'); const {chromium} = require('playwright'); const waitForNetworkSettled = require('./networkSettled'); const maths = require('./maths'); async function run(browser, config) { const context = await browser.newContext({ screen: {width: 1920, height: 1080}, }); const page = await context.newPage(); const client = await page.context().newCDPSession(page) await client.send('Network.enable') await client.send('Network.emulateNetworkConditions', { offline: false, downloadThroughput: (4 * 1024 * 1024) / 8, uploadThroughput: (4 * 1024 * 1024) / 8, latency: 20 }) if (config.runType === "native") { await page.route(/.*?adequa\.js/, route => route.abort()); await page.route(/.*?potions\.js/, route => route.abort()); } await page.goto(config.pageUrl, {waituntil: 'domcontentloaded'}); if(config.cookieBannerAcceptSelector) { await waitForNetworkSettled(page, async () => { await page.click(config.cookieBannerAcceptSelector); }); } const start = Date.now(); if(config.runType === "potions") { await page.waitForFunction(() => { try { return !!adequa.widgets.products.listeners[0]; } catch (e) { return false } }); } await page.click(config.addToCartButtonSelector); await page.waitForSelector( config.runType === "potions" ? config.potionsBannerSelector : config.nativeBannerSelector); const time = Date.now() - start; await context.close(); return time; } (async (config) => { const browser = await chromium.launch({headless:false}); const runTiming = []; for (const i of Array(config.numberOfRuns).keys()) { console.log(`${i + 1}/${config.numberOfRuns}`) runTiming.push(await run(browser, config)); } await browser.close(); fs.writeFileSync( `results/${config.pageUrl .replace("https:", "") .replaceAll("/", "") .replaceAll(".", "")}_domloaded_${config.runType}`, JSON.stringify({ min: Math.min(...runTiming), max: Math.max(...runTiming), mean: maths.mean(runTiming), median: maths.median(runTiming), p75: maths.quantile(runTiming, .75), p95: maths.quantile(runTiming, .95), p99: maths.quantile(runTiming, .99), raw: runTiming })); })({ pageUrl: "https://www.alltricks.fr/", cookieBannerAcceptSelector: "#didomi-notice-agree-button", addToCartButtonSelector: "form > div > button", potionsBannerSelector: "#adq_products", nativeBannerSelector: ".allbox-cart-back:not(.mfp-hide) .recommendedProductModule .alltricks-Product--3columns", runType: "potions", // native | potions numberOfRuns: 10 });
  • networkSettled.js
javascript
module.exports = async function waitForNetworkSettled(page, action, longPolls = 0) { let networkSettledCallback; const networkSettledPromise = new Promise(f => networkSettledCallback = f); let requestCounter = 0; let actionDone = false; const maybeSettle = () => { if (actionDone && requestCounter <= longPolls) networkSettledCallback(); }; const onRequest = () => { ++requestCounter; }; const onRequestDone = () => { const evaluate = page.evaluate(() => new Promise(f => setTimeout(f, 0))); evaluate.catch(e => null).then(() => { --requestCounter; maybeSettle(); }); }; page.on('request', onRequest); page.on('requestfinished', onRequestDone); page.on('requestfailed', onRequestDone); const result = await action(); actionDone = true; maybeSettle(); await networkSettledPromise; page.removeListener('request', onRequest); page.removeListener('requestfinished', onRequestDone); page.removeListener('requestfailed', onRequestDone); return result; };
  • maths.js
javascript
const asc = arr => arr.sort((a, b) => a - b); const sum = arr => arr.reduce((a, b) => a + b, 0); const mean = arr => sum(arr) / arr.length; const quantile = (arr, q) => { const sorted = asc(arr); const pos = (sorted.length - 1) * q; const base = Math.floor(pos); const rest = pos - base; if (sorted[base + 1] !== undefined) { return sorted[base] + rest * (sorted[base + 1] - sorted[base]); } else { return sorted[base]; } }; const median = arr => quantile(arr, .50); module.exports = { asc, sum, mean, quantile, median }
Share