Repository: stoplightio/spectral
Pull request #882 (2020-01-01 11:42:06)

fix: ruleset path for Example Object validation
The `example` field has `Any` values in all contexts
it can be used so the rule should not be triggered for that field.

The `examples` field always has values of `Example Object` type in
all contexts, so this is what the rule should trigger on.
And since the `examples` field takes a map of example objects
the JSON path expression needs the final `.*` to work.

Updated the tests to validate `examples` field instead of `example` and added
one test.

**Checklist**

- [x] Tests added / updated
- [ ] Docs added / updated

**Does this PR introduce a breaking change?**

- [ ] Yes
- [x] No

nulltoken: @johlo Looks pretty cool, thanks!

Next to the newly added test `validate multiple valid examples`, would you mind adding some additional ones to cover the following use cases?
- multiple examples with one of them exposing both `value` and `externalValue`
- multiple examples with one of them exposing neither `value` nor `externalValue`

johlo:  
>     * multiple examples with one of them exposing both `value` and `externalValue`
> 
>     * multiple examples with one of them exposing neither `value` nor `externalValue`

Done, amended to the old commit.
johlo: btw, when preparing this PR I've only run the `yarn test.prod` tests, I couldn't run `yarn test.harness` since `yarn build.binary` fails to build the binary (because I'm using node 13.5?).  
nulltoken: >Done, amended to the old commit.

@johlo :+1:

@P0lip Could you please take a look?

Patch:
diff --git a/src/rulesets/oas/index.json b/src/rulesets/oas/index.json
index 557861ca..31df2cf1 100644
--- a/src/rulesets/oas/index.json
+++ b/src/rulesets/oas/index.json
@@ -115,7 +115,7 @@
       "description": "Example should have either a `value` or `externalValue` field.",
       "recommended": true,
       "type": "style",
-      "given": "$..example",
+      "given": "$..examples.*",
       "then": {
         "function": "xor",
         "functionOptions": {


Test patch:
diff --git a/src/rulesets/oas/__tests__/example-value-or-externalValue.ts b/src/rulesets/oas/__tests__/example-value-or-externalValue.ts
index e5381170..796ccc07 100644
--- a/src/rulesets/oas/__tests__/example-value-or-externalValue.ts
+++ b/src/rulesets/oas/__tests__/example-value-or-externalValue.ts
@@ -12,30 +12,65 @@ describe('example-value-or-externalValue', () => {
   });
 
   test('validate if just externalValue', async () => {
-    const results = await s.run({ example: { externalValue: 'value' } });
+    const results = await s.run({ examples: { first: { externalValue: 'value' } } });
     expect(results.length).toEqual(0);
   });
 
   test('validate if just value', async () => {
-    const results = await s.run({ example: { value: 'value' } });
+    const results = await s.run({ examples: { first: { value: 'value' } } });
+    expect(results.length).toEqual(0);
+  });
+
+  test('multiple examples - validate all value or externalValue', async () => {
+    const results = await s.run({
+      examples: {
+        first: { value: 'value1' },
+        second: { externalValue: 'external-value2' },
+        third: { value: 'value3' },
+      },
+    });
     expect(results.length).toEqual(0);
   });
 
   test('return warnings if missing externalValue and value', async () => {
-    const results = await s.run({ example: {} });
+    const results = await s.run({ examples: { first: {} } });
     expect(results).toEqual([
       {
         code: 'example-value-or-externalValue',
         message: 'Example should have either a `value` or `externalValue` field.',
-        path: ['example'],
+        path: ['examples', 'first'],
         range: {
           end: {
             character: 15,
-            line: 1,
+            line: 2,
           },
           start: {
             character: 12,
-            line: 1,
+            line: 2,
+          },
+        },
+        severity: DiagnosticSeverity.Warning,
+      },
+    ]);
+  });
+
+  test('multiple examples - return warnings if missing externalValue and value in one', async () => {
+    const results = await s.run({
+      examples: { first: { value: 'value1' }, second: { externalValue: 'external-value2' }, third: {} },
+    });
+    expect(results).toEqual([
+      {
+        code: 'example-value-or-externalValue',
+        message: 'Example should have either a `value` or `externalValue` field.',
+        path: ['examples', 'third'],
+        range: {
+          end: {
+            character: 15,
+            line: 8,
+          },
+          start: {
+            character: 12,
+            line: 8,
           },
         },
         severity: DiagnosticSeverity.Warning,
@@ -44,20 +79,48 @@ describe('example-value-or-externalValue', () => {
   });
 
   test('return warnings if both externalValue and value', async () => {
-    const results = await s.run({ example: { externalValue: 'externalValue', value: 'value' } });
+    const results = await s.run({ examples: { first: { externalValue: 'externalValue', value: 'value' } } });
     expect(results).toEqual([
       {
         code: 'example-value-or-externalValue',
         message: 'Example should have either a `value` or `externalValue` field.',
-        path: ['example'],
+        path: ['examples', 'first'],
         range: {
           end: {
-            character: 20,
-            line: 3,
+            character: 22,
+            line: 4,
           },
           start: {
             character: 12,
-            line: 1,
+            line: 2,
+          },
+        },
+        severity: DiagnosticSeverity.Warning,
+      },
+    ]);
+  });
+
+  test('multiple examples - return warnings if both externalValue and value in one', async () => {
+    const results = await s.run({
+      examples: {
+        first: { value: 'value1' },
+        second: { externalValue: 'external-value2', value: 'value2' },
+        third: { externalValue: 'external-value3' },
+      },
+    });
+    expect(results).toEqual([
+      {
+        code: 'example-value-or-externalValue',
+        message: 'Example should have either a `value` or `externalValue` field.',
+        path: ['examples', 'second'],
+        range: {
+          end: {
+            character: 23,
+            line: 7,
+          },
+          start: {
+            character: 13,
+            line: 5,
           },
         },
         severity: DiagnosticSeverity.Warning,