<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Get started with k6 on Grafana Labs</title><link>https://grafana.com/docs/k6/v2.3.x/examples/get-started-with-k6/</link><description>Recent content in Get started with k6 on Grafana Labs</description><generator>Hugo -- gohugo.io</generator><language>en</language><atom:link href="/docs/k6/v2.3.x/examples/get-started-with-k6/index.xml" rel="self" type="application/rss+xml"/><item><title>Test for functional behavior</title><link>https://grafana.com/docs/k6/v2.3.x/examples/get-started-with-k6/test-for-functional-behavior/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/examples/get-started-with-k6/test-for-functional-behavior/</guid><content><![CDATA[&lt;h1 id=&#34;test-for-functional-behavior&#34;&gt;Test for functional behavior&lt;/h1&gt;
&lt;p&gt;In this tutorial, learn how to write a test that does the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sends a POST request to the new endpoint&lt;/li&gt;
&lt;li&gt;Creates a check for the response status&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;script-the-request&#34;&gt;Script the Request&lt;/h2&gt;
&lt;p&gt;The first thing to do is to add logic for the endpoint.
To do that, you need to make an 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/http-requests/&#34;&gt;HTTP request&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Import the HTTP module.&lt;/li&gt;
&lt;li&gt;Create a payload to authenticate the user.&lt;/li&gt;
&lt;li&gt;Use the 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/post/&#34;&gt;&lt;code&gt;http.post&lt;/code&gt;&lt;/a&gt; method to send your request with the payload to an endpoint.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To test, copy this file and save it as &lt;code&gt;api-test.js&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;// import necessary module
import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  // define URL and payload
  const url = &amp;#39;https://quickpizza.grafana.com/api/users/token/login&amp;#39;;
  const payload = JSON.stringify({
    username: &amp;#39;default&amp;#39;,
    password: &amp;#39;12345678&amp;#39;,
  });

  const params = {
    headers: {
      &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39;,
    },
  };

  // send a post request and save response as a variable
  const res = http.post(url, payload, params);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Run the script using the &lt;code&gt;k6 run&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run api-test.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After the test finishes, k6 reports the 
    &lt;a href=&#34;/docs/k6/v2.3.x/results-output/end-of-test/#the-default-summary&#34;&gt;default result summary&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;          /\      |‾‾| /‾‾/   /‾‾/
     /\  /  \     |  |/  /   /  /
    /  \/    \    |     (   /   ‾‾\
   /          \   |  |\  \ |  (‾)  |
  / __________ \  |__| \__\ \_____/ .io

  execution: local
     script: api-test.js
     output: -
  ...&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As an optional step, you can log the response body to the console to make sure you&amp;rsquo;re getting the right response.&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;
&lt;!-- eslint-disable no-undef  --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export default function () {
  // ...

  const res = http.post(url, payload, params);

  // Log the request body
  console.log(res.body);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;!-- eslint-enable no-undef  --&gt;
&lt;h2 id=&#34;add-response-checks&#34;&gt;Add response checks&lt;/h2&gt;
&lt;p&gt;Once you&amp;rsquo;re sure the request is well-formed, add a 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/checks/&#34;&gt;check&lt;/a&gt; that validates whether the system responds with the expected status code.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Update your script so it has the following check function.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;// Import necessary modules
import { check } from &amp;#39;k6&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  // define URL and payload
  const url = &amp;#39;https://quickpizza.grafana.com/api/users/token/login&amp;#39;;
  const payload = JSON.stringify({
    username: &amp;#39;default&amp;#39;,
    password: &amp;#39;12345678&amp;#39;,
  });
  const params = {
    headers: {
      &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39;,
    },
  };

  // send a post request and save response as a variable
  const res = http.post(url, payload, params);

  // check that response is 200
  check(res, {
    &amp;#39;response code was 200&amp;#39;: (res) =&amp;gt; res.status == 200,
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Run the script again.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run api-test.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Inspect the result output for your check.
It should look something like this.&lt;/p&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;✓ response code was 200&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;Under larger loads, this check will fail in some iterations.
&lt;strong&gt;Failed checks do not stop tests.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Rather, k6 tracks the success rate and presents it in your 
    &lt;a href=&#34;/docs/k6/v2.3.x/results-output/end-of-test/&#34;&gt;end of test&lt;/a&gt; summary.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h2 id=&#34;next-steps&#34;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;In this tutorial, you&amp;rsquo;ve used k6 to make a POST request and check that it responds with a &lt;code&gt;200&lt;/code&gt; status.&lt;/p&gt;
&lt;p&gt;However, these tests make only one request, which doesn&amp;rsquo;t say much about how the system will respond under load.
For that, you need to 
    &lt;a href=&#34;/docs/k6/v2.3.x/examples/get-started-with-k6/test-for-performance/&#34;&gt;test under load&lt;/a&gt;.&lt;/p&gt;
]]></content><description>&lt;h1 id="test-for-functional-behavior">Test for functional behavior&lt;/h1>
&lt;p>In this tutorial, learn how to write a test that does the following:&lt;/p>
&lt;ul>
&lt;li>Sends a POST request to the new endpoint&lt;/li>
&lt;li>Creates a check for the response status&lt;/li>
&lt;/ul>
&lt;h2 id="script-the-request">Script the Request&lt;/h2>
&lt;p>The first thing to do is to add logic for the endpoint.
To do that, you need to make an
&lt;a href="/docs/k6/v2.3.x/using-k6/http-requests/">HTTP request&lt;/a>:&lt;/p></description></item><item><title>Test for performance</title><link>https://grafana.com/docs/k6/v2.3.x/examples/get-started-with-k6/test-for-performance/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/examples/get-started-with-k6/test-for-performance/</guid><content><![CDATA[&lt;h1 id=&#34;test-for-performance&#34;&gt;Test for performance&lt;/h1&gt;
&lt;p&gt;In the previous section, you made a working script to test an endpoint functionality.
The next step is to test how this system responds under load.
This requires setting up a few 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/&#34;&gt;&lt;code&gt;options&lt;/code&gt;&lt;/a&gt; to configure the parts of the test that don&amp;rsquo;t deal with test logic.&lt;/p&gt;
&lt;p&gt;In this tutorial, learn how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/thresholds/&#34;&gt;thresholds&lt;/a&gt; to assert for performance criteria&lt;/li&gt;
&lt;li&gt;Configure load increases through 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/&#34;&gt;scenarios&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These examples build on the script from the 
    &lt;a href=&#34;/docs/k6/v2.3.x/examples/get-started-with-k6/test-for-functional-behavior/&#34;&gt;previous section&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;context-meet-service-level-objectives&#34;&gt;Context: meet service-level objectives&lt;/h2&gt;
&lt;p&gt;To assess the login endpoint&amp;rsquo;s performance, your team may have defined &lt;a href=&#34;https://sre.google/sre-book/service-level-objectives/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;service level objectives&lt;/a&gt; (SLOs). For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;99% of requests should be successful&lt;/li&gt;
&lt;li&gt;99% of requests should have a latency of 1000ms or less&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The service must meet these SLOs under different types of usual traffic.&lt;/p&gt;
&lt;h2 id=&#34;assert-for-performance-with-thresholds&#34;&gt;Assert for performance with thresholds&lt;/h2&gt;
&lt;p&gt;To codify the SLOs, add 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/thresholds/&#34;&gt;&lt;em&gt;thresholds&lt;/em&gt;&lt;/a&gt; to test that your system performs to its goal criteria.&lt;/p&gt;
&lt;p&gt;Thresholds are set in the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/&#34;&gt;&lt;code&gt;options&lt;/code&gt;&lt;/a&gt; object.&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const options = {
  // define thresholds
  thresholds: {
    http_req_failed: [&amp;#39;rate&amp;lt;0.01&amp;#39;], // http errors should be less than 1%
    http_req_duration: [&amp;#39;p(99)&amp;lt;1000&amp;#39;], // 99% of requests should be below 1s
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Add this &lt;code&gt;options&lt;/code&gt; object with thresholds to your script &lt;code&gt;api-test.js&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;// import necessary modules
import { check } from &amp;#39;k6&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

// define configuration
export const options = {
  // define thresholds
  thresholds: {
    http_req_failed: [&amp;#39;rate&amp;lt;0.01&amp;#39;], // http errors should be less than 1%
    http_req_duration: [&amp;#39;p(99)&amp;lt;1000&amp;#39;], // 99% of requests should be below 1s
  },
};

export default function () {
  // define URL and request body
  const url = &amp;#39;https://quickpizza.grafana.com/api/users/token/login&amp;#39;;
  const payload = JSON.stringify({
    username: &amp;#39;default&amp;#39;,
    password: &amp;#39;1234&amp;#39;,
  });
  const params = {
    headers: {
      &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39;,
    },
  };

  // send a post request and save response as a variable
  const res = http.post(url, payload, params);

  // check that response is 200
  check(res, {
    &amp;#39;response code was 200&amp;#39;: (res) =&amp;gt; res.status == 200,
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Run the test.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run api-test.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Inspect the console output to determine whether performance crossed a threshold.&lt;/p&gt;

&lt;div class=&#34;code-snippet code-snippet__mini&#34;&gt;&lt;div class=&#34;lang-toolbar__mini&#34;&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet code-snippet__border&#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-none&#34;&gt;  █ THRESHOLDS

    http_req_duration
    ✓ &amp;#39;p(99)&amp;lt;1000&amp;#39; p(99)=148.21ms

    http_req_failed
    ✗ &amp;#39;rate&amp;lt;0.01&amp;#39; rate=20.%&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The ✓ and ✗ symbols indicate whether the performance thresholds passed or failed.&lt;/p&gt;
&lt;h2 id=&#34;test-performance-under-increasing-load&#34;&gt;Test performance under increasing load&lt;/h2&gt;
&lt;p&gt;Now your script has logic to simulate user behavior, and assertions for functionality (checks) and performance (thresholds).&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s time to increase the load to see how it performs.
To increase the load, use the scenarios property.
Scenarios schedule load according to the number of 
    &lt;a href=&#34;/docs/k6/v2.3.x/get-started/running-k6/#add-vus&#34;&gt;virtual users (VUs)&lt;/a&gt;, number of iterations, VUs, or by iteration rate.&lt;/p&gt;
&lt;h3 id=&#34;run-a-smoke-test&#34;&gt;Run a smoke test&lt;/h3&gt;
&lt;p&gt;Start small. Run a 
    &lt;a href=&#34;/docs/k6/v2.3.x/testing-guides/test-types/smoke-testing/&#34; title=&#34;a small test to confirm the script works properly&#34;&gt;smoke test&lt;/a&gt; to check that your script can handle a minimal load.&lt;/p&gt;
&lt;p&gt;To do so, use the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/k6-options/reference/#iterations&#34;&gt;&lt;code&gt;--iterations&lt;/code&gt;&lt;/a&gt; flag with an argument of 10 or fewer.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run --iterations 10 api-test.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If the service can&amp;rsquo;t receive 10 iterations, the system has some serious performance issues to debug.
Good thing you ran the test early!&lt;/p&gt;
&lt;h3 id=&#34;run-a-test-against-an-average-load&#34;&gt;Run a test against an average load&lt;/h3&gt;
&lt;p&gt;Generally, traffic doesn&amp;rsquo;t arrive all at once.
Rather, it gradually increases to a peak load.
To simulate this, testers increase the load in &lt;em&gt;stages&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Add the following &lt;code&gt;scenario&lt;/code&gt; property to your &lt;code&gt;options&lt;/code&gt; object and rerun the test.&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const options = {
  // define thresholds
  thresholds: {
    http_req_failed: [&amp;#39;rate&amp;lt;0.01&amp;#39;], // http errors should be less than 1%
    http_req_duration: [&amp;#39;p(99)&amp;lt;1000&amp;#39;], // 99% of requests should be below 1s
  },
  // define scenarios
  scenarios: {
    // arbitrary name of scenario
    average_load: {
      executor: &amp;#39;ramping-vus&amp;#39;,
      stages: [
        // ramp up to average load of 20 virtual users
        { duration: &amp;#39;10s&amp;#39;, target: 20 },
        // maintain load
        { duration: &amp;#39;50s&amp;#39;, target: 20 },
        // ramp down to zero
        { duration: &amp;#39;5s&amp;#39;, target: 0 },
      ],
    },
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Since this is a learning environment, the stages are still quite short.
Where the smoke test defined the load in terms of iterations, this configuration uses the 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/executors/ramping-vus/&#34;&gt;&lt;code&gt;ramping-vus&lt;/code&gt; executor&lt;/a&gt; to express load through virtual users and duration.&lt;/p&gt;
&lt;p&gt;Run the test with no command-line flags:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run api-test.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The load is small, so the server should perform within thresholds.
However, this test server may be under load by many k6 learners, so the results are unpredictable.&lt;/p&gt;


&lt;div class=&#34;admonition admonition-note&#34;&gt;&lt;blockquote&gt;&lt;p class=&#34;title text-uppercase&#34;&gt;Note&lt;/p&gt;&lt;p&gt;At this point, it&amp;rsquo;d be nice to have a graphical interface to visualize metrics as they occur.
k6 has many output formats, which can serve as inputs for many visualization tools, both open source and commercial.
For ideas, read &lt;a href=&#34;https://k6.io/blog/ways-to-visualize-k6-results&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Ways to visualize k6 results&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;h3 id=&#34;ramp-up-until-threshold-fails&#34;&gt;Ramp up until threshold fails&lt;/h3&gt;
&lt;p&gt;Finally, run a 
    &lt;a href=&#34;/docs/k6/v2.3.x/testing-guides/test-types/breakpoint-testing/&#34;&gt;breakpoint test&lt;/a&gt;, where you probe the system&amp;rsquo;s limits.
In this case, run the test until the availability (error rate) threshold is crossed.&lt;/p&gt;
&lt;p&gt;To do this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add the &lt;code&gt;abortOnFail&lt;/code&gt; property to &lt;code&gt;http_req_failed&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const options = {
  // define thresholds
  thresholds: {
    http_req_failed: [{ threshold: &amp;#39;rate&amp;lt;0.01&amp;#39;, abortOnFail: true }], // http errors should be less than 1%, otherwise abort the test
    http_req_duration: [&amp;#39;p(99)&amp;lt;1000&amp;#39;], // 99% of requests should be below 1s
  },
  // ...
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Update the &lt;code&gt;scenarios&lt;/code&gt; property to ramp the test up until it fails.&lt;/li&gt;
&lt;/ol&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const options = {
  thresholds: {
    http_req_failed: [{ threshold: &amp;#39;rate&amp;lt;0.01&amp;#39;, abortOnFail: true }],
    http_req_duration: [&amp;#39;p(99)&amp;lt;1000&amp;#39;],
  },
  scenarios: {
    // define scenarios
    breaking: {
      executor: &amp;#39;ramping-vus&amp;#39;,
      stages: [
        { duration: &amp;#39;10s&amp;#39;, target: 20 },
        { duration: &amp;#39;50s&amp;#39;, target: 20 },
        { duration: &amp;#39;50s&amp;#39;, target: 40 },
        { duration: &amp;#39;50s&amp;#39;, target: 60 },
        { duration: &amp;#39;50s&amp;#39;, target: 80 },
        { duration: &amp;#39;50s&amp;#39;, target: 100 },
        { duration: &amp;#39;50s&amp;#39;, target: 120 },
        { duration: &amp;#39;50s&amp;#39;, target: 140 },
        //....
      ],
    },
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here is the full script.&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;// import necessary modules
import { check } from &amp;#39;k6&amp;#39;;
import http from &amp;#39;k6/http&amp;#39;;

// define configuration
export const options = {
  // define thresholds
  thresholds: {
    http_req_failed: [{ threshold: &amp;#39;rate&amp;lt;0.01&amp;#39;, abortOnFail: true }], // availability threshold for error rate
    http_req_duration: [&amp;#39;p(99)&amp;lt;1000&amp;#39;], // Latency threshold for percentile
  },
  // define scenarios
  scenarios: {
    breaking: {
      executor: &amp;#39;ramping-vus&amp;#39;,
      stages: [
        { duration: &amp;#39;10s&amp;#39;, target: 20 },
        { duration: &amp;#39;50s&amp;#39;, target: 20 },
        { duration: &amp;#39;50s&amp;#39;, target: 40 },
        { duration: &amp;#39;50s&amp;#39;, target: 60 },
        { duration: &amp;#39;50s&amp;#39;, target: 80 },
        { duration: &amp;#39;50s&amp;#39;, target: 100 },
        { duration: &amp;#39;50s&amp;#39;, target: 120 },
        { duration: &amp;#39;50s&amp;#39;, target: 140 },
        //....
      ],
    },
  },
};

export default function () {
  // define URL and request body
  const url = &amp;#39;https://quickpizza.grafana.com/api/users/token/login&amp;#39;;
  const payload = JSON.stringify({
    username: &amp;#39;default&amp;#39;,
    password: &amp;#39;1234&amp;#39;,
  });
  const params = {
    headers: {
      &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39;,
    },
  };

  // send a post request and save response as a variable
  const res = http.post(url, payload, params);

  // check that response is 200
  check(res, {
    &amp;#39;response code was 200&amp;#39;: (res) =&amp;gt; res.status == 200,
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Run the test.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run api-test.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Did the threshold fail? If not, add another stage with a higher target and try again. Repeat until the threshold aborts the test:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;ERRO[0010] thresholds on metrics &amp;#39;http_req_duration, http_req_failed&amp;#39; were breached; at least one has abortOnFail enabled, stopping test prematurely&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;In this tutorial, you used 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/thresholds/&#34;&gt;thresholds&lt;/a&gt; to assert performance and 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/&#34;&gt;Scenarios&lt;/a&gt; to schedule different load patterns. To learn more about the usual load patterns and their goals, read 
    &lt;a href=&#34;/docs/k6/v2.3.x/testing-guides/test-types/&#34;&gt;Load Test Types&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The 
    &lt;a href=&#34;/docs/k6/v2.3.x/examples/get-started-with-k6/analyze-results/&#34;&gt;next step of this tutorial shows how to interpret test results&lt;/a&gt;. This involves filtering results and adding custom metrics.&lt;/p&gt;
]]></content><description>&lt;h1 id="test-for-performance">Test for performance&lt;/h1>
&lt;p>In the previous section, you made a working script to test an endpoint functionality.
The next step is to test how this system responds under load.
This requires setting up a few
&lt;a href="/docs/k6/v2.3.x/using-k6/k6-options/">&lt;code>options&lt;/code>&lt;/a> to configure the parts of the test that don&amp;rsquo;t deal with test logic.&lt;/p></description></item><item><title>Analyze results</title><link>https://grafana.com/docs/k6/v2.3.x/examples/get-started-with-k6/analyze-results/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/examples/get-started-with-k6/analyze-results/</guid><content><![CDATA[&lt;h1 id=&#34;analyze-results&#34;&gt;Analyze results&lt;/h1&gt;
&lt;p&gt;In this tutorial, learn how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Apply tags to filter specific results&lt;/li&gt;
&lt;li&gt;Learn about k6 metrics&lt;/li&gt;
&lt;li&gt;Use &lt;a href=&#34;https://jqlang.github.io/jq/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;jq&lt;/a&gt; to filter JSON results&lt;/li&gt;
&lt;li&gt;Define groups to organize the test&lt;/li&gt;
&lt;li&gt;Create custom metrics&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;context-k6-result-outputs&#34;&gt;Context: k6 result outputs&lt;/h2&gt;
&lt;p&gt;k6 provides many 
    &lt;a href=&#34;/docs/k6/v2.3.x/results-output/&#34;&gt;result outputs&lt;/a&gt;.
By default, the 
    &lt;a href=&#34;/docs/k6/v2.3.x/results-output/end-of-test/&#34;&gt;end-of-test summary&lt;/a&gt; provides the aggregated results of the test metrics.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;  █ THRESHOLDS

    http_req_duration
    ✓ &amp;#39;p(95)&amp;lt;1500&amp;#39; p(95)=148.21ms
    ✓ &amp;#39;p(90)&amp;lt;2000&amp;#39; p(90)=146.88ms

    http_req_failed
    ✓ &amp;#39;rate&amp;lt;0.01&amp;#39; rate=0.00%


  █ TOTAL RESULTS

    checks_total.......................: 90      13.122179/s
    checks_succeeded...................: 100.00% 90 out of 90
    checks_failed......................: 0.00%   0 out of 90

    ✓ test-api.k6.io is up
    ✓ status is 200

    CUSTOM
    custom_waiting_time................: avg=152.355556 min=120      med=141      max=684      p(90)=147.2    p(95)=148.8

    HTTP
    http_req_duration..................: avg=140.36ms   min=119.08ms med=140.96ms max=154.63ms p(90)=146.88ms p(95)=148.21ms
      { expected_response:true }.......: avg=140.36ms   min=119.08ms med=140.96ms max=154.63ms p(90)=146.88ms p(95)=148.21ms
    http_req_failed....................: 0.00%  0 out of 45
    http_reqs..........................: 45     6.56109/s

    EXECUTION
    iteration_duration.................: avg=152.38ms   min=119.37ms med=141.27ms max=684.62ms p(90)=147.11ms p(95)=148.39ms
    iterations.........................: 45     6.56109/s
    vus................................: 1      min=1       max=1
    vus_max............................: 1      min=1       max=1

    NETWORK
    data_received......................: 519 kB 76 kB/s
    data_sent..........................: 4.9 kB 718 B/s&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For simplicity to learn about 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/metrics/reference/&#34;&gt;k6 metric results&lt;/a&gt;, this tutorial uses the 
    &lt;a href=&#34;/docs/k6/v2.3.x/results-output/real-time/json/&#34;&gt;JSON output&lt;/a&gt; and &lt;a href=&#34;https://jqlang.github.io/jq/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;jq&lt;/a&gt; to filter results.&lt;/p&gt;
&lt;p&gt;For other options to analyze test results such as storage and time-series visualizations in real-time, refer to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
    &lt;a href=&#34;/docs/k6/v2.3.x/results-output/&#34;&gt;Results output&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://k6.io/blog/ways-to-visualize-k6-results/&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;Ways to visualize k6 results&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;write-time-series-results-to-a-json-file&#34;&gt;Write time-series results to a JSON file&lt;/h2&gt;
&lt;p&gt;To output results to a JSON file, use the &lt;code&gt;--out&lt;/code&gt; flag.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run --out json=results.json api-test.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Then run this &lt;code&gt;jq&lt;/code&gt; command to filter the latency results; &lt;code&gt;http_req_duration&lt;/code&gt; metric.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;jq &amp;#39;. | select(.type == &amp;#34;Point&amp;#34; and .metric == &amp;#34;http_req_duration&amp;#34;)&amp;#39; results.json&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;k6 results have a number of 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/tags-and-groups/#system-tags&#34;&gt;built-in tags&lt;/a&gt;. For example, filter results to only results where the status is 200.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;jq &amp;#39;. | select(.type == &amp;#34;Point&amp;#34; and .data.tags.status == &amp;#34;200&amp;#34;)&amp;#39; results.json&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Or calculate the aggregated value of any metric with any particular tags.&lt;/p&gt;



  

  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;average&#34;&gt;average&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;min&#34;&gt;min&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;2&#34; data-label=&#34;max&#34;&gt;max&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;average&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-average&#34;&gt;jq &amp;#39;. | select(.type == &amp;#34;Point&amp;#34; and .metric == &amp;#34;http_req_duration&amp;#34;) | .data.value&amp;#39; results.json | jq -s &amp;#39;add/length&amp;#39;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;min&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-min&#34;&gt;jq &amp;#39;. | select(.type == &amp;#34;Point&amp;#34; and .metric == &amp;#34;http_req_duration&amp;#34;) | .data.value&amp;#39; results.json | jq -s min&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;max&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-max&#34;&gt;jq &amp;#39;. | select(.type == &amp;#34;Point&amp;#34; and .metric == &amp;#34;http_req_duration&amp;#34;) | .data.value&amp;#39; results.json | jq -s max&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;apply-custom-tags&#34;&gt;Apply custom tags&lt;/h2&gt;
&lt;p&gt;You can also apply 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/tags-and-groups/#tags&#34;&gt;&lt;em&gt;Tags&lt;/em&gt;&lt;/a&gt; to requests or code blocks. For example, this is how you can add a 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/tags-and-groups/#tags&#34;&gt;&lt;code&gt;tags&lt;/code&gt;&lt;/a&gt; to the 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-http/params/&#34;&gt;request params&lt;/a&gt;.&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;const params = {
  headers: {
    &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39;,
  },
  tags: {
    &amp;#39;my-custom-tag&amp;#39;: &amp;#39;auth-api&amp;#39;,
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Create a new script named &amp;ldquo;tagged-login.js&amp;rdquo;, and add a custom tag to it.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;

export default function () {
  const url = &amp;#39;https://quickpizza.grafana.com&amp;#39;;
  const payload = JSON.stringify({
    username: &amp;#39;test_case&amp;#39;,
    password: &amp;#39;12345678&amp;#39;,
  });

  const params = {
    headers: {
      &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39;,
    },
    //apply tags
    tags: {
      &amp;#39;my-custom-tag&amp;#39;: &amp;#39;auth-api&amp;#39;,
    },
  };

  //Create user, with tags
  http.post(`${url}/api/users`, payload, params);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Run the test:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run --out json=results.json tagged-login.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Filter the results for this custom tag:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;jq &amp;#39;. | select(.type == &amp;#34;Point&amp;#34; and .metric == &amp;#34;http_req_duration&amp;#34; and .data.tags.&amp;#34;my-custom-tag&amp;#34; == &amp;#34;auth-api&amp;#34;)&amp;#39; results.json&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;organize-requests-in-groups&#34;&gt;Organize requests in groups&lt;/h2&gt;
&lt;p&gt;You can also organize your test logic into 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/tags-and-groups/#groups&#34;&gt;Groups&lt;/a&gt;. Test logic inside a &lt;code&gt;group&lt;/code&gt; tags all requests and metrics within its block.
Groups can help you organize the test as a series of logical transactions or blocks.&lt;/p&gt;
&lt;h3 id=&#34;context-a-new-test-to-group-test-logic&#34;&gt;Context: a new test to group test logic&lt;/h3&gt;
&lt;p&gt;Results filtering isn&amp;rsquo;t very meaningful in a test that makes one request.
And the API test script is getting long.
To learn more about how to compare results and other k6 APIs, write a test for the following situation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A dummy example&lt;/strong&gt;: your development team wants to evaluate the performance of two user-facing flows.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;visit an endpoint, then another one
&lt;ul&gt;
&lt;li&gt;A GET request to &lt;code&gt;https://test.k6.io/contacts.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A GET to &lt;code&gt;https://test.k6.io/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;play the coinflip game:
&lt;ul&gt;
&lt;li&gt;A POST request to &lt;code&gt;https://test.k6.io/flip_coin.php&lt;/code&gt; with the query param &lt;code&gt;bet=heads&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Another POST to &lt;code&gt;https://test.k6.io/flip_coin.php&lt;/code&gt; with the query param &lt;code&gt;bet=tails&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;Can you figure out how to 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/http-requests/&#34;&gt;script the requests&lt;/a&gt;?
If not, use the following script. Since this example simulates a human user rather than an API call, it has a sleep between each request. Run with &lt;code&gt;k6 run multiple-flows.js&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { group, sleep } from &amp;#39;k6&amp;#39;;

//set URL as variable
const baseUrl = &amp;#39;https://test.k6.io&amp;#39;;

export default function () {
  // visit contacts
  http.get(`${baseUrl}/contacts.php`);
  sleep(1);
  // return to the home page
  http.get(`${baseUrl}/`);
  sleep(1);

  //play coinflip game
  http.get(`${baseUrl}/flip_coin.php?bet=heads`);
  sleep(1);
  http.get(`${baseUrl}/flip_coin.php?bet=tails`);
  sleep(1);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;add-group-functions&#34;&gt;Add Group functions&lt;/h3&gt;
&lt;p&gt;Wrap the two endpoints in different groups.
Name one group &lt;code&gt;Contacts flow&lt;/code&gt; and another &lt;code&gt;Coinflip game&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;//import necessary modules
import http from &amp;#39;k6/http&amp;#39;;
import { group, sleep } from &amp;#39;k6&amp;#39;;

//set baseURL
const baseUrl = &amp;#39;https://test.k6.io&amp;#39;;

export default function () {
  // visit some endpoints in one group
  group(&amp;#39;Contacts flow&amp;#39;, function () {
    http.get(`${baseUrl}/contacts.php`);
    sleep(1);
    // return to the home page
    http.get(`${baseUrl}/`);
    sleep(1);
  });

  // Coinflip players in another group
  group(&amp;#39;Coinflip game&amp;#39;, function () {
    http.get(`${baseUrl}/flip_coin.php?bet=heads`);
    sleep(1);
    http.get(`${baseUrl}/flip_coin.php?bet=tails`);
    sleep(1);
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&#34;run-and-filter&#34;&gt;Run and filter&lt;/h3&gt;
&lt;p&gt;Inspect the results for only the &lt;code&gt;Coinflip game&lt;/code&gt; group.
To do so:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Save the preceding script as &lt;code&gt;multiple-flows.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run the script with the command:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run multiple-flows.js --out json=results.json --iterations 10&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Inspect the results with &lt;code&gt;jq&lt;/code&gt;. Group names have a &lt;code&gt;::&lt;/code&gt; prefix.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;jq &amp;#39;. | select(.data.tags.group == &amp;#34;::Coinflip game&amp;#34;)&amp;#39; results.json&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;add-a-custom-metric&#34;&gt;Add a custom metric&lt;/h2&gt;
&lt;p&gt;As you have seen in the output, all k6 tests emit metrics.
However, if the built-in metrics aren&amp;rsquo;t enough, you can 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/metrics/create-custom-metrics/&#34;&gt;create custom metrics&lt;/a&gt;.
A common use case is to collect metrics of a particular scope of your test.&lt;/p&gt;
&lt;p&gt;As an example, create a metric that collects latency results for each group:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Import 
    &lt;a href=&#34;/docs/k6/v2.3.x/javascript-api/k6-metrics/trend/&#34;&gt;&lt;code&gt;Trend&lt;/code&gt;&lt;/a&gt; from the k6 metrics module.&lt;/li&gt;
&lt;li&gt;Create two duration trend metric functions.&lt;/li&gt;
&lt;li&gt;In each group, add the &lt;code&gt;duration&lt;/code&gt; time to the trend for requests to &lt;code&gt;contacts&lt;/code&gt; and the &lt;code&gt;coin_flip&lt;/code&gt; endpoints.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;//import necessary modules
import http from &amp;#39;k6/http&amp;#39;;
import { group, sleep } from &amp;#39;k6&amp;#39;;
import { Trend } from &amp;#39;k6/metrics&amp;#39;;

//set baseURL
const baseUrl = &amp;#39;https://test.k6.io&amp;#39;;

// Create custom trend metrics
const contactsLatency = new Trend(&amp;#39;contacts_duration&amp;#39;);
const coinflipLatency = new Trend(&amp;#39;coinflip_duration&amp;#39;);

export default function () {
  // Put visits to contact page in one group
  let res;
  group(&amp;#39;Contacts flow&amp;#39;, function () {
    // save response as variable
    res = http.get(`${baseUrl}/contacts.php`);
    // add duration property to metric
    contactsLatency.add(res.timings.duration);
    sleep(1);

    res = http.get(`${baseUrl}/`);
    // add duration property to metric
    contactsLatency.add(res.timings.duration);
    sleep(1);
  });

  // Coinflip players in another group

  group(&amp;#39;Coinflip game&amp;#39;, function () {
    // save response as variable
    let res = http.get(`${baseUrl}/flip_coin.php?bet=heads`);
    // add duration property to metric
    coinflipLatency.add(res.timings.duration);
    sleep(1);

    res = http.get(`${baseUrl}/flip_coin.php?bet=tails`);
    // add duration property to metric
    coinflipLatency.add(res.timings.duration);
    sleep(1);
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Run the test with small number of iterations and output the results to &lt;code&gt;results.json&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run multiple-flows.js --out json=results.json --iterations 10&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Look for the custom trend metrics in the end-of-test console summary.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;coinflip_duration..............: avg=119.6438  min=116.481  med=118.4755 max=135.498  p(90)=121.8459 p(95)=123.89565
contacts_duration..............: avg=125.76985 min=116.973  med=120.6735 max=200.507  p(90)=127.9271 p(95)=153.87245&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can also query custom metric results from the JSON results. For example, to get the aggregated results as.&lt;/p&gt;



  

  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;avg&#34;&gt;avg&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;min&#34;&gt;min&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;2&#34; data-label=&#34;max&#34;&gt;max&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;avg&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-avg&#34;&gt;jq &amp;#39;. | select(.type == &amp;#34;Point&amp;#34; and .metric == &amp;#34;coinflip_duration&amp;#34;) | .data.value&amp;#39; results.json | jq -s &amp;#39;add/length&amp;#39;&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;min&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-min&#34;&gt;jq &amp;#39;. | select(.type == &amp;#34;Point&amp;#34; and .metric == &amp;#34;coinflip_duration&amp;#34;) | .data.value&amp;#39; results.json | jq -s min&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;max&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-max&#34;&gt;jq &amp;#39;. | select(.type == &amp;#34;Point&amp;#34; and .metric == &amp;#34;coinflip_duration&amp;#34;) | .data.value&amp;#39; results.json | jq -s max&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;In this tutorial, you looked at granular output and filtered by built-in and custom tags.
Then you made a new script with groups.
Finally, you added a new metric for each group.
A next step would be to create a 
    &lt;a href=&#34;/docs/k6/v2.3.x/results-output/end-of-test/custom-summary/&#34;&gt;Custom end-of-test summary&lt;/a&gt; or to 
    &lt;a href=&#34;/docs/k6/v2.3.x/results-output/real-time/#service&#34;&gt;stream the results to a database&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For ongoing operations, you can modularize your logic and configuration.
That&amp;rsquo;s the subject of the 
    &lt;a href=&#34;/docs/k6/v2.3.x/examples/get-started-with-k6/reuse-and-re-run-tests/&#34;&gt;next step of this tutorial&lt;/a&gt;.&lt;/p&gt;
]]></content><description>&lt;h1 id="analyze-results">Analyze results&lt;/h1>
&lt;p>In this tutorial, learn how to:&lt;/p>
&lt;ul>
&lt;li>Apply tags to filter specific results&lt;/li>
&lt;li>Learn about k6 metrics&lt;/li>
&lt;li>Use &lt;a href="https://jqlang.github.io/jq/" target="_blank" rel="noopener noreferrer">jq&lt;/a> to filter JSON results&lt;/li>
&lt;li>Define groups to organize the test&lt;/li>
&lt;li>Create custom metrics&lt;/li>
&lt;/ul>
&lt;h2 id="context-k6-result-outputs">Context: k6 result outputs&lt;/h2>
&lt;p>k6 provides many
&lt;a href="/docs/k6/v2.3.x/results-output/">result outputs&lt;/a>.
By default, the
&lt;a href="/docs/k6/v2.3.x/results-output/end-of-test/">end-of-test summary&lt;/a> provides the aggregated results of the test metrics.&lt;/p></description></item><item><title>Reuse and re-run tests</title><link>https://grafana.com/docs/k6/v2.3.x/examples/get-started-with-k6/reuse-and-re-run-tests/</link><pubDate>Mon, 21 Sep 2026 15:16:28 +0000</pubDate><guid>https://grafana.com/docs/k6/v2.3.x/examples/get-started-with-k6/reuse-and-re-run-tests/</guid><content><![CDATA[&lt;h1 id=&#34;reuse-and-re-run-tests&#34;&gt;Reuse and re-run tests&lt;/h1&gt;
&lt;p&gt;In the previous tutorials, you designed k6 scripts to assert performance and make comparing results easy.&lt;/p&gt;
&lt;p&gt;In this tutorial, learn how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modularize test scripts into reusable components&lt;/li&gt;
&lt;li&gt;Dynamically configure scripts with environment variables&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;example-script&#34;&gt;Example script&lt;/h2&gt;
&lt;p&gt;For fun, let&amp;rsquo;s combine the scripts from the previous tutorials.
Use the logic of the &lt;code&gt;multiple-flows.js&lt;/code&gt; test with the thresholds and scenario of the &lt;code&gt;api-test.js&lt;/code&gt; (feel free to add more checks, requests, groups, and so on).
Take note of the features of this script:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;default&lt;/code&gt; function has two groups, &lt;code&gt;Contacts flow&lt;/code&gt;, and &lt;code&gt;Coinflip game&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;options&lt;/code&gt; object has two properties, &lt;code&gt;thresholds&lt;/code&gt; and &lt;code&gt;scenarios&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the following sections, learn how to split these components into separate files, and combine them dynamically at run time.&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { group, sleep } from &amp;#39;k6&amp;#39;;
import { Trend } from &amp;#39;k6/metrics&amp;#39;;

//define configuration
export const options = {
  scenarios: {
    //arbitrary name of scenario:
    breaking: {
      executor: &amp;#39;ramping-vus&amp;#39;,
      stages: [
        { duration: &amp;#39;10s&amp;#39;, target: 20 },
        { duration: &amp;#39;50s&amp;#39;, target: 20 },
        { duration: &amp;#39;50s&amp;#39;, target: 40 },
        { duration: &amp;#39;50s&amp;#39;, target: 60 },
        { duration: &amp;#39;50s&amp;#39;, target: 80 },
        { duration: &amp;#39;50s&amp;#39;, target: 100 },
        { duration: &amp;#39;50s&amp;#39;, target: 120 },
        { duration: &amp;#39;50s&amp;#39;, target: 140 },
        //....
      ],
    },
  },
  //define thresholds
  thresholds: {
    http_req_failed: [{ threshold: &amp;#39;rate&amp;lt;0.01&amp;#39;, abortOnFail: true }], // availability threshold for error rate
    http_req_duration: [&amp;#39;p(99)&amp;lt;1000&amp;#39;], // Latency threshold for percentile
  },
};

//set baseURL
const baseUrl = &amp;#39;https://test.k6.io&amp;#39;;

// Create custom trends
const contactsLatency = new Trend(&amp;#39;contacts_duration&amp;#39;);
const coinflipLatency = new Trend(&amp;#39;coinflip_duration&amp;#39;);

export default function () {
  // Put visits to contact page in one group
  let res;
  group(&amp;#39;Contacts flow&amp;#39;, function () {
    // save response as variable
    res = http.get(`${baseUrl}/contacts.php`);
    // add duration property to metric
    contactsLatency.add(res.timings.duration);
    sleep(1);

    res = http.get(`${baseUrl}/`);
    // add duration property to metric
    contactsLatency.add(res.timings.duration);
    sleep(1);
  });

  // Coinflip players in another group

  group(&amp;#39;Coinflip game&amp;#39;, function () {
    // save response as variable
    let res = http.get(`${baseUrl}/flip_coin.php?bet=heads`);
    // add duration property to metric
    coinflipLatency.add(res.timings.duration);
    sleep(1);

    res = http.get(`${baseUrl}/flip_coin.php?bet=tails`);
    // add duration property to metric
    coinflipLatency.add(res.timings.duration);
    sleep(1);
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id=&#34;modularize-logic&#34;&gt;Modularize logic&lt;/h2&gt;
&lt;p&gt;With 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/modules/&#34;&gt;modules&lt;/a&gt;, you can use logic and variables from other files.
Use modules to extract the functions to their own files.&lt;/p&gt;
&lt;p&gt;To do so, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Copy the previous script (&lt;code&gt;whole-tutorial.js&lt;/code&gt;) and save it as &lt;code&gt;main.js&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Extract the &lt;code&gt;Contacts flow&lt;/code&gt; group function from &lt;code&gt;main.js&lt;/code&gt; script file and paste it into a new file called &lt;code&gt;contacts.js&lt;/code&gt;&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;
&lt;!-- eslint-disable no-undef  --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export function contacts() {
  group(&amp;#39;Contacts flow&amp;#39;, function () {
    // save response as variable
    let res = http.get(`${baseUrl}/contacts.php`);
    // add duration property to metric
    contactsLatency.add(res.timings.duration);
    sleep(1);

    res = http.get(`${baseUrl}/`);
    // add duration property to metric
    contactsLatency.add(res.timings.duration);
    sleep(1);
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;!-- eslint-enable no-undef  --&gt;
&lt;p&gt;As is, this script won&amp;rsquo;t work, since it has undeclared functions and variables.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the necessary imports and variables. This script uses the &lt;code&gt;group&lt;/code&gt;, &lt;code&gt;sleep&lt;/code&gt;, and &lt;code&gt;http&lt;/code&gt; functions or libraries. It also has a custom metric. Since this metric is specific to the group, you can add it &lt;code&gt;contacts.js&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, pass &lt;code&gt;baseUrl&lt;/code&gt; as a parameter of the &lt;code&gt;contacts&lt;/code&gt; function.&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { Trend } from &amp;#39;k6/metrics&amp;#39;;
import { group, sleep } from &amp;#39;k6&amp;#39;;

const contactsLatency = new Trend(&amp;#39;contact_duration&amp;#39;);

export function contacts(baseUrl) {
  group(&amp;#39;Contacts flow&amp;#39;, function () {
    // save response as variable
    let res = http.get(`${baseUrl}/contacts.php`);
    // add duration property to metric
    contactsLatency.add(res.timings.duration);
    sleep(1);

    res = http.get(`${baseUrl}/`);
    // add duration property to metric
    contactsLatency.add(res.timings.duration);
    sleep(1);
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Repeat the process with the &lt;code&gt;coinflip&lt;/code&gt; group in a file called &lt;code&gt;coinflip.js&lt;/code&gt;.
Use the tabs to see the final three files should (&lt;code&gt;options&lt;/code&gt; moved to the bottom of &lt;code&gt;main.js&lt;/code&gt; for better readability).&lt;/p&gt;



  

  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;main&#34;&gt;main&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;contacts&#34;&gt;contacts&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;2&#34; data-label=&#34;coinflip&#34;&gt;coinflip&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;main&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-main&#34;&gt;import { contacts } from &amp;#39;./contacts.js&amp;#39;;
import { coinflip } from &amp;#39;./coinflip.js&amp;#39;;

const baseUrl = &amp;#39;https://test.k6.io&amp;#39;;

export default function () {
  // Put visits to contact page in one group
  contacts(baseUrl);
  // Coinflip players in another group
  coinflip(baseUrl);
}

//define configuration
export const options = {
  scenarios: {
    //arbitrary name of scenario:
    breaking: {
      executor: &amp;#39;ramping-vus&amp;#39;,
      stages: [
        { duration: &amp;#39;10s&amp;#39;, target: 20 },
        { duration: &amp;#39;50s&amp;#39;, target: 20 },
        { duration: &amp;#39;50s&amp;#39;, target: 40 },
        { duration: &amp;#39;50s&amp;#39;, target: 60 },
        { duration: &amp;#39;50s&amp;#39;, target: 80 },
        { duration: &amp;#39;50s&amp;#39;, target: 100 },
        { duration: &amp;#39;50s&amp;#39;, target: 120 },
        { duration: &amp;#39;50s&amp;#39;, target: 140 },
        //....
      ],
    },
  },
  //define thresholds
  thresholds: {
    http_req_failed: [{ threshold: &amp;#39;rate&amp;lt;0.01&amp;#39;, abortOnFail: true }], // availability threshold for error rate
    http_req_duration: [&amp;#39;p(99)&amp;lt;1000&amp;#39;], // Latency threshold for percentile
  },
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;contacts&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-contacts&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { Trend } from &amp;#39;k6/metrics&amp;#39;;
import { group, sleep } from &amp;#39;k6&amp;#39;;

const contactsLatency = new Trend(&amp;#39;contact_duration&amp;#39;);

export function contacts(baseUrl) {
  group(&amp;#39;Contacts flow&amp;#39;, function () {
    // save response as variable
    let res = http.get(`${baseUrl}/contacts.php`);
    // add duration property to metric
    contactsLatency.add(res.timings.duration);
    sleep(1);

    res = http.get(`${baseUrl}/`);
    // add duration property to metric
    contactsLatency.add(res.timings.duration);
    sleep(1);
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;coinflip&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-coinflip&#34;&gt;import http from &amp;#39;k6/http&amp;#39;;
import { Trend } from &amp;#39;k6/metrics&amp;#39;;
import { group, sleep } from &amp;#39;k6&amp;#39;;

const coinflipLatency = new Trend(&amp;#39;coinflip_duration&amp;#39;);

export function coinflip(baseUrl) {
  group(&amp;#39;Coinflip game&amp;#39;, function () {
    // save response as variable
    let res = http.get(`${baseUrl}/flip_coin.php?bet=heads`);
    // add duration property to metric
    coinflipLatency.add(res.timings.duration);
    sleep(1);
    // mutate for new request
    res = http.get(`${baseUrl}/flip_coin.php?bet=tails`);
    // add duration property to metric
    coinflipLatency.add(res.timings.duration);
    sleep(1);
  });
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Run the test:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;# setting the workload to 10 iterations to limit run time
k6 run main.js --iterations 10&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The results should be very similar to running the script in a combined file, since these are the same test.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;modularize-workload&#34;&gt;Modularize workload&lt;/h2&gt;
&lt;p&gt;Now that the iteration code is totally modularized, you might modularize your &lt;code&gt;options&lt;/code&gt;, too.&lt;/p&gt;
&lt;p&gt;The following example creates a module &lt;code&gt;config.js&lt;/code&gt; to export the threshold and workload settings.&lt;/p&gt;



  

  


&lt;div data-element=&#34;tabs&#34;&gt;
  &lt;div data-element=&#34;tabs-bar&#34;&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;0&#34; data-label=&#34;main&#34;&gt;main&lt;/div&gt;
    
      &lt;div data-element=&#34;tab&#34; data-key=&#34;1&#34; data-label=&#34;config&#34;&gt;config&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div data-element=&#34;tab-content&#34;&gt;
    
&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;main&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-main&#34;&gt;import { coinflip } from &amp;#39;./coinflip.js&amp;#39;;
import { contacts } from &amp;#39;./contacts.js&amp;#39;;
import { thresholdsSettings, breakingWorkload } from &amp;#39;./config.js&amp;#39;;

export const options = {
  scenarios: { breaking: breakingWorkload },
  thresholds: thresholdsSettings,
};

const baseUrl = &amp;#39;https://test.k6.io&amp;#39;;

export default function () {
  contacts(baseUrl);
  coinflip(baseUrl);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;config&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-config&#34;&gt;export const thresholdsSettings = {
  http_req_failed: [{ threshold: &amp;#39;rate&amp;lt;0.01&amp;#39;, abortOnFail: true }],
  http_req_duration: [&amp;#39;p(99)&amp;lt;1000&amp;#39;],
};

export const breakingWorkload = {
  executor: &amp;#39;ramping-vus&amp;#39;,
  stages: [
    { duration: &amp;#39;10s&amp;#39;, target: 20 },
    { duration: &amp;#39;50s&amp;#39;, target: 20 },
    { duration: &amp;#39;50s&amp;#39;, target: 40 },
    { duration: &amp;#39;50s&amp;#39;, target: 60 },
    { duration: &amp;#39;50s&amp;#39;, target: 80 },
    { duration: &amp;#39;50s&amp;#39;, target: 100 },
    { duration: &amp;#39;50s&amp;#39;, target: 120 },
    { duration: &amp;#39;50s&amp;#39;, target: 140 },
    //....
  ],
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Notice the length of this final script and compare it with the script at the beginning of this page.
Though the final execution is the same, it&amp;rsquo;s half the size and more readable.&lt;/p&gt;
&lt;p&gt;Besides shortness, this modularity lets you compose scripts from many parts, or dynamically configure scripts at run time.&lt;/p&gt;
&lt;h2 id=&#34;mix-and-match-logic&#34;&gt;Mix and match logic&lt;/h2&gt;
&lt;p&gt;With modularized configuration and logic, you can define named scenarios for different workloads and 
    &lt;a href=&#34;/docs/k6/v2.3.x/using-k6/scenarios/#run-selected-scenarios&#34;&gt;select one with &lt;code&gt;--scenario&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Change &lt;code&gt;main.js&lt;/code&gt; and &lt;code&gt;config.js&lt;/code&gt; to define a smoke test with five iterations and a breaking test, then choose the workload when you run the script.&lt;/p&gt;
&lt;p&gt;To do this, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add the workload settings for configuring the smoke test to &lt;code&gt;config.js&lt;/code&gt;:&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;export const smokeWorkload = {
  executor: &amp;#39;shared-iterations&amp;#39;,
  iterations: 5,
  vus: 1,
};

export const thresholdsSettings = {
  http_req_failed: [{ threshold: &amp;#39;rate&amp;lt;0.01&amp;#39;, abortOnFail: true }],
  http_req_duration: [&amp;#39;p(99)&amp;lt;1000&amp;#39;],
};

export const breakingWorkload = {
  executor: &amp;#39;ramping-vus&amp;#39;,
  stages: [
    { duration: &amp;#39;10s&amp;#39;, target: 20 },
    { duration: &amp;#39;50s&amp;#39;, target: 20 },
    { duration: &amp;#39;50s&amp;#39;, target: 40 },
    { duration: &amp;#39;50s&amp;#39;, target: 60 },
    { duration: &amp;#39;50s&amp;#39;, target: 80 },
    { duration: &amp;#39;50s&amp;#39;, target: 100 },
    { duration: &amp;#39;50s&amp;#39;, target: 120 },
    { duration: &amp;#39;50s&amp;#39;, target: 140 },
    //....
  ],
};&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Edit &lt;code&gt;main.js&lt;/code&gt; to define a named scenario for each workload:&lt;/p&gt;
&lt;!-- md-k6:skip --&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;JavaScript&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-javascript&#34;&gt;import { coinflip } from &amp;#39;./coinflip.js&amp;#39;;
import { contacts } from &amp;#39;./contacts.js&amp;#39;;
import { thresholdsSettings, breakingWorkload, smokeWorkload } from &amp;#39;./config.js&amp;#39;;

export const options = {
  scenarios: {
    smoke: smokeWorkload,
    breaking: breakingWorkload,
  },
  thresholds: thresholdsSettings,
};

const baseUrl = &amp;#39;https://test.k6.io&amp;#39;;

export default function () {
  contacts(baseUrl);
  coinflip(baseUrl);
}&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the smoke test:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run --scenario smoke main.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When you want to run the breaking test, select that workload instead:&lt;/p&gt;

&lt;div class=&#34;code-snippet &#34;&gt;&lt;div class=&#34;lang-toolbar&#34;&gt;
    &lt;span class=&#34;lang-toolbar__item lang-toolbar__item-active&#34;&gt;Bash&lt;/span&gt;
    &lt;span class=&#34;code-clipboard&#34;&gt;
      &lt;button x-data=&#34;app_code_snippet()&#34; x-init=&#34;init()&#34; @click=&#34;copy()&#34;&gt;
        &lt;img class=&#34;code-clipboard__icon&#34; src=&#34;/media/images/icons/icon-copy-small-2.svg&#34; alt=&#34;Copy code to clipboard&#34; width=&#34;14&#34; height=&#34;13&#34;&gt;
        &lt;span&gt;Copy&lt;/span&gt;
      &lt;/button&gt;
    &lt;/span&gt;
    &lt;div class=&#34;lang-toolbar__border&#34;&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;div class=&#34;code-snippet &#34;&gt;
    &lt;pre data-expanded=&#34;false&#34;&gt;&lt;code class=&#34;language-bash&#34;&gt;k6 run --scenario breaking main.js&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Always select the intended workload for this example. Without &lt;code&gt;--scenario&lt;/code&gt;, k6 runs both scenarios, including the breaking test.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This was a simple example to showcase how you can modularize a test.
As your test suite grows and more people are involved in performance testing, your modularization strategy becomes essential to building and maintaining an efficient testing suite.&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next steps&lt;/h2&gt;
&lt;p&gt;Now you&amp;rsquo;ve seen examples to write tests, assert for performance, filter results, and modularize scripts.
Notice how the tests progress in complexity: from single endpoints to holistic tests, from small to large loads, and from single tests to reusable modules. These progressions are typical in testing, with the next step being to automate. It might be impractical to automate a tutorial, but if you are interested,
read the 
    &lt;a href=&#34;/docs/k6/v2.3.x/testing-guides/automated-performance-testing/&#34;&gt;Automated performance testing&lt;/a&gt; guide.&lt;/p&gt;
&lt;p&gt;More likely, you want to learn more about k6. The &lt;a href=&#34;https://github.com/grafana/k6-learn&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;k6-learn repository&lt;/a&gt; has more details to practice.
Or, you can read and explore the 
    &lt;a href=&#34;/docs/k6/v2.3.x/testing-guides/&#34;&gt;testing guides&lt;/a&gt; and try to build out your testing strategy.&lt;/p&gt;
&lt;p&gt;Happy testing!&lt;/p&gt;
]]></content><description>&lt;h1 id="reuse-and-re-run-tests">Reuse and re-run tests&lt;/h1>
&lt;p>In the previous tutorials, you designed k6 scripts to assert performance and make comparing results easy.&lt;/p>
&lt;p>In this tutorial, learn how to:&lt;/p></description></item></channel></rss>