Menu
Grafana Cloud

Create a k6 scripted check

This tutorial shows how to create your first k6 scripted check.

k6 scripted checks use the k6 OSS engine in the background, and give you the flexibility to create checks with complex logic and workflows by writing a JavaScript script.

In this tutorial you will:

  • Create a k6 scripted check using the test-api.k6.io service. The check will:
    • Generate the details for a random user.
    • Register a new user in the test application.
    • Log in to the test application.
    • Add a crocodile object to the user’s list, then delete it.
    • Log out.
  • Set up assertions for each request to ensure they’re working as expected.

Before you begin

Note

This tutorial uses the test-api.k6.io service, which is a public shared environment. You can use it and follow along this tutorial, but it’s recommended to avoid high-load tests. The service is also open source if you’d like to deploy a private instance.

Create a k6 scripted check

To create a k6 scripted check:

  1. Open your Grafana instance.
  2. On the left-hand menu, select Testing & Synthetics.
  3. Click Synthetics.
  4. Click Add new check.
  5. Select Scripted.

After that, you will see the Add Scripted check page where you can configure your new check. The first step is to define the check:

  1. Fill out Job name and Instance.
  2. Click Probes.

Next, you have to configure the Probes, which represent the locations where you want to run your test from, and how frequent you want your check to run:

  1. Select at least one probe from the Probe locations drop-down.
  2. You can leave the Frequency and Timeout fields with the default values.
  3. Click Script.

Register and log in to an application

The Script section is where you can configure the specific endpoints you want the k6 scripted check to test. The check comes with an example script that you can use as a starting point.

For this tutorial, the first step is to make a log in request to the test-api.k6.io application. One advantage of using a scripted check is that you can generate a random name for your user. To do that, edit the default script:

JavaScript
import { check } from 'k6';
import http from 'k6/http';
import { randomString, randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';

export default function () {
  // Generate user info
  const first_name = randomString(10);
  const last_name = randomString(10);
  const email = `${first_name}.${last_name}@test.com`;
  const password = randomString(10);
}

Next, you can make a request to the user/register endpoint by using the variables you created, as well as set up an assertion to ensure your request returns a 201 HTTP status code:

JavaScript
import { check } from 'k6';
import http from 'k6/http';
import { randomString, randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';

export default function () {
  // Generate user info
  const first_name = randomString(10);
  const last_name = randomString(10);
  const email = `${first_name}.${last_name}@test.com`;
  const password = randomString(10);

  // STEP 1: Register a new user
  let response = http.post('https://test-api.k6.io/user/register/', {
    first_name,
    last_name,
    username: email,
    email,
    password,
  });

  check(response, {
    '1. User registration': (r) => r.status === 201,
  }) || fail(`User registration failed with ${response.status}`);
}

It’s important to set up assertions for each request you make. That way you can have Synthetic Monitoring automatically validate things such as the response code from your request, or that the response body includes a specific property and value.

Next, you can make a POST request to the auth/cookie/login endpoint to log in to the test-api.k6.io application with the new user you just created:

JavaScript
import { check } from 'k6';
import http from 'k6/http';
import { randomString, randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';

export default function () {
  // Generate user info
  const first_name = randomString(10);
  const last_name = randomString(10);
  const email = `${first_name}.${last_name}@test.com`;
  const password = randomString(10);

  // STEP 1: Register a new user
  let response = http.post('https://test-api.k6.io/user/register/', {
    first_name,
    last_name,
    username: email,
    email,
    password,
  });

  check(response, {
    '1. User registration': (r) => r.status === 201,
  }) || fail(`User registration failed with ${response.status}`);

  // STEP 2: Autheticate
  response = http.post('https://test-api.k6.io/auth/cookie/login/', { username: email, password });

  check(response, {
    '2a. login successful': (r) => r.status === 200,
    '2b. user name is correct': (r) => r.json('first_name') === first_name,
    '2c. user email is correct': (r) => r.json('email') === email,
  });
}

Similar to the first request, you can set up assertions to make sure the log in request returns a 200 HTTP status code, and that the user name and email match the ones your script automatically generated.

Note that this login call will create a session cookie, which is needed to authenticate subsequent calls. k6 handles the session cookie just as a browser would. It transparently manages the receipt, storage, and transmission of cookies.

Create and delete an object

The next step is to configure a POST call to create a crocodile in the test application, and then grab the newly created crocodile ID to use in the next request and delete it.

JavaScript
import { check } from 'k6';
import http from 'k6/http';
import { randomString, randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';

export default function () {
  // Generate user info
  const first_name = randomString(10);
  const last_name = randomString(10);
  const email = `${first_name}.${last_name}@test.com`;
  const password = randomString(10);

  // STEP 1: Register a new user
  let response = http.post('https://test-api.k6.io/user/register/', {
    first_name,
    last_name,
    username: email,
    email,
    password,
  });

  check(response, {
    '1. User registration': (r) => r.status === 201,
  }) || fail(`User registration failed with ${response.status}`);

  // STEP 2: Autheticate
  response = http.post('https://test-api.k6.io/auth/cookie/login/', { username: email, password });

  check(response, {
    '2a. login successful': (r) => r.status === 200,
    '2b. user name is correct': (r) => r.json('first_name') === first_name,
    '2c. user email is correct': (r) => r.json('email') === email,
  });

  // STEP 3: Create a "crocodile" object
  const name = randomString(10);
  const sex = ['M', 'F'][randomIntBetween(0, 1)];
  const date_of_birth = new Date().toISOString().split('T')[0];

  response = http.post('https://test-api.k6.io/my/crocodiles/', { name, sex, date_of_birth });

  const id = parseInt(response.json('id'));
  check(response, {
    '3a. Crocodile created and has and id': (r) => r.status === 201 && id && id > 0,
    '3b. Crocodile name is correct': (r) => r.json('name') === name,
  });

  // STEP 4: Delete the "crocodile"
  // (The http.url helper will group distinct URLs together in the metrics)
  response = http.del(http.url`https://test-api.k6.io/my/crocodiles/${id}/`);
  check(response, {
    '4a. Crocodile was deleted': (r) => r.status === 204,
  });
}

Note

For the DELETE endpoint, the examples uses an additional method named http.url. This is important because of how Synthetic Monitoring and active series work.

Active series are a concept specific to Grafana Cloud Metrics. They represent a time series that has received data within the last 30 minutes. If your script includes a unique URL, which is the case for the delete endpoint since it includes the unique crocodile ID at the end, it’ll create a new time series for it. That can have an impact on your billing, and in how easy it is to visualize your results when you’re querying the data from your check runs.

By using the http.url method, you can make the DELETE request to the correct endpoint, while making sure that the check metrics will be grouped together by the URL without the unique ID.

Log out of an application

The final step is to log out of the application. To do that, add another request to your script:

JavaScript
import { check } from 'k6';
import http from 'k6/http';
import { randomString, randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';

export default function () {
  // Generate user info
  const first_name = randomString(10);
  const last_name = randomString(10);
  const email = `${first_name}.${last_name}@test.com`;
  const password = randomString(10);

  // STEP 1: Register a new user
  let response = http.post('https://test-api.k6.io/user/register/', {
    first_name,
    last_name,
    username: email,
    email,
    password,
  });

  check(response, {
    '1. User registration': (r) => r.status === 201,
  }) || fail(`User registration failed with ${response.status}`);

  // STEP 2: Autheticate
  response = http.post('https://test-api.k6.io/auth/cookie/login/', { username: email, password });

  check(response, {
    '2a. login successful': (r) => r.status === 200,
    '2b. user name is correct': (r) => r.json('first_name') === first_name,
    '2c. user email is correct': (r) => r.json('email') === email,
  });

  // STEP 3: Create a "crocodile" object
  const name = randomString(10);
  const sex = ['M', 'F'][randomIntBetween(0, 1)];
  const date_of_birth = new Date().toISOString().split('T')[0];

  response = http.post('https://test-api.k6.io/my/crocodiles/', { name, sex, date_of_birth });

  const id = parseInt(response.json('id'));
  check(response, {
    '3a. Crocodile created and has and id': (r) => r.status === 201 && id && id > 0,
    '3b. Crocodile name is correct': (r) => r.json('name') === name,
  });

  // STEP 4: Delete the "crocodile"
  // (The http.url helper will group distinct URLs together in the metrics)
  response = http.del(http.url`https://test-api.k6.io/my/crocodiles/${id}/`);
  check(response, {
    '4a. Crocodile was deleted': (r) => r.status === 204,
  });

  // STEP 5: Logout
  response = http.post(`https://test-api.k6.io/auth/cookie/logout/`);
  check(response, {
    '5a. Logout successful': (r) => r.status === 200,
  });
}

Next, click Test at the end of the screen to make sure your check is working correctly, and then click Save.

Your check will now run from the probe locations that you selected, and with the default frequency value. Your check will make sure that the endpoints you configured are working correctly, and if you have any issues, you will be able to see them in your check dashboard.

Next steps

Now that you have a k6 scripted check configured, you can:

  • Refer to Check types to get more information about the metrics and options available for the k6 scripted check type.
  • Refer to Analyze results to learn more about how you can visualize and analyze the data collected by your check
  • Refer to Synthetic Monitoring alerting to learn how to create and configure alerts in case your check fails.
  • Refer to the Grafana Cloud k6 documentation to learn about performance testing, and how you can reuse the same script you created in this tutorial to run a performance test.