Value for custom class not printing properly in second file

I am getting problems with using my own Class object in different files, the use case is to load a value in the inital script.js file from another file, then pass this to a function in another file (test.js)
I have defined a custom class as following at the top of script.js:

class NumberStuff{
    val1;
    val2;
    constructor(val1, val2) {
        this.val1 = val1;
        this.val2 = val2;
    }
    get val1(){
        return this.val1;
    }
    set val1(val1){
        this.val1 = val1;
    }
    get val2 (){
        return this.val2;
    }
    set val2(val2){
        this.val2= val2;
    }
}
import { func } from "./test.js";

export const myObj = new NumberStuff(0,0); //exported for use in another file, initially with 0

export function setup(){
    const file = JSON.parse(open("./example.json"));
    let val1_load = file[0].val1;
    let val2_load = file[0].val2;

    myObj.val1 = val1_load ;
    myObj.val2 = val2_load ;
    console.log(`val1: ${myObj.val1}`);
    console.log(`val2: ${myObj.val2}`);
    // both print statements work here in script.js

}

export default function() {
    func(); //call second file here
}

within the second file, here I called it test.js, I simply import and try to print this, for now. this value will be used in some tests.

import { myObj } from "./script.js";

export function numbers() {
    group("Front page", function() {
        console.log(myObj.val1); //prints 0
    }
}

this console log prints me 0, when it should be printing whatever I loaded from the file earlier in the test, either the object was not passed properly, or my understanding of k6 invocation of scripts may be wrong, and the value cannot be passed… or maybe I am overlooking something completely javascript wise.

please advise, as I have tried a lot of different stuff to no avail.

Hi @basilzuberi, welcome to the community forum!

You can’t set the value of a variable in the init stage from the setup() function. You can’t even do that even in much simpler situation like this:

var myObj = "value";

export function setup(){
    myObj = "another value";
}

export default function() {
    console.log(myObj);  // ths will print "value"
}

You can pass values between setup() and default like this (“You can pass only data (i.e. JSON) between setup and the other stages. You cannot pass functions.”):

export function setup(){
    return "another value";
}

export default function(data) {
    console.log(data);  // this will print "another value"
}

Or you can do this, but your data will be instantiated for every VU:

var myObj = initMyObj();

function initMyObj(){
    return "another value";
}

export default function() {
    console.log(myObj);   // this will print "another value"
}

And your script also gave me the error: GoError: the "open" function is only available in the init stage (i.e. the global scope)

I think your best bet would be using SharedArray like this (but in this case the elements of the data array won’t be instances of Numberstuf but rather simple object):

example.json:

[{"val1": 12, "val2": 25}]

script.js:

class NumberStuff{
    val1;
    val2;
    constructor(val1, val2) {
        this.val1 = val1;
        this.val2 = val2;
    }
    get val1(){
        return this.val1;
    }
    set val1(val1){
        this.val1 = val1;
    }
    get val2 (){
        return this.val2;
    }
    set val2(val2){
        this.val2= val2;
    }
}
import { numbers } from "./test.js";
import { SharedArray } from 'k6/data';

export const data = new SharedArray('data', function () {
  const arr = new Array(1);
  const file = JSON.parse(open("./example.json"));
  arr[0] = new NumberStuff(file[0].val1,file[0].val2);
  return arr;
});


export default function() {
  numbers(); //call second file here
}

test.js:

import { data } from "./script.js";

export function numbers() {
    console.log(data[0].val1); //prints 12
}

1 Like

Thank you, we used this solution and it works for us.

1 Like

One quick question regarding changing the value of “data[0].val1”.

if I attempt to do something like this:

import { data } from "./script.js";

export function numbers() {
    let counter = data[0].val1;
    // bunch of tests
    counter = counter + 1;
}

This only increases it by one, and keeping the “let counter” statement above makes counter “undefined”

or even something as simple as:

import { data } from "./script.js";

export function numbers() {
   // bunch of tests using data[0].val1
   data[0].val1 = data[0].val1 + 1;
}

I am getting an error stating something similar to this: TypeError Cannot assign to read only property (value) of object val1. I tried changing the object to become Writable: true using Object.assignProperty within script.js but this does not work either, giving the same error.

my full use-case if it makes sense is: I want to be able to “remember” what the last saved customer ID was that I am testing, so that we do not iterate over these again, until our test environment is clean (hence the loading within shared data… I save the ID information within handleSummary)

Would you happen to know how I can increment this “id” that I am passing onto my tests?

thank you so much for all your help so far.

@basilzuberi

As far as I know SharedArray is the only way to share data between VUs, but as the documentation says: “Once constructed, a SharedArray is read-only, so you can’t use a SharedArray to communicate data between VUs .”

You can find out in the handleSummary,that how many iterations ran during the test. It may help your problem:

export function handleSummary(d){
  console.log("iterations ran:",d.metrics.iterations.values.count)
}