cosmjs-util/packages/json-rpc/src/parse.spec.ts
2020-06-24 15:46:20 +02:00

430 lines
12 KiB
TypeScript

import {
parseJsonRpcErrorResponse,
parseJsonRpcId,
parseJsonRpcResponse,
parseJsonRpcSuccessResponse,
} from "./parse";
import { jsonRpcCode, JsonRpcErrorResponse, JsonRpcRequest, JsonRpcSuccessResponse } from "./types";
describe("parse", () => {
describe("parseJsonRpcId", () => {
it("works for number IDs", () => {
const request: JsonRpcRequest = {
jsonrpc: "2.0",
id: 123,
method: "foo",
params: {},
};
expect(parseJsonRpcId(request)).toEqual(123);
});
it("works for string IDs", () => {
const request: JsonRpcRequest = {
jsonrpc: "2.0",
id: "329fg3b",
method: "foo",
params: {},
};
expect(parseJsonRpcId(request)).toEqual("329fg3b");
});
it("returns null for invaid IDs", () => {
// unset
{
const request = {
jsonrpc: "2.0",
method: "foo",
params: {},
};
expect(parseJsonRpcId(request)).toBeNull();
}
// wrong type (object)
{
const request = {
jsonrpc: "2.0",
id: { content: 123 },
method: "foo",
params: {},
};
expect(parseJsonRpcId(request)).toBeNull();
}
// wrong type (Array)
{
const request = {
jsonrpc: "2.0",
id: [1, 2, 3],
method: "foo",
params: {},
};
expect(parseJsonRpcId(request)).toBeNull();
}
// wrong type (null)
{
const request = {
jsonrpc: "2.0",
id: null,
method: "foo",
params: {},
};
expect(parseJsonRpcId(request)).toBeNull();
}
});
});
describe("parseJsonRpcErrorResponse", () => {
it("works for valid error", () => {
const response: any = {
jsonrpc: "2.0",
id: 123,
error: {
code: jsonRpcCode.serverError.default,
message: "Something bad happened",
data: [2, 3, 4],
},
};
expect(parseJsonRpcErrorResponse(response)).toEqual(response);
});
it("works for error with string ID", () => {
const response: any = {
jsonrpc: "2.0",
id: "a3g4g34g",
error: {
code: jsonRpcCode.parseError,
message: "Could not parse request ID",
},
};
expect(parseJsonRpcErrorResponse(response)).toEqual(response);
});
it("works for error with null ID", () => {
const response: any = {
jsonrpc: "2.0",
id: null,
error: {
code: jsonRpcCode.parseError,
message: "Could not parse request ID",
},
};
expect(parseJsonRpcErrorResponse(response)).toEqual(response);
});
it("works for error with null data", () => {
const response: any = {
jsonrpc: "2.0",
id: 123,
error: {
code: jsonRpcCode.serverError.default,
message: "Something bad happened",
data: null,
},
};
expect(parseJsonRpcErrorResponse(response)).toEqual(response);
});
it("works for error with unset data", () => {
const response: any = {
jsonrpc: "2.0",
id: 123,
error: {
code: jsonRpcCode.serverError.default,
message: "Something bad happened",
},
};
expect(parseJsonRpcErrorResponse(response)).toEqual(response);
});
it("throws for invalid type", () => {
const expectedError = /data must be JSON compatible dictionary/i;
expect(() => parseJsonRpcErrorResponse(undefined)).toThrowError(expectedError);
expect(() => parseJsonRpcErrorResponse(null)).toThrowError(expectedError);
expect(() => parseJsonRpcErrorResponse(false)).toThrowError(expectedError);
expect(() => parseJsonRpcErrorResponse("error")).toThrowError(expectedError);
expect(() => parseJsonRpcErrorResponse(42)).toThrowError(expectedError);
expect(() => parseJsonRpcErrorResponse(() => true)).toThrowError(expectedError);
expect(() => parseJsonRpcErrorResponse({ foo: () => true })).toThrowError(expectedError);
expect(() => parseJsonRpcErrorResponse({ foo: () => new Uint8Array([]) })).toThrowError(expectedError);
});
it("throws for invalid version", () => {
// wrong type
{
const response: any = {
jsonrpc: 2.0,
id: 123,
error: {
code: jsonRpcCode.serverError.default,
message: "Something bad happened",
},
};
expect(() => parseJsonRpcErrorResponse(response)).toThrowError(/got unexpected jsonrpc version/i);
}
// wrong version
{
const response: any = {
jsonrpc: "1.0",
id: 123,
error: {
code: jsonRpcCode.serverError.default,
message: "Something bad happened",
},
};
expect(() => parseJsonRpcErrorResponse(response)).toThrowError(/got unexpected jsonrpc version/i);
}
// unset
{
const response: any = {
id: 123,
error: {
code: jsonRpcCode.serverError.default,
message: "Something bad happened",
},
};
expect(() => parseJsonRpcErrorResponse(response)).toThrowError(/got unexpected jsonrpc version/i);
}
});
it("throws for invalid ID", () => {
// wrong type
{
const response: any = {
jsonrpc: "2.0",
id: [1, 2, 3],
error: {
code: jsonRpcCode.serverError.default,
message: "Something bad happened",
},
};
expect(() => parseJsonRpcErrorResponse(response)).toThrowError(/invalid id field/i);
}
// unset
{
const response: any = {
jsonrpc: "2.0",
error: {
code: jsonRpcCode.serverError.default,
message: "Something bad happened",
},
};
expect(() => parseJsonRpcErrorResponse(response)).toThrowError(/invalid id field/i);
}
});
it("throws for success response", () => {
const response: JsonRpcSuccessResponse = {
jsonrpc: "2.0",
id: 123,
result: 3000,
};
expect(() => parseJsonRpcErrorResponse(response)).toThrowError(/invalid error field/i);
});
});
describe("parseJsonRpcSuccessResponse", () => {
it("works for response with dict result", () => {
const response: any = {
jsonrpc: "2.0",
id: 123,
result: {
foo: "bar",
},
};
expect(parseJsonRpcSuccessResponse(response)).toEqual(response);
});
it("works for response with null result", () => {
const response: any = {
jsonrpc: "2.0",
id: 123,
result: null,
};
expect(parseJsonRpcSuccessResponse(response)).toEqual(response);
});
it("works for response with number ID", () => {
const response: any = {
jsonrpc: "2.0",
id: 123,
result: {},
};
expect(parseJsonRpcSuccessResponse(response)).toEqual(response);
});
it("works for response with string ID", () => {
const response: any = {
jsonrpc: "2.0",
id: "40gfh408g",
result: {},
};
expect(parseJsonRpcSuccessResponse(response)).toEqual(response);
});
it("throws for invalid type", () => {
const expectedError = /data must be JSON compatible dictionary/i;
expect(() => parseJsonRpcSuccessResponse(undefined)).toThrowError(expectedError);
expect(() => parseJsonRpcSuccessResponse(null)).toThrowError(expectedError);
expect(() => parseJsonRpcSuccessResponse(false)).toThrowError(expectedError);
expect(() => parseJsonRpcSuccessResponse("success")).toThrowError(expectedError);
expect(() => parseJsonRpcSuccessResponse(42)).toThrowError(expectedError);
expect(() => parseJsonRpcSuccessResponse(() => true)).toThrowError(expectedError);
expect(() => parseJsonRpcSuccessResponse({ foo: () => true })).toThrowError(expectedError);
});
it("throws for invalid version", () => {
// wrong type
{
const response: any = {
jsonrpc: 2.0,
id: 123,
result: 3000,
};
expect(() => parseJsonRpcSuccessResponse(response)).toThrowError(/got unexpected jsonrpc version/i);
}
// wrong version
{
const response: any = {
jsonrpc: "1.0",
id: 123,
result: 3000,
};
expect(() => parseJsonRpcSuccessResponse(response)).toThrowError(/got unexpected jsonrpc version/i);
}
// unset
{
const response: any = {
id: 123,
result: 3000,
};
expect(() => parseJsonRpcSuccessResponse(response)).toThrowError(/got unexpected jsonrpc version/i);
}
});
it("throws for invalid ID", () => {
// wrong type
{
const response: any = {
jsonrpc: "2.0",
id: [1, 2, 3],
result: 3000,
};
expect(() => parseJsonRpcSuccessResponse(response)).toThrowError(/invalid id field/i);
}
// wrong type
{
const response: any = {
jsonrpc: "2.0",
id: null,
result: 3000,
};
expect(() => parseJsonRpcSuccessResponse(response)).toThrowError(/invalid id field/i);
}
// unset
{
const response: any = {
jsonrpc: "2.0",
result: 3000,
};
expect(() => parseJsonRpcSuccessResponse(response)).toThrowError(/invalid id field/i);
}
});
it("throws for error response", () => {
const response: JsonRpcErrorResponse = {
jsonrpc: "2.0",
id: 123,
error: {
code: jsonRpcCode.parseError,
message: "Could not parse request ID",
},
};
expect(() => parseJsonRpcSuccessResponse(response)).toThrowError(/invalid result field/i);
});
});
describe("parseJsonRpcResponse", () => {
it("works for success response", () => {
const response: any = {
jsonrpc: "2.0",
id: 123,
result: 3000,
};
expect(parseJsonRpcResponse(response)).toEqual(response);
});
it("works for error response", () => {
const response: any = {
jsonrpc: "2.0",
id: 123,
error: {
code: jsonRpcCode.serverError.default,
message: "Something bad happened",
data: [2, 3, 4],
},
};
expect(parseJsonRpcResponse(response)).toEqual(response);
});
it("favours error if response is error and success at the same time", () => {
const response: any = {
jsonrpc: "2.0",
id: 123,
result: 3000,
error: {
code: jsonRpcCode.serverError.default,
message: "Something bad happened",
},
};
expect(parseJsonRpcResponse(response)).toEqual({
jsonrpc: "2.0",
id: 123,
error: {
code: jsonRpcCode.serverError.default,
message: "Something bad happened",
},
});
});
it("throws for invalid type", () => {
const expectedError = /data must be JSON compatible dictionary/i;
expect(() => parseJsonRpcResponse(undefined)).toThrowError(expectedError);
expect(() => parseJsonRpcResponse(null)).toThrowError(expectedError);
expect(() => parseJsonRpcResponse(false)).toThrowError(expectedError);
expect(() => parseJsonRpcResponse("error")).toThrowError(expectedError);
expect(() => parseJsonRpcResponse(42)).toThrowError(expectedError);
expect(() => parseJsonRpcResponse(() => true)).toThrowError(expectedError);
expect(() => parseJsonRpcResponse({ foo: () => true })).toThrowError(expectedError);
expect(() => parseJsonRpcResponse({ foo: () => new Uint8Array([]) })).toThrowError(expectedError);
});
it("throws for invalid version", () => {
const expectedError = /got unexpected jsonrpc version/i;
// wrong type
{
const response: any = {
jsonrpc: 2.0,
id: 123,
result: 3000,
};
expect(() => parseJsonRpcResponse(response)).toThrowError(expectedError);
}
// wrong version
{
const response: any = {
jsonrpc: "1.0",
id: 123,
result: 3000,
};
expect(() => parseJsonRpcResponse(response)).toThrowError(expectedError);
}
// unset
{
const response: any = {
id: 123,
result: 3000,
};
expect(() => parseJsonRpcResponse(response)).toThrowError(expectedError);
}
});
});
});