<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>end-to-end - Deployment Every Day</title>
	<atom:link href="http://deploymenteveryday.com/tag/end-to-end/feed/" rel="self" type="application/rss+xml" />
	<link>http://deploymenteveryday.com</link>
	<description>JVM (java/kotlin) performance, programming, frequent deployments, devops</description>
	<lastBuildDate>Wed, 08 May 2024 09:54:25 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>
	<item>
		<title>How to make performance benchmark 530% worse by relying on web app automation defaults?</title>
		<link>http://deploymenteveryday.com/how-to-make-performance-benchmark-530-worse-by-relying-on-web-app-automation-defaults/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=how-to-make-performance-benchmark-530-worse-by-relying-on-web-app-automation-defaults</link>
					<comments>http://deploymenteveryday.com/how-to-make-performance-benchmark-530-worse-by-relying-on-web-app-automation-defaults/#comments</comments>
		
		<dc:creator><![CDATA[Mikolaj Grzaslewicz]]></dc:creator>
		<pubDate>Sun, 05 May 2024 12:26:21 +0000</pubDate>
				<category><![CDATA[performance]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[DOMContentLoaded]]></category>
		<category><![CDATA[end-to-end]]></category>
		<category><![CDATA[playwright]]></category>
		<category><![CDATA[selenium]]></category>
		<guid isPermaLink="false">https://deploymenteveryday.com/?p=112</guid>

					<description><![CDATA[<p>Let&#8217;s start with a necessary definitions: what are DOMContentLoaded and load events in the web browser? DOMContentLoaded According to docs when browser fires this event it means load event When browser fires load event it means DOM content is fully loaded. Browser has finished Both events are NOT about REST calls. And both are not [&#8230;]</p>
<p>The post <a href="http://deploymenteveryday.com/how-to-make-performance-benchmark-530-worse-by-relying-on-web-app-automation-defaults/">How to make performance benchmark 530% worse by relying on web app automation defaults?</a> first appeared on <a href="http://deploymenteveryday.com">Deployment Every Day</a>.</p>]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Let&#8217;s start with a necessary definitions: what are <code>DOMContentLoaded</code> and <code>load</code> events in the web browser?</h2>



<h3 class="wp-block-heading"><code>DOMContentLoaded</code></h3>



<p class="wp-block-paragraph">According to <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event">docs</a> when browser fires this event it means</p>



<ul class="wp-block-list">
<li>DOM has been completely parsed</li>



<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#defer"><code>&lt;script defer src="…"&gt;</code></a>&nbsp;and&nbsp;<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#module"><code>&lt;script type="module"&gt;</code></a> has been loaded</li>



<li>async script, images, frames might not be loaded yet</li>
</ul>



<h3 class="wp-block-heading"><code>load event</code></h3>



<p class="wp-block-paragraph">When browser fires <code>load event</code> it means DOM content is fully loaded. Browser has finished</p>



<ul class="wp-block-list">
<li>executing all asynchronous resources from the DOM tree</li>



<li>loading images, frames etc.</li>



<li>it comes always after <code>DOMContentLoaded</code></li>
</ul>



<p class="wp-block-paragraph">Both events are NOT about REST calls. And both are not relevant to the user browsing the website.</p>



<h2 class="wp-block-heading">What do web apps automation tools like playwright and selenium do by default?</h2>



<p class="wp-block-paragraph">Take a look at following lines of code measuring navigating to a page and waiting for a button to be visible.</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="1359" height="607" src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-github-button.png" alt="" class="wp-image-116" srcset="http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-github-button.png 1359w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-github-button-300x134.png 300w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-github-button-1024x457.png 1024w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-github-button-768x343.png 768w" sizes="(max-width: 1359px) 100vw, 1359px" /></figure>



<p class="wp-block-paragraph">using playwright</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers cbp-blur-enabled cbp-unblur-on-hover" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:14px;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * 14px);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="val millisBefore = System.currentTimeMillis()
page.navigate(&quot;https://github.com&quot;)
page.getByText(&quot;Try Now&quot;).waitFor()
val latency = System.currentTimeMillis() - millisBefore" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">val</span><span style="color: #D8DEE9FF"> millisBefore </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> System.</span><span style="color: #88C0D0">currentTimeMillis</span><span style="color: #D8DEE9FF">()</span></span>
<span class="line cbp-no-blur"><span style="color: #D8DEE9FF">page.</span><span style="color: #88C0D0">navigate</span><span style="color: #D8DEE9FF">(</span><span style="color: #A3BE8C">&quot;https://github.com&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line cbp-no-blur"><span style="color: #D8DEE9FF">page.</span><span style="color: #88C0D0">getByText</span><span style="color: #D8DEE9FF">(</span><span style="color: #A3BE8C">&quot;Try Now&quot;</span><span style="color: #D8DEE9FF">).</span><span style="color: #88C0D0">waitFor</span><span style="color: #D8DEE9FF">()</span></span>
<span class="line"><span style="color: #81A1C1">val</span><span style="color: #D8DEE9FF"> latency </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> System.</span><span style="color: #88C0D0">currentTimeMillis</span><span style="color: #D8DEE9FF">() </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> millisBefore</span></span></code></pre></div>



<p class="wp-block-paragraph">or doing the same with selenium</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers cbp-blur-enabled cbp-unblur-on-hover" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:14px;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * 14px);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="val millisBefore = System.currentTimeMillis()
driver.navigate().to(&quot;https://github.com&quot;)
WebDriverWait(driver, 30, 100).until(ExpectedConditions.visibilityOfElementLocated(By.linkText(&quot;Sign up for GitHub&quot;)))
val latency = System.currentTimeMillis() - millisBefore" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">val</span><span style="color: #D8DEE9FF"> millisBefore </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> System.</span><span style="color: #88C0D0">currentTimeMillis</span><span style="color: #D8DEE9FF">()</span></span>
<span class="line cbp-no-blur"><span style="color: #D8DEE9FF">driver.</span><span style="color: #88C0D0">navigate</span><span style="color: #D8DEE9FF">().</span><span style="color: #88C0D0">to</span><span style="color: #D8DEE9FF">(</span><span style="color: #A3BE8C">&quot;https://github.com&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line cbp-no-blur"><span style="color: #88C0D0">WebDriverWait</span><span style="color: #D8DEE9FF">(driver, </span><span style="color: #B48EAD">30</span><span style="color: #D8DEE9FF">, </span><span style="color: #B48EAD">100</span><span style="color: #D8DEE9FF">).</span><span style="color: #88C0D0">until</span><span style="color: #D8DEE9FF">(ExpectedConditions.</span><span style="color: #88C0D0">visibilityOfElementLocated</span><span style="color: #D8DEE9FF">(By.</span><span style="color: #88C0D0">linkText</span><span style="color: #D8DEE9FF">(</span><span style="color: #A3BE8C">&quot;Sign up for GitHub&quot;</span><span style="color: #D8DEE9FF">)))</span></span>
<span class="line"><span style="color: #81A1C1">val</span><span style="color: #D8DEE9FF"> latency </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> System.</span><span style="color: #88C0D0">currentTimeMillis</span><span style="color: #D8DEE9FF">() </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> millisBefore</span></span></code></pre></div>



<p class="wp-block-paragraph">When you navigate to a page, by default those automation tools wait for <code>load</code> event. So the line with locator is not executed until then.</p>



<p class="wp-block-paragraph">You might think <em>Pff, so what. It&#8217;s just a technical detail</em></p>



<p class="wp-block-paragraph">It is indeed a technical detail but it impacts performance benchmark <mark>dramatically</mark>.</p>



<h2 class="wp-block-heading">Waiting for <code>DOMContentLoaded</code> VS <code>load</code> VS <code>NOT waiting for any event</code>. Fight!</h2>



<p class="wp-block-paragraph">Let&#8217;s measure how quickly user can see github call to action button.</p>



<h3 class="wp-block-heading">Baseline benchmark &#8211; wait for <code>load</code> event</h3>



<p class="wp-block-paragraph">Take 1000 samples. Wait for <code>load</code> event, then wait for github call to action button</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:14px;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * 14px);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="// only most important code shown here. Processing measurements is out of the scope
page.navigate(&quot;https://github.com&quot;)
page.getByText(&quot;Sign up for GitHub&quot;).first().waitFor(WaitForOptions().setTimeout(2000.0))" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// only most important code shown here. Processing measurements is out of the scope</span></span>
<span class="line"><span style="color: #D8DEE9FF">page.</span><span style="color: #88C0D0">navigate</span><span style="color: #D8DEE9FF">(</span><span style="color: #A3BE8C">&quot;https://github.com&quot;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">page.</span><span style="color: #88C0D0">getByText</span><span style="color: #D8DEE9FF">(</span><span style="color: #A3BE8C">&quot;Sign up for GitHub&quot;</span><span style="color: #D8DEE9FF">).</span><span style="color: #88C0D0">first</span><span style="color: #D8DEE9FF">().</span><span style="color: #88C0D0">waitFor</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">WaitForOptions</span><span style="color: #D8DEE9FF">().</span><span style="color: #88C0D0">setTimeout</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">2000.0</span><span style="color: #D8DEE9FF">))</span></span></code></pre></div>



<p class="wp-block-paragraph">It looks like this</p>



<figure class="wp-block-image size-full is-style-zoooom"><img decoding="async" width="1303" height="885" src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-load-event-p95.png" alt="" class="wp-image-117" srcset="http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-load-event-p95.png 1303w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-load-event-p95-300x204.png 300w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-load-event-p95-1024x696.png 1024w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-load-event-p95-768x522.png 768w" sizes="(max-width: 1303px) 100vw, 1303px" /><figcaption class="wp-element-caption">wait for <code>load</code> event` at percentile 95, button measured as visible after 914 ms</figcaption></figure>



<h4 class="wp-block-heading">How to interpret the video of web app measurement?</h4>



<p class="wp-block-paragraph">Playwright video recording is imperfect. Video frame is often not aligned with what was seen in web browser. I confirmed that with modifying the measured page after measurement end.</p>



<p class="wp-block-paragraph">During recording web app, right after measurement end timer is added to the page. This way it doesn&#8217;t interfere with measurement and helps to see when measurement has actually finished on the video.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:14px;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(2 * 0.6 * 14px);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const measuerementEndMillis = ..; // depends on the measuerement
const timerDiv = document.createElement('div');
timerDiv.style.position = 'fixed';
timerDiv.style.top = '0';
timerDiv.style.left = '0';
timerDiv.style.opacity = '0.8';
timerDiv.style.fontSize = '14px';
timerDiv.style.backgroundColor = 'yellow';
timerDiv.style.zIndex = '10000';
document.body.appendChild(timerDiv);

setInterval(function() {
  const now = performance.now();
  timerDiv.textContent = now.toFixed(0) + ' ms, ' + (now - measurementEndMillis).toFixed(0) + ' ms';
}, 20);" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">measuerementEndMillis</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">..</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// depends on the measuerement</span></span>
<span class="line"><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">timerDiv</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">document</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">createElement</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">div</span><span style="color: #ECEFF4">&#39;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">timerDiv</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">style</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">position</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">fixed</span><span style="color: #ECEFF4">&#39;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">timerDiv</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">style</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">top</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">0</span><span style="color: #ECEFF4">&#39;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">timerDiv</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">style</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">left</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">0</span><span style="color: #ECEFF4">&#39;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">timerDiv</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">style</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">opacity</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">0.8</span><span style="color: #ECEFF4">&#39;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">timerDiv</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">style</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">fontSize</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">14px</span><span style="color: #ECEFF4">&#39;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">timerDiv</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">style</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">backgroundColor</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">yellow</span><span style="color: #ECEFF4">&#39;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">timerDiv</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">style</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">zIndex</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C">10000</span><span style="color: #ECEFF4">&#39;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">document</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">body</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">appendChild</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">timerDiv</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #88C0D0">setInterval</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">function</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">now</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">performance</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">now</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">timerDiv</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">textContent</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">now</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">toFixed</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C"> ms, </span><span style="color: #ECEFF4">&#39;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">now</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">measurementEndMillis</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">.</span><span style="color: #88C0D0">toFixed</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&#39;</span><span style="color: #A3BE8C"> ms</span><span style="color: #ECEFF4">&#39;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">},</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">20</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span></code></pre></div>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" width="556" height="140" src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-github-timer.png" alt="" class="wp-image-136" srcset="http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-github-timer.png 556w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-github-timer-300x76.png 300w" sizes="(max-width: 556px) 100vw, 556px" /><figcaption class="wp-element-caption">X, Y<br>X &#8211; milliseconds since time origin (page started loading)<br>Y &#8211; milliseconds since measurement end. Timer is added after locator is satisfied so it doesn&#8217;t disturb the measurement</figcaption></figure>
</div>


<p class="wp-block-paragraph"><strong>When measuring very fast page like github.com landing page, you&#8217;re often going to see a blank page and right after that frames recorded some time after measurement end (signup button visible). Frames are lost. Based on that you should treat every moment of playwright video as possibly inaccurate</strong>.</p>



<p class="wp-block-paragraph">Having said that, let&#8217;s move on.</p>



<figure class="wp-block-video"><video height="450" style="aspect-ratio: 800 / 450;" width="800" controls src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-load-event-p95.webm"></video><figcaption class="wp-element-caption">wait for <code>load</code> event at percentile 95, button measured as visible after 914 ms. Mind the significant part of the video with button visible, yet measurement is not finished</figcaption></figure>



<h3 class="wp-block-heading">Experiment benchmark 1 &#8211; no waiting</h3>



<p class="wp-block-paragraph">Take 1000 samples. Don&#8217;t wait for any event, wait for github call to action button</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers cbp-blur-enabled cbp-unblur-on-hover" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:14px;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * 14px);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="import com.microsoft.playwright.Page.NavigateOptions
import com.microsoft.playwright.options.WaitUntilState.COMMIT

// from playwright docs WaitUntilState.COMMIT:
// consider operation to be finished when network response is received and the document started loading
page.navigate(&quot;https://github.com&quot;, NavigateOptions().setWaitUntil(COMMIT))
page.locator(&quot;#summary-val&quot;).first().waitFor()" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> com.microsoft.playwright.Page.NavigateOptions</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> com.microsoft.playwright.options.WaitUntilState.COMMIT</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// from playwright docs WaitUntilState.COMMIT:</span></span>
<span class="line"><span style="color: #616E88">// consider operation to be finished when network response is received and the document started loading</span></span>
<span class="line cbp-no-blur"><span style="color: #D8DEE9FF">page.</span><span style="color: #88C0D0">navigate</span><span style="color: #D8DEE9FF">(</span><span style="color: #A3BE8C">&quot;https://github.com&quot;</span><span style="color: #D8DEE9FF">, </span><span style="color: #88C0D0">NavigateOptions</span><span style="color: #D8DEE9FF">().</span><span style="color: #88C0D0">setWaitUntil</span><span style="color: #D8DEE9FF">(COMMIT))</span></span>
<span class="line cbp-no-blur"><span style="color: #D8DEE9FF">page.</span><span style="color: #88C0D0">locator</span><span style="color: #D8DEE9FF">(</span><span style="color: #A3BE8C">&quot;#summary-val&quot;</span><span style="color: #D8DEE9FF">).</span><span style="color: #88C0D0">first</span><span style="color: #D8DEE9FF">().</span><span style="color: #88C0D0">waitFor</span><span style="color: #D8DEE9FF">()</span></span></code></pre></div>



<p class="wp-block-paragraph">In selenium you have to opt out from waiting for <code>DOMCompleteEvent</code> this way</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:14px;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * 14px);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="val options = new ChromeOptions()
options.setPageLoadStrategy(PageLoadStrategy.NONE)    
val driver = new ChromeDriver(options)
driver.navigate(..).to()" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">val</span><span style="color: #D8DEE9FF"> options </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> new </span><span style="color: #88C0D0">ChromeOptions</span><span style="color: #D8DEE9FF">()</span></span>
<span class="line"><span style="color: #D8DEE9FF">options.</span><span style="color: #88C0D0">setPageLoadStrategy</span><span style="color: #D8DEE9FF">(PageLoadStrategy.NONE)    </span></span>
<span class="line"><span style="color: #81A1C1">val</span><span style="color: #D8DEE9FF"> driver </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> new </span><span style="color: #88C0D0">ChromeDriver</span><span style="color: #D8DEE9FF">(options)</span></span>
<span class="line"><span style="color: #D8DEE9FF">driver.</span><span style="color: #88C0D0">navigate</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">..</span><span style="color: #D8DEE9FF">).</span><span style="color: #88C0D0">to</span><span style="color: #D8DEE9FF">()</span></span></code></pre></div>



<figure class="wp-block-image size-full is-style-zoooom"><img decoding="async" width="1301" height="887" src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-no-wait-p95.png" alt="" class="wp-image-119" srcset="http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-no-wait-p95.png 1301w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-no-wait-p95-300x205.png 300w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-no-wait-p95-1024x698.png 1024w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-no-wait-p95-768x524.png 768w" sizes="(max-width: 1301px) 100vw, 1301px" /><figcaption class="wp-element-caption">no wait for event at percentile 95, button measured as visible after 156 ms</figcaption></figure>



<figure class="wp-block-video"><video height="450" style="aspect-ratio: 800 / 450;" width="800" controls src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-no-wait-p95.webm"></video><figcaption class="wp-element-caption">no wait for event at percentile 95, button measured as visible after 156 ms</figcaption></figure>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading">Experiment benchmark 2 &#8211; wait for <code>DOMContentLoaded</code> event</h3>



<p class="wp-block-paragraph">Take 1000 samples. Wait for <code>DOMContentLoaded</code>, wait wait for github call to action button</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers cbp-blur-enabled cbp-unblur-on-hover" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:14px;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * 14px);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="import com.microsoft.playwright.Page.NavigateOptions
import com.microsoft.playwright.options.WaitUntilState.DOMCONTENTLOADED

// from playwright docs WaitUntilState.DOMCONTENTLOADED:
// consider operation to be finished when the DOMContentLoaded event is fired.
page.navigate(&quot;https://github.com&quot;, NavigateOptions().setWaitUntil(DOMCONTENTLOADED))
page.locator(&quot;#summary-val&quot;).first().waitFor()" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> com.microsoft.playwright.Page.NavigateOptions</span></span>
<span class="line"><span style="color: #81A1C1">import</span><span style="color: #D8DEE9FF"> com.microsoft.playwright.options.WaitUntilState.DOMCONTENTLOADED</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// from playwright docs WaitUntilState.DOMCONTENTLOADED:</span></span>
<span class="line"><span style="color: #616E88">// consider operation to be finished when the DOMContentLoaded event is fired.</span></span>
<span class="line cbp-no-blur"><span style="color: #D8DEE9FF">page.</span><span style="color: #88C0D0">navigate</span><span style="color: #D8DEE9FF">(</span><span style="color: #A3BE8C">&quot;https://github.com&quot;</span><span style="color: #D8DEE9FF">, </span><span style="color: #88C0D0">NavigateOptions</span><span style="color: #D8DEE9FF">().</span><span style="color: #88C0D0">setWaitUntil</span><span style="color: #D8DEE9FF">(DOMCONTENTLOADED))</span></span>
<span class="line cbp-no-blur"><span style="color: #D8DEE9FF">page.</span><span style="color: #88C0D0">locator</span><span style="color: #D8DEE9FF">(</span><span style="color: #A3BE8C">&quot;#summary-val&quot;</span><span style="color: #D8DEE9FF">).</span><span style="color: #88C0D0">first</span><span style="color: #D8DEE9FF">().</span><span style="color: #88C0D0">waitFor</span><span style="color: #D8DEE9FF">()</span></span></code></pre></div>



<p class="wp-block-paragraph">In selenium you have to opt out from waiting for <code>DOMContentLoaded</code> event this way</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:14px;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#d8dee9ff;--cbp-line-number-width:calc(1 * 0.6 * 14px);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="val options = new ChromeOptions()
options.setPageLoadStrategy(PageLoadStrategy.EAGER)    
val driver = new ChromeDriver(options)
driver.navigate(..).to()" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">val</span><span style="color: #D8DEE9FF"> options </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> new </span><span style="color: #88C0D0">ChromeOptions</span><span style="color: #D8DEE9FF">()</span></span>
<span class="line"><span style="color: #D8DEE9FF">options.</span><span style="color: #88C0D0">setPageLoadStrategy</span><span style="color: #D8DEE9FF">(PageLoadStrategy.EAGER)    </span></span>
<span class="line"><span style="color: #81A1C1">val</span><span style="color: #D8DEE9FF"> driver </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> new </span><span style="color: #88C0D0">ChromeDriver</span><span style="color: #D8DEE9FF">(options)</span></span>
<span class="line"><span style="color: #D8DEE9FF">driver.</span><span style="color: #88C0D0">navigate</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">..</span><span style="color: #D8DEE9FF">).</span><span style="color: #88C0D0">to</span><span style="color: #D8DEE9FF">()</span></span></code></pre></div>



<figure class="wp-block-image size-full is-style-zoooom"><img decoding="async" width="1303" height="887" src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-DOMContentLoaded-p95.png" alt="" class="wp-image-121" srcset="http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-DOMContentLoaded-p95.png 1303w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-DOMContentLoaded-p95-300x204.png 300w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-DOMContentLoaded-p95-1024x697.png 1024w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-DOMContentLoaded-p95-768x523.png 768w" sizes="(max-width: 1303px) 100vw, 1303px" /><figcaption class="wp-element-caption">wait for <code>DOMContentLoaded</code> event at percentile 95, button measured as visible after 802 ms</figcaption></figure>



<figure class="wp-block-video"><video height="450" style="aspect-ratio: 800 / 450;" width="800" controls src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-DOMContentLoaded-p95.webm"></video><figcaption class="wp-element-caption">wait for <code>DOMContentLoaded</code> event at percentile 95, button measured as visible after 802 ms. Mind the significant part of the video with button visible, yet measurement is not finished</figcaption></figure>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading">And now let&#8217;s compare the results</h3>



<h4 class="wp-block-heading">P95 comparison</h4>



<figure class="wp-block-table"><table><tbody><tr><td>no waiting</td><td>wait for <code>DOMContentLoaded</code></td><td>wait for <code>load</code> event</td></tr><tr><td>156 ms</td><td>802 ms</td><td>914 ms</td></tr></tbody></table><figcaption class="wp-element-caption">95th percentile  across different type of loading website in playwright/selenium</figcaption></figure>



<p class="wp-block-paragraph">Percentiles do not answer the question <em>how distribution compares</em>? Down the line you&#8217;re going to see <a href="https://en.wikipedia.org/wiki/Hodges%E2%80%93Lehmann_estimator" target="_blank" rel="noopener" title="">Hodges-Lehman estimator</a></p>



<h4 class="wp-block-heading">What hypotheses are we verifying here?</h4>



<ul class="wp-block-list">
<li><code>load</code> event
<ul class="wp-block-list">
<li>(baseline) null hypothesis: waiting for <code>load</code> event has completion has no performance impact</li>



<li>(experiment 1) alternative hypothesis: waiting for <code>load</code>event has impact on measured latencies</li>
</ul>
</li>



<li><code>DOMContentLoaded</code> event
<ul class="wp-block-list">
<li>(baseline) null hypothesis: waiting for <code>DOMContentLoad</code> event has has no impact on measured latencies</li>



<li>(experiment 2) alternative hypothesis: waiting for <code>DOMContentLoad</code>event has impact on measured latencies</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading">Waiting for <code>load</code> event VS not waiting for any event</h3>



<figure class="wp-block-image size-full is-style-zoooom"><img decoding="async" width="1303" height="429" src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-load-vs-no-wait.png" alt="" class="wp-image-124" srcset="http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-load-vs-no-wait.png 1303w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-load-vs-no-wait-300x99.png 300w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-load-vs-no-wait-1024x337.png 1024w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-load-vs-no-wait-768x253.png 768w" sizes="(max-width: 1303px) 100vw, 1303px" /><figcaption class="wp-element-caption">83.829% improvement when not waiting for any browser event</figcaption></figure>



<p class="wp-block-paragraph">Title of this blog post says there is 530% performance degradation when you rely on browser automation defaults. So where is it? When you reverse baseline VS experiment, there it is</p>



<figure class="wp-block-image size-full is-style-zoooom"><img decoding="async" width="1301" height="279" src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-no-wait-vs-wait-for-load.png" alt="" class="wp-image-125" srcset="http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-no-wait-vs-wait-for-load.png 1301w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-no-wait-vs-wait-for-load-300x64.png 300w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-no-wait-vs-wait-for-load-1024x220.png 1024w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-no-wait-vs-wait-for-load-768x165.png 768w" sizes="(max-width: 1301px) 100vw, 1301px" /><figcaption class="wp-element-caption">Null hypothesis is rejected, waiting for <code>load</code> event comes with bigger latencies</figcaption></figure>



<p class="wp-block-paragraph">Null hypothesis is rejected, waiting for <code>load</code> event comes with bigger latencies</p>



<figure class="wp-block-image size-full is-style-zoooom"><img decoding="async" width="1302" height="312" src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-no-wait-vs-wait-for-load-after-ttfb.png" alt="" class="wp-image-126" srcset="http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-no-wait-vs-wait-for-load-after-ttfb.png 1302w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-no-wait-vs-wait-for-load-after-ttfb-300x72.png 300w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-no-wait-vs-wait-for-load-after-ttfb-1024x245.png 1024w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-no-wait-vs-wait-for-load-after-ttfb-768x184.png 768w" sizes="(max-width: 1302px) 100vw, 1302px" /><figcaption class="wp-element-caption">Time to first byte is irrelevant for hypothesis verification. When you remove it from measured latencies it unfolds more accurate impact on frontend part.</figcaption></figure>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading">Waiting for <code>DOMContentLoaded</code> VS not waiting for any event</h3>



<figure class="wp-block-image size-full is-style-zoooom"><img decoding="async" width="1300" height="279" src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-DOMContentLoaded-vs-no-wait.png" alt="" class="wp-image-128" srcset="http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-DOMContentLoaded-vs-no-wait.png 1300w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-DOMContentLoaded-vs-no-wait-300x64.png 300w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-DOMContentLoaded-vs-no-wait-1024x220.png 1024w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-DOMContentLoaded-vs-no-wait-768x165.png 768w" sizes="(max-width: 1300px) 100vw, 1300px" /><figcaption class="wp-element-caption">79.642% smaller latencies when not waiting for any browser event</figcaption></figure>



<p class="wp-block-paragraph">Null hypothesis is rejected, waiting for <code>DOMContentLoaded </code>increases measured latencies</p>



<h3 class="wp-block-heading">Waiting for <code>DOMContentLoaded</code> VS waiting for <code>load</code> event</h3>



<p class="wp-block-paragraph">Having 2 experiments we can compare them too. Since <code>load</code> event comes always after <code>DOMContentLoaded</code> it&#8217;s expected to see bigger latencies which is reflected in measurements</p>



<figure class="wp-block-image size-full is-style-zoooom"><img decoding="async" width="1300" height="278" src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-DOMContentLoaded-vs-wait-for-load.png" alt="" class="wp-image-129" srcset="http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-DOMContentLoaded-vs-wait-for-load.png 1300w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-DOMContentLoaded-vs-wait-for-load-300x64.png 300w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-DOMContentLoaded-vs-wait-for-load-1024x219.png 1024w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-comparison-wait-for-DOMContentLoaded-vs-wait-for-load-768x164.png 768w" sizes="(max-width: 1300px) 100vw, 1300px" /></figure>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">Based on measurements, what are undesired effects of waiting for <code>DOMContentLoad</code> or <code>load</code> event?</h2>



<ul class="wp-block-list">
<li>To understand better following part take a look at difference between accuracy and precision</li>
</ul>



<figure class="wp-block-image size-full is-resized"><img decoding="async" width="764" height="794" src="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-Accuracy-vs-Precision.png" alt="" class="wp-image-130" style="width:507px;height:auto" srcset="http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-Accuracy-vs-Precision.png 764w, http://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-Accuracy-vs-Precision-289x300.png 289w" sizes="(max-width: 764px) 100vw, 764px" /></figure>



<ul class="wp-block-list">
<li>The undesired effects</li>



<li>Measuring something neither reflecting user experience nor relevant to user experience. User sees a button and clicks a button regardless of events in the browser
<ul class="wp-block-list">
<li>No user ever thought &#8220;<em>I politely wish this site had dom completion faster</em>&#8220;. User thinks &#8220;<em>Why the f^%@ is this button not working yet?!!??</em>&#8220;</li>
</ul>
</li>



<li>(much) longer benchmarks
<ul class="wp-block-list">
<li>for ones that aim for measurement count, e.g. we want to have 200 samples</li>
</ul>
</li>



<li>Less precise benchmarks
<ul class="wp-block-list">
<li>for ones that aim for duration, e.g. running for 10 minutes</li>



<li>because you will get less samples</li>
</ul>
</li>



<li>Less accurate benchmarks
<ul class="wp-block-list">
<li>because you&#8217;re not measuring what user experiencies</li>



<li>As a result system under benchmark might actually meet some acceptance criteria, while measurements show it&#8217;s not</li>
</ul>
</li>



<li>Disturbs calculating correlations and figuring out frontend latency causation</li>
</ul>



<h2 class="wp-block-heading">Side effects of not waiting for <code>DOMContentLoaded</code> or <code>loaded</code> event</h2>



<p class="wp-block-paragraph">User can click a visible button, that does not react on clicks yet. Which actually is a reality <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p class="wp-block-paragraph">However that complicates measurements. Frameworks do not check if a button has event listeners. It often requires polling for a desired button state. e.g. await condition click and check if expected message is visible</p>



<h2 class="wp-block-heading">Summary</h2>



<p class="wp-block-paragraph">I&#8217;ve taken thousands of measurements of a few different sites, not only github. Systems behave the same. Waiting for browser events makes measured latencies inaccurate. It might be 10% away from real user experience, it might be 530%.</p>



<p class="wp-block-paragraph">It&#8217;s non-zero, reproducible and deterministic. So if you already made an effort to make synthetic performance benchmarks, I&#8217;d recommend putting an effort also in increasing their accuracy.</p>



<h3 class="wp-block-heading">Consider changing default options for browser automation</h3>



<p class="wp-block-paragraph">For playwright and selenium (and whatever browser automation tools there are) you should opt out from waiting for any browser events if you&#8217;re using those tools for performance measurements.</p>



<figure class="wp-block-table"><table><tbody><tr><td>Option</td><td>Selenium</td><td>Playwright</td></tr><tr><td>wait for response received (<strong>best for performance benchmarks</strong>)</td><td>NONE</td><td>COMMIT</td></tr><tr><td>wait for load event (<strong>default</strong>)</td><td>NORMAL</td><td>LOAD</td></tr><tr><td>wait for DOMContentLoaded event (another option)</td><td>EAGER</td><td>DOMCONTENTLOADED</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"></p><p>The post <a href="http://deploymenteveryday.com/how-to-make-performance-benchmark-530-worse-by-relying-on-web-app-automation-defaults/">How to make performance benchmark 530% worse by relying on web app automation defaults?</a> first appeared on <a href="http://deploymenteveryday.com">Deployment Every Day</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>http://deploymenteveryday.com/how-to-make-performance-benchmark-530-worse-by-relying-on-web-app-automation-defaults/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		<enclosure url="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-load-event-p95.webm" length="43031" type="video/webm" />
<enclosure url="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-no-wait-p95.webm" length="41413" type="video/webm" />
<enclosure url="https://deploymenteveryday.com/wp-content/uploads/2024/05/blog_post_should-you-wait-for-DOMContentLoaded-wait-for-DOMContentLoaded-p95.webm" length="41614" type="video/webm" />

			</item>
	</channel>
</rss>
