How would I go about executing multiple script files in a single run?

Development team has provided Postman collection for performance testing. There would be around 20 collection. Each collection represents end to end micro services. I am using Postman to K6 converter. It gives me 20 JS files. VU level , stages/options and threshold/ checks needs to be different for each K6 JS file. This project would be added inside Git. We need to define pipeline to execute all the JS files.

APPROACH 1

I decide to write let’s say start.js and then call all other 20 JS files within start.js. I will invoke start.js from Git yml file.
Sample start.js looks as below-

import "./PostmanScripts/libs/shim/core.js";
import "./PostmanScripts/libs/shim/urijs.js";

import { group, http, sleep } from 'k6';
import startSiteTest from "./PostmanScripts/Test/Site/startSiteTest.js";

export let options = {
  stages: testData.siteCRUDOptions,
  teardownTimeout: testData.teardownTimeout,
  thresholds: testData.thresholds
}

postman[Symbol.for("initial")]({
  options,
  collection: {
  },
  environment: {
    AUTH0_BASE_URL: `${__ENV.AUTH0_BASE_URL}`,
  }
});

export default function () {
  //Call Test Collection 1 - Create Site
  startSiteTest();
  sleep(2);
  startFreeTrailTest();
}

However,
postman[Symbol.for("initial")]({

has to be declared once. It is mandatory that it contains VU options. Due to this, I cannot define options, VU stages, threshold inside individual JS files.

I want something like below to achieve my goal. However, it is not working.
Inside Start.js –
I will add
postman[Symbol.for("initial")]({

Here I will define all the environment variables.

In each individual JS file, lets say test.js I will define following.

    import http from "k6/http";

    import * as testData from "../../TestData/siteCRUDOptions.js";

    export let options = {
      stages: [
        { duration: "10s", target: 2 },
        { duration: "10s", target: 3 },
      ]
    }


    export default function() {
      console.log("ENV " +  `${__ENV.AUTH0_BASE_URL}`);
      http.get("http://test.loadimpact.com");
    };

Now, I will call start.js from Git.
However, with this approach VU would not get spanned. It seems not allowed. Everytime, test.js or any other file gets called only with 1 VU and 1 Iteration.

APPROACH 2

Create shell script, lets say start.sh. It contains all the JS files calls. Invoke start.js from Git, define it in yml file

k6 run PostmanScripts/Test/Site/test.js
k6 run PostmanScripts/Test/Site/test2.js

APPROACH 3

Write a docker compose script. This would start up a docker container for each test and run it inside there

    services:
      k6_test:
        image: loadimpact/k6
        container_name: test_k6
        command: k6 run /tests/test_spec.js

      k6_test2:
        image: loadimpact/k6
        container_name: test2_k6
        command: k6 run /tests/test2_spec.js

Which would be the better approach? Is there any other way?

Adding @Murat

Thank you for posting ! :pray:t3:

Let me see if I got this right. You’d like to be able to split your tests into multiple files and execute them as a test suite, right?

You’re on the right track with both of your alternatives, however; only the default function and options of the entry file will be read, as you’ve noticed. To go around this, you’d need to manually execute the default function of the other test files from your entry files default function.

I’ve provided a working example below, showcasing what you’re trying to accomplish.

start.js

import http from "k6/http";
import { sleep, check } from "k6";
import runTestOne from "./test1.js";
import runTestTwo from "./test2.js";

export default function() {
    runTestOne();
    runTestTwo();
};

It imports the exported default function from each test file and runs them as part of the default function of start.js. Your actual test files would then look a little something like this:

test1.js

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

export default function() {
  let res = http.get("http://test.loadimpact.com");
  sleep(1);

  check(res, {
      "status is 200": (r) => r.status === 200,
      "response body": (r) => r.body.indexOf("Feel free to browse")
  });
}

test2.js

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

export default function() {
  let res = http.get("http://something-else.example.com");
  sleep(1);

  check(res, {
      "status is 200": (r) => r.status === 200,
      "response body": (r) => r.body.indexOf("Im something completely different")
  });
}

Feel free to reply to this thread if you need any additional assistance. :+1:t2:

1 Like

how about the test1.js and test2.js options function, how can i set the distribution of test1.js to run stagesA and test2.js to run stagesB?

1 Like

You currently can’t at least not easily. You can try to approximate things by keeping time internally in the VUs, but it will probably be a bit flaky. Test suites / execute multiple scripts with k6 · Issue #1342 · grafana/k6 · GitHub is a proposal in how we can quickly implement that soon after https://github.com/loadimpact/k6/pull/1007 is done.

1 Like

@simme thanks a lot!! is there also the possibility to return parameters from runTestOne() and pass as parameter to runTestTwo()? For example: first test is a login script and it returns accessToken to be passed to the other functions

No worries!

Is there also the possibility to return parameters from runTestOne() and pass as parameter to runTestTwo() ? For example: first test is a login script and it returns accessToken to be passed to the other functions

Sure! Just return it from runTestOnce and assign it to a const or let as part of the logic in the default function.

1 Like

thanks!! With this possibility i can make my tests more modular.

1 Like

I found that export function setup() is never called if it specified in test1.js or test2.js
Is it expected behavior?

Correct! The same goes for the setup function. Only the one exported from the entrypoint will be executed. If you want to split it up per test, you’ll have to do it the same way as with the different test functions, that is, import it into your entrypoint and run it as part of that setup function, like:

import { setup as setupOne } from './test1.js'
import { setup as setupTwo } from './test2.js'

export function setup() {
  setupOne();
  setupTwo();
}

The multi-scenario capabilities of the new k6 v0.27.0 should make this much more natural:

3 Likes

Hey @simme need a help I am doing performance testing and used the similar method as define in start.js but the problem is each test.js file has its
export default option how should i include that in the file calling all the tests cases.

@Murtaza-Multan

You wouldn’t. :sweat_smile: Only one options variable per k6 run I’m afraid. However, I’d recommend that you check out the approach suggested by @ned instead, as it comes with a lot of benefits.

Best, Simme

Thanks for the response @simme. I have already implement Scenarios in my code but still, the issue remains intact. As each scenario needs to get authenticated using the certificate and we can pass one tls Auth certificate in options variable that means single cert per k6 run. :slightly_frowning_face:

Yeah… and I think what everyone is looking for is what LoadRunner can do - and what you HAVE to do to run good performance tests.

If you’re testing a banking application where two services share a database… Lets say you’re testing transfer and account summary…

You cannot validate account summary performance on it’s own… I mean you can do that… and see what impact it has independently… but the fact is that you are testing the system in a way that it will NEVER be used. Yes it has value for isolating things but at some point , you have to put 4 or 5 people in the car and drive it - not just the driver… (to continue the car analogy) I want suitcases, luggage racks… underinflated tires… etc… That’s the real world… So… especially when two services share a database, you MUST test the “real” scenario eventually in the test cycle.

It’s important to be able to orchestrate a concurrent scenario of scenarios… Understand that the [concurrent] mix of those scenarios… is a new scenario…

Hi friend, thank you in advance for any help you can provide.
I have a few questions:

  1. Is there a way to control the number of requests for test1 and test2? If yes, how?

  2. Is there a way to just call start.js one time per Vuser? if yes, how?

Hi @DiegoCommunityKsix,
welcome to the community forum :tada:, sorry for the late reply.

Is there a way to control the number of requests for test1 and test2? If yes, how?

Scenarios are the way for defining it, check the documentation for details.

Is there a way to just call start.js one time per Vuser? if yes, how?

Check Test lifecycle for understanding more about the k6 script parts, everything executed in init code will run once per VU.

Please, the next time consider opening a new topic if you haven’t something direct to add to the marked solution.

Hi @simme , thank you so much for the example, I could implement this on my script. i have a question related to HTML report, I put this script

export function handleSummary(data) {
return {
“GlobalReport.html”: htmlReport(data),
stdout: textSummary(data, { indent: " ", enableColors: true }),
};
}

on each file hoping that when I run the start.js, the report will be generated for all the files but the actual result only report for start.js was generated. is there a way to generate the report for all the files in order to have a general report and detail report for each test1 and test2?

Thank you :pray: