karatelabs / karate

Test Automation Made Simple
https://karatelabs.github.io/karate
MIT License
8.09k stars 1.94k forks source link

DynamicObject<JSFunction> context error when using karate.callSingle and karate.merge in karate-config.js #1883

Closed hueller closed 1 year ago

hueller commented 2 years ago

I know that there have already been several bug reports related to DynamicObject context errors, but I'm still able to reproduce an issue also against the current Karate develop branch.

Please find attached my sample project, which contains two Maven projects:

To reproduce the issue, first myproject-helpers needs to be built (mvn install) and then UsersRunner in myproject can be executed: mvn test -Dtest=UsersRunner

The two .feature files in myproject-helpers are used in the following way in myproject:

utils.feature gets called via call read in the first scenario of users.feature, which in general works fine:

* def uuidUtils = call read('classpath:examples/helpers/utils.feature@getUUIDUtils')
* print uuidUtils.getRandomUUID()

However, it stops working with the DynamicObject context error, when I try to include the second .feature file markers.feature via karate-config.js. This markers.feature file contains a self-validating expression, which I want to make 'globally' available by merging it into the config object:

// Read marker scenarios and merge them into config to make them globally available
var dateMarkers = karate.callSingle('classpath:examples/helpers/markers.feature@getDateMarkers');
config = karate.merge(config, dateMarkers);

karate.callSingle alone doesn't seem to cause an issue. But when also karate.merge gets called, the above mentioned call read('classpath:examples/helpers/utils.feature@getUUIDUtils') fails with the DynamicObject context error.

I have no idea why this is happening and if there are other options to make self-validating expressions globally available, so I appreciate your help! Thanks a lot!

Archive.zip

ptrthomas commented 2 years ago

@hueller my first reaction is that this will be hard - so I'm going to come back to this later. my advice would be to make any "common" routines you need Java code since I am assuming (just speed reading the above) that you are trying to re-use stuff across 2 java maven modules - which will be a challenge in pure JS

some relevant discussion and work-arounds here (sorry, long read): https://github.com/karatelabs/karate/issues/1558

the other reason why I will not rush to solve this is that Graal issue number 631 (see link above) may solve this horrible JS limitation once and for all. I need to find time to upgrade karate's graal dep and remove all the ugly JS context-swapping code we have right now

hueller commented 2 years ago

Ok thanks, but how can I use Java code for common routines without declaring them within JavaScript functions in .feature files? That's what I'm already doing in the attached example:

@ignore
Feature: Utils scenarios

  @getUUIDUtils
  Scenario: UUID Utils
    * def getRandomUUID =
  """
    function() {
      return java.util.UUID.randomUUID() + ''
    }
  """

And yes, what I want to achieve is to define common routines in one shared Maven module, which I can include in multiple concrete Karate projects. As mentioned above, this is working in general, but the additional usage of karate.callSingle and karate.merge in karate-config.js to include shared self-validating expressions seems to brake the whole thing (I forgot to mention in my first post that this was working in old Nashorn times with Karate 0.9.x).

Also the #? EXPR marker seems to work with JavaScript expressions only what I can read in the docs.

ptrthomas commented 2 years ago

@hueller you can reuse java easily because it just needs to be on the classpath. please refer: https://stackoverflow.com/a/58339662/143475

hueller commented 2 years ago

Ok, thanks! Looking forward for the Karate release which includes the Graal VM fix.

For now I'll try to implement a workaround to not rely on the karate.merge call anymore (which seems to break my setup) and also on using Java for reusable functions/methods.

pshrm commented 2 years ago

@ptrthomas - I am trying to migrate my common utilities JS functions to Java. I use couple of JS functions provided by karate currently. e.g., karate.prevRequest is there a way to replicated them in Java directly?

ptrthomas commented 2 years ago

@pshrm karate.prevRequest is Java behind the scenes so I don't understand your question. you are welcome to look at the source code and figure it out: https://github.com/karatelabs/karate/blob/v1.2.0.RC1/karate-core/src/main/java/com/intuit/karate/core/ScenarioBridge.java#L521

ptrthomas commented 2 years ago

tagging a reference for some planned refactoring: https://github.com/oracle/graal/issues/631#issuecomment-885768584

ptrthomas commented 2 years ago

@hueller I think this is finally fixed ! I haven't tried your sample project yet, and if you can use the develop branch and see if things work fine including karate.merge() that will save me a bit of time

ptrthomas commented 1 year ago

1.3.0 released