We want to execute component test using Karate against a SpringBoot application that uses application-demo.yml to set it´s properties. For example (application-demo.yml):
...
services:
database:
host: localhost
port: 5432
spring:
datasource:
jdbcUrl: jdbc:database://${services.database.host}:${services.database.port}/database
...
Our Karate code is included within the same repo so that we can execute our component tests using a runner as part of the same CI/CD that will bring up the SprintBoot application.
We do have karate.env set to a specific environment (in this case "demo") In our karate-config.js we set common values in the config object (for example, baseURL of the SpringBoot application)
...
let config = {
baseUrl: 'http://localhost:8082'
};
...
Then in our environment specific karate config (karate-config-demo.js), we have additional parameters to be set in the config object. We wanted to avoid duplication of properties so we took the springboot application-demo.yml as the source of the new parameters.
...
const configYaml = karate.read('classpath:application-demo.yml');
let config = {
database: {
jdbcUrl: configYaml.spring.datasource.jdbcUrl
...
}
};
...
By doing this, karate config object will contain values like this:
database.jdbcUrl = jdbc:database://${services.database.host}:${services.database.port}/database
which is a problem as it is not replacing the placeholders with the corresponding values from the yml file.
Got a couple of questions:
As per the documentation, we can see the config object is "merged" between karate-config and karate-config-demo, so a combined object will be available for the feature files (overriding key/values if already exist). But if we try to print the content of that karate config object we can see it only shows the properties set in that karate-config-demo.js but will not show the ones from karate-config.js Is there any way to access to ALL the properties set in that config object from karate-config-demo.js ?
To workaround the placeholder issue, we decided to use a Javascript function that takes a json object (config) and the yml and then replaces the placeholders ${} with the corresponding values from the yml. That function is defined in a separate file (let´s say js/replace.js) and contains a function that takes two arguments: function fn(jsonData, yamlData) and returns a json object. That json object will be used by karate-config-demo.js to return the config object as the output of the function. Something like this:
let replacePlaceholders = karate.read('classpath:js/replace.js');
config = replacePlaceholders(config, configYaml);
return config;
The problem we see is that the json objects sent as parameter to the replace function are "transformed" and they are no longer json objects within the function. rinting the jsonData at the beginning of the replace function we see this
{database={jdbcUrl=jdbc:database://${services.database.host}:${services.database.port}/database}}
We cannot parse it into a json as it´s not a proper json object. We were able to make it work by sending the string representation (JSON.stringify) of the json as parameters instead of the json object. In the javascript function we had to parse it again to json (JSON.parse). Is there any way to avoid this double transformation by passing proper json object to the javascript function ? What´s the reason of that json transformation... or are we doing something wrong here ?
Tried different options to send the json objects as parameters but no luck. They are always transformed to non-json objects.