Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions src/ExamplePairing/ExamplePairing.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,39 @@ import ReactDOM from "react-dom";
import ExamplePairing from "./ExamplePairing";
import examples from "@open-rpc/examples";
import refParser from "json-schema-ref-parser";
import { OpenrpcDocument } from "@open-rpc/meta-schema";
import { MethodObject, OpenrpcDocument, ExamplePairingObject } from "@open-rpc/meta-schema";

it("renders handles no method", async () => {
const div = document.createElement("div");
ReactDOM.render(<ExamplePairing method={undefined} examplePosition={0}/>, div);
ReactDOM.render(<ExamplePairing methodName={undefined} examplePairing={{} as any} />, div);
expect(div.innerHTML).toBe("");
ReactDOM.unmountComponentAtNode(div);
});

it("renders handles no method examples", async () => {
const div = document.createElement("div");
ReactDOM.render(<ExamplePairing method={{} as any} examplePosition={0} />, div);
expect(div.innerHTML).toBe("");
ReactDOM.unmountComponentAtNode(div);
});

it("renders handles no examplePosition", async () => {
const div = document.createElement("div");
const simpleMath = await refParser.dereference(examples.simpleMath) as OpenrpcDocument;
ReactDOM.render(<ExamplePairing method={simpleMath.methods[0]} />, div);
ReactDOM.render(<ExamplePairing methodName={"foo"} />, div);
expect(div.innerHTML).toBe("");
ReactDOM.unmountComponentAtNode(div);
});

it("renders examples", async () => {
const div = document.createElement("div");
const simpleMath = await refParser.dereference(examples.simpleMath) as OpenrpcDocument;
ReactDOM.render(<ExamplePairing method={simpleMath.methods[0]} examplePosition={0} />, div);
ReactDOM.render(
<ExamplePairing
methodName={simpleMath.methods[0].name}
examplePairing={simpleMath.methods[0].examples && simpleMath.methods[0].examples[0] as any}
/>
, div);
expect(div.innerHTML.includes("2")).toBe(true);
expect(div.innerHTML.includes("4")).toBe(true);
ReactDOM.unmountComponentAtNode(div);
});

it("renders examples with params by-name", async () => {
const div = document.createElement("div");
ReactDOM.render(<ExamplePairing method={{
const method: MethodObject = {
examples: [
{
name: "fooExample",
Expand Down Expand Up @@ -68,7 +65,13 @@ it("renders examples with params by-name", async () => {
type: "string",
},
},
}} examplePosition={0} />, div);
};
ReactDOM.render(
<ExamplePairing
methodName={method.name}
examplePairing={method.examples && method.examples[0] as ExamplePairingObject}
paramStructure={method.paramStructure || "by-position"} />
, div);
expect(div.innerHTML.includes("foo")).toBe(true);
expect(div.innerHTML.includes("bar")).toBe(true);
ReactDOM.unmountComponentAtNode(div);
Expand Down
32 changes: 14 additions & 18 deletions src/ExamplePairing/ExamplePairing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import Grid from "@material-ui/core/Grid";
import { Card, CardContent, Theme, withStyles, WithStyles } from "@material-ui/core";
import ReactJson from "react-json-view";
import ReactMarkdown from "react-markdown";
import { MethodObject, ExampleObject, ExamplePairingObject } from "@open-rpc/meta-schema";
import { ExampleObject, ExamplePairingObject } from "@open-rpc/meta-schema";
import _ from "lodash";

export type TParamStructure = "either" | "by-name" | "by-position";

interface IProps extends WithStyles<typeof styles> {
examplePosition?: number;
method?: MethodObject;
examplePairing?: ExamplePairingObject;
paramStructure?: TParamStructure;
methodName?: string;
reactJsonOptions?: any;
}

Expand All @@ -22,37 +23,32 @@ const styles = (theme: Theme) => ({

class ExamplePairing extends Component<IProps, {}> {
public render() {
const { examplePosition, method, classes } = this.props;
if (_.isUndefined(examplePosition)) {
const { examplePairing, paramStructure, classes, methodName } = this.props;
if (_.isUndefined(examplePairing)) {
return null;
}
let example;
if (method && method.examples && method.examples[examplePosition]) {
example = method.examples[examplePosition] as ExamplePairingObject;
}
if (!example || _.isEmpty(example)) {
if (_.isUndefined(methodName)) {
return null;
}
const paramStructure: TParamStructure = method?.paramStructure || "either";
const params = paramStructure === "by-name"
? (example.params as ExampleObject[]).reduce(((memo, p) => {
? (examplePairing.params as ExampleObject[]).reduce(((memo, p) => {
memo[p.name] = p.value;
return memo;
}), {} as any)
: (example.params as ExampleObject[]).map(((p) => p.value));
: (examplePairing.params as ExampleObject[]).map(((p) => p.value));

return (
<Grid container spacing={10}>
<Grid item xs={12}>
<ReactMarkdown source={example.description} className={classes.description} />
<ReactMarkdown source={examplePairing.description} className={classes.description} />
</Grid>
<Grid item xs={6}>
<Card>
<CardContent>
{example.params && <ReactJson src={{
{examplePairing.params && <ReactJson src={{
id: 1,
jsonrpc: "2.0",
method: method && method.name,
method: methodName,
params,
}} {...this.props.reactJsonOptions} />}
</CardContent>
Expand All @@ -61,10 +57,10 @@ class ExamplePairing extends Component<IProps, {}> {
<Grid item xs={6}>
<Card>
<CardContent>
{example.result && <ReactJson src={{
{examplePairing.result && <ReactJson src={{
id: 1,
jsonrpc: "2.0",
result: (example.result as ExampleObject).value,
result: (examplePairing.result as ExampleObject).value,
}} {...this.props.reactJsonOptions} />}
</CardContent>
</Card>
Expand Down
112 changes: 110 additions & 2 deletions src/ExamplePairings/ExamplePairings.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,118 @@ it("renders examples", async () => {
<ExamplePairings
method={simpleMath.methods[0]}
examples={simpleMath.methods[0].examples as ExamplePairingObject[]
} />
, div);
} />
, div);
expect(div.innerHTML.includes("simpleMathAdditionTwo")).toBe(true);
expect(div.innerHTML.includes("2")).toBe(true);
expect(div.innerHTML.includes("4")).toBe(true);
ReactDOM.unmountComponentAtNode(div);
});

it("renders examples with only schema examples", async () => {
const div = document.createElement("div");
const testDoc: OpenrpcDocument = {
info: {
title: "test",
version: "0.0.0",
},
methods: [
{
name: "test-method",
params: [{
name: "testparam1",
schema: {
examples: ["bob"],
type: "string",
},
}],
result: {
name: "test-method-result",
schema: {
examples: ["potato"],
type: "string",
},
},
},
],
openrpc: "1.0.0",
};
ReactDOM.render(
<ExamplePairings
method={testDoc.methods[0]}
examples={testDoc.methods[0].examples as ExamplePairingObject[]
} />
, div);
expect(div.innerHTML.includes("potato")).toBe(true);
expect(div.innerHTML.includes("bob")).toBe(true);
ReactDOM.unmountComponentAtNode(div);
});

it("renders examples with only schema examples with no params", async () => {
const div = document.createElement("div");
const testDoc: OpenrpcDocument = {
info: {
title: "test",
version: "0.0.0",
},
methods: [
{
name: "test-method",
params: [],
result: {
name: "test-method-result",
schema: {
examples: ["potato"],
type: "string",
},
},
},
],
openrpc: "1.0.0",
};
ReactDOM.render(
<ExamplePairings
method={testDoc.methods[0]}
examples={testDoc.methods[0].examples as ExamplePairingObject[]
} />
, div);
expect(div.innerHTML.includes("potato")).toBe(true);
expect(div.innerHTML.includes("bob")).toBe(true);
ReactDOM.unmountComponentAtNode(div);
});

it("renders examples with only schema examples and no method", async () => {
const div = document.createElement("div");
const testDoc: OpenrpcDocument = {
info: {
title: "test",
version: "0.0.0",
},
methods: [
{
name: "test-method",
params: [{
name: "testparam1",
schema: {
examples: ["bob"],
type: "string",
},
}],
result: {
name: "test-method-result",
schema: {
examples: ["potato"],
type: "string",
},
},
},
],
openrpc: "1.0.0",
};
ReactDOM.render(
<ExamplePairings
examples={testDoc.methods[0].examples as ExamplePairingObject[]
} />
, div);
ReactDOM.unmountComponentAtNode(div);
});
53 changes: 48 additions & 5 deletions src/ExamplePairings/ExamplePairings.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { Component } from "react";
import ExamplePairing from "../ExamplePairing/ExamplePairing";
import { Typography, List, ListItem, ListItemText, Grid, MenuItem, Menu, withStyles } from "@material-ui/core";
import { MethodObject, ExamplePairingObject } from "@open-rpc/meta-schema";
import { MethodObject, ExamplePairingObject, ContentDescriptorObject, ReferenceObject } from "@open-rpc/meta-schema";

interface IProps {
method?: MethodObject;
Expand All @@ -15,6 +15,47 @@ interface IState {
currentExample?: ExamplePairingObject;
}

const newExample: ExamplePairingObject = {
name: "generated-example",
params: [
],
result: {
name: "example-result",
value: null,
},
};
const getExamplesFromMethod = (method?: MethodObject): ExamplePairingObject[] => {
if (!method) { return []; }
const examples: ExamplePairingObject[] = [];

(method.params as ContentDescriptorObject[]).forEach((param, index: number) => {
if (param.schema.examples && param.schema.examples.length > 0) {
param.schema.examples.forEach((ex: any, i: number) => {
if (!examples[i]) {
examples.push({ ...newExample });
}
examples[i].params.push({
name: param.name,
value: ex,
});
});
}
});
const methodResult = method.result as ContentDescriptorObject;
if (methodResult && methodResult.schema && methodResult.schema.examples && methodResult.schema.examples.length > 0) {
methodResult.schema.examples.forEach((ex: any, i: number) => {
if (!examples[i]) {
examples.push({ ...newExample });
}
examples[i].result = {
name: methodResult.name,
value: ex,
};
});
}
return examples;
};

class ExamplePairings extends Component<IProps, IState> {
constructor(props: IProps) {
super(props);
Expand Down Expand Up @@ -43,8 +84,10 @@ class ExamplePairings extends Component<IProps, IState> {
this.setState({ anchorEl: null });
}
public render() {
const { examples, method } = this.props;
let { examples } = this.props;
const { method } = this.props;
const { anchorEl } = this.state;
examples = examples || getExamplesFromMethod(method);
if (!examples || examples.length === 0) {
return null;
}
Expand Down Expand Up @@ -84,10 +127,10 @@ class ExamplePairings extends Component<IProps, IState> {
</List>
</Grid>
<Grid item xs={12}>
{this.props.examples &&
{examples &&
<ExamplePairing
method={method}
examplePosition={this.state.selectedIndex}
examplePairing={examples[this.state.selectedIndex]}
methodName={this.props.method && this.props.method.name}
reactJsonOptions={this.props.reactJsonOptions} />}
</Grid>
</Grid>
Expand Down