diff --git a/packages/insomnia-smoke-test/tests/smoke/mock.test.ts b/packages/insomnia-smoke-test/tests/smoke/mock.test.ts index 95bcd29864..c349fef4b7 100644 --- a/packages/insomnia-smoke-test/tests/smoke/mock.test.ts +++ b/packages/insomnia-smoke-test/tests/smoke/mock.test.ts @@ -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(); diff --git a/packages/insomnia/src/ui/components/editors/mock-response-extractor.tsx b/packages/insomnia/src/ui/components/editors/mock-response-extractor.tsx index 1b99484af1..5e0d9debd6 100644 --- a/packages/insomnia/src/ui/components/editors/mock-response-extractor.tsx +++ b/packages/insomnia/src/ui/components/editors/mock-response-extractor.tsx @@ -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 ( @@ -30,21 +41,84 @@ export const MockResponseExtractor = () => {
diff --git a/packages/insomnia/src/ui/routes/actions.tsx b/packages/insomnia/src/ui/routes/actions.tsx index 94343c784a..1267e33e2a 100644 --- a/packages/insomnia/src/ui/routes/actions.tsx +++ b/packages/insomnia/src/ui/routes/actions.tsx @@ -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; diff --git a/packages/insomnia/src/ui/routes/mock-route.tsx b/packages/insomnia/src/ui/routes/mock-route.tsx index d9e0844f5c..87a6f80174 100644 --- a/packages/insomnia/src/ui/routes/mock-route.tsx +++ b/packages/insomnia/src/ui/routes/mock-route.tsx @@ -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 { @@ -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; @@ -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) { @@ -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({ diff --git a/packages/insomnia/src/ui/routes/mock-server.tsx b/packages/insomnia/src/ui/routes/mock-server.tsx index 79940413f7..5ab40c5de9 100644 --- a/packages/insomnia/src/ui/routes/mock-server.tsx +++ b/packages/insomnia/src/ui/routes/mock-server.tsx @@ -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