Skip to content

Commit 709a74f

Browse files
authored
Merge pull request #484 from open-rpc/fix/example-fallback-to-ajv-result
fix: example rule now falls back to ajv to check the result against the schema
2 parents 9dded0e + 78a9d97 commit 709a74f

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

src/rules/examples-rule.test.ts

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
2+
import ExamplesRule from "./examples-rule";
3+
4+
describe("ExamplesRule", () => {
5+
it("should validate example calls with ajv as the fallback", () => {
6+
const rule = new ExamplesRule();
7+
const openrpcDocument = {
8+
openrpc: "1.0.0",
9+
info: {
10+
title: "my api",
11+
version: "0.0.0-development",
12+
},
13+
servers: [
14+
{
15+
name: "my api",
16+
url: "http://localhost:3333",
17+
},
18+
],
19+
methods: [
20+
{
21+
name: "foo",
22+
params: [],
23+
result: {
24+
name: "fooResult",
25+
schema: {
26+
type: "string",
27+
},
28+
},
29+
examples: [
30+
{
31+
name: "fooExample",
32+
summary: "foo example",
33+
description: "this is an example of foo",
34+
params: [
35+
{
36+
name: "barParam",
37+
value: "bar",
38+
},
39+
{
40+
name: "barParam2",
41+
value: "bar",
42+
}
43+
],
44+
result: {
45+
name: "fooResult",
46+
value: "potato",
47+
}
48+
}
49+
]
50+
},
51+
],
52+
} as any;
53+
const calls = rule.getCalls(openrpcDocument, openrpcDocument.methods[0]);
54+
calls[0].result = "different";
55+
const result = rule.validateCall(calls[0]);
56+
expect(result.valid).toBe(true);
57+
});
58+
it("should not validate example calls with ajv as a callback", () => {
59+
const rule = new ExamplesRule();
60+
const openrpcDocument = {
61+
openrpc: "1.0.0",
62+
info: {
63+
title: "my api",
64+
version: "0.0.0-development",
65+
},
66+
servers: [
67+
{
68+
name: "my api",
69+
url: "http://localhost:3333",
70+
},
71+
],
72+
methods: [
73+
{
74+
name: "foo",
75+
params: [],
76+
result: {
77+
name: "fooResult",
78+
schema: {
79+
type: "string",
80+
},
81+
},
82+
examples: [
83+
{
84+
name: "fooExample",
85+
summary: "foo example",
86+
description: "this is an example of foo",
87+
params: [
88+
{
89+
name: "barParam",
90+
value: "bar",
91+
},
92+
{
93+
name: "barParam2",
94+
value: "bar",
95+
}
96+
],
97+
result: {
98+
name: "fooResult",
99+
value: "potato",
100+
}
101+
}
102+
]
103+
},
104+
],
105+
} as any;
106+
const calls = rule.getCalls(openrpcDocument, openrpcDocument.methods[0]);
107+
calls[0].result = false;
108+
const result = rule.validateCall(calls[0]);
109+
expect(result.valid).toBe(false);
110+
});
111+
it("should not validate example calls with ajv as a callback and just give a good error message if the schema doesnt parse", () => {
112+
const rule = new ExamplesRule();
113+
const openrpcDocument = {
114+
openrpc: "1.0.0",
115+
info: {
116+
title: "my api",
117+
version: "0.0.0-development",
118+
},
119+
servers: [
120+
{
121+
name: "my api",
122+
url: "http://localhost:3333",
123+
},
124+
],
125+
methods: [
126+
{
127+
name: "foo",
128+
params: [],
129+
result: {
130+
name: "fooResult",
131+
schema: {
132+
type: "string",
133+
unevaluatedProperties: false,
134+
},
135+
},
136+
examples: [
137+
{
138+
name: "fooExample",
139+
summary: "foo example",
140+
description: "this is an example of foo",
141+
params: [
142+
{
143+
name: "barParam",
144+
value: "bar",
145+
},
146+
{
147+
name: "barParam2",
148+
value: "bar",
149+
}
150+
],
151+
result: {
152+
name: "fooResult",
153+
value: "potato",
154+
}
155+
}
156+
]
157+
},
158+
],
159+
} as any;
160+
const calls = rule.getCalls(openrpcDocument, openrpcDocument.methods[0]);
161+
calls[0].result = false;
162+
const result = rule.validateCall(calls[0]);
163+
expect(result.valid).toBe(false);
164+
});
165+
});

src/rules/examples-rule.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Call, IOptions } from "../coverage";
33
import { isEqual } from "lodash";
44
import Rule from "./rule";
55
import paramsToObj from "../utils/params-to-obj";
6+
import Ajv from "ajv";
67

78
interface RulesOptions {
89
skip: string[];
@@ -54,6 +55,20 @@ class ExamplesRule implements Rule {
5455
call.expectedResult,
5556
call.result
5657
);
58+
if (!call.valid) {
59+
// try to use ajv to check schema instead
60+
try {
61+
const ajv = new Ajv();
62+
const validate = ajv.compile(call.resultSchema);
63+
call.valid = validate(call.result);
64+
if (!call.valid) {
65+
call.reason = `expected ${JSON.stringify(call.expectedResult)} but got ${JSON.stringify(call.result)} and schema validation failed: ${JSON.stringify(validate.errors)}`;
66+
}
67+
return call;
68+
} catch (e: any) {
69+
call.valid = false;
70+
}
71+
}
5772
if (!call.valid) {
5873
call.reason = `expected ${JSON.stringify(call.expectedResult)} but got ${JSON.stringify(call.result)}`;
5974
}

0 commit comments

Comments
 (0)