redocly-cli icon indicating copy to clipboard operation
redocly-cli copied to clipboard

docs: update to assertions

Open adamaltman opened this issue 3 years ago • 12 comments

What/Why/How?

Docs for a desired update to assertions.

  1. Change context to if.
  2. Change if list to conform to assertion object (see the docs -- if, message, suggest, severityare ignored when used inside of theiflist. The assertion object in theiflist must contain the subject and at least one assertion (such asdefined: true`).
  3. Add support for 3 additional locator properties: filterInParentKeys, filterOutParentKeys, matchParentKeys (regex). See the docs for more details.
  4. Remove undefined because it is the same as defined: false.
  5. Add support for message placeholders as described in the documentation: {{assertionName}}, {{subject}}, {{property}}, {{problems}}.

Reference

This would replace various other tickets:

  • #855
  • #781
  • #714

This would influence #780 because a custom function could provide a list of problems (which are added to the problems list used for the placeholders) so the return signature would need to be able to include that.

Testing

This is the docs only.

adamaltman avatar Sep 07 '22 11:09 adamaltman

Coverage report

St.:grey_question:
Category Percentage Covered / Total
🟡 Statements 73.04% 3256/4458
🟡 Branches 64.73% 1808/2793
🟡 Functions 65.46% 544/831
🟡 Lines 72.94% 3024/4146

Test suite run success

498 tests passing in 85 suites.

Report generated by 🧪jest coverage report action from 5a8e8fb7e2d0cb44385b2484f500b74f7e1eccf5

github-actions[bot] avatar Sep 07 '22 11:09 github-actions[bot]

In case we have assertion like this (I know it doesn't make much sense but Im interested in implementation behaviour):

assert/put-200-and-201:
      subject: 
        - ResponsesMap
      if:
        - subject:
            - PathsMap
            - Operation
          filterInParentKeys:
            - put
            - /path
          defined: true
      message: Must mutually define 200 and 201 responses for PUT requests.
      severity: error
      mutuallyRequired:
        - '200'
        - '201'

Will it apply assertion for ResponsesMap inside PathsMap AND ResponsesMap inside Operation (like 2 separate assertions) ? Or ResponsesMap which is inside of Operation which is inside of PathsMap (I dont like this approach because it requires strong knowledge of types hierarchy and correct order in subject field but on the other side adds possibility to create more specific selectors)?

roman-sainchuk avatar Sep 28 '22 14:09 roman-sainchuk

@roman-sainchuk the first one (like 2 separate assertions).

I'm not sure if we want to support array for subject at all.

RomanHotsiy avatar Sep 28 '22 15:09 RomanHotsiy

I'd say to support array only for top level subject field. As for me its not clear how it supposed to work if we have several items in where list where each of them has multiple subjects

roman-sainchuk avatar Sep 28 '22 15:09 roman-sainchuk

I would just remove this to simplify things.

RomanHotsiy avatar Sep 28 '22 15:09 RomanHotsiy

Add support for 3 additional locator properties: filterInParentKeys, filterOutParentKeys, matchParentKeys (regex). See the docs for more details.

From my understanding these properties are mutually exclusive along with property locator. Is that correct?

roman-sainchuk avatar Sep 28 '22 18:09 roman-sainchuk

From my understanding these properties are mutually exclusive along with property locator. Is that correct?

No, I don't think so. Let's sync tomorrow.

RomanHotsiy avatar Sep 29 '22 02:09 RomanHotsiy

I agree with simplifying if possible. Flattening the subject may be fine.

Those properties (filterInParentKeys, filterOutParentKeys, matchParentKeys) shouldn't be mutually exclusive, and people should be aware they could create nonsense combinations (as is with most things in life):

filterInParentKeys:
  - put
filterOutParentKeys:
  - put

adamaltman avatar Sep 29 '22 12:09 adamaltman

We had a small discussion with @ohorbachevskyi about new syntax and ended up with idea to put top level subject, property, new locators and assertion inside do block. So this way users have better visual separation of preconditions and assertion's action itself.

Example:

assert/put-200-and-201:
      where:
        - subject: Operation
           filterInParentKeys:
            - put
           defined: true
      do:
          subject:  ResponsesMap
          mutuallyRequired:
            - '200'
            - '201'
      message: Must mutually define 200 and 201 responses for PUT requests.
      severity: error

I think do block can be even a list as well as where block where we can define different assertions or different subjects.

Example:

assert/put-200-and-201:
      where:
        - subject: Operation
           filterInParentKeys:
            - put
           defined: true
      do:
         -  subject:  ResponsesMap
            mutuallyRequired:
              - '200'
              - '201'
        -  subject:  Parameter
            property: in
            defined: true           
      message: Must mutually define 200 and 201 responses for PUT requests and define in parameter.
      severity: error

roman-sainchuk avatar Sep 29 '22 15:09 roman-sainchuk

I wonder if this:



assert/media-type-map-not-pdf:
  
    subject: MediaTypesMap    
    disallowed: ['application/pdf']

    where:
      - subject: Operation
        filterOutParentKeys:
          - put

could be expressed with the following:

assert/media-type-map-not-pdf:
  
    subject: MediaTypesMap    
    disallowed: ['application/pdf']

    where:
      - subject: PathItem
        disallowed:
          - put

If yes, having filterIn/Out/matchParentKeys sounds redundant. @adamaltman, @RomanHotsiy what do you think? Am I missing something?

tatomyr avatar Sep 30 '22 12:09 tatomyr

could be expressed with the following:

It can't. The where condition will eliminate the whole PathItem that has put property in it, not only put operation.

RomanHotsiy avatar Sep 30 '22 12:09 RomanHotsiy

Ah, indeed, thanks. I'm constantly forgetting about this 🙂.

tatomyr avatar Sep 30 '22 13:09 tatomyr

I'm not sure about the do word. I feel it is used in combination with while and introduces the same confusion as if without else.

adamaltman avatar Oct 09 '22 18:10 adamaltman

There is a language Gherkin (used for describing behavior) which used the keywords Given, When, Then. I'm not saying this because those keywords make sense in our system (they don't IMO), but I think there are actually 3 parts here:

  • subject evaluated (maybe name subject and rename subject to type)
  • additional conditions (where)
  • assertions (maybe we call them assertions? it's the most logical word)

The before:

    assert/operation-id-delete:
      context:
        - type: Operation
          matchParentKeys:
            - delete
      subject: Operation
      property: operationId
      pattern: /Delete/
      casing: PascalCase

The result:

    assert/operation-id-delete:
      where:
        - type: Operation
          filterInParentKeys:
            - delete
      subject: 
        type: Operation
        property: operationId
      assertions:      
        pattern: /Delete/
        casing: PascalCase

However, that specific example wouldn't require the where, it could be:

    assert/operation-id-delete:
      subject: 
        type: Operation
        property: operationId
        filterInParentKeys:
          - delete
      assertions:      
        pattern: /Delete/
        casing: PascalCase

Also, I found a practical use case that requires where (because Webhooks also have PathItem objects):

    assert/path-must-be-ref-file:
      subject: 
         type: PathItem
      where:
        - type: PathsMap
      assertions:
        ref: /^(.\/paths|paths)\/.*yaml$/

adamaltman avatar Oct 09 '22 18:10 adamaltman

I reworked it more and decided to open it as a separate PR: https://github.com/Redocly/redocly-cli/pull/917

adamaltman avatar Oct 23 '22 17:10 adamaltman