// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. /* eslint-env node */ /* Ensure the `--firefox.preference=network.http.http3.enable:true` is set for this test. */ async function captureNetworkRequest(commands) { var capture_network_request = []; var capture_resource = await commands.js.run(` return performance.getEntriesByType("resource"); `); for (var i = 0; i < capture_resource.length; i++) { capture_network_request.push(capture_resource[i].name); } return capture_network_request; } async function waitForScrollRequestsEnd( prevCount, maxStableCount, timeout, commands, context ) { let starttime = await commands.js.run(`return performance.now();`); let endtime = await commands.js.run(`return performance.now();`); let changing = true; let newCount = -1; let stableCount = 0; while ( ((await commands.js.run(`return performance.now();`)) - starttime < timeout) & changing ) { // Wait a bit before making another round await commands.wait.byTime(100); newCount = (await captureNetworkRequest(commands)).length; context.log.debug(`${newCount}, ${prevCount}, ${stableCount}`); // Check if we are approaching stability if (newCount == prevCount) { // Gather the end time now if (stableCount == 0) { endtime = await commands.js.run(`return performance.now();`); } stableCount++; } else { prevCount = newCount; stableCount = 0; } if (stableCount >= maxStableCount) { // Stability achieved changing = false; } } return { start: starttime, end: endtime, numResources: newCount, }; } async function test(context, commands) { let rootUrl = "https://www.facebook.com/lambofgod/"; let waitTime = 1000; let numScrolls = 5; const average = arr => arr.reduce((p, c) => p + c, 0) / arr.length; if (typeof context.options.browsertime !== "undefined") { if (typeof context.options.browsertime.waitTime !== "undefined") { waitTime = context.options.browsertime.waitTime; } if (typeof context.options.browsertime.numScrolls !== "undefined") { numScrolls = context.options.browsertime.numScrolls; } } // Make firefox learn of HTTP/3 server await commands.navigate(rootUrl); let cycles = 1; for (let cycle = 0; cycle < cycles; cycle++) { // Measure the pageload await commands.measure.start("pageload"); await commands.navigate(rootUrl); await commands.measure.stop(); // Initial scroll to make the new user popup show await commands.js.runAndWait( `window.scrollTo({ top: 1000, behavior: 'smooth' })` ); await commands.wait.byTime(1000); await commands.click.byLinkTextAndWait("Not Now"); let vals = []; let badIterations = 0; for (let iteration = 0; iteration < numScrolls; iteration++) { // Clear old resources await commands.js.run(`performance.clearResourceTimings();`); // Get current resource count let currCount = (await captureNetworkRequest(commands)).length; // Scroll to a ridiculously high value for "infinite" down-scrolling commands.js.runAndWait(` window.scrollTo({ top: 100000000 }) `); /* The maxStableCount of 22 was chosen as a trade-off between fast iterations and minimizing the number of bad iterations. */ let newInfo = await waitForScrollRequestsEnd( currCount, 22, 120000, commands, context ); // Gather metrics let ndiff = newInfo.numResources - currCount; let tdiff = (newInfo.end - newInfo.start) / 1000; // Check if we had a bad iteration if (ndiff == 0) { context.log.info("Bad iteration, redoing..."); iteration--; badIterations++; if (badIterations == 5) { throw new Error("Too many bad scroll iterations occurred"); } continue; } vals.push(ndiff / tdiff); // Wait X seconds before scrolling again await commands.wait.byTime(waitTime); } if (!vals.length) { throw new Error("No requestsPerSecond values were obtained"); } commands.measure.result[0].browserScripts.pageinfo.requestsPerSecond = average(vals); } } module.exports = { test, owner: "Network Team", component: "netwerk", name: "facebook-scroll", description: "Measures the number of requests per second after a scroll.", };