Skip to content

Commit

Permalink
fix(Response Tabs): Tabs with a menu inside are not accessible - Resp…
Browse files Browse the repository at this point in the history
…onse Panes (#7477)

* use thing scrollbars in the app

* fix menu/toast overflow content shift

* update content and auth dropdowns

* Update auth wrapper styles

* update body editors

* Request/request-group panes

* update request script editor

* update e2e tests

* remove log
  • Loading branch information
gatzjames authored Jun 5, 2024
1 parent 57e9898 commit 79cc2ef
Show file tree
Hide file tree
Showing 17 changed files with 1,244 additions and 1,032 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ test.describe('Environment Editor', async () => {
await page.getByLabel('Request Collection').getByTestId('New Request').press('Enter');

// Add number variable to request body
await page.getByRole('tab', { name: 'Plain' }).click();
await page.getByRole('tab', { name: 'Body' }).click();
await page.locator('pre').filter({ hasText: '_.exampleObject.anotherNumber' }).press('Enter');

await page.getByTestId('CodeEditor').getByRole('textbox').press('Enter');
Expand Down
14 changes: 7 additions & 7 deletions packages/insomnia-smoke-test/tests/smoke/graphql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ test('can render schema and send GraphQL requests', async ({ app, page }) => {

// Open the graphql request
await page.getByLabel('Request Collection').getByTestId('GraphQL request').press('Enter');
await page.getByRole('tab', { name: 'GraphQL' }).click();
await page.getByRole('tab', { name: 'Body' }).click();
// Assert the schema is fetched after switching to GraphQL request
await expect(page.locator('.graphql-editor__meta')).toContainText('schema fetched just now');
await expect(page.getByText('Schema fetched just now')).toBeVisible();

// Assert schema documentation stuff
await page.getByRole('button', { name: 'schema' }).click();
Expand Down Expand Up @@ -63,9 +63,9 @@ test('can render schema and send GraphQL requests with object variables', async

// Open the graphql request
await page.getByLabel('Request Collection').getByTestId('GraphQL request with variables').press('Enter');
await page.getByRole('tab', { name: 'GraphQL' }).click();
await page.getByRole('tab', { name: 'Body' }).click();
// Assert the schema is fetched after switching to GraphQL request
await expect(page.locator('.graphql-editor__meta')).toContainText('schema fetched just now');
await expect(page.getByText('Schema fetched just now')).toBeVisible();

// Assert schema documentation stuff
await page.getByRole('button', { name: 'schema' }).click();
Expand Down Expand Up @@ -105,9 +105,9 @@ test('can render numeric environment', async ({ app, page }) => {

// Open the graphql request
await page.getByLabel('Request Collection').getByTestId('GraphQL request with number').press('Enter');
await page.getByRole('tab', { name: 'GraphQL' }).click();
await page.getByRole('tab', { name: 'Body' }).click();
// Assert the schema is fetched after switching to GraphQL request
await expect(page.locator('.graphql-editor__meta')).toContainText('schema fetched just now');
await expect(page.getByText('Schema fetched just now')).toBeVisible();

// Assert schema documentation stuff
await page.getByRole('button', { name: 'schema' }).click();
Expand Down Expand Up @@ -144,7 +144,7 @@ test('can send GraphQL requests after editing and prettifying query', async ({ a
await page.getByLabel('Request Collection').getByTestId('GraphQL request').press('Enter');

// Edit and prettify query
await page.getByRole('tab', { name: 'GraphQL' }).click();
await page.getByRole('tab', { name: 'Body' }).click();
await page.locator('pre[role="presentation"]:has-text("bearer")').click();
await page.locator('.app').press('Enter');
await page.locator('text=Prettify GraphQL').click();
Expand Down
3 changes: 2 additions & 1 deletion packages/insomnia-smoke-test/tests/smoke/oauth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ test('can make oauth2 requests', async ({ app, page }) => {
await expect(responseBody).toContainText('"sub": "admin"');

// Navigate to the OAuth2 Tab and refresh the token from there
await page.getByRole('tab', { name: 'OAuth 2' }).click();
await page.getByRole('tab', { name: 'Auth' }).click();
await expect(page.getByRole('button', { name: 'OAuth 2.0' })).toBeVisible();

const tokenInput = page.locator('[for="Access-Token"] > input');
const prevToken = await tokenInput.inputValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,13 @@ test.describe('pre-request features tests', async () => {
// set request body
await page.getByRole('tab', { name: 'Body' }).click();
await page.getByRole('button', { name: 'Body' }).click();
await page.getByRole('menuitem', { name: 'JSON' }).click();
await page.getByRole('option', { name: 'JSON' }).click();

const bodyEditor = page.getByTestId('CodeEditor').getByRole('textbox');
await bodyEditor.fill('{ "rawBody": {{ _.rawBody }}, "urlencodedBody": {{ _.urlencodedBody }}, "gqlBody": {{ _.gqlBody }}, "fileBody": {{ _.fileBody }}, "formdataBody": {{ _.formdataBody }} }');

// enter script
await page.getByTestId('pre-request-script-tab').click();
await page.getByRole('tab', { name: 'Scripts' }).click();
const preRequestScriptEditor = page.getByTestId('CodeEditor').getByRole('textbox');
await preRequestScriptEditor.fill(`
const rawReq = {
Expand Down Expand Up @@ -500,10 +500,10 @@ test.describe('unhappy paths', async () => {
// set request body
await page.getByRole('tab', { name: 'Body' }).click();
await page.getByRole('button', { name: 'Body' }).click();
await page.getByRole('menuitem', { name: 'JSON' }).click();
await page.getByRole('option', { name: 'JSON' }).click();

// enter script
await page.getByTestId('pre-request-script-tab').click();
await page.getByRole('tab', { name: 'Scripts' }).click();
const preRequestScriptEditor = page.getByTestId('CodeEditor').getByRole('textbox');
await preRequestScriptEditor.fill(tc.preReqScript);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ test('Request tabs', async ({ page }) => {
await page.getByRole('menuitemradio', { name: 'HTTP Request' }).press('Enter');
await page.getByRole('tab', { name: 'Body' }).click();
await page.getByRole('button', { name: 'Body' }).click();
await page.getByRole('menuitem', { name: 'JSON' }).click();
await page.getByRole('option', { name: 'JSON' }).click();
await page.getByRole('tab', { name: 'Auth' }).click();
await page.getByRole('button', { name: 'Auth' }).click();
await page.getByRole('menuitem', { name: 'OAuth 1.0' }).click();
await page.getByRole('tab', { name: 'Parameters' }).click();
await page.getByLabel('OAuth 1.0', { exact: true }).click();
await page.getByRole('tab', { name: 'Params' }).click();
await page.getByRole('tab', { name: 'Headers' }).click();
await page.getByRole('tab', { name: 'Docs' }).click();
await page.locator('text=Add Description').click();
Expand All @@ -26,11 +26,11 @@ test('WS tabs', async ({ page }) => {

await page.getByLabel('Create in collection').click();
await page.getByRole('menuitemradio', { name: 'WebSocket Request' }).click();
await page.getByRole('tab', { name: 'JSON' }).click();
await page.getByLabel('Websocket request pane tabs').getByRole('button', { name: 'JSON' }).click();
await page.getByRole('menuitem', { name: 'JSON' }).click();
await page.getByRole('tab', { name: 'Body' }).click();
await page.getByRole('button', { name: 'JSON' }).click();
await page.getByRole('option', { name: 'JSON' }).click();
await page.getByRole('tab', { name: 'Auth' }).click();
await page.getByRole('tab', { name: 'Parameters' }).click();
await page.getByRole('tab', { name: 'Params' }).click();
await page.getByRole('tab', { name: 'Headers' }).click();
await page.getByRole('tab', { name: 'Docs' }).click();
await page.getByRole('button', { name: 'Add Description' }).click();
Expand Down
2 changes: 1 addition & 1 deletion packages/insomnia/src/index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en-US" class="w-full h-full">
<html lang="en-US" class="w-full h-full overflow-hidden">
<head>
<meta charset="utf-8" />
<meta
Expand Down
186 changes: 136 additions & 50 deletions packages/insomnia/src/ui/components/dropdowns/auth-dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { IconName } from '@fortawesome/fontawesome-svg-core';
import React, { FC, useCallback } from 'react';
import { Button, Collection, Header, ListBox, ListBoxItem, Popover, Section, Select, SelectValue } from 'react-aria-components';
import { useParams } from 'react-router-dom';

import {
getAuthTypeName,
HAWK_ALGORITHM_SHA256,
} from '../../../common/constants';
import type { AuthTypeAPIKey, AuthTypeAwsIam, AuthTypeBasic, AuthTypeNTLM, AuthTypes, RequestAuthentication } from '../../../models/request';
import { getAuthObjectOrNull } from '../../../network/authentication';
import { SIGNATURE_METHOD_HMAC_SHA1 } from '../../../network/o-auth-1/constants';
import { GRANT_TYPE_AUTHORIZATION_CODE } from '../../../network/o-auth-2/constants';
import { useRequestGroupPatcher, useRequestPatcher } from '../../hooks/use-request';
import { Dropdown, DropdownButton, DropdownItem, DropdownSection, ItemContent } from '../base/dropdown';
import { Icon } from '../icon';

function castOneAuthTypeToAnother(type: AuthTypes, oldAuth: RequestAuthentication | {}): RequestAuthentication {
switch (type) {
Expand Down Expand Up @@ -133,6 +134,7 @@ interface Props {
authTypes?: AuthTypes[];
disabled?: boolean;
}

export const AuthDropdown: FC<Props> = ({ authentication, authTypes = defaultTypes, disabled = false }) => {
const { requestId, requestGroupId } = useParams() as { organizationId: string; projectId: string; workspaceId: string; requestId?: string; requestGroupId?: string };
const patchRequest = useRequestPatcher();
Expand All @@ -147,57 +149,141 @@ export const AuthDropdown: FC<Props> = ({ authentication, authTypes = defaultTyp
requestGroupId && patchRequestGroup(requestGroupId, { authentication: newAuthentication });
}, [authentication, patchRequest, patchRequestGroup, requestGroupId, requestId]);

const isSelected = useCallback((type: AuthTypes) => {
return type === getAuthObjectOrNull(authentication)?.type;
}, [authentication]);
const selectedAuthType = getAuthObjectOrNull(authentication)?.type || 'none';

const authTypesItems: {
id: AuthTypes;
name: string;
}[] = [
{
id: 'apikey',
name: 'API Key',
},
{
id: 'basic',
name: 'Basic',
},
{
id: 'digest',
name: 'Digest',
},
{
id: 'ntlm',
name: 'NTLM',
},
{
id: 'oauth1',
name: 'OAuth 1.0',
},
{
id: 'oauth2',
name: 'OAuth 2.0',
},
{
id: 'iam',
name: 'AWS IAM',
},
{
id: 'bearer',
name: 'Bearer Token',
},
{
id: 'hawk',
name: 'Hawk',
},
{
id: 'asap',
name: 'Atlassian ASAP',
},
{
id: 'netrc',
name: 'Netrc',
},
];

const authTypeSections: {
id: string;
icon: IconName;
name: string;
items: {
id: AuthTypes;
name: string;
}[];
}[] = [
{
id: 'Auth Types',
name: 'Auth Types',
icon: 'lock',
items: authTypesItems.filter(item => authTypes.includes(item.id)),
},
{
id: 'Other',
name: 'Other',
icon: 'ellipsis-h',
items: [
{
id: 'none',
name: 'None',
},
],
},
];

return (
<Dropdown
aria-label='Authentication Dropdown'
<Select
isDisabled={disabled}
triggerButton={
<DropdownButton className="tall !text-[--hl]">
{getAuthTypeName(getAuthObjectOrNull(authentication)?.type)}
<i className="fa fa-caret-down space-left" />
</DropdownButton>
}
aria-label="Change Authentication type"
name="auth-type"
onSelectionChange={authType => {
onClick(authType as AuthTypes);
}}
selectedKey={selectedAuthType}
>
<DropdownSection
aria-label='Auth types section'
title="Auth Types"
>
{authTypes.map(authType =>
<DropdownItem
key={authType}
aria-label={getAuthTypeName(authType, true)}
>
<ItemContent
icon={isSelected(authType) ? 'check' : 'empty'}
label={getAuthTypeName(authType, true)}
onClick={() => onClick(authType)}
/>
</DropdownItem>
)}
</DropdownSection>
<DropdownSection
aria-label="Other types section"
title="Other"
>
<DropdownItem aria-label='None' key="none">
<ItemContent
icon={isSelected('none') ? 'check' : 'empty'}
label={'No Authentication'}
onClick={() => onClick('none')}
/>
</DropdownItem>
<DropdownItem aria-label='Inherit from parent' key="inherit">
<ItemContent
icon={getAuthObjectOrNull(authentication) === null ? 'check' : 'empty'}
label={'Inherit from parent'}
onClick={() => onClick()}
/>
</DropdownItem>
</DropdownSection>
</Dropdown>
<Button className="px-4 min-w-[17ch] py-1 font-bold flex flex-1 items-center justify-between gap-2 aria-pressed:bg-[--hl-sm] rounded-sm text-[--color-font] hover:bg-[--hl-xs] focus:ring-inset ring-1 ring-transparent focus:ring-[--hl-md] transition-all text-sm">
<SelectValue className="flex truncate items-center justify-center gap-2">
{({ selectedText }) => (
<div className='flex items-center gap-2 text-[--hl]'>
{selectedText || 'Auth Type'}
</div>
)}
</SelectValue>
<Icon icon="caret-down" />
</Button>
<Popover className="min-w-max">
<ListBox
items={authTypeSections}
className="border select-none text-sm min-w-max border-solid border-[--hl-sm] shadow-lg bg-[--color-bg] py-2 rounded-md overflow-y-auto max-h-[85vh] focus:outline-none"
>
{item => (
<Section>
<Header className='pl-2 py-1 flex items-center gap-2 text-[--hl] text-xs uppercase'>
<Icon icon={item.icon} /> <span>{item.name}</span>
</Header>
<Collection items={item.items}>
{item => (
<ListBoxItem
className="flex gap-2 px-[--padding-md] aria-selected:font-bold items-center text-[--color-font] h-[--line-height-xs] w-full text-md whitespace-nowrap bg-transparent hover:bg-[--hl-sm] disabled:cursor-not-allowed focus:bg-[--hl-xs] focus:outline-none transition-colors"
aria-label={item.name}
textValue={item.name}
>
{({ isSelected }) => (
<>
<span>{item.name}</span>
{isSelected && (
<Icon
icon="check"
className="text-[--color-success] justify-self-end"
/>
)}
</>
)}
</ListBoxItem>
)}
</Collection>
</Section>
)}
</ListBox>
</Popover>
</Select>
);
};
Loading

0 comments on commit 79cc2ef

Please sign in to comment.