Skip to content

Commit

Permalink
Merge branch 'develop' into feat/env-variables-proper-error
Browse files Browse the repository at this point in the history
  • Loading branch information
CurryYangxx authored Apr 3, 2024
2 parents 68b0f20 + c12c4ff commit 3a932aa
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 42 deletions.
17 changes: 5 additions & 12 deletions packages/insomnia-smoke-test/tests/smoke/mock.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
import { loadFixture } from '../../playwright/paths';
import { test } from '../../playwright/test';

test('can make a mock route', async ({ app, page }) => {
test('can make a mock route', async ({ page }) => {
test.slow(process.platform === 'darwin' || process.platform === 'win32', 'Slow app start on these platforms');
const text = await loadFixture('smoke-test-collection.yaml');
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);

await page.getByRole('button', { name: 'Create in project' }).click();
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();

await page.getByLabel('New Mock Server').click();
await page.getByRole('button', { name: 'Create', exact: true }).click();
await page.getByRole('button', { name: 'New Mock Route' }).click();
await page.getByText('GET/').click();
await page.getByTestId('CodeEditor').getByRole('textbox').fill('123');
await page.getByLabel('Project Actions').click();
await page.getByText('Rename').click();
await page.locator('#prompt-input').fill('/123');
await page.getByRole('button', { name: 'Rename' }).click();

await page.getByRole('button', { name: 'Test' }).click();
await page.getByText('No body returned for response').click();
Expand Down
2 changes: 1 addition & 1 deletion packages/insomnia/bin/yarn-standalone.js
Original file line number Diff line number Diff line change
Expand Up @@ -76190,7 +76190,7 @@ function read(buf, options) {
* gotten conjoined to the key or otherwise shenanigan'd.
*
* Work out how much base64 we used, then drop all non-base64
* chars from the beginning up to this point in the the string.
* chars from the beginning up to this point in the string.
* Then offset in this and try to make up for missing = chars.
*/
var data = m[2] + (m[3] ? m[3] : '');
Expand Down
2 changes: 1 addition & 1 deletion packages/insomnia/src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export const displayModifierKey = (key: keyof Omit<KeyCombination, 'keyCode'>) =
}

if (isWindows()) {
// Note: Although this unicode character for the Windows doesn't exist, the the Unicode character U+229E ⊞ SQUARED PLUS is very commonly used for this purpose. For example, Wikipedia uses it as a simulation of the windows logo. Though, Windows itself uses `Windows` or `Win`, so we'll go with `Win` here.
// Note: Although this unicode character for the Windows doesn't exist, the Unicode character U+229E ⊞ SQUARED PLUS is very commonly used for this purpose. For example, Wikipedia uses it as a simulation of the windows logo. Though, Windows itself uses `Windows` or `Win`, so we'll go with `Win` here.
// see: https://en.wikipedia.org/wiki/Windows_key
return 'Win';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ function getGraphQLContent(body: GraphQLBody, query?: string, operationName?: st
content.query = query;
}

if (operationName) {
content.operationName = operationName;
// The below items are optional; should be set to undefined if present and empty
const isString = (value?: string): value is string => typeof value === 'string' || (value as unknown) instanceof String;
if (isString(operationName)) {
content.operationName = operationName.length ? operationName : undefined;
}

if (variables) {
content.variables = variables;
if (isString(variables)) {
content.variables = variables.length ? variables : undefined;
}

return JSON.stringify(content);
Expand Down Expand Up @@ -284,9 +286,11 @@ export const GraphQLEditor: FC<Props> = ({
try {
const content = getGraphQLContent(state.body, undefined, operationName, variablesInput);
onChange(content);

setState(state => ({
...state,
body: { ...state.body, variablesInput },
// If variables are empty, remove them from the body
body: { ...state.body, variables: variablesInput.length ? variablesInput : undefined },
variablesSyntaxError: '',
}));
} catch (err) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,32 @@ import fs from 'fs/promises';
import React, { useState } from 'react';
import { Button } from 'react-aria-components';
import { useNavigate, useParams } from 'react-router-dom';
import { useRouteLoaderData } from 'react-router-dom';
import {
useFetcher,
useRouteLoaderData,
} from 'react-router-dom';

import { invariant } from '../../../utils/invariant';
import { useMockRoutePatcher } from '../../routes/mock-route';
import { RequestLoaderData } from '../../routes/request';
import { WorkspaceLoaderData } from '../../routes/workspace';
import { HelpTooltip } from '../help-tooltip';
import { Icon } from '../icon';
import { showPrompt } from '../modals';

export const MockResponseExtractor = () => {
const {
activeWorkspace,
} = useRouteLoaderData(':workspaceId') as WorkspaceLoaderData;
const { mockServerAndRoutes, activeResponse } = useRouteLoaderData('request/:requestId') as RequestLoaderData;
const patchMockRoute = useMockRoutePatcher();
const navigate = useNavigate();
const {
organizationId,
projectId,
workspaceId,
} = useParams();
const fetcher = useFetcher();
const [selectedMockServer, setSelectedMockServer] = useState('');
const [selectedMockRoute, setSelectedMockRoute] = useState('');
return (
Expand All @@ -30,21 +41,84 @@ export const MockResponseExtractor = () => {
<form
onSubmit={async e => {
e.preventDefault();
if (!selectedMockServer || !selectedMockRoute) {
if (selectedMockServer && selectedMockRoute) {
if (activeResponse) {
// TODO: move this out of the renderer, and upsert mock
const body = await fs.readFile(activeResponse.bodyPath);

patchMockRoute(selectedMockRoute, {
body: body.toString(),
mimeType: activeResponse.contentType,
statusCode: activeResponse.statusCode,
headers: activeResponse.headers,
});
}
return;
}
let path = '/new-route';
try {
path = activeResponse ? new URL(activeResponse.url).pathname : '/new-route';
} catch (e) {
console.log(e);
}
if (!selectedMockServer) {
showPrompt({
title: 'Create Mock Route',
defaultValue: path,
label: 'Name',
onComplete: async name => {
invariant(activeResponse, 'Active response must be defined');
const body = await fs.readFile(activeResponse.bodyPath);
// TODO: consider setting selected mock server here rather than redirecting
fetcher.submit(
JSON.stringify({
name: name,
body: body.toString(),
mimeType: activeResponse.contentType,
statusCode: activeResponse.statusCode,
headers: activeResponse.headers,
mockServerName: activeWorkspace.name,
}),
{
encType: 'application/json',
method: 'post',
action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/mock-server/mock-route/new`,
}
);
},
});
return;
}
if (!selectedMockRoute) {
showPrompt({
title: 'Create Mock Route',
defaultValue: path,
label: 'Name',
onComplete: async name => {
invariant(activeResponse, 'Active response must be defined');
const body = await fs.readFile(activeResponse.bodyPath);

if (activeResponse) {
// TODO: move this out of the renderer, and upsert mock
const body = await fs.readFile(activeResponse.bodyPath);
// setSelectedMockRoute(newRoute._id);

patchMockRoute(selectedMockRoute, {
body: body.toString(),
mimeType: activeResponse.contentType,
statusCode: activeResponse.statusCode,
headers: activeResponse.headers,
fetcher.submit(
JSON.stringify({
name: name,
parentId: selectedMockServer,
body: body.toString(),
mimeType: activeResponse.contentType,
statusCode: activeResponse.statusCode,
headers: activeResponse.headers,
}),
{
encType: 'application/json',
method: 'post',
action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/mock-server/mock-route/new`,
}
);
},
});
}

}}
>
<div className="form-row">
Expand All @@ -61,7 +135,7 @@ export const MockResponseExtractor = () => {
setSelectedMockServer(selected);
}}
>
<option value="">-- Select... --</option>
<option value="">-- Create new... --</option>
{mockServerAndRoutes
.map(w => (
<option key={w._id} value={w._id}>
Expand All @@ -87,7 +161,7 @@ export const MockResponseExtractor = () => {
setSelectedMockRoute(selected);
}}
>
<option value="">-- Select... --</option>
<option value="">-- Create new... --</option>
{mockServerAndRoutes.find(s => s._id === selectedMockServer)?.routes
.map(w => (
<option key={w._id} value={w._id}>
Expand All @@ -112,10 +186,9 @@ export const MockResponseExtractor = () => {
</Button>
<Button
type="submit"
isDisabled={!selectedMockServer || !selectedMockRoute}
className="hover:no-underline bg-[--color-surprise] hover:bg-opacity-90 border border-solid border-[--hl-md] py-2 px-3 text-[--color-font-surprise] transition-colors rounded-sm"
>
Export
Extract to mock route
</Button>
</div>
</form>
Expand Down
3 changes: 2 additions & 1 deletion packages/insomnia/src/ui/components/request-url-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ export const RequestUrlBar = forwardRef<RequestUrlBarHandle, Props>(({
};
}, [sendOrConnect]);

useInterval(sendOrConnect, currentInterval ? currentInterval : null);
useInterval(sendOrConnect, currentInterval && fetcher.state === 'idle' ? currentInterval : null);
useTimeoutWhen(sendOrConnect, currentTimeout, !!currentTimeout);
const patchRequest = useRequestPatcher();

Expand Down Expand Up @@ -336,6 +336,7 @@ export const RequestUrlBar = forwardRef<RequestUrlBarHandle, Props>(({
defaultValue: '3',
submitName: 'Start',
onComplete: seconds => {
sendOrConnect();
setCurrentInterval(+seconds * 1000);
},
})}
Expand Down
21 changes: 19 additions & 2 deletions packages/insomnia/src/ui/routes/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1211,9 +1211,26 @@ export const createMockRouteAction: ActionFunction = async ({ request, params })

const patch = await request.json();
invariant(typeof patch.name === 'string', 'Name is required');
invariant(typeof patch.parentId === 'string', 'parentId is required');
// TODO: remove this hack
if (patch.mockServerName) {
const activeWorkspace = await models.workspace.getById(workspaceId);
invariant(activeWorkspace, 'Active workspace not found');
const workspace = await models.workspace.create({
name: activeWorkspace.name,
scope: 'mock-server',
parentId: projectId,
});
invariant(workspace, 'Workspace not found');
// create a mock server under the workspace with the same name
const newServer = await models.mockServer.getOrCreateForParentId(workspace._id, { name: activeWorkspace.name });
// TODO: filterout the mockServerName from the patch, or use an alternate method to create new workspace and server
const mockRoute = await models.mockRoute.create({ ...patch, parentId: newServer._id });
return redirect(`/organization/${organizationId}/project/${projectId}/workspace/${newServer.parentId}/mock-server/mock-route/${mockRoute._id}`);
}
const mockServer = await models.mockServer.getById(patch.parentId);
invariant(mockServer, 'Mock server not found');
const mockRoute = await models.mockRoute.create(patch);
return redirect(`/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/mock-server/mock-route/${mockRoute._id}`);
return redirect(`/organization/${organizationId}/project/${projectId}/workspace/${mockServer.parentId}/mock-server/mock-route/${mockRoute._id}`);
};
export const updateMockRouteAction: ActionFunction = async ({ request, params }) => {
const { mockRouteId } = params;
Expand Down
24 changes: 23 additions & 1 deletion packages/insomnia/src/ui/routes/mock-route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ import { CodeEditor } from '../components/codemirror/code-editor';
import { MockResponseHeadersEditor } from '../components/editors/mock-response-headers-editor';
import { MockResponsePane } from '../components/mocks/mock-response-pane';
import { MockUrlBar } from '../components/mocks/mock-url-bar';
import { showAlert } from '../components/modals';
import { showAlert, showModal } from '../components/modals';
import { AlertModal } from '../components/modals/alert-modal';
import { EmptyStatePane } from '../components/panes/empty-state-pane';
import { Pane, PaneBody, PaneHeader } from '../components/panes/pane';
import { SvgIcon } from '../components/svg-icon';
import { MockServerLoaderData } from './mock-server';
import { useRootLoaderData } from './root';

export interface MockRouteLoaderData {
Expand Down Expand Up @@ -91,6 +93,8 @@ export const useMockRoutePatcher = () => {

export const MockRouteRoute = () => {
const { mockServer, mockRoute } = useRouteLoaderData(':mockRouteId') as MockRouteLoaderData;
const { mockRoutes } = useRouteLoaderData('mock-server') as MockServerLoaderData;

const { userSession } = useRootLoaderData();
const patchMockRoute = useMockRoutePatcher();
const mockbinUrl = mockServer.useInsomniaCloud ? getMockServiceURL() : mockServer.url;
Expand Down Expand Up @@ -142,6 +146,15 @@ export const MockRouteRoute = () => {
});

const upsertMockbinHar = async (pathInput?: string) => {
const hasRouteInServer = mockRoutes.filter(m => m._id !== mockRoute._id).find(m => m.name === pathInput);
if (hasRouteInServer) {
showModal(AlertModal, {
title: 'Error',
message: `Path "${pathInput}" must be unique. Please enter a different name.`,
});

return;
};
const compoundId = mockRoute.parentId + pathInput;
const error = await upsertBinOnRemoteFromResponse(compoundId);
if (error) {
Expand All @@ -163,6 +176,15 @@ export const MockRouteRoute = () => {
});
};
const onSend = async (pathInput: string) => {
const hasRouteInServer = mockRoutes.filter(m => m._id !== mockRoute._id).find(m => m.name === pathInput);
if (hasRouteInServer) {
showModal(AlertModal, {
title: 'Error',
message: `Path "${pathInput}" must be unique. Please enter a different name.`,
});

return;
};
await upsertMockbinHar(pathInput);
const compoundId = mockRoute.parentId + pathInput;
createandSendPrivateRequest({
Expand Down
23 changes: 20 additions & 3 deletions packages/insomnia/src/ui/routes/mock-server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@ import { WorkspaceSyncDropdown } from '../components/dropdowns/workspace-sync-dr
import { EditableInput } from '../components/editable-input';
import { Icon } from '../components/icon';
import { showModal, showPrompt } from '../components/modals';
import { AlertModal } from '../components/modals/alert-modal';
import { AskModal } from '../components/modals/ask-modal';
import { EmptyStatePane } from '../components/panes/empty-state-pane';
import { SidebarLayout } from '../components/sidebar-layout';
import { SvgIcon } from '../components/svg-icon';
import { formatMethodName } from '../components/tags/method-tag';
import { MockRouteResponse, MockRouteRoute, useMockRoutePatcher } from './mock-route';
interface LoaderData {
export interface MockServerLoaderData {
mockServerId: string;
mockRoutes: MockRoute[];
}
export const loader: LoaderFunction = async ({ params }): Promise<LoaderData> => {
export const loader: LoaderFunction = async ({ params }): Promise<MockServerLoaderData> => {
const { organizationId, projectId, workspaceId } = params;
invariant(organizationId, 'Organization ID is required');
invariant(projectId, 'Project ID is required');
Expand All @@ -46,7 +47,7 @@ const MockServerRoute = () => {
workspaceId: string;
mockRouteId: string;
};
const { mockServerId, mockRoutes } = useLoaderData() as LoaderData;
const { mockServerId, mockRoutes } = useLoaderData() as MockServerLoaderData;
const fetcher = useFetcher();
const navigate = useNavigate();
const patchMockRoute = useMockRoutePatcher();
Expand All @@ -66,6 +67,14 @@ const MockServerRoute = () => {
defaultValue: mockRoutes.find(s => s._id === id)?.name,
submitName: 'Rename',
onComplete: name => {
const hasRouteInServer = mockRoutes.filter(m => m._id !== id).find(m => m.name === name);
if (hasRouteInServer) {
showModal(AlertModal, {
title: 'Error',
message: `Path "${name}" must be unique. Please enter a different name.`,
});
return;
};
name && patchMockRoute(id, { name });
},
});
Expand Down Expand Up @@ -195,6 +204,14 @@ const MockServerRoute = () => {
});
}}
onSubmit={name => {
const hasRouteInServer = mockRoutes.filter(m => m._id !== item._id).find(m => m.name === name);
if (hasRouteInServer) {
showModal(AlertModal, {
title: 'Error',
message: `Path "${name}" must be unique. Please enter a different name.`,
});
return;
};
name && fetcher.submit(
{ name },
{
Expand Down
Loading

0 comments on commit 3a932aa

Please sign in to comment.