From 734b64f53f86f0dfd6fe7f65add940a498ffa79c Mon Sep 17 00:00:00 2001 From: Hexxa Date: Mon, 5 Aug 2024 10:21:37 +0800 Subject: [PATCH] feat(GUI): enable test results pane (#7737) * feat: enable the test result pane * test: bring back tests and cleanups * chore: replace tabitem with tabpanel * chore: useMemo for test result counts * refactor: abstract RequestTestResultRows as a component --- packages/insomnia-sdk/src/objects/test.ts | 5 + .../after-response-script-features.test.ts | 22 +-- .../smoke/pre-request-script-features.test.ts | 22 +-- .../smoke/pre-request-script-window.test.ts | 1 + packages/insomnia/src/models/response.ts | 3 + packages/insomnia/src/network/network.ts | 7 +- .../editors/mock-response-extractor.tsx | 9 +- .../panes/request-test-result-pane.tsx | 157 ++++++++++++++++++ .../src/ui/components/panes/response-pane.tsx | 43 ++++- .../src/ui/components/response-timer.tsx | 6 +- packages/insomnia/src/ui/routes/request.tsx | 23 ++- 11 files changed, 263 insertions(+), 35 deletions(-) create mode 100644 packages/insomnia/src/ui/components/panes/request-test-result-pane.tsx diff --git a/packages/insomnia-sdk/src/objects/test.ts b/packages/insomnia-sdk/src/objects/test.ts index 06f35e0c11..0300f3524a 100644 --- a/packages/insomnia-sdk/src/objects/test.ts +++ b/packages/insomnia-sdk/src/objects/test.ts @@ -12,6 +12,7 @@ export function test( testCase: msg, status: 'passed', executionTime, + category: 'unknown', }); } catch (e) { const executionTime = performance.now() - started; @@ -20,6 +21,7 @@ export function test( status: 'failed', executionTime, errorMessage: `${e}`, + category: 'unknown', }); } } @@ -33,15 +35,18 @@ export function skip( testCase: msg, status: 'skipped', executionTime: 0, + category: 'unknown', }); } export type TestStatus = 'passed' | 'failed' | 'skipped'; +export type TestCategory = 'unknown' | 'pre-request' | 'after-response'; export interface RequestTestResult { testCase: string; status: TestStatus; executionTime: number; // milliseconds errorMessage?: string; + category: TestCategory; } export interface TestHandler { diff --git a/packages/insomnia-smoke-test/tests/smoke/after-response-script-features.test.ts b/packages/insomnia-smoke-test/tests/smoke/after-response-script-features.test.ts index c5c33d4620..ee64302da4 100644 --- a/packages/insomnia-smoke-test/tests/smoke/after-response-script-features.test.ts +++ b/packages/insomnia-smoke-test/tests/smoke/after-response-script-features.test.ts @@ -19,20 +19,20 @@ test.describe('after-response script features tests', async () => { await page.getByLabel('After-response Scripts').click(); }); - // test('insomnia.test and insomnia.expect can work together', async ({ page }) => { - // const responsePane = page.getByTestId('response-pane'); + test('post: insomnia.test and insomnia.expect can work together', async ({ page }) => { + await page.getByLabel('Request Collection').getByTestId('tests with expect and test').press('Enter'); - // await page.getByLabel('Request Collection').getByTestId('tests with expect and test').press('Enter'); + // send + await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); - // // send - // await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); + // verify + await page.getByRole('tab', { name: 'Tests' }).click(); - // // verify - // await page.getByRole('tab', { name: 'Console' }).click(); - - // await expect(responsePane).toContainText('✓ happy tests'); - // await expect(responsePane).toContainText('✕ unhappy tests: AssertionError: expected 199 to deeply equal 200'); - // }); + const rows = page.getByTestId('test-result-row'); + await expect(rows.first()).toContainText('PASS'); + await expect(rows.nth(1)).toContainText('FAIL'); + await expect(rows.nth(1)).toContainText('AssertionError:'); + }); test('environment and baseEnvironment can be persisted', async ({ page }) => { const statusTag = page.locator('[data-testid="response-status-tag"]:visible'); diff --git a/packages/insomnia-smoke-test/tests/smoke/pre-request-script-features.test.ts b/packages/insomnia-smoke-test/tests/smoke/pre-request-script-features.test.ts index 14100b9b54..39111eb0fa 100644 --- a/packages/insomnia-smoke-test/tests/smoke/pre-request-script-features.test.ts +++ b/packages/insomnia-smoke-test/tests/smoke/pre-request-script-features.test.ts @@ -399,20 +399,20 @@ test.describe('pre-request features tests', async () => { await expect(responsePane).toContainText('fixtures/certificates/fake.pfx'); // original proxy }); - // test('insomnia.test and insomnia.expect can work together ', async ({ page }) => { - // const responsePane = page.getByTestId('response-pane'); + test('pre: insomnia.test and insomnia.expect can work together', async ({ page }) => { + await page.getByLabel('Request Collection').getByTestId('insomnia.test').press('Enter'); - // await page.getByLabel('Request Collection').getByTestId('insomnia.test').press('Enter'); + // send + await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); - // // send - // await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click(); + // verify + await page.getByRole('tab', { name: 'Tests' }).click(); - // // verify - // await page.getByRole('tab', { name: 'Console' }).click(); - - // await expect(responsePane).toContainText('✓ happy tests'); - // await expect(responsePane).toContainText('✕ unhappy tests: AssertionError: expected 199 to deeply equal 200'); - // }); + const rows = page.getByTestId('test-result-row'); + await expect(rows.first()).toContainText('PASS'); + await expect(rows.nth(1)).toContainText('FAIL'); + await expect(rows.nth(1)).toContainText('AssertionError:'); + }); test('environment and baseEnvironment can be persisted', async ({ page }) => { const statusTag = page.locator('[data-testid="response-status-tag"]:visible'); diff --git a/packages/insomnia-smoke-test/tests/smoke/pre-request-script-window.test.ts b/packages/insomnia-smoke-test/tests/smoke/pre-request-script-window.test.ts index b644c146ac..4ed833306c 100644 --- a/packages/insomnia-smoke-test/tests/smoke/pre-request-script-window.test.ts +++ b/packages/insomnia-smoke-test/tests/smoke/pre-request-script-window.test.ts @@ -56,6 +56,7 @@ test.describe('test hidden window handling', async () => { expect(await page.locator('.pane-two pre').innerText()).toEqual('Timeout: Running script took too long'); await page.getByRole('tab', { name: 'Console' }).click(); await page.getByRole('tab', { name: 'Preview' }).click(); + const windows = await app.windows(); const hiddenWindow = windows[1]; hiddenWindow.close(); diff --git a/packages/insomnia/src/models/response.ts b/packages/insomnia/src/models/response.ts index 538898c982..c0786656a0 100644 --- a/packages/insomnia/src/models/response.ts +++ b/packages/insomnia/src/models/response.ts @@ -1,4 +1,5 @@ import fs from 'fs'; +import type { RequestTestResult } from 'insomnia-sdk'; import { Readable } from 'stream'; import zlib from 'zlib'; @@ -46,6 +47,7 @@ export interface BaseResponse { // Things from the request settingStoreCookies: boolean | null; settingSendCookies: boolean | null; + requestTestResults: RequestTestResult[]; } export type Response = BaseModel & BaseResponse; @@ -80,6 +82,7 @@ export function init(): BaseResponse { // Responses sent before environment filtering will have a special value // so they don't show up at all when filtering is on. environmentId: '__LEGACY__', + requestTestResults: [], }; } diff --git a/packages/insomnia/src/network/network.ts b/packages/insomnia/src/network/network.ts index 37ee422cec..1f18eba498 100644 --- a/packages/insomnia/src/network/network.ts +++ b/packages/insomnia/src/network/network.ts @@ -177,6 +177,7 @@ export const tryToExecutePreRequestScript = async ({ settings, cookieJar, globals: activeGlobalEnvironment, + requestTestResults: new Array(), }; } const joinedScript = [...folderScripts].join('\n'); @@ -207,6 +208,7 @@ export const tryToExecutePreRequestScript = async ({ settings: mutatedContext.settings || settings, globals: mutatedContext.globals, cookieJar: mutatedContext.cookieJar, + requestTestResults: mutatedContext.requestTestResults, }; }; @@ -411,7 +413,10 @@ export async function tryToExecuteAfterResponseScript(context: RequestAndContext await fn${i}(); `); if (folderScripts.length === 0) { - return context; + return { + ...context, + requestTestResults: new Array(), + }; } const joinedScript = [...folderScripts].join('\n'); 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 436f748154..10a35a21c5 100644 --- a/packages/insomnia/src/ui/components/editors/mock-response-extractor.tsx +++ b/packages/insomnia/src/ui/components/editors/mock-response-extractor.tsx @@ -37,11 +37,12 @@ export const MockResponseExtractor = () => { const mimeType = maybeMimeType && isInMockContentTypeList(maybeMimeType) ? maybeMimeType : 'text/plain'; return (
-
+
- Transform this {getContentTypeName(activeResponse?.contentType) || ''} response to a new mock route or overwrite an existing one. + Transform this + {activeResponse?.contentType ? getContentTypeName(activeResponse?.contentType) === 'Other' ? '' : ` ${getContentTypeName(activeResponse?.contentType)}` : ''} response to a new mock route or overwrite an existing one.
{ @@ -151,7 +152,7 @@ export const MockResponseExtractor = () => { setSelectedMockRoute(''); }} > - + {mockServerAndRoutes .map(w => ( + {mockServerAndRoutes.find(s => s._id === selectedMockServer)?.routes .map(w => (
diff --git a/packages/insomnia/src/ui/routes/request.tsx b/packages/insomnia/src/ui/routes/request.tsx index 5e556281b6..a08295e784 100644 --- a/packages/insomnia/src/ui/routes/request.tsx +++ b/packages/insomnia/src/ui/routes/request.tsx @@ -2,6 +2,7 @@ import { createWriteStream } from 'node:fs'; import path from 'node:path'; import * as contentDisposition from 'content-disposition'; +import type { RequestTestResult } from 'insomnia-sdk'; import { extension as mimeExtension } from 'mime-types'; import { type ActionFunction, type LoaderFunction, redirect } from 'react-router-dom'; @@ -421,19 +422,35 @@ export const sendAction: ActionFunction = async ({ request, params }) => { const requestMeta = await models.requestMeta.getByParentId(requestId); invariant(requestMeta, 'RequestMeta not found'); - const responsePatch = await responseTransform(response, requestData.activeEnvironmentId, renderedRequest, renderedResult.context); - const is2XXWithBodyPath = responsePatch.statusCode && responsePatch.statusCode >= 200 && responsePatch.statusCode < 300 && responsePatch.bodyPath; + const baseResponsePatch = await responseTransform(response, requestData.activeEnvironmentId, renderedRequest, renderedResult.context); + + const is2XXWithBodyPath = baseResponsePatch.statusCode && baseResponsePatch.statusCode >= 200 && baseResponsePatch.statusCode < 300 && baseResponsePatch.bodyPath; const shouldWriteToFile = shouldPromptForPathAfterResponse && is2XXWithBodyPath; mutatedContext.request.afterResponseScript = afterResponseScript; window.main.addExecutionStep({ requestId, stepName: 'Executing after-response script' }); - await tryToExecuteAfterResponseScript({ + const postMutatedContext = await tryToExecuteAfterResponseScript({ ...requestData, ...mutatedContext, response, }); window.main.completeExecutionStep({ requestId }); + const responsePatch = postMutatedContext ? + { + ...baseResponsePatch, + // both pre-request and after-response test results are collected + requestTestResults: [ + ...mutatedContext.requestTestResults.map( + (result: RequestTestResult): RequestTestResult => ({ ...result, category: 'pre-request' }), + ), + ...postMutatedContext.requestTestResults.map( + (result: RequestTestResult): RequestTestResult => ({ ...result, category: 'after-response' }), + ), + ], + } + : baseResponsePatch; + if (!shouldWriteToFile) { const response = await models.response.create(responsePatch, requestData.settings.maxHistoryResponses); await models.requestMeta.update(requestMeta, { activeResponseId: response._id });