k6

Pass Variable from one function to another in load test using K6


New to K6, for benchmarking my http request I am using K6 in my pipeline. Now here is my code which have two section

first section is responsible for creating an user and second is trying updating the same user using a profileID which is generated as a part of first request.

import http from "k6/http";
import { check, sleep, group } from "k6";
import { Trend } from "k6/metrics";

import { LOGIN_URL, BASE_URL } from "../test/support/constants/endpoints.js";
import {
  generateSampleUserDataFinal,
  generateRandomPhoneNumber,
  generateRandomOrganisationContactID,
  generateRandomUserTypeId,
} from "../test/support/data/perf.sampledata.js";


let TC01_CreateNewUser = new Trend("TC01_CreateNewUser");
let TC02_UpdateExistingUser = new Trend("TC02_UpdateExistingUser");

function login() {
  let authResponse = http.post(`${LOGIN_URL}`);
  let authData = authResponse.json().data;
  if (!authData) {
    console.error("Login failed: ", authResponse.body);
  }
  return authData;
}

function generateRandomSleepTimer() {
  let sleepTime = Math.floor(Math.random() * 3 + 1);
  return parseInt(sleepTime);
}


export function createNewUser(
  authToken,
  sleepTime,
  generateSampleUserData
) {
  group("TC01: Create a new User", function () {
    const response = http.post(
      `${BASE_URL}/User`,
      generateSampleUserData,
      {
        headers: {
          Authorization: authToken,
          "Content-Type": "application/json",
        },
        tags: { name: "Create a new User" },
      }
    );
    const responseDuration = response.timings.duration;
    TC01_CreateNewUser.add(responseDuration);
    console.log("Response: ", response.body);
    profileId = JSON.parse(response.body).data;
    const checkResult = check(response, {
      "is status 200": (r) => r.status === 200,
    });
    let responseMessage;
    try {
      responseMessage = response.json();
    } catch (e) {
      console.error("Failed to parse JSON response: ", response.body);
    }
    check(responseMessage, {
      "Success!": (r) => r && r.message === "Success!",
    });
    sleep(sleepTime);
   return  profileId ;
  });
}


 export function updateExistingUser(authToken, sleepTime, profileId) {
   group("TC02: Update an existing User", function () {
      console.log("Profile ID: ====> : ", profileId);
      const response = http.put(
       `${BASE_URL}/User`,
       {
         UserProfileID: `${profileId}`,
         organisationContactID: `${generateRandomOrganisationContactID()}`,
         name: "Performnace Benchmark Testing",
         UserTypeID: `${generateRandomUserTypeId()}`,
         email: "perftest@test.com",
         phoneNumber: `${generateRandomPhoneNumber()}`
       },
       {
         headers: {
           Authorization: authToken,
           "Content-Type": "application/json",
         },
         tags: { name: "Update an existing User" },
       }
     );
     const responseDuration = response.timings.duration;
     TC02_UpdateExistingUser.add(responseDuration);
     console.log("Response: ", response.body);
     const checkResult = check(response, {
       "is status 200": (r) => r.status === 200,
     });
     let responseMessage;
     try {
       responseMessage = response.json();
     } catch (e) {
       console.error("Failed to parse JSON response: ", response.body);
     }
     check(responseMessage, {
       "Success!": (r) => r && r.message === "Success!",
     });
     sleep(sleepTime);
   });
 }
 
 
 export default function () {
  const authToken = login();
  if (!authToken) {
    console.error("No auth token, exiting test");
    return;
  }
  const sleepTime = generateRandomSleepTimer();
  const UserProfileID = generateRandomUserProfileID();
  let generateSampleUserData = generateSampleUserDataFinal(); //This is function which generate a random payload
  let profileId;

  createNewUser(authToken, sleepTime, generateSampleUserData);
  updateExistingUser(authToken, sleepTime, profileId);
}

Getting response for first section

INFO[0001] Response:  {"responseCode":200,"message":"Success!","data":"372"}  source=console
INFO[0002] Response:  {"responseCode":200,"message":"Success!","data":"373"}  source=console
INFO[0003] Response:  {"responseCode":200,"message":"Success!","data":"374"}  source=console

but for second I am getting

INFO[0003] Profile ID: ====> undefined           source=console 

How to fix this issue ? How I can user data handler to pass data between the function. In JMeter usually I can use a post processer to capture the value and use it further.


Solution

  • let profileId;
    
    createNewUser(authToken, sleepTime, generateSampleUserData);
    updateExistingUser(authToken, sleepTime, profileId);
    

    You are never assigning a value to your variable profileId, which means it will keep its default value of undefined.

    Similarly, you are not returning a value from your function createNewUser. You are only return a value from your anonymous function passed as the second argument to group, but you never do anything with the return value:

    export function createNewUser(
      authToken,
      sleepTime,
      generateSampleUserData
    ) {
      group("TC01: Create a new User", function () {
        const response = …
        profileId = JSON.parse(response.body).data;
        // …
        return profileId ;
      });
    }
    

    group already returns the return value of the anonymous function, but you need to return it from createNewUser too. Also note that profileId is not declared (e.g. with var, let, or const), which means it will be a global variable.

    So putting it altogether to have a working script:

    export function createNewUser(
        authToken,
        sleepTime,
        generateSampleUserData) {
      return group("TC01: Create a new User", function () {
        const response = …
        const profileId = JSON.parse(response.body).data;
        // …
        return profileId ;
      });
    }
    
    export default function () {
      // …
      const profileId = authToken, sleepTime, generateSampleUserData);
      updateExistingUser(authToken, sleepTime, profileId);
    }
    

    This has nothing to do with k6 specifically, but follows the general rules of JavaScript: variables only have values if you assign a value to them and you need to return values from functions if you want to use them in the subsequent steps. Needless to say, variables and constants are scoped to the body of their function; you cannot modify them from unrelated functions and variable a declared in function f is independent from variable a declared in function g.