Hello there,
TLDR: I have a few test cases that share a code, and there are some issues accessing exported methods.
There are some tests that access the Keycloak App through the API (could be any other application), so I wrote a simple client that wraps some common methods and it’s available as a class in a standalone file keycloak.js:
export class Keycloak {
/**
* Creates a keycloak client from the server URL and params.
*
* Currently, accepted params:
* - offlineTokens (boolean): request offline tokens instead of regular refresh tokens
* @param {String} keycloakURL the keycloak server URL
* @param {String} adminUsername Master real admin user username
* @param {String} adminPassword Master real admin user password
*/
constructor(keycloakURL, adminUsername, adminPassword) {
this.keycloakURL = keycloakURL;
this.username = adminUsername;
this.password = adminPassword;
this.populatedRealms = [];
}
// Some other methods
// ...
dropTestAssets() {
let accessToken = this.getMasterAccessToken();
for (let i = 0; i < this.populatedRealms.length; i++) {
let realmDeletionResponse = http.delete(
this.customEndpoint(`/auth/admin/realms/${this.populatedRealms[i].id}`),
{},
{
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${accessToken}`
}
});
check(realmDeletionResponse, {
'Was realm deleted?': (resp) => resp.status === 201,
});
}
this.populatedRealms = [];
}
}
My idea is to import this client every time I would write a new test, so I can reuse its methods:
import {check} from 'k6';
import {
getTestConfig,
Keycloak,
} from "./keycloak.js";
const config = getTestConfig();
export let options = {
insecureSkipTLSVerify: true,
summaryTimeUnit: 'ms',
setupTimeout: '5m',
teardownTimeout: '5m',
thresholds: {
'http_req_duration{status:200}': ['max>=0'],
'http_req_duration{status:201}': ['max>=0'],
'http_req_duration{status:400}': ['max>=0'],
'http_req_duration{status:401}': ['max>=0'],
'http_req_duration{status:403}': ['max>=0'],
'http_req_duration{status:429}': ['max>=0'],
'http_req_duration{status:500}': ['max>=0'],
'http_req_duration{status:502}': ['max>=0'],
},
summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(90)', 'p(95)', 'p(99)', 'p(99.99)', 'count'],
};
export function setup() {
let keycloak = new Keycloak(config.keycloakURL, config.username, config.password);
check(keycloak, {
'Built Keycloak client': () => (keycloak != null),
})
let realmsNumber = 1;
let clientsPerRealm = 10;
let usersPerRealm = 100;
let realms = keycloak.populateTestAssets(realmsNumber, clientsPerRealm, usersPerRealm);
return {
keycloakClient: keycloak,
loadedRealms: realms,
}
}
export default function (toolbox) {
toolbox.keycloakClient.dropTestAssets() // <--- Fails there
}
export function teardown(toolbox) {
check(toolbox.keycloakClient, {
'Is client available?': () => (toolbox.keycloakClient != null),
})
toolbox.keycloakClient.dropTestAssets() // <--- Fails there
}
But once I initialized the client in the setup()
method and returned it to be available in the execution in the teardown
function I’m always getting an error:
ERRO[0009] TypeError: Object has no member 'dropTestAssets'
default ✓ [======================================] 1 VUs 1s
at teardown (file:///Users/some/path/is/hidden/keycloak_dummy_k6.js:58:4(15))
at native hint="script exception"
Feels like it’s not able to access the method (am I missing a keyword public
) or do I need to implicitly cast the object to the Keycloak
class?
I would appreciate any kind of feedback, thanks!