feat(Response Pane): improve tabs styles (#7765)

* update tabs styling for response panes

* Rename Timeline to Console in e2e tests

* timeline -> console in mock panes

* update e2e
This commit is contained in:
James Gatz 2024-07-26 14:35:26 +02:00 committed by GitHub
parent 41bbb70da6
commit f411eb7f21
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 142 additions and 118 deletions

View File

@ -34,7 +34,7 @@ test('can use node-libcurl, httpsnippet, hidden browser window', async ({ app, p
await page.getByLabel('Request Collection').getByTestId('sends request with pre-request script').press('Enter');
await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click();
await expect(statusTag).toContainText('200 OK');
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
});
test('can use external modules in scripts ', async ({ app, page }) => {

View File

@ -28,7 +28,7 @@ test.describe('after-response script features tests', async () => {
await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click();
// verify
await page.getByRole('tab', { name: 'Timeline' }).click();
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');

View File

@ -45,7 +45,7 @@ test('can send requests', async ({ app, page }) => {
await page.getByLabel('Request Collection').getByTestId('connects to event stream and shows ping response').press('Enter');
await page.getByTestId('request-pane').getByRole('button', { name: 'Connect' }).click();
await expect(statusTag).toContainText('200 OK');
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await expect(responseBody).toContainText('Connected to 127.0.0.1');
await page.getByTestId('request-pane').getByRole('button', { name: 'Disconnect' }).click();
@ -66,7 +66,7 @@ test('can send requests', async ({ app, page }) => {
await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click();
await expect(statusTag).toContainText('200 OK');
// TODO(filipe): re-add a check for the preview that is less flaky
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await page.locator('pre').filter({ hasText: '< Content-Type: application/pdf' }).click();
await page.getByLabel('Request Collection').getByTestId('sends request with basic authentication').press('Enter');
@ -77,7 +77,7 @@ test('can send requests', async ({ app, page }) => {
await page.getByLabel('Request Collection').getByTestId('sends request with cookie and get cookie in response').press('Enter');
await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click();
await expect(statusTag).toContainText('200 OK');
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await expect(responseBody).toContainText('Set-Cookie: insomnia-test-cookie=value123');
});

View File

@ -44,7 +44,7 @@ test.describe('Cookie editor', async () => {
await page.click('[data-testid="request-pane"] button:has-text("Send")');
// Check in the timeline that the cookie was sent
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await page.click('text=foo2=bar2; foo=b123ar');
// Send ws request
@ -53,7 +53,7 @@ test.describe('Cookie editor', async () => {
await page.click('[data-testid="request-pane"] >> text=Connect');
// Check in the timeline that the cookie was sent
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await page.click('text=foo2=bar2; foo=b123ar;');
});

View File

@ -30,7 +30,7 @@ test.describe('Environment Editor', async () => {
// Send a request check variables defaulted to base env since new env is empty
await page.getByLabel('Request Collection').getByTestId('New Request').press('Enter');
await page.getByRole('button', { name: 'Send' }).click();
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await page.getByText('baseenv0').click();
await page.getByText('baseenv1').click();
});
@ -53,7 +53,7 @@ test.describe('Environment Editor', async () => {
await page.getByLabel('Request Collection').getByTestId('New Request').press('Enter');
// await page.waitForTimeout(60000);
await page.getByRole('button', { name: 'Send' }).click();
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await page.getByText('subenvB0').click();
await page.getByText('subenvB1').click();
});
@ -94,7 +94,7 @@ test.describe('Environment Editor', async () => {
// Check new variables are in the timeline
await page.getByRole('button', { name: 'Send' }).click();
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
// FIXME(filipe) - adding variables to request body can be so fast they don't get picked up when sending request

View File

@ -15,6 +15,6 @@ test('can make a mock route: WARNING: THIS TEST DEPENDS ON mock.insomnia.moe to
await page.getByRole('button', { name: 'Test' }).click();
await page.getByText('No body returned for response').click();
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await page.getByText('HTTP/2 200').click();
});

View File

@ -368,7 +368,7 @@ test.describe('pre-request features tests', async () => {
await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click();
// verify
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await expect(responsePane).toContainText('localhost:2222'); // original proxy
await expect(responsePane).toContainText('Trying 127.0.0.1:8888'); // updated proxy
});
@ -395,7 +395,7 @@ test.describe('pre-request features tests', async () => {
// send
await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click();
// verify
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await expect(responsePane).toContainText('fixtures/certificates/fake.pfx'); // original proxy
});
@ -408,7 +408,7 @@ test.describe('pre-request features tests', async () => {
await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click();
// verify
await page.getByRole('tab', { name: 'Timeline' }).click();
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');

View File

@ -54,8 +54,8 @@ test.describe('test hidden window handling', async () => {
await page.waitForSelector('[data-testid="response-status-tag"]:visible');
expect(await page.locator('.pane-two pre').innerText()).toEqual('Timeout: Running script took too long');
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Preview' }).click();
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();

View File

@ -29,7 +29,7 @@ test('Check filter responses by environment preference', async ({ app, page }) =
// Send a request
await page.getByLabel('Request Collection').getByTestId('example http').press('Enter');
await page.click('[data-testid="request-pane"] button:has-text("Send")');
await page.click('text=Timeline');
await page.click('text=Console');
await page.locator('text=HTTP/1.1 200 OK').click();
// Set filter responses by environment
@ -40,6 +40,6 @@ test('Check filter responses by environment preference', async ({ app, page }) =
// Re-send the request and check timeline
await page.locator('[data-testid="request-pane"] button:has-text("Send")').click();
await page.click('text=Timeline');
await page.click('text=Console');
await page.locator('text=HTTP/1.1 200 OK').click();
});

View File

@ -25,7 +25,7 @@ test('can make websocket connection', async ({ app, page }) => {
await expect(page.locator('.app')).toContainText('ws://localhost:4010');
await page.click('text=Connect');
await expect(statusTag).toContainText('101 Switching Protocols');
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await expect(responseBody).toContainText('WebSocket connection established');
await page.click('text=Disconnect');
await expect(responseBody).toContainText('Closing connection with code 1005');
@ -35,7 +35,7 @@ test('can make websocket connection', async ({ app, page }) => {
await expect(page.locator('.app')).toContainText('ws://localhost:4010/basic-auth');
await page.click('text=Connect');
await expect(statusTag).toContainText('101 Switching Protocols');
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await expect(responseBody).toContainText('> authorization: Basic dXNlcjpwYXNzd29yZA==');
// Can connect with Bearer Auth
@ -43,7 +43,7 @@ test('can make websocket connection', async ({ app, page }) => {
await expect(page.locator('.app')).toContainText('ws://localhost:4010/bearer');
await page.click('text=Connect');
await expect(statusTag).toContainText('101 Switching Protocols');
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await expect(responseBody).toContainText('> authorization: Bearer insomnia-cool-token-!!!1112113243111');
// Can handle redirects
@ -51,7 +51,7 @@ test('can make websocket connection', async ({ app, page }) => {
await expect(page.locator('.app')).toContainText('ws://localhost:4010/redirect');
await page.click('text=Connect');
await expect(statusTag).toContainText('101 Switching Protocols');
await page.getByRole('tab', { name: 'Timeline' }).click();
await page.getByRole('tab', { name: 'Console' }).click();
await expect(responseBody).toContainText('WebSocket connection established');
const webSocketActiveConnections = page.locator('[data-testid="WebSocketSpinner__Connected"]');

View File

@ -120,7 +120,7 @@ export const MockResponsePane = () => {
<TabItem key="headers" title="Headers">
<ResponseHeadersViewer headers={activeResponse?.headers || []} />
</TabItem>
<TabItem key="timeline" title="Timeline">
<TabItem key="timeline" title="Console">
<ResponseTimelineViewer
key={activeResponse?._id}
timeline={timeline}

View File

@ -1,6 +1,7 @@
import fs from 'fs';
import { extension as mimeExtension } from 'mime-types';
import React, { type FC, useCallback } from 'react';
import { Tab, TabList, TabPanel, Tabs, Toolbar } from 'react-aria-components';
import { useRouteLoaderData } from 'react-router-dom';
import { PREVIEW_MODE_SOURCE } from '../../../common/constants';
@ -12,7 +13,6 @@ import { useExecutionState } from '../../hooks/use-execution-state';
import { useRequestMetaPatcher } from '../../hooks/use-request';
import type { RequestLoaderData } from '../../routes/request';
import { useRootLoaderData } from '../../routes/root';
import { PanelContainer, TabItem, Tabs } from '../base/tabs';
import { PreviewModeDropdown } from '../dropdowns/preview-mode-dropdown';
import { ResponseHistoryDropdown } from '../dropdowns/response-history-dropdown';
import { MockResponseExtractor } from '../editors/mock-response-extractor';
@ -157,16 +157,52 @@ export const ResponsePane: FC<Props> = ({
/>
</PaneHeader>
)}
<Tabs aria-label="Response pane tabs">
<TabItem
key="preview"
title={
<Tabs aria-label='Request group tabs' className="flex-1 w-full h-full flex flex-col">
<TabList className='w-full flex-shrink-0 overflow-x-auto border-solid scro border-b border-b-[--hl-md] bg-[--color-bg] flex items-center h-[--line-height-sm]' aria-label='Request pane tabs'>
<Tab
className='flex-shrink-0 h-full flex items-center justify-between cursor-pointer gap-2 outline-none select-none px-3 py-1 text-[--hl] aria-selected:text-[--color-font] hover:bg-[--hl-sm] hover:text-[--color-font] aria-selected:bg-[--hl-xs] aria-selected:focus:bg-[--hl-sm] aria-selected:hover:bg-[--hl-sm] focus:bg-[--hl-sm] transition-colors duration-300'
id='preview'
>
Preview
</Tab>
<Tab
className='flex-shrink-0 h-full flex items-center justify-between cursor-pointer gap-2 outline-none select-none px-3 py-1 text-[--hl] aria-selected:text-[--color-font] hover:bg-[--hl-sm] hover:text-[--color-font] aria-selected:bg-[--hl-xs] aria-selected:focus:bg-[--hl-sm] aria-selected:hover:bg-[--hl-sm] focus:bg-[--hl-sm] transition-colors duration-300'
id='headers'
>
Headers
{activeResponse.headers.length > 0 && (
<span className="p-2 aspect-square flex items-center justify-between border-solid border border-[--hl-md] overflow-hidden rounded-lg text-xs shadow-small">{activeResponse.headers.length}</span>
)}
</Tab>
<Tab
className='flex-shrink-0 h-full flex items-center justify-between cursor-pointer gap-2 outline-none select-none px-3 py-1 text-[--hl] aria-selected:text-[--color-font] hover:bg-[--hl-sm] hover:text-[--color-font] aria-selected:bg-[--hl-xs] aria-selected:focus:bg-[--hl-sm] aria-selected:hover:bg-[--hl-sm] focus:bg-[--hl-sm] transition-colors duration-300'
id='cookies'
>
Cookies
{cookieHeaders.length > 0 && (
<span className="p-2 aspect-square flex items-center justify-between border-solid border border-[--hl-md] overflow-hidden rounded-lg text-xs shadow-small">{cookieHeaders.length}</span>
)}
</Tab>
<Tab
className='flex-shrink-0 h-full flex items-center justify-between cursor-pointer gap-2 outline-none select-none px-3 py-1 text-[--hl] aria-selected:text-[--color-font] hover:bg-[--hl-sm] hover:text-[--color-font] aria-selected:bg-[--hl-xs] aria-selected:focus:bg-[--hl-sm] aria-selected:hover:bg-[--hl-sm] focus:bg-[--hl-sm] transition-colors duration-300'
id='mock-response'
>
Mock
</Tab>
<Tab
className='flex-shrink-0 h-full flex items-center justify-between cursor-pointer gap-2 outline-none select-none px-3 py-1 text-[--hl] aria-selected:text-[--color-font] hover:bg-[--hl-sm] hover:text-[--color-font] aria-selected:bg-[--hl-xs] aria-selected:focus:bg-[--hl-sm] aria-selected:hover:bg-[--hl-sm] focus:bg-[--hl-sm] transition-colors duration-300'
id='timeline'
>
Console
</Tab>
</TabList>
<TabPanel className='w-full flex-1 flex flex-col overflow-hidden' id='preview'>
<Toolbar className="w-full flex-shrink-0 h-[--line-height-sm] border-b border-solid border-[--hl-md] flex items-center px-2">
<PreviewModeDropdown
download={handleDownloadResponseBody}
copyToClipboard={handleCopyResponseToClipboard}
/>
}
>
</Toolbar>
<ResponseViewer
key={activeResponse._id}
bytes={Math.max(activeResponse.bytesContent, activeResponse.bytesRead)}
@ -184,36 +220,13 @@ export const ResponsePane: FC<Props> = ({
updateFilter={activeResponse.error ? undefined : handleSetFilter}
url={activeResponse.url}
/>
</TabItem>
<TabItem
key="headers"
title={
<div className='flex items-center gap-2'>
Headers
{activeResponse.headers.length > 0 && (
<span className="p-2 aspect-square flex items-center color-inherit justify-between border-solid border border-[--hl-md] overflow-hidden rounded-lg text-xs shadow-small">{activeResponse.headers.length}</span>
)}
</div>
}
>
<PanelContainer className="pad">
</TabPanel>
<TabPanel className='w-full flex-1 flex flex-col overflow-y-auto' id='headers'>
<ErrorBoundary key={activeResponse._id} errorClassName="font-error pad text-center">
<ResponseHeadersViewer headers={activeResponse.headers} />
</ErrorBoundary>
</PanelContainer>
</TabItem>
<TabItem
key="cookies"
title={
<div className='flex items-center gap-2'>
Cookies
{cookieHeaders.length > 0 && (
<span className="p-2 aspect-square flex items-center color-inherit justify-between border-solid border border-[--hl-md] overflow-hidden rounded-lg text-xs shadow-small">{cookieHeaders.length}</span>
)}
</div>
}
>
<PanelContainer className="pad">
</TabPanel>
<TabPanel className='w-full flex-1 flex flex-col overflow-y-auto' id='cookies'>
<ErrorBoundary key={activeResponse._id} errorClassName="font-error pad text-center">
<ResponseCookiesViewer
cookiesSent={activeResponse.settingSendCookies}
@ -221,19 +234,23 @@ export const ResponsePane: FC<Props> = ({
headers={cookieHeaders}
/>
</ErrorBoundary>
</PanelContainer>
</TabItem>
<TabItem key="timeline" title="Timeline">
</TabPanel>
<TabPanel
className='w-full flex-1 flex flex-col overflow-y-auto'
id='mock-response'
>
<MockResponseExtractor />
</TabPanel>
<TabPanel className='w-full flex-1 flex flex-col overflow-y-auto' id='timeline'>
<ErrorBoundary key={activeResponse._id} errorClassName="font-error pad text-center">
<ResponseTimelineViewer
key={activeResponse._id}
timeline={timeline}
/>
</ErrorBoundary>
</TabItem>
<TabItem key="mock-response" title="Mock Response">
<MockResponseExtractor />
</TabItem>
</TabPanel>
</Tabs>
<ErrorBoundary errorClassName="font-error pad text-center">
{isExecuting && <ResponseTimer

View File

@ -1,6 +1,6 @@
import fs from 'fs';
import React, { type FC, useEffect, useState } from 'react';
import { Button, Input, SearchField } from 'react-aria-components';
import { Button, Input, SearchField, Tab, TabList, TabPanel, Tabs } from 'react-aria-components';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import { useRouteLoaderData } from 'react-router-dom';
import styled from 'styled-components';
@ -13,7 +13,6 @@ import type { Response } from '../../../models/response';
import type { WebSocketResponse } from '../../../models/websocket-response';
import { useRealtimeConnectionEvents } from '../../hooks/use-realtime-connection-events';
import type { RequestLoaderData, WebSocketRequestLoaderData } from '../../routes/request';
import { PanelContainer, TabItem, Tabs } from '../base/tabs';
import { ResponseHistoryDropdown } from '../dropdowns/response-history-dropdown';
import { ErrorBoundary } from '../error-boundary';
import { Icon } from '../icon';
@ -135,8 +134,40 @@ const RealtimeActiveResponsePane: FC<{ response: WebSocketResponse | Response }>
activeResponse={response}
/>
</PaneHeader>
<Tabs aria-label="Curl response pane tabs">
<TabItem key="events" title="Events">
<Tabs aria-label='Request group tabs' className="flex-1 w-full h-full flex flex-col">
<TabList className='w-full flex-shrink-0 overflow-x-auto border-solid scro border-b border-b-[--hl-md] bg-[--color-bg] flex items-center h-[--line-height-sm]' aria-label='Request pane tabs'>
<Tab
className='flex-shrink-0 h-full flex items-center justify-between cursor-pointer gap-2 outline-none select-none px-3 py-1 text-[--hl] aria-selected:text-[--color-font] hover:bg-[--hl-sm] hover:text-[--color-font] aria-selected:bg-[--hl-xs] aria-selected:focus:bg-[--hl-sm] aria-selected:hover:bg-[--hl-sm] focus:bg-[--hl-sm] transition-colors duration-300'
id='events'
>
Events
</Tab>
<Tab
className='flex-shrink-0 h-full flex items-center justify-between cursor-pointer gap-2 outline-none select-none px-3 py-1 text-[--hl] aria-selected:text-[--color-font] hover:bg-[--hl-sm] hover:text-[--color-font] aria-selected:bg-[--hl-xs] aria-selected:focus:bg-[--hl-sm] aria-selected:hover:bg-[--hl-sm] focus:bg-[--hl-sm] transition-colors duration-300'
id='headers'
>
Headers
{response.headers.length > 0 && (
<span className="p-2 aspect-square flex items-center justify-between border-solid border border-[--hl-md] overflow-hidden rounded-lg text-xs shadow-small">{response.headers.length}</span>
)}
</Tab>
<Tab
className='flex-shrink-0 h-full flex items-center justify-between cursor-pointer gap-2 outline-none select-none px-3 py-1 text-[--hl] aria-selected:text-[--color-font] hover:bg-[--hl-sm] hover:text-[--color-font] aria-selected:bg-[--hl-xs] aria-selected:focus:bg-[--hl-sm] aria-selected:hover:bg-[--hl-sm] focus:bg-[--hl-sm] transition-colors duration-300'
id='cookies'
>
Cookies
{cookieHeaders.length > 0 && (
<span className="p-2 aspect-square flex items-center justify-between border-solid border border-[--hl-md] overflow-hidden rounded-lg text-xs shadow-small">{cookieHeaders.length}</span>
)}
</Tab>
<Tab
className='flex-shrink-0 h-full flex items-center justify-between cursor-pointer gap-2 outline-none select-none px-3 py-1 text-[--hl] aria-selected:text-[--color-font] hover:bg-[--hl-sm] hover:text-[--color-font] aria-selected:bg-[--hl-xs] aria-selected:focus:bg-[--hl-sm] aria-selected:hover:bg-[--hl-sm] focus:bg-[--hl-sm] transition-colors duration-300'
id='timeline'
>
Console
</Tab>
</TabList>
<TabPanel className='w-full flex-1 flex flex-col overflow-hidden' id='events'>
<PanelGroup direction='vertical' className='h-full w-full grid grid-rows-[repeat(auto-fit,minmax(0,1fr))]'>
{response.error ? <ResponseErrorViewer url={response.url} error={response.error} />
: <>
@ -210,36 +241,13 @@ const RealtimeActiveResponsePane: FC<{ response: WebSocketResponse | Response }>
)}
</>}
</PanelGroup>
</TabItem>
<TabItem
key="headers"
title={
<div className='flex items-center gap-2'>
Headers
{response.headers.length > 0 && (
<span className="p-2 aspect-square flex items-center color-inherit justify-between border-solid border border-[--hl-md] overflow-hidden rounded-lg text-xs shadow-small">{response.headers.length}</span>
)}
</div>
}
>
<PanelContainer className="pad">
</TabPanel>
<TabPanel className='w-full flex-1 flex flex-col overflow-y-auto' id='headers'>
<ErrorBoundary key={response._id} errorClassName="font-error pad text-center">
<ResponseHeadersViewer headers={response.headers} />
</ErrorBoundary>
</PanelContainer>
</TabItem>
<TabItem
key="cookies"
title={
<div className='flex items-center gap-2'>
Cookies
{cookieHeaders.length > 0 && (
<span className="p-2 aspect-square flex items-center color-inherit justify-between border-solid border border-[--hl-md] overflow-hidden rounded-lg text-xs shadow-small">{cookieHeaders.length}</span>
)}
</div>
}
>
<PanelContainer className="pad">
</TabPanel>
<TabPanel className='w-full flex-1 flex flex-col overflow-y-auto' id='cookies'>
<ErrorBoundary key={response._id} errorClassName="font-error pad text-center">
<ResponseCookiesViewer
cookiesSent={response.settingSendCookies}
@ -247,15 +255,14 @@ const RealtimeActiveResponsePane: FC<{ response: WebSocketResponse | Response }>
headers={cookieHeaders}
/>
</ErrorBoundary>
</PanelContainer>
</TabItem>
<TabItem key="timeline" title="Timeline">
</TabPanel>
<TabPanel className='w-full flex-1 flex flex-col overflow-hidden' id='timeline'>
<ResponseTimelineViewer
key={response._id}
timeline={timeline}
pinToBottom={true}
/>
</TabItem>
</TabPanel>
</Tabs>
</ Pane>
);