taverntesting / tavern

A command-line tool and Python library and Pytest plugin for automated testing of RESTful APIs, with a simple, concise and flexible YAML-based syntax
https://taverntesting.github.io/
MIT License
1.02k stars 192 forks source link

Question about list slicing in response validaton using tavern.request_vars #937

Open adrpp opened 2 months ago

adrpp commented 2 months ago

Hello,

having a request consisting of top-level object holding a list, how do I refer to such list element in response validation using "{tavern.request_vars}" ?

tavern version: 2.11.0

example:

- name: some test
    request:
      url: <truncated>
      method: POST
      json:
        requestBodyList:
          - complexListElement:
              attribute: some_value
    response:
      status_code: 200
      json:
        responseBodyList:
          - attribute: "{tavern.request_vars.json.requestBodyList[0].attribute}" 

Output (with the syntax above, e.g. "{tavern.request_vars.json.requestBodyList[0].attribute}" ):

Errors:
E   tavern._core.exceptions.MissingFormatError: tavern.request_vars.json.requestBodyList[0].attribute
------------------------------ Captured log call -------------------------------
ERROR    tavern._core.dict_util:dict_util.py:41 Failed to resolve string '{tavern.request_vars.json.requestBodyList[0].attribute}' 
ERROR    tavern._core.dict_util:dict_util.py:44 Key(s) not found in format: tavern.request_vars.json.requestBodyList[0].attribute

Tested the other notation mentioned in docs, thing.nested.0, gives String.Formatter error, as mentioned in docs, this got most probably deprecated up from 1.0 version, e.g.

...
response:
      status_code: 200
      json:
        responseBodyList:
          - attribute: "{tavern.request_vars.json.requestBodyList.0.attribute}" 
field_name = 'tavern.request_vars.json.requestBodyList.0.attribute', args = []
kwargs = <truncated>

    def get_field(self, field_name, args, kwargs):
        first, rest = _string.formatter_field_name_split(field_name)

        obj = self.get_value(first, args, kwargs)

        # loop through the rest of the field_name, doing
        #  getattr or getitem as needed
        for is_attr, i in rest:
            if is_attr:
>               obj = getattr(obj, i)
E               AttributeError: 'BoxList' object has no attribute '0'

Didn't find an example for this in the docs, besides of https://tavern.readthedocs.io/en/latest/basics.html#response -> "thing.nested[0]" , however this applies to save keyword/section.

Is there known way how to achieve list slicing while using tavern.request_vars in the response.json section ?

Thanks for any hint, Regards, Adrian

michaelboulton commented 2 months ago

I've added some more tests/examples in https://github.com/taverntesting/tavern/pull/938 for this, it should work - I'm guessing it's not your actual data but in the example you've posted it's probably because you're missing the complexListElement element and it should be:

    response:
      status_code: 200
      json:
        responseBodyList:
          - attribute: "{tavern.request_vars.json.requestBodyList[0].complexListElement.attribute}" 

I don't know if there is a way this could be made more obvious to the end user though, it should already print what format vars are available if you have debug logging turned on

adrpp commented 1 month ago

Hi @michaelboulton,

sorry for the response delay in first place :) In meanwhile I've refactored the code to call custom callable to flatten the response object, so I had to refactor it back to be able to confirm that what you've written works well too :)

thanks for the support