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

Path variable being concatenated #1990

Closed
snow23man opened this issue Apr 22, 2022 · 19 comments
Closed

Path variable being concatenated #1990

snow23man opened this issue Apr 22, 2022 · 19 comments
Labels

Comments

@snow23man
Copy link

When you use a "helper feature file" and call it from your main feature file in a scenario, the "path" variable is being concatenated. Resetting doesn't change the result, neither does using a different variable than path in the scenario.
In version 1.1.0 you could essentially re-use the path variable without problems, however on version 1.2.0.RC6 there is this concatenation issue.
I've attached 2 basic features that reproduce the issue.
Inside the main feature the url and path get set. The helper feature file will read those and work no problem. However when the scenario from the main feature does it's call instead of being "https://api.publicapis.org/entries", since it gets concatenated it becomes "https://api.publicapis.org/entries.org/entries".
features.zip
.

@ptrthomas
Copy link
Member

@snow23man let me stop you right at the point when you keep referring to path variable.

path is NOT a variable. neither is url. can we clear that up first before you proceed ? you seem to using karate in ways that are not intended or supported.

anyway to try and get to a conclusion sooner, here is my best attempt to interpret what you are trying to do. feel free to build on the example below. the latest version of karate supports a call to a scenario in the same feature. you can cut and paste this into a new feature, and it will actually work (unlike your example):

Feature:

Background:
* def baseUrl = 'https://httpbin.org/'
	
Scenario:
* def result = call read('@called')
* url baseUrl
* path 'anything'
* method get

@ignore @called
Scenario:
* url baseUrl
* path 'get'
* method get

@snow23man
Copy link
Author

snow23man commented Apr 22, 2022

@ptrthomas if it's not intended or supported usage, how come it has been working fine this way for years. That being said, changing to declare a variable of baseUrl in the background of the main feature file and then set the path to that in the helper feature and again setting in the scenario right after the call to the helper feature has worked for both. So thanks for the help in the end, took a long road to get here

@ptrthomas
Copy link
Member

it has been working fine this way for years

I have no problem if you consider it a "bug" (that can be blamed on me if it makes people feel better) which is now fixed. anyway, glad to know you have a way forward

@kdefives
Copy link

kdefives commented May 19, 2022

@snow23man let me stop you right at the point when you keep referring to path variable.

path is NOT a variable. neither is url. can we clear that up first before you proceed ? you seem to using karate in ways that are not intended or supported.

anyway to try and get to a conclusion sooner, here is my best attempt to interpret what you are trying to do. feel free to build on the example below. the latest version of karate supports a call to a scenario in the same feature. you can cut and paste this into a new feature, and it will actually work (unlike your example):

Feature:

Background:
* def baseUrl = 'https://httpbin.org/'
	
Scenario:
* def result = call read('@called')
* url baseUrl
* path 'anything'
* method get

@ignore @called
Scenario:
* url baseUrl
* path 'get'
* method get

Thanks for your suggestion @ptrthomas :-)
Nevertheless, i have the feeling that this way to do is not usefull. In fact, in your example, you declare an "ignored" Scenario that will be called by other Scenario inside the same Feature. Ok.
But imagine we have multiple Feature (around 50 for instances), which means that we could have 50 .feature files. All my feature need to call the same endpoint everytime, for instance to generate a clean JWT token. Then, using your example, it means i will have to duplicate the "ignored called" scenario on each of my Feature? It seems not the best.

It is an idea/suggestion, but i think it could be over usefull to externalize "ignored called" scenario inside a dedicated .feature file which could be called by all other .feature file is needed. As it works perfectly with Karate version <= 1.1.0.

Anyway, i think i found a solution to cover this need, i could use "url" parameter only including the path inside instead of using "path" parameter. Like this at it seems to avoid the concatenaion issue with the "path" parameter:
Given url my_url + "/" + my_path

Instead of:

Given url my_url
Given path my_path

I do not know if it is correct but it seems to works.

Regards,

@ptrthomas
Copy link
Member

@kdefives I'm sorry I don't follow, your description is confusing. I'll pick one line out of your comment and respond to that if it helps.

All my feature need to call the same endpoint everytime

that's simple, just use a variable like everybody else. I don't see the problem.

@kdefives
Copy link

kdefives commented May 19, 2022

@kdefives I'm sorry I don't follow, your description is confusing. I'll pick one line out of your comment and respond to that if it helps.

All my feature need to call the same endpoint everytime

that's simple, just use a variable like everybody else. I don't see the problem.

I cannot use a variable, because each distinct call must generate a unique JWT token dynamically.

I will try to explain what i do with a simple example, sorry in advance if it is not clear enough:

Feature file A:

Feature:

Background:
* def baseUrl = my_url_to_test
	
Scenario:
* def token = call read('./jwt-generator.feature@called-to-generate-jwt')
* And def unique_token_value = token.response.value
* And header Authorization = 'Bearer ' + unique_token_value 
* url baseUrl
* path 'anything'
* method get

Feature file B:

Feature:

Background:
* def baseUrl = my_url_to_test
	
Scenario:
* def token = call read('./jwt-generator.feature@called-to-generate-jwt')
* And def unique_token_value = token.response.value
* And header Authorization = 'Bearer ' + unique_token_value 
* url baseUrl
* path 'anything-else'
* method get

Feature file JWT token generator (jwt-generator.feature):

@ignore
Feature:

Background:
* def baseUrl = my_url_generator_jwt

@called-to-generate-jwt	
Scenario:
* url baseUrl
* path 'token'
* method get

If i follow your suggestion, i have to duplicate the content of jwt-generator.feature inside each of my *.feature to test.

@ptrthomas
Copy link
Member

@kdefives still confused. but if you mean the JWT URL is different, you can pass arguments to call:

* def token = call read('./jwt-generator.feature@called-to-generate-jwt') { baseUrl: 'blah' }

@kdefives
Copy link

kdefives commented May 19, 2022

Yes but it is not avoiding the problem of concatenation using path parameter. Because if i am executing this code, then the http call did by the Scenario @called-to-generate-jwt will be [my_url_generator_jw]/anything/token' instead of [my_url_generator_jw]/token'

We do not understand why the path parameter from Scenario of Feature file A is concatenated to the path of Scenario @called-to-generate-jwt

The workaround i found below:

Feature file A:

Feature:

Background:
* def baseUrl = my_url_to_test
	
Scenario:
* def token = call read('./jwt-generator.feature@called-to-generate-jwt')
* And def unique_token_value = token.response.value
* And header Authorization = 'Bearer ' + unique_token_value 
* url baseUrl + '/anything'
* method get

Feature file B:

Feature:

Background:
* def baseUrl = my_url_to_test
	
Scenario:
* def token = call read('./jwt-generator.feature@called-to-generate-jwt')
* And def unique_token_value = token.response.value
* And header Authorization = 'Bearer ' + unique_token_value 
* url baseUrl + '/anything-else'
* method get

Feature file JWT token generator (jwt-generator.feature):

@ignore
Feature:

Background:
* def baseUrl = my_url_generator_jwt

@called-to-generate-jwt	
Scenario:
* url baseUrl + '/token'
* method get

Avoid using path parameter and concatenate manually using url parameter.

@ptrthomas
Copy link
Member

@kdefives I mean that you should also not have that Background section in jwt-generator.feature at all. let the baseUrl be set completely by the call argument. did you try this at all ?

I'm sorry if you need more discussion, submit a proper way to replicate: https://github.com/karatelabs/karate/wiki/How-to-Submit-an-Issue

@kdefives
Copy link

kdefives commented May 19, 2022

@ptrthomas your solution is working too. 👍 ==> Update: The solution is finally not working.

My implementation below:

Feature file B:

Feature:

Background:
* def baseUrl = my_url_to_test
	
Scenario:
* def token = call read('./jwt-generator.feature@called-to-generate-jwt') { baseUrl: #(mockJwtGeneratorUrl) }
* And def unique_token_value = token.response.value
* And header Authorization = 'Bearer ' + unique_token_value 
* url baseUrl
* path 'anything-else'
* method get

Feature file JWT token generator (jwt-generator.feature):

@ignore
Feature:

@called-to-generate-jwt	
Scenario:
* url baseUrl
* path 'token'
* method get

Just to really understand what happened, the problem of concatenation of paths inside Scenario of jwt-generator.feature was due to the "Background" declared inside jwt-generator.feature (side effect)?

@ptrthomas
Copy link
Member

@kdefives I need to check and it certainly can be a bug. it makes it easier if people follow the process, and right now I don't consider it a priority. I also wish that this feedback comes at the time we urge people to try RC releases (for months)

if anyone can replicate this in a way that proves it is a bug, I can open an issue

@kdefives
Copy link

@ptrthomas your solution is working too. 👍 ==> Update: The solution is finally not working.

My implementation below:

Feature file B:

Feature:

Background:
* def baseUrl = my_url_to_test
	
Scenario:
* def token = call read('./jwt-generator.feature@called-to-generate-jwt') { baseUrl: #(mockJwtGeneratorUrl) }
* And def unique_token_value = token.response.value
* And header Authorization = 'Bearer ' + unique_token_value 
* url baseUrl
* path 'anything-else'
* method get

Feature file JWT token generator (jwt-generator.feature):

@ignore
Feature:

@called-to-generate-jwt	
Scenario:
* url baseUrl
* path 'token'
* method get

Just to really understand what happened, the problem of concatenation of paths inside Scenario of jwt-generator.feature was due to the "Background" declared inside jwt-generator.feature (side effect)?

My test was wrong. Finally, using this suggested solution it is still not working. For peoples who faced the same issue, the workaround i found which is working is to use:
Given url my_url + my_path

instead of:
Given url my_url
Given path my_path

Thanks for this discussion which helped me to found this workaround.
Regards

@ptrthomas
Copy link
Member

@kdefives great. yes path is designed to be "magically concatenated" to the URL. this makes writing REST tests easier and I tried to explain this in the docs as best as I can. if you or anyone else has some suggestions on how better I can explain this difference, I am all ears

@cheanwei
Copy link

cheanwei commented Jul 6, 2022

I understood the issue which @kdefives is facing becuase I also facing the same issue. It make senses to magically concatenated the path parameter to the url declared in the same feature file. but it does not make sense to concatenated the path to the url declared in the called feature file. The called feature file has totally different baseUrl which is for token generation.
I think the issue only occured when the called feature file is being triggered using configure headers function such as karate.configure("headers", () => karate.call("jwtTokenGenerator.feature")) in the karate-config.js. In this case, the path declared in another feature file is being concatenated to the token generation url which does not make sense to me at all.

@ptrthomas
Copy link
Member

@cheanwei open a new issue, follow this process and create the SIMPLEST example you possibly can: https://github.com/karatelabs/karate/wiki/How-to-Submit-an-Issue

before that let me say that karate's design is that when you make a call you WILL lose any url or path information already set. if you want to change this please be prepared to contribute code. I hope that is fair. the "problem" you refer to has been reported only by 2-3 people and in my opinion because they misunderstood this design of karate. if it used to work earlier it was a bug. if we make it work again, other (more important) parts of karate will stop working.

if you contribute a fix and it doesn't break any other tests, we can consider including it.

@cheanwei
Copy link

cheanwei commented Jul 6, 2022

@ptrthomas I am new to Karate. I just started to use Karate since version 1.2.0.RC1. In fact I like the design of Karate and agree to lose any url or path information when I make a call to another scenario. This works fine until I update Karate to version 1.2.0. Unfortunately, I don't have time to create the example repo which reproduce the issue now. The temporary solution for me now is to roll back the Karate version to 1.2.0.RC1.

@ptrthomas
Copy link
Member

no worries. there are 3 people in this thread and I still haven't got any idea what the problem is. I'm not spending any more time on this

@ptrthomas ptrthomas mentioned this issue Jul 31, 2022
5 tasks
@ptrthomas
Copy link
Member

tagging #2054 as I think it is relevant to this thread

@ptrthomas
Copy link
Member

all: I'm willing to acknowledge that url should be NOT reset ever, even when calling a feature. you can always force it by hard-coding. when I though about it, this was the original intent and it got lost in discussion and refactoring, my bad.

posted some thoughts here, do comment if you have a PoV: #2202 (comment)

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

No branches or pull requests

4 participants