mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 06:39:48 +00:00
gRPC with Insomnia export format V4 (#2830)
* feat: initial commit to export grpc entities * feat: grpc requests and protofiles in v4 export format * test(export): add grpc requests and protofiles in export tests * test(models): add isProtoFile tests
This commit is contained in:
parent
8f8acf83f2
commit
ccd270a9fb
@ -187,6 +187,24 @@ describe('export', () => {
|
||||
name: 'Request 1',
|
||||
parentId: w._id,
|
||||
});
|
||||
const pf1 = await models.protoFile.create({
|
||||
name: 'ProtoFile 1',
|
||||
parentId: w._id,
|
||||
});
|
||||
const gr1 = await models.grpcRequest.create({
|
||||
name: 'Grpc Request 1',
|
||||
parentId: w._id,
|
||||
protoFileId: pf1._id,
|
||||
});
|
||||
const pf2 = await models.protoFile.create({
|
||||
name: 'ProtoFile 2',
|
||||
parentId: w._id,
|
||||
});
|
||||
const gr2 = await models.grpcRequest.create({
|
||||
name: 'Grpc Request 2',
|
||||
parentId: w._id,
|
||||
protoFileId: pf2._id,
|
||||
});
|
||||
const f2 = await models.requestGroup.create({
|
||||
name: 'Folder 2',
|
||||
parentId: w._id,
|
||||
@ -229,13 +247,17 @@ describe('export', () => {
|
||||
expect.objectContaining({ _id: f2._id }),
|
||||
expect.objectContaining({ _id: r2._id }),
|
||||
expect.objectContaining({ _id: ePub._id }),
|
||||
expect.objectContaining({ _id: gr1._id }),
|
||||
expect.objectContaining({ _id: pf1._id }),
|
||||
expect.objectContaining({ _id: gr2._id }),
|
||||
expect.objectContaining({ _id: pf2._id }),
|
||||
]),
|
||||
});
|
||||
expect(exportWorkspacesDataJson.resources.length).toBe(8);
|
||||
expect(exportWorkspacesDataJson.resources.length).toBe(12);
|
||||
|
||||
// Test export some requests only.
|
||||
const exportRequestsJson = await importUtil.exportRequestsData([r1], false, 'json');
|
||||
const exportRequestsYaml = await importUtil.exportRequestsData([r1], false, 'yaml');
|
||||
const exportRequestsJson = await importUtil.exportRequestsData([r1, gr1], false, 'json');
|
||||
const exportRequestsYaml = await importUtil.exportRequestsData([r1, gr1], false, 'yaml');
|
||||
const exportRequestsDataJSON = JSON.parse(exportRequestsJson);
|
||||
const exportRequestsDataYAML = YAML.parse(exportRequestsYaml);
|
||||
|
||||
@ -250,11 +272,14 @@ describe('export', () => {
|
||||
expect.objectContaining({ _id: jar._id }),
|
||||
expect.objectContaining({ _id: r1._id }),
|
||||
expect.objectContaining({ _id: ePub._id }),
|
||||
expect.objectContaining({ _id: gr1._id }),
|
||||
expect.objectContaining({ _id: pf1._id }),
|
||||
expect.objectContaining({ _id: pf2._id }),
|
||||
]),
|
||||
});
|
||||
|
||||
expect(exportRequestsDataJSON.resources.length).toBe(6);
|
||||
expect(exportRequestsDataYAML.resources.length).toBe(6);
|
||||
expect(exportRequestsDataJSON.resources.length).toBe(9);
|
||||
expect(exportRequestsDataYAML.resources.length).toBe(9);
|
||||
|
||||
// Ensure JSON and YAML are the same
|
||||
expect(exportRequestsDataJSON.resources).toEqual(exportRequestsDataYAML.resources);
|
||||
@ -266,10 +291,19 @@ describe('export', () => {
|
||||
contents: 'openapi: "3.0.0"',
|
||||
});
|
||||
const jar = await models.cookieJar.getOrCreateForParentId(w._id);
|
||||
const pf1 = await models.protoFile.create({
|
||||
name: 'ProtoFile 1',
|
||||
parentId: w._id,
|
||||
});
|
||||
const r1 = await models.request.create({
|
||||
name: 'Request 1',
|
||||
parentId: w._id,
|
||||
});
|
||||
const gr1 = await models.grpcRequest.create({
|
||||
name: 'Grpc Request 1',
|
||||
parentId: w._id,
|
||||
protoFileId: pf1._id,
|
||||
});
|
||||
const f2 = await models.requestGroup.create({
|
||||
name: 'Folder 2',
|
||||
parentId: w._id,
|
||||
@ -278,6 +312,11 @@ describe('export', () => {
|
||||
name: 'Request 2',
|
||||
parentId: f2._id,
|
||||
});
|
||||
const gr2 = await models.grpcRequest.create({
|
||||
name: 'Grpc Request 2',
|
||||
parentId: f2._id,
|
||||
protoFileId: pf1._id,
|
||||
});
|
||||
const uts1 = await models.unitTestSuite.create({
|
||||
name: 'Unit Test Suite One',
|
||||
parentId: w._id,
|
||||
@ -308,8 +347,11 @@ describe('export', () => {
|
||||
expect.objectContaining({ _id: w._id }),
|
||||
expect.objectContaining({ _id: eBase._id }),
|
||||
expect.objectContaining({ _id: jar._id }),
|
||||
expect.objectContaining({ _id: pf1._id }),
|
||||
expect.objectContaining({ _id: r1._id }),
|
||||
expect.objectContaining({ _id: r2._id }),
|
||||
expect.objectContaining({ _id: gr1._id }),
|
||||
expect.objectContaining({ _id: gr2._id }),
|
||||
expect.objectContaining({ _id: uts1._id }),
|
||||
expect.objectContaining({ _id: ut1._id }),
|
||||
expect.objectContaining({ _id: ePub._id }),
|
||||
|
@ -12,6 +12,7 @@ import fs from 'fs';
|
||||
import { fnOrString, generateId } from './misc';
|
||||
import YAML from 'yaml';
|
||||
import { trackEvent } from './analytics';
|
||||
import { isGrpcRequest, isProtoFile, isRequest, isRequestGroup } from '../models/helpers/is-model';
|
||||
|
||||
const WORKSPACE_ID_KEY = '__WORKSPACE_ID__';
|
||||
const BASE_ENVIRONMENT_ID_KEY = '__BASE_ENVIRONMENT_ID__';
|
||||
@ -19,6 +20,7 @@ const BASE_ENVIRONMENT_ID_KEY = '__BASE_ENVIRONMENT_ID__';
|
||||
const EXPORT_FORMAT = 4;
|
||||
|
||||
const EXPORT_TYPE_REQUEST = 'request';
|
||||
const EXPORT_TYPE_GRPC_REQUEST = 'grpc_request';
|
||||
const EXPORT_TYPE_REQUEST_GROUP = 'request_group';
|
||||
const EXPORT_TYPE_UNIT_TEST_SUITE = 'unit_test_suite';
|
||||
const EXPORT_TYPE_UNIT_TEST = 'unit_test';
|
||||
@ -26,12 +28,14 @@ const EXPORT_TYPE_WORKSPACE = 'workspace';
|
||||
const EXPORT_TYPE_COOKIE_JAR = 'cookie_jar';
|
||||
const EXPORT_TYPE_ENVIRONMENT = 'environment';
|
||||
const EXPORT_TYPE_API_SPEC = 'api_spec';
|
||||
const EXPORT_TYPE_PROTO_FILE = 'proto_file';
|
||||
|
||||
// If we come across an ID of this form, we will replace it with a new one
|
||||
const REPLACE_ID_REGEX = /__\w+_\d+__/g;
|
||||
|
||||
const MODELS = {
|
||||
[EXPORT_TYPE_REQUEST]: models.request,
|
||||
[EXPORT_TYPE_GRPC_REQUEST]: models.grpcRequest,
|
||||
[EXPORT_TYPE_REQUEST_GROUP]: models.requestGroup,
|
||||
[EXPORT_TYPE_UNIT_TEST_SUITE]: models.unitTestSuite,
|
||||
[EXPORT_TYPE_UNIT_TEST]: models.unitTest,
|
||||
@ -39,6 +43,7 @@ const MODELS = {
|
||||
[EXPORT_TYPE_COOKIE_JAR]: models.cookieJar,
|
||||
[EXPORT_TYPE_ENVIRONMENT]: models.environment,
|
||||
[EXPORT_TYPE_API_SPEC]: models.apiSpec,
|
||||
[EXPORT_TYPE_PROTO_FILE]: models.protoFile,
|
||||
};
|
||||
|
||||
export type ImportResult = {
|
||||
@ -197,7 +202,7 @@ export async function importRaw(
|
||||
// Hack to switch to GraphQL based on finding `graphql` in the URL path
|
||||
// TODO: Support this in a better way
|
||||
if (
|
||||
model.type === models.request.type &&
|
||||
isRequest(model) &&
|
||||
resource.body &&
|
||||
typeof resource.body.text === 'string' &&
|
||||
typeof resource.url === 'string' &&
|
||||
@ -209,7 +214,7 @@ export async function importRaw(
|
||||
|
||||
// Try adding Content-Type JSON if no Content-Type exists
|
||||
if (
|
||||
model.type === models.request.type &&
|
||||
isRequest(model) &&
|
||||
resource.body &&
|
||||
typeof resource.body.text === 'string' &&
|
||||
Array.isArray(resource.headers) &&
|
||||
@ -278,7 +283,7 @@ export async function exportWorkspacesHAR(
|
||||
includePrivateDocs: boolean = false,
|
||||
): Promise<string> {
|
||||
const docs: Array<BaseModel> = await getDocWithDescendants(parentDoc, includePrivateDocs);
|
||||
const requests: Array<BaseModel> = docs.filter(doc => doc.type === models.request.type);
|
||||
const requests: Array<BaseModel> = docs.filter(isRequest);
|
||||
return exportRequestsHAR(requests, includePrivateDocs);
|
||||
}
|
||||
|
||||
@ -342,7 +347,7 @@ export async function exportWorkspacesData(
|
||||
format: 'json' | 'yaml',
|
||||
): Promise<string> {
|
||||
const docs: Array<BaseModel> = await getDocWithDescendants(parentDoc, includePrivateDocs);
|
||||
const requests: Array<BaseModel> = docs.filter(doc => doc.type === models.request.type);
|
||||
const requests: Array<BaseModel> = docs.filter(doc => isRequest(doc) || isGrpcRequest(doc));
|
||||
return exportRequestsData(requests, includePrivateDocs, format);
|
||||
}
|
||||
|
||||
@ -385,7 +390,8 @@ export async function exportRequestsData(
|
||||
d.type === models.environment.type ||
|
||||
d.type === models.apiSpec.type ||
|
||||
d.type === models.unitTestSuite.type ||
|
||||
d.type === models.unitTest.type
|
||||
d.type === models.unitTest.type ||
|
||||
isProtoFile(d)
|
||||
);
|
||||
});
|
||||
docs.push(...descendants);
|
||||
@ -398,8 +404,10 @@ export async function exportRequestsData(
|
||||
!(
|
||||
d.type === models.unitTestSuite.type ||
|
||||
d.type === models.unitTest.type ||
|
||||
d.type === models.request.type ||
|
||||
d.type === models.requestGroup.type ||
|
||||
isRequest(d) ||
|
||||
isGrpcRequest(d) ||
|
||||
isRequestGroup(d) ||
|
||||
isProtoFile(d) ||
|
||||
d.type === models.workspace.type ||
|
||||
d.type === models.cookieJar.type ||
|
||||
d.type === models.environment.type ||
|
||||
@ -422,10 +430,14 @@ export async function exportRequestsData(
|
||||
d._type = EXPORT_TYPE_UNIT_TEST_SUITE;
|
||||
} else if (d.type === models.unitTest.type) {
|
||||
d._type = EXPORT_TYPE_UNIT_TEST;
|
||||
} else if (d.type === models.requestGroup.type) {
|
||||
} else if (isRequestGroup(d)) {
|
||||
d._type = EXPORT_TYPE_REQUEST_GROUP;
|
||||
} else if (d.type === models.request.type) {
|
||||
} else if (isRequest(d)) {
|
||||
d._type = EXPORT_TYPE_REQUEST;
|
||||
} else if (isGrpcRequest(d)) {
|
||||
d._type = EXPORT_TYPE_GRPC_REQUEST;
|
||||
} else if (isProtoFile(d)) {
|
||||
d._type = EXPORT_TYPE_PROTO_FILE;
|
||||
} else if (d.type === models.apiSpec.type) {
|
||||
d._type = EXPORT_TYPE_API_SPEC;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { difference } from 'lodash';
|
||||
import {
|
||||
isGrpcRequest,
|
||||
isGrpcRequestId,
|
||||
isProtoFile,
|
||||
isRequest,
|
||||
isRequestGroup,
|
||||
isRequestId,
|
||||
@ -76,3 +77,16 @@ describe('isRequestGroup', () => {
|
||||
expect(isRequestGroup({ type })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isProtoFile', () => {
|
||||
const supported = [models.protoFile.type];
|
||||
const unsupported = difference(allTypes, supported);
|
||||
|
||||
it.each(supported)('should return true: "%s"', type => {
|
||||
expect(isProtoFile({ type })).toBe(true);
|
||||
});
|
||||
|
||||
it.each(unsupported)('should return false: "%s"', type => {
|
||||
expect(isProtoFile({ type })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
// @flow
|
||||
import type { BaseModel } from '../index';
|
||||
import { grpcRequest, request, requestGroup } from '../index';
|
||||
import { grpcRequest, request, requestGroup, protoFile } from '../index';
|
||||
|
||||
export function isGrpcRequest(obj: BaseModel): boolean {
|
||||
return obj.type === grpcRequest.type;
|
||||
@ -21,3 +21,7 @@ export function isRequestId(id: string): boolean {
|
||||
export function isRequestGroup(obj: BaseModel): boolean {
|
||||
return obj.type === requestGroup.type;
|
||||
}
|
||||
|
||||
export function isProtoFile(obj: BaseModel): boolean {
|
||||
return obj.type === protoFile.type;
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
// @flow
|
||||
import * as models from '../index';
|
||||
import { isGrpcRequest } from './is-model';
|
||||
import { isGrpcRequest, isGrpcRequestId } from './is-model';
|
||||
import type { GrpcRequest } from '../grpc-request';
|
||||
|
||||
export function getById(requestId: string): Promise<Request | GrpcRequest | null> {
|
||||
return isGrpcRequestId(requestId)
|
||||
? models.grpcRequest.getById(requestId)
|
||||
: models.request.getById(requestId);
|
||||
}
|
||||
|
||||
export function remove<T>(request: T): Promise<void> {
|
||||
return isGrpcRequest(request)
|
||||
|
@ -3,11 +3,14 @@ import React, { PureComponent } from 'react';
|
||||
import autobind from 'autobind-decorator';
|
||||
import MethodTag from '../tags/method-tag';
|
||||
import type { Request } from '../../../models/request';
|
||||
import type { GrpcRequest } from '../../../models/grpc-request';
|
||||
import { isGrpcRequest } from '../../../models/helpers/is-model';
|
||||
import GrpcTag from '../tags/grpc-tag';
|
||||
|
||||
type Props = {
|
||||
handleSetItemSelected: Function,
|
||||
isSelected: boolean,
|
||||
request: Request,
|
||||
request: Request | GrpcRequest,
|
||||
};
|
||||
|
||||
@autobind
|
||||
@ -21,6 +24,8 @@ class RequestRow extends PureComponent<Props> {
|
||||
|
||||
render() {
|
||||
const { request, isSelected } = this.props;
|
||||
const isGrpc = isGrpcRequest(request);
|
||||
|
||||
return (
|
||||
<li className="tree__row">
|
||||
<div className="tree__item tree__item--request">
|
||||
@ -28,7 +33,7 @@ class RequestRow extends PureComponent<Props> {
|
||||
<input type="checkbox" checked={isSelected} onChange={this.handleSelect} />
|
||||
</div>
|
||||
<button className="wide">
|
||||
<MethodTag method={request.method} />
|
||||
{isGrpc ? <GrpcTag /> : <MethodTag method={request.method} />}
|
||||
<span className="inline-block">{request.name}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -2,10 +2,11 @@
|
||||
import * as React from 'react';
|
||||
import RequestRow from './request-row';
|
||||
import RequestGroupRow from './request-group-row';
|
||||
import * as models from '../../../models/index';
|
||||
import type { Node } from '../modals/export-requests-modal';
|
||||
import type { Request } from '../../../models/request';
|
||||
import type { RequestGroup } from '../../../models/request-group';
|
||||
import { isGrpcRequest, isRequest } from '../../../models/helpers/is-model';
|
||||
import type { GrpcRequest } from '../../../models/grpc-request';
|
||||
|
||||
type Props = {
|
||||
root: ?Node,
|
||||
@ -19,9 +20,9 @@ class Tree extends React.PureComponent<Props> {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (node.doc.type === models.request.type) {
|
||||
// Directly cast to Request will result in error, so cast it to any first.
|
||||
const request: Request = ((node.doc: any): Request);
|
||||
if (isRequest(node.doc) || isGrpcRequest(node.doc)) {
|
||||
// Directly casting will result in error, so cast it to any first.
|
||||
const request: Request | GrpcRequest = ((node.doc: any): Request | GrpcRequest);
|
||||
return (
|
||||
<RequestRow
|
||||
key={node.doc._id}
|
||||
|
@ -9,9 +9,11 @@ import Tree from '../export-requests/tree';
|
||||
import type { Request } from '../../../models/request';
|
||||
import type { RequestGroup } from '../../../models/request-group';
|
||||
import * as models from '../../../models';
|
||||
import type { GrpcRequest } from '../../../models/grpc-request';
|
||||
import { isGrpcRequest, isRequest, isRequestGroup } from '../../../models/helpers/is-model';
|
||||
|
||||
export type Node = {
|
||||
doc: Request | RequestGroup,
|
||||
doc: Request | GrpcRequest | RequestGroup,
|
||||
children: Array<Node>,
|
||||
collapsed: boolean,
|
||||
totalRequests: number,
|
||||
@ -64,7 +66,8 @@ class ExportRequestsModal extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
getSelectedRequestIds(node: Node): Array<string> {
|
||||
if (node.doc.type === models.request.type && node.selectedRequests === node.totalRequests) {
|
||||
const docIsRequest = isRequest(node.doc) || isGrpcRequest(node.doc);
|
||||
if (docIsRequest && node.selectedRequests === node.totalRequests) {
|
||||
return [node.doc._id];
|
||||
}
|
||||
const requestIds: Array<string> = [];
|
||||
@ -105,7 +108,9 @@ class ExportRequestsModal extends PureComponent<Props, State> {
|
||||
let totalRequests = children
|
||||
.map(child => child.totalRequests)
|
||||
.reduce((acc, totalRequests) => acc + totalRequests, 0);
|
||||
if (item.doc.type === models.request.type) {
|
||||
|
||||
const docIsRequest = isRequest(item.doc) || isGrpcRequest(item.doc);
|
||||
if (docIsRequest) {
|
||||
totalRequests++;
|
||||
}
|
||||
return {
|
||||
@ -146,7 +151,7 @@ class ExportRequestsModal extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
setRequestGroupCollapsed(node: Node, isCollapsed: boolean, requestGroupId: string): boolean {
|
||||
if (node.doc.type !== models.requestGroup.type) {
|
||||
if (!isRequestGroup(node.doc)) {
|
||||
return false;
|
||||
}
|
||||
if (node.doc._id === requestGroupId) {
|
||||
|
@ -13,6 +13,7 @@ import AlertModal from '../../components/modals/alert-modal';
|
||||
import PaymentNotificationModal from '../../components/modals/payment-notification-modal';
|
||||
import LoginModal from '../../components/modals/login-modal';
|
||||
import * as models from '../../../models';
|
||||
import * as requestOperations from '../../../models/helpers/request-operations';
|
||||
import SelectModal from '../../components/modals/select-modal';
|
||||
import { showError, showModal } from '../../components/modals/index';
|
||||
import * as db from '../../../common/database';
|
||||
@ -535,7 +536,7 @@ export function exportRequestsToFile(requestIds) {
|
||||
const privateEnvironments = [];
|
||||
const workspaceLookup = {};
|
||||
for (const requestId of requestIds) {
|
||||
const request = await models.request.getById(requestId);
|
||||
const request = await requestOperations.getById(requestId);
|
||||
if (request == null) {
|
||||
continue;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user