307 lines
34 KiB
HTML
307 lines
34 KiB
HTML
<!DOCTYPE html><html lang="en" style="font-size:16px"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="https://www.sitespeed.io/img/ico/sitespeed.io-144.png"><meta name="author" content="Peter Hedenskog"><meta name="description" content="Tutorials and documentation for scripting in Browsertime and sitespeed.io"><meta name="keywords" content="scripting, tutorial, sitespeed.io, browsertime, web performance"><title>Tutorial: Examples</title><!--[if lt IE 9]>
|
||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||
<![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(baseURL=(baseURL="https://www.sitespeed.io/documentation/sitespeed.io/scripting/").replace(/https?:\/\//i,"")).substr(baseURL.indexOf("/"))</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><style>article ul{list-style:disc}</style><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="light"><div class="sidebar-container"><div class="sidebar" id="sidebar"><a href="/" class="sidebar-title sidebar-title-anchor">sitespeed.io scripting</a><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-tutorials"><div>Tutorials</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="tutorial-01-Introduction.html">Introduction</a></div><div class="sidebar-section-children"><a href="tutorial-02-Running-Scripts.html">Running and managing scripts</a></div><div class="sidebar-section-children"><a href="tutorial-03-Measurement-Commands.html">Measure</a></div><div class="sidebar-section-children"><a href="tutorial-04-Interact-with-the-page.html">Interact with the page</a></div><div class="sidebar-section-children"><a href="tutorial-05-Interact-Browser.html">Interact with the browser</a></div><div class="sidebar-section-children"><a href="tutorial-06-Error-handling.html">Error handling</a></div><div class="sidebar-section-children"><a href="tutorial-07-Debugging-Scripts.html">Debugging scripts</a></div><div class="sidebar-section-children"><a href="tutorial-08-Setting-Up-IntelliSense.html">Code completion and IntelliSense</a></div><div class="sidebar-section-children"><a href="tutorial-09-Examples.html">Examples</a></div><div class="sidebar-section-children"><a href="tutorial-10-Selenium.html">Running Selenium code</a></div><div class="sidebar-section-children"><a href="tutorial-11-Chrome-Devtools-Protocol.html">Chrome Devtools Protocol (CDP)</a></div><div class="sidebar-section-children"><a href="tutorial-12-Android.html">Android devices</a></div><div class="sidebar-section-children"><a href="tutorial-13-Tips-and-tricks.html">Tips and tricks</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="Actions.html">Actions</a></div><div class="sidebar-section-children"><a href="AddText.html">AddText</a></div><div class="sidebar-section-children"><a href="AndroidCommand.html">AndroidCommand</a></div><div class="sidebar-section-children"><a href="Cache.html">Cache</a></div><div class="sidebar-section-children"><a href="ChromeDevelopmentToolsProtocol.html">ChromeDevelopmentToolsProtocol</a></div><div class="sidebar-section-children"><a href="ChromeTrace.html">ChromeTrace</a></div><div class="sidebar-section-children"><a href="Click.html">Click</a></div><div class="sidebar-section-children"><a href="ClickAndHold.html">ClickAndHold</a></div><div class="sidebar-section-children"><a href="Commands.html">Commands</a></div><div class="sidebar-section-children"><a href="ContextClick.html">ContextClick</a></div><div class="sidebar-section-children"><a href="Debug.html">Debug</a></div><div class="sidebar-section-children"><a href="DoubleClick.html">DoubleClick</a></div><div class="sidebar-section-children"><a href="Element.html">Element</a></div><div class="sidebar-section-children"><a href="GeckoProfiler.html">GeckoProfiler</a></div><div class="sidebar-section-children"><a href="JavaScript.html">JavaScript</a></div><div class="sidebar-section-children"><a href="Measure.html">Measure</a></div><div class="sidebar-section-children"><a href="Meta.html">Meta</a></div><div class="sidebar-section-children"><a href="MouseMove.html">MouseMove</a></div><div class="sidebar-section-children"><a href="Navigation.html">Navigation</a></div><div class="sidebar-section-children"><a href="Screenshot.html">Screenshot</a></div><div class="sidebar-section-children"><a href="Scroll.html">Scroll</a></div><div class="sidebar-section-children"><a href="Select.html">Select</a></div><div class="sidebar-section-children"><a href="Set.html">Set</a></div><div class="sidebar-section-children"><a href="SingleClick.html">SingleClick</a></div><div class="sidebar-section-children"><a href="StopWatch.html">StopWatch</a></div><div class="sidebar-section-children"><a href="Switch.html">Switch</a></div><div class="sidebar-section-children"><a href="Wait.html">Wait</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"><div class="navbar-item"><a id="" href="." target="">Start</a></div><div class="navbar-item"><a id="" href="https://www.sitespeed.io/documentation/sitespeed.io/" target="">Back to documentation</a></div></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section><header><h2>Examples</h2></header><article><p>Here are some examples on how you can use the scripting capabilities.</p><h3 id="measure-multiple-pages">Measure multiple pages</h3><p>Test multiple pages in a script:</p><pre class="prettyprint source lang-JavaScript"><code>/**
|
||
* @param {import('browsertime').BrowsertimeContext} context
|
||
* @param {import('browsertime').BrowsertimeCommands} commands
|
||
*/
|
||
export default async function (context, commands) {
|
||
await commands.measure.start('https://www.sitespeed.io');
|
||
await commands.measure.start('https://www.sitespeed.io/examples/');
|
||
return commands.measure.start('https://www.sitespeed.io/documentation/');
|
||
};
|
||
</code></pre><h3 id="measure-multiple-pages-and-start-white">Measure multiple pages and start white</h3><p>Sometimes recording a video and measuring multiple pages you will see that the layout is kept in the browser until the first paint of the new page. You can hack that by removing the current body and set the background color to white. Then every video will start white.</p><pre class="prettyprint source lang-JavaScript"><code>/**
|
||
* @param {import('browsertime').BrowsertimeContext} context
|
||
* @param {import('browsertime').BrowsertimeCommands} commands
|
||
*/
|
||
export default async function (context, commands) {
|
||
await commands.measure.start('https://www.sitespeed.io');
|
||
await commands.js.run('document.body.innerHTML = ""; document.body.style.backgroundColor = "white";');
|
||
await commands.measure.start('https://www.sitespeed.io/examples/');
|
||
await commands.js.run('document.body.innerHTML = ""; document.body.style.backgroundColor = "white";');
|
||
return commands.measure.start('https://www.sitespeed.io/documentation/');
|
||
};
|
||
</code></pre><h3 id="measuring-interaction-to-next-paint---inp">Measuring Interaction to next paint - INP</h3><p>One of the new metrics Google is pushing is <a href="https://web.dev/articles/inp">Interaction to next paint</a>. You can use it when you collect RUM and using sitespeed.io. To measure it you need to interact with a web page. The best way to do that is using the Action API.</p><pre class="prettyprint source lang-JavaScript"><code>/**
|
||
* @param {import('browsertime').BrowsertimeContext} context
|
||
* @param {import('browsertime').BrowsertimeCommands} commands
|
||
*/
|
||
export default async function (context, commands) {
|
||
// Start to measure
|
||
await commands.measure.start();
|
||
// Go to a page ...
|
||
await commands.navigate('https://en.m.wikipedia.org/wiki/Barack_Obama');
|
||
|
||
// When the page has finished loading you can find the navigation and click on it
|
||
const element = await commands.element.getByXpath(
|
||
'//*[@id="mw-mf-main-menu-button"]'
|
||
);
|
||
await commands.action.getActions().click(element).perform();
|
||
|
||
// If you want to do multiple actions, remember to clear() the Action API manually
|
||
|
||
// Add some wait for the menu to show up
|
||
await commands.wait.byTime(2000);
|
||
|
||
// Measure everything, that means you will run the JavaScript that collects the interaction to next paint
|
||
return commands.measure.stop();
|
||
}
|
||
</code></pre><p>You will see the metric in the page summary and in the metrics section.</p><h3 id="measure-a-login-step">Measure a login step</h3><pre class="prettyprint source lang-JavaScript"><code>/**
|
||
* @param {import('browsertime').BrowsertimeContext} context
|
||
* @param {import('browsertime').BrowsertimeCommands} commands
|
||
*/
|
||
export default async function (context, commands) {
|
||
// Navigate to a URL, but do not measure the URL
|
||
await commands.navigate(
|
||
'https://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Main+Page'
|
||
);
|
||
|
||
try {
|
||
// Add text into an input field, finding the field by id
|
||
await commands.addText.byId('login', 'wpName1');
|
||
await commands.addText.byId('password', 'wpPassword1');
|
||
|
||
// Start the measurement and give it the alias login
|
||
// The alias will be used when the metrics is sent to
|
||
// Graphite/InfluxDB
|
||
await commands.measure.start('login');
|
||
|
||
// Find the submit button and click it and wait for the
|
||
// page complete check to finish on the next loaded URL
|
||
await commands.click.byIdAndWait('wpLoginAttempt');
|
||
// Stop and collect the metrics
|
||
return commands.measure.stop();
|
||
} catch (e) {
|
||
// We try/catch so we will catch if the the input fields can't be found
|
||
// The error is automatically logged in Browsertime an rethrown here
|
||
// We could have an alternative flow ...
|
||
// else we can just let it cascade since it caught later on and reported in
|
||
// the HTML
|
||
throw e;
|
||
}
|
||
};
|
||
</code></pre><h3 id="measure-the-login-step-and-more">Measure the login step and more</h3><pre class="prettyprint source lang-JavaScript"><code>/**
|
||
* @param {import('browsertime').BrowsertimeContext} context
|
||
* @param {import('browsertime').BrowsertimeCommands} commands
|
||
*/
|
||
export default async function (context, commands) {
|
||
// We start by navigating to the login page.
|
||
await commands.navigate(
|
||
'https://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Main+Page'
|
||
);
|
||
|
||
// When we fill in a input field/click on a link we wanna
|
||
// try/catch that if the HTML on the page changes in the feature
|
||
// sitespeed.io will automatically log the error in a user friendly
|
||
// way, and the error will be re-thrown so you can act on it.
|
||
try {
|
||
// Add text into an input field, finding the field by id
|
||
await commands.addText.byId('login', 'wpName1');
|
||
await commands.addText.byId('password', 'wpPassword1');
|
||
|
||
// Start the measurement before we click on the
|
||
// submit button. Sitespeed.io will start the video recording
|
||
// and prepare everything.
|
||
await commands.measure.start('login');
|
||
// Find the sumbit button and click it and then wait
|
||
// for the pageCompleteCheck to finish
|
||
await commands.click.byIdAndWait('wpLoginAttempt');
|
||
// Stop and collect the measurement before the next page we want to measure
|
||
await commands.measure.stop();
|
||
// Measure the Barack Obama page as a logged in user
|
||
await commands.measure.start(
|
||
'https://en.wikipedia.org/wiki/Barack_Obama'
|
||
);
|
||
// And then measure the president page
|
||
return commands.measure.start('https://en.wikipedia.org/wiki/President_of_the_United_States');
|
||
} catch (e) {
|
||
// We try/catch so we will catch if the the input fields can't be found
|
||
// The error is automatically logged in Browsertime and re-thrown here
|
||
// We could have an alternative flow ...
|
||
// else we can just let it cascade since it caught later on and reported in
|
||
// the HTML
|
||
throw e;
|
||
}
|
||
};
|
||
</code></pre><h3 id="measure-one-page-after-you-logged-in">Measure one page after you logged in</h3><p>Testing a page after you have logged in: First create a script that logs in the user (login.mjs):</p><pre class="prettyprint source lang-JavaScript"><code>/**
|
||
* @param {import('browsertime').BrowsertimeContext} context
|
||
* @param {import('browsertime').BrowsertimeCommands} commands
|
||
*/
|
||
export default async function (context, commands) {
|
||
await commands.navigate(
|
||
'https://en.wikipedia.org/w/index.php?title=Special:UserLogin&returnto=Main+Page'
|
||
);
|
||
|
||
try {
|
||
await commands.addText.byId('login', 'wpName1');
|
||
await commands.addText.byId('password', 'wpPassword1');
|
||
// Click on the submit button with id wpLoginAttempt
|
||
await commands.click.byIdAndWait('wpLoginAttempt');
|
||
// wait on a specific id to appear on the page after you logged in
|
||
return commands.wait.byId('pt-userpage', 10000);
|
||
} catch (e) {
|
||
// We try/catch so we will catch if the the input fields can't be found
|
||
// The error is automatically logged in Browsertime and re-thrown here
|
||
// We could have an alternative flow ...
|
||
// else we can just let it cascade since it caught later on and reported in
|
||
// the HTML
|
||
throw e;
|
||
}
|
||
};
|
||
</code></pre><p>Then access the page that you want to test:</p><pre class="prettyprint source lang-bash"><code>sitespeed.io --preScript login.mjs https://en.wikipedia.org/wiki/Barack_Obama
|
||
</code></pre><h4 id="a-more-complicated-login-example">A more complicated login example</h4><pre class="prettyprint source lang-JavaScript"><code>/**
|
||
* @param {import('browsertime').BrowsertimeContext} context
|
||
* @param {import('browsertime').BrowsertimeCommands} commands
|
||
*/
|
||
export default async function (context, commands) {
|
||
await commands.navigate(
|
||
'https://example.org'
|
||
);
|
||
try {
|
||
// Find the sign in button and click it
|
||
await commands.click.byId('sign_in_button');
|
||
// Wait some time for the page to open a new login frame
|
||
await commands.wait.byTime(2000);
|
||
// Switch to the login frame
|
||
await commands.switch.toFrame('loginFrame');
|
||
// Find the username fields by xpath (just as an example)
|
||
await commands.addText.byXpath(
|
||
'peter@example.org',
|
||
'//*[@id="userName"]'
|
||
);
|
||
// Click on the next button
|
||
await commands.click.byId('verifyUserButton');
|
||
// Wait for the GUI to display the password field so we can select it
|
||
await commands.wait.byTime(2000);
|
||
// Wait for the actual password field
|
||
await commands.wait.byId('password', 5000);
|
||
// Fill in the password
|
||
await commands.addText.byId('dejh8Ghgs6ga(1217)', 'password');
|
||
// Click the submit button
|
||
await commands.click.byId('btnSubmit');
|
||
// In your implementation it is probably better to wait for an id
|
||
await commands.wait.byTime(5000);
|
||
// Measure the next page as a logged in user
|
||
return commands.measure.start(
|
||
'https://example.org/logged/in/page'
|
||
);
|
||
} catch(e) {
|
||
// We try/catch so we will catch if the the input fields can't be found
|
||
// We could have an alternative flow ...
|
||
// else we can just let it cascade since it caught later on and reported in
|
||
// the HTML
|
||
throw e;
|
||
}
|
||
};
|
||
</code></pre><h3 id="scroll-the-page">Scroll the page</h3><p>You can scroll the page to trigger metrics. To get the Cumulative Layout Shift metric for Chrome closer to what real users get you can scroll the page and measure that. Depending on how your page work, you may want to tune the delay between the scrolling.</p><pre class="prettyprint source lang-JavaScript"><code>/**
|
||
* @param {import('browsertime').BrowsertimeContext} context
|
||
* @param {import('browsertime').BrowsertimeCommands} commands
|
||
*/
|
||
export default async function (context, commands) {
|
||
const delayTime = 250;
|
||
|
||
await commands.measure.start();
|
||
await commands.navigate(
|
||
'https://www.sitespeed.io/documentation/sitespeed.io/performance-dashboard/'
|
||
);
|
||
await commands.scroll.toBottom(delayTime);
|
||
return commands.measure.stop();
|
||
};
|
||
</code></pre><h3 id="add-your-own-metrics">Add your own metrics</h3><p>You can add your own metrics by adding the extra JavaScript that is executed after the page has loaded BUT did you know that also can add your own metrics directly through scripting? The metrics will be added to the metric tab in the HTML output and automatically sent to Graphite/InfluxDB.</p><p>In this example we collect the temperature from our Android phone that runs the tests:</p><pre class="prettyprint source lang-JavaScript"><code>/**
|
||
* @param {import('browsertime').BrowsertimeContext} context
|
||
* @param {import('browsertime').BrowsertimeCommands} commands
|
||
*/
|
||
export default async function (context, commands) {
|
||
// Get the temperature from the phone
|
||
const temperature = await commands.android.shell("dumpsys battery | grep temperature | grep -Eo '[0-9]{1,3}'");
|
||
// Start the test
|
||
await commands.measure.start(
|
||
'https://www.sitespeed.io'
|
||
);
|
||
// This is the magic where we add that new metric. It needs to happen
|
||
// after measure.start so we know where that metric belong
|
||
commands.measure.add('batteryTemperature', temperature/10);
|
||
};
|
||
</code></pre><p>In this example we collect the number of comments on a blog post using commands.js.run() to collect an element, use regex to parse out the number, and add it back as a custom metric.</p><pre class="prettyprint source lang-JavaScript"><code>/**
|
||
* @param {import('browsertime').BrowsertimeContext} context
|
||
* @param {import('browsertime').BrowsertimeCommands} commands
|
||
*/
|
||
export default async function (context, commands) {
|
||
await commands.measure.start('blog-post'); //alias is now blog-post
|
||
await commands.navigate('https://www.exampleBlog/blog-post');
|
||
|
||
//use commands.js.run to return the element using pure javascript
|
||
const element = await commands.js.run('return(document.getElementsByClassName("comment-count")[0].innerText)');
|
||
|
||
//parse out just the number of comments
|
||
var elementMetric = element.match(/\d/)[0];
|
||
|
||
// need to stop the measurement before you can add it as a metric
|
||
await commands.measure.stop();
|
||
|
||
// metric will now be added to the html and outpout to graphite/influx if you're using it
|
||
await commands.measure.add('commentsCount', elementMetric);
|
||
};
|
||
</code></pre><h3 id="measure-a-checkout-process">Measure a checkout process</h3><p>One of the really cool things with scripting is that you can measure all the pages in a checkout process. This is an example shop where you put one item in your cart and checkout as a guest.</p><pre class="prettyprint source lang-JavaScript"><code>/**
|
||
* @param {import('browsertime').BrowsertimeContext} context
|
||
* @param {import('browsertime').BrowsertimeCommands} commands
|
||
*/
|
||
export default async function (context, commands) {
|
||
// Start by measuring the first page of the shop
|
||
await commands.measure.start('https://shop.example.org');
|
||
|
||
// Then the product page
|
||
// Either your shop has a generic item used for testing that you can use
|
||
// or in real life you maybe need to add a check that the item really exists in stock
|
||
// and if not, try another product
|
||
await commands.measure.start('https://shop.example.org/prodcucs/theproduct');
|
||
|
||
// Add the item to your cart
|
||
await commands.click.bySelector('.add-to-cart');
|
||
|
||
// Go to the cart (and measure it)
|
||
await commands.measure.start('https://shop.example.org/cart/');
|
||
|
||
// Checkout as guest but you could also login as a customer
|
||
// We hide the HTML to avoid that the click on the link will
|
||
// fire First Visual Change. Best case you don't need to but we
|
||
// want an complex example
|
||
await commands.js.run('for (let node of document.body.childNodes) { if (node.style) node.style.display = "none";}');
|
||
await commands.measure.start('CheckoutAsGuest');
|
||
await commands.click.bySelectorAndWait('.checkout-as-guest');
|
||
// Make sure to stop measuring and collect the metrics for the CheckoutAsGuest step
|
||
await commands.measure.stop();
|
||
|
||
// Finish your checkout
|
||
await commands.js.run('document.body.style.display = "none"');
|
||
await commands.measure.start('FinishCheckout');
|
||
await commands.click.bySelectorAndWait('.checkout-finish');
|
||
// And collect metrics for the FinishCheckout step
|
||
return commands.measure.stop();
|
||
// In a real web shop you probably can't finish the last step or you can return the item
|
||
// so the stock is correct. Either you do that at the end of your script or you
|
||
// add the item id in the context object like context.itemId = yyyy. Then in your
|
||
// postScript you can do what's needed with that id.
|
||
};
|
||
</code></pre><h3 id="test-multiple-urls">Test multiple URLs</h3><p>If you want to test multiple URLs and need to do some specific things before each URL, you can do something like this (we pass on our <a href="#pass-your-own-options-to-your-script">own options</a> to the script):</p><pre class="prettyprint source lang-JavaScript"><code>/**
|
||
* @param {import('browsertime').BrowsertimeContext} context
|
||
* @param {import('browsertime').BrowsertimeCommands} commands
|
||
*/
|
||
module.exports = async function (context, commands) {
|
||
const urls = context.options.urls;
|
||
for (let url of urls) {
|
||
// Do the stuff for each url that you need to do
|
||
// Maybe login a user or add a cookie or something
|
||
// Then test the URL
|
||
await commands.measure.start(url);
|
||
// When the test is finished, clear the browser cache
|
||
await commands.cache.clear();
|
||
// Navigate to a blank page so you kind of start from scratch for the next URL
|
||
await commands.navigate('about:blank');
|
||
}
|
||
};
|
||
</code></pre><p>Then run your tests like this:</p><pre class="prettyprint source lang-bash"><code>sitespeed.io testMultipleUrls.js --multi --browsertime.urls https://www.sitespeed.io --browsertime.urls https://www.sitespeed.io/documentation -n 1
|
||
</code></pre><p>Or if you use JSON configuration, the same configuration looks like this:</p><pre class="prettyprint source lang-json"><code>{
|
||
"browsertime": {
|
||
"urls": ["url1", "url2", "url3"]
|
||
}
|
||
}
|
||
</code></pre></article></section><footer class="footer" id="PeOAagUepe"><div class="wrapper">© <a href="https://www.sitespeed.io">sitespeed.io</a> 2024</div></footer></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><a href="/" class="sidebar-title sidebar-title-anchor">sitespeed.io scripting</a><div class="mobile-nav-links"><div class="navbar-item"><a id="" href="." target="">Start</a></div><div class="navbar-item"><a id="" href="https://www.sitespeed.io/documentation/sitespeed.io/" target="">Back to documentation</a></div></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-tutorials"><div>Tutorials</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="tutorial-01-Introduction.html">Introduction</a></div><div class="sidebar-section-children"><a href="tutorial-02-Running-Scripts.html">Running and managing scripts</a></div><div class="sidebar-section-children"><a href="tutorial-03-Measurement-Commands.html">Measure</a></div><div class="sidebar-section-children"><a href="tutorial-04-Interact-with-the-page.html">Interact with the page</a></div><div class="sidebar-section-children"><a href="tutorial-05-Interact-Browser.html">Interact with the browser</a></div><div class="sidebar-section-children"><a href="tutorial-06-Error-handling.html">Error handling</a></div><div class="sidebar-section-children"><a href="tutorial-07-Debugging-Scripts.html">Debugging scripts</a></div><div class="sidebar-section-children"><a href="tutorial-08-Setting-Up-IntelliSense.html">Code completion and IntelliSense</a></div><div class="sidebar-section-children"><a href="tutorial-09-Examples.html">Examples</a></div><div class="sidebar-section-children"><a href="tutorial-10-Selenium.html">Running Selenium code</a></div><div class="sidebar-section-children"><a href="tutorial-11-Chrome-Devtools-Protocol.html">Chrome Devtools Protocol (CDP)</a></div><div class="sidebar-section-children"><a href="tutorial-12-Android.html">Android devices</a></div><div class="sidebar-section-children"><a href="tutorial-13-Tips-and-tricks.html">Tips and tricks</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="Actions.html">Actions</a></div><div class="sidebar-section-children"><a href="AddText.html">AddText</a></div><div class="sidebar-section-children"><a href="AndroidCommand.html">AndroidCommand</a></div><div class="sidebar-section-children"><a href="Cache.html">Cache</a></div><div class="sidebar-section-children"><a href="ChromeDevelopmentToolsProtocol.html">ChromeDevelopmentToolsProtocol</a></div><div class="sidebar-section-children"><a href="ChromeTrace.html">ChromeTrace</a></div><div class="sidebar-section-children"><a href="Click.html">Click</a></div><div class="sidebar-section-children"><a href="ClickAndHold.html">ClickAndHold</a></div><div class="sidebar-section-children"><a href="Commands.html">Commands</a></div><div class="sidebar-section-children"><a href="ContextClick.html">ContextClick</a></div><div class="sidebar-section-children"><a href="Debug.html">Debug</a></div><div class="sidebar-section-children"><a href="DoubleClick.html">DoubleClick</a></div><div class="sidebar-section-children"><a href="Element.html">Element</a></div><div class="sidebar-section-children"><a href="GeckoProfiler.html">GeckoProfiler</a></div><div class="sidebar-section-children"><a href="JavaScript.html">JavaScript</a></div><div class="sidebar-section-children"><a href="Measure.html">Measure</a></div><div class="sidebar-section-children"><a href="Meta.html">Meta</a></div><div class="sidebar-section-children"><a href="MouseMove.html">MouseMove</a></div><div class="sidebar-section-children"><a href="Navigation.html">Navigation</a></div><div class="sidebar-section-children"><a href="Screenshot.html">Screenshot</a></div><div class="sidebar-section-children"><a href="Scroll.html">Scroll</a></div><div class="sidebar-section-children"><a href="Select.html">Select</a></div><div class="sidebar-section-children"><a href="Set.html">Set</a></div><div class="sidebar-section-children"><a href="SingleClick.html">SingleClick</a></div><div class="sidebar-section-children"><a href="StopWatch.html">StopWatch</a></div><div class="sidebar-section-children"><a href="Switch.html">Switch</a></div><div class="sidebar-section-children"><a href="Wait.html">Wait</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div></div></div><script type="text/javascript" src="scripts/core.min.js"></script><script src="scripts/search.min.js" defer="defer"></script><script src="scripts/third-party/fuse.js" defer="defer"></script><script type="text/javascript">var tocbotInstance=tocbot.init({tocSelector:"#eed4d2a0bfd64539bb9df78095dec881",contentSelector:".main-content",headingSelector:"h1, h2, h3",hasInnerContainers:!0,scrollContainer:".main-content",headingsOffset:130,onClick:bringLinkToView})</script></body></html> |