emanualjade / test-openapi

Automatic API integration testing
MIT License
14 stars 4 forks source link

Support for JSON references (IETF standard) in task definitions #5

Open jpettit opened 5 years ago

jpettit commented 5 years ago

Allow tasks to reference any external file (including js functions, other task files, openapi specs, etc) using the $ref notation.

jpettit commented 5 years ago

ehmicky @ehmicky 01:34

At the moment there is no real way to do this. I.e. you would have to perform the signIn function on the CLI before calling test-openapi.

However I've got plans to introduce this feature like this:

Allow using JSON references (IETF standard) in task definitions. I.e. any task could reference any external file (including functions, or other task files) using the $ref notation:

- name: exampleTask
  call:
    headers.authorization:
      $ref: path/to/signin.js

Arguments can be passed by using a sibling property args:

- name: exampleTask
  call:
    headers.authorization:
      $ref: path/to/signin.js
      args: [user@email.com, password]

If any task property is a function, it will be fired with the current task as last argument, and substituted with the return value. For example path/to/signin.js could be:

module.exports = async function(email, password, task) {
  const authorization = await fetchAuthorization(email, password)
  return authorization
}

For the validate property, the task passed as argument will include with the HTTP request and response. This allows dynamic validation in cases where JSON schemas are not expressive enough. E.g. to validate that the response is in sorting order.

To do the above will require some initial work for it to be done:

I've built my own JSON reference tool out of issues with the two current main libraries. However it needs to be put into its own repository. It also currently has some issues, and needs testing. I would like JSON references to be format-agnostic. I.e. you can reference any format (YAML, JSON, JavaScript, TOML, JSON5, etc.) unless you're referencing a function (in which case you will reference JavaScript). I've got code for this here but it also needs to be put into its own repository and tested. I can open a GitHub issue if you want to keep track of the progress there.

Would the above solution work for you, or do you think it could be built differently?

jpettit commented 5 years ago

I think your example function above could certainly be improved. If we're just doing some async http request we're most likely just wrapping the user's custom js (like your example). I wonder what it would look like to infer the arguments from the sibling args array and just wrap the $ref value (/path/to/signin.js) automatically. The idea here is that it seems like a barrier to have to write wrappers in addition to the custom js code that most people will already have. Perhaps the task could look like this?

- name: exampleTask
  call:
    headers.authorization:
      $ref: path/to/signin.js#fetchAuthorization
      args: [user@email.com, password]

# The above $ref is similar to how openapi refs work: $ref: ./path/to/some.yaml#/components/foo/bar

I like it though - just spitballing an idea to reduce code complexity

ehmicky commented 5 years ago

Using JSON pointers is part of the JSON reference standard so this will be covered.

mk-pmb commented 4 years ago

We should also support a path argument so we can dive deeper into the default export.

- name: exampleTask
  call:
    headers.authorization:
      $ref: path/to/session.js
      path:
        - Session
        - prototype
        - login
      args: ["user@example.net", "password"]

However, path could be confused with a file path. Maybe dive or sth. would be better. Or prop and it could be a string if it's just one element. Or we could even assume dot notation if a string is given instead of a list.