Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Karate v1.3.x regression: karate.keysOf(), karate.valuesOf(), and karate.filterKeys() behave incorrectly within a JavaScript function #2224

Closed
nathanchilton opened this issue Dec 20, 2022 · 10 comments
Assignees
Milestone

Comments

@nathanchilton
Copy link

nathanchilton commented Dec 20, 2022

Description

Note: I am also seeing this behavior in 1.4.0.RC2

We are attempting to upgrade from Karate v1.1.0 to v1.3.1, but one more thing is holding me back:

The behavior of karate.keysOf(), karate.valuesOf(), and karate.filterKeys() is incorrect when these are used inside of a JavaScript function.

In Karate v1.1.0 and v1.2.0, the behavior of these methods inside a JavaScript function would match the behavior in a basic Karate step, but this is not the case with Karate v1.3.1.

The attached tests will pass with Karate v1.1.0 and v1.2.0, but will fail with v1.3.1.
The 4th scenario will always pass, because it does not contain any assertions. It just makes it easy to see the difference in behavior by logging the output of these different ways of calling karate.keysOf(), karate.valuesOf(), and karate.filterKeys().

Note:
My original example was more complicated, but as I have worked with this more, I see that the problem is even easier to demonstrate and is a bigger problem for us than I originally realized.

Scenarios for demonstration of problem

Feature: Reproduce LinkedHashMap bug

  Background:
    * def key_value_pairs = {a: 1, b: 2, c: 3}

  Scenario: Test that karate.keysOf() behaves the same inside and outside of a JavaScript function
    * def test_keysOf =
      """
      function test_keysOf(key_value_pairs) {
        return karate.keysOf(key_value_pairs)
      }
      """
    * match test_keysOf(key_value_pairs) == karate.keysOf(key_value_pairs)

  Scenario: Test that karate.valuesOf() behaves the same inside and outside of a JavaScript function
    * def test_keysOf =
      """
      function test_keysOf(key_value_pairs) {
        return karate.valuesOf(key_value_pairs)
      }
      """
    * match test_keysOf(key_value_pairs) == karate.valuesOf(key_value_pairs)

  Scenario: Test that karate.filterKeys() behaves the same inside and outside of a JavaScript function
    * def test_keysOf =
      """
      function test_keysOf(key_value_pairs, keys_to_keep) {
        return karate.filterKeys(key_value_pairs, keys_to_keep)
      }
      """
    * match test_keysOf(key_value_pairs, ['a', 'c']) == karate.filterKeys(key_value_pairs, ['a', 'c'])

  Scenario: Demonstrate problem with karate.keysOf(), karate.valuesOf(), and karate.filterKeys() by logging, without assertion

    # Log the keys, values, and result of running 'filterKeys'
    * karate.log("karate.keysOf(key_value_pairs)", karate.keysOf(key_value_pairs))
    * karate.log("karate.valuesOf(key_value_pairs)", karate.valuesOf(key_value_pairs))
    * karate.log("karate.filterKeys(key_value_pairs, ['a', 'c'])", karate.filterKeys(key_value_pairs, ['a', 'c']))

    # the output of "eval" will match the behavior of the Karate steps shown above
    * eval
      """
      karate.log("karate.keysOf(key_value_pairs)", karate.keysOf(key_value_pairs))
      karate.log("karate.valuesOf(key_value_pairs)", karate.valuesOf(key_value_pairs))
      karate.log("karate.filterKeys(key_value_pairs, ['a', 'c'])", karate.filterKeys(key_value_pairs, ['a', 'c']))
      """

    # Here is the bug, the behavior is all wrong, when run from inside a JavaScript function
    * def log_key_value_pairs =
      """
      function log_key_value_pairs(key_value_pairs) {
        karate.log("karate.keysOf(key_value_pairs)", karate.keysOf(key_value_pairs))
        karate.log("karate.valuesOf(key_value_pairs)", karate.valuesOf(key_value_pairs))
        karate.log("karate.filterKeys(key_value_pairs, ['a', 'c'])", karate.filterKeys(key_value_pairs, ['a', 'c']))
      }
      """
    * log_key_value_pairs(key_value_pairs)
@nathanchilton nathanchilton changed the title Karate v1.3.x regression: Exception thrown when using karate.valuesOf() within a JavaScript function Karate v1.3.x regression: karate.valuesOf() behaves incorrectly within a JavaScript function Dec 21, 2022
@nathanchilton nathanchilton changed the title Karate v1.3.x regression: karate.valuesOf() behaves incorrectly within a JavaScript function Karate v1.3.x regression: karate.keysOf(), karate.valuesOf(), and karate.filterKeys() behave incorrectly within a JavaScript function Dec 21, 2022
@nathanchilton
Copy link
Author

When using these methods from within a JavaScript function in Karate v1.3.1, karate.keysOf(key_value_pairs) returns an array of strings which appear to be method names:

[
  "get",
  "values",
  "clear",
  "replaceAll",
  "entrySet",
  "forEach",
  "keySet",
  "containsValue",
  "getOrDefault",
  "remove",
  "put",
  "clone",
  "isEmpty",
  "replace",
  "size",
  "merge",
  "putAll",
  "putIfAbsent",
  "compute",
  "containsKey",
  "computeIfAbsent",
  "computeIfPresent",
  "equals",
  "toString",
  "hashCode"
]

and karate.valuesOf(key_value_pairs) returns essentially the same list of methods, but with the class as well:

[
  "java.util.LinkedHashMap.get",
  "java.util.LinkedHashMap.values",
  "java.util.LinkedHashMap.clear",
  "java.util.LinkedHashMap.replaceAll",
  "java.util.LinkedHashMap.entrySet",
  "java.util.LinkedHashMap.forEach",
  "java.util.LinkedHashMap.keySet",
  "java.util.LinkedHashMap.containsValue",
  "java.util.LinkedHashMap.getOrDefault",
  "java.util.LinkedHashMap.remove",
  "java.util.LinkedHashMap.put",
  "java.util.LinkedHashMap.clone",
  "java.util.LinkedHashMap.isEmpty",
  "java.util.LinkedHashMap.replace",
  "java.util.LinkedHashMap.size",
  "java.util.LinkedHashMap.merge",
  "java.util.LinkedHashMap.putAll",
  "java.util.LinkedHashMap.putIfAbsent",
  "java.util.LinkedHashMap.compute",
  "java.util.LinkedHashMap.containsKey",
  "java.util.LinkedHashMap.computeIfAbsent",
  "java.util.LinkedHashMap.computeIfPresent",
  "java.util.LinkedHashMap.equals",
  "java.util.LinkedHashMap.toString",
  "java.util.LinkedHashMap.hashCode"
]

@nathanchilton
Copy link
Author

I suspect that the problem is not these functions, but is the fact that we are receiving a java.util.LinkedHashMap object in the JavaScript functions

@ptrthomas
Copy link
Member

possible similar issue reported here: https://stackoverflow.com/q/75008620/143475

@ptrthomas
Copy link
Member

@nathanchilton fixed. do see if you can test by building locally

ptrthomas added a commit that referenced this issue Jan 8, 2023
ptrthomas added a commit that referenced this issue Jan 9, 2023
@ptrthomas
Copy link
Member

as a note for anyone coming across this in future, the pure JS equivalents such as Object.keys(), Object.entries() etc should now work fine.

@ptrthomas
Copy link
Member

@nathanchilton 1.4.0.RC3 has been released, please try it and let us know

@nathanchilton
Copy link
Author

@ptrthomas Thank you! I will take a look and confirm that it is working.

@nathanchilton
Copy link
Author

@ptrthomas I just tested with 1.4.0.RC3 and I can confirm that the issue has been resolved. Thank you!

@ptrthomas
Copy link
Member

@nathanchilton great, thanks for the feedback !

@ptrthomas
Copy link
Member

I'll re-open this, as the process we follow is it is fixed but closed only when the official 1.4.0 release is out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants