[Remote Clusters] Added a11y tests and fixed violations (#96989)

* Added a11y tests for Remote Clusters plugin and fixed discovered violations

* Added an a11y test for a delete modal

* Updated payload type casting

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Yulia Čech 2021-04-20 08:51:28 +02:00 committed by GitHub
parent 69edee5b75
commit bd5e9ba10a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 271 additions and 115 deletions

View file

@ -45,7 +45,7 @@ export interface Cluster {
hasDeprecatedProxySetting?: boolean;
}
interface ClusterPayloadEs {
export interface ClusterPayloadEs {
skip_unavailable?: boolean | null;
mode?: 'sniff' | 'proxy' | null;
proxy_address?: string | null;

View file

@ -10,4 +10,5 @@ export {
serializeCluster,
Cluster,
ClusterInfoEs,
ClusterPayloadEs,
} from './cluster_serialization';

View file

@ -47,8 +47,8 @@ import {
convertCloudUrlToProxyConnection,
convertProxyConnectionToCloudUrl,
validateCluster,
isCloudUrlEnabled,
} from './validators';
import { isCloudUrlEnabled } from './validators/validate_cloud_url';
const defaultClusterValues: Cluster = {
name: '',
@ -369,7 +369,7 @@ export class RemoteClusterForm extends Component<Props, State> {
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty onClick={this.toggleRequest}>
<EuiButtonEmpty onClick={this.toggleRequest} data-test-subj="remoteClustersRequestButton">
{isRequestVisible ? (
<FormattedMessage
id="xpack.remoteClusters.remoteClusterForm.hideRequestButtonLabel"

View file

@ -38,7 +38,7 @@ export class RequestFlyout extends PureComponent<Props> {
return (
<EuiFlyout maxWidth={480} onClose={close}>
<EuiFlyoutHeader>
<EuiTitle>
<EuiTitle data-test-subj="remoteClusterRequestFlyoutTitle">
<h2>
{name ? (
<FormattedMessage

View file

@ -41,13 +41,11 @@ export function ConnectionStatus({ isConnected, mode }) {
return (
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>{icon}</EuiFlexItem>
<span className="eui-displayBlock">{icon}</span>
</EuiFlexItem>
<EuiFlexItem className="remoteClustersConnectionStatus__message">
<EuiText size="s">{message}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
<EuiFlexItem grow={false} className="remoteClustersConnectionStatus__message">
<EuiText size="s">{message}</EuiText>
</EuiFlexItem>
{!isConnected && mode === SNIFF_MODE && (

View file

@ -183,9 +183,9 @@ export class DetailPanel extends Component {
mode,
}) {
return (
<EuiDescriptionList data-test-subj="remoteClusterDetailPanelStatusValues">
<EuiFlexGroup>
<EuiFlexItem>
<EuiFlexGroup data-test-subj="remoteClusterDetailPanelStatusValues">
<EuiFlexItem>
<EuiDescriptionList>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
@ -194,13 +194,10 @@ export class DetailPanel extends Component {
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailIsConnected">
<ConnectionStatus isConnected={isConnected} mode={mode} />
</EuiDescriptionListDescription>
</EuiFlexItem>
<EuiFlexItem>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
@ -209,17 +206,10 @@ export class DetailPanel extends Component {
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailConnectedNodesCount">
{connectedNodesCount}
</EuiDescriptionListDescription>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<EuiFlexGroup>
<EuiFlexItem>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
@ -228,7 +218,6 @@ export class DetailPanel extends Component {
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailSeeds">
{seeds.map((seed) => (
<EuiText size="s" key={seed}>
@ -236,9 +225,11 @@ export class DetailPanel extends Component {
</EuiText>
))}
</EuiDescriptionListDescription>
</EuiFlexItem>
</EuiDescriptionList>
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexItem>
<EuiDescriptionList>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
@ -247,17 +238,10 @@ export class DetailPanel extends Component {
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailSkipUnavailable">
{this.renderSkipUnavailableValue(skipUnavailable)}
</EuiDescriptionListDescription>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<EuiFlexGroup>
<EuiFlexItem>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
@ -266,13 +250,10 @@ export class DetailPanel extends Component {
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailMaxConnections">
{maxConnectionsPerCluster}
</EuiDescriptionListDescription>
</EuiFlexItem>
<EuiFlexItem>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
@ -281,13 +262,12 @@ export class DetailPanel extends Component {
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailInitialConnectTimeout">
{initialConnectTimeout}
</EuiDescriptionListDescription>
</EuiFlexItem>
</EuiFlexGroup>
</EuiDescriptionList>
</EuiDescriptionList>
</EuiFlexItem>
</EuiFlexGroup>
);
}
@ -302,9 +282,9 @@ export class DetailPanel extends Component {
serverName,
}) {
return (
<EuiDescriptionList data-test-subj="remoteClusterDetailPanelStatusValues">
<EuiFlexGroup>
<EuiFlexItem>
<EuiFlexGroup>
<EuiFlexItem>
<EuiDescriptionList>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
@ -313,13 +293,10 @@ export class DetailPanel extends Component {
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailIsConnected">
<ConnectionStatus isConnected={isConnected} mode={mode} />
</EuiDescriptionListDescription>
</EuiFlexItem>
<EuiFlexItem>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
@ -328,17 +305,10 @@ export class DetailPanel extends Component {
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailConnectedSocketsCount">
{connectedSocketsCount ? connectedSocketsCount : '-'}
</EuiDescriptionListDescription>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<EuiFlexGroup>
<EuiFlexItem>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
@ -347,66 +317,10 @@ export class DetailPanel extends Component {
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailProxyAddress">
{proxyAddress}
</EuiDescriptionListDescription>
</EuiFlexItem>
<EuiFlexItem>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
id="xpack.remoteClusters.detailPanel.skipUnavailableLabel"
defaultMessage="Skip unavailable"
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailSkipUnavailable">
{this.renderSkipUnavailableValue(skipUnavailable)}
</EuiDescriptionListDescription>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<EuiFlexGroup>
<EuiFlexItem>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
id="xpack.remoteClusters.detailPanel.maxSocketConnectionsLabel"
defaultMessage="Maximum socket connections"
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailMaxSocketConnections">
{proxySocketConnections ? proxySocketConnections : '-'}
</EuiDescriptionListDescription>
</EuiFlexItem>
<EuiFlexItem>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
id="xpack.remoteClusters.detailPanel.initialConnectTimeoutLabel"
defaultMessage="Initial connect timeout"
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailInitialConnectTimeout">
{initialConnectTimeout}
</EuiDescriptionListDescription>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<EuiFlexGroup>
<EuiFlexItem>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
@ -415,23 +329,61 @@ export class DetailPanel extends Component {
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailServerName">
{serverName ? serverName : '-'}
</EuiDescriptionListDescription>
</EuiFlexItem>
</EuiFlexGroup>
</EuiDescriptionList>
</EuiDescriptionList>
</EuiFlexItem>
<EuiFlexItem>
<EuiDescriptionList>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
id="xpack.remoteClusters.detailPanel.skipUnavailableLabel"
defaultMessage="Skip unavailable"
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailSkipUnavailable">
{this.renderSkipUnavailableValue(skipUnavailable)}
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
id="xpack.remoteClusters.detailPanel.maxSocketConnectionsLabel"
defaultMessage="Maximum socket connections"
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailMaxSocketConnections">
{proxySocketConnections ? proxySocketConnections : '-'}
</EuiDescriptionListDescription>
<EuiDescriptionListTitle>
<EuiTitle size="xs">
<FormattedMessage
id="xpack.remoteClusters.detailPanel.initialConnectTimeoutLabel"
defaultMessage="Initial connect timeout"
/>
</EuiTitle>
</EuiDescriptionListTitle>
<EuiDescriptionListDescription data-test-subj="remoteClusterDetailInitialConnectTimeout">
{initialConnectTimeout}
</EuiDescriptionListDescription>
</EuiDescriptionList>
</EuiFlexItem>
</EuiFlexGroup>
);
}
renderCluster(cluster) {
return (
<section
aria-labelledby="xpack.remoteClusters.detailPanel.statusTitle"
aria-labelledby="clusterStatus"
data-test-subj="remoteClusterDetailPanelStatusSection"
>
<EuiTitle size="s">
<EuiTitle size="s" id="clusterStatus">
<h3>
<FormattedMessage
id="xpack.remoteClusters.detailPanel.statusTitle"

View file

@ -0,0 +1,204 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { FtrProviderContext } from '../ftr_provider_context';
import { ClusterPayloadEs } from '../../../plugins/remote_clusters/common/lib';
const emptyPrompt = 'remoteClusterListEmptyPrompt';
const createButton = 'remoteClusterEmptyPromptCreateButton';
const pageTitle = 'remoteClusterPageTitle';
const nameLink = 'remoteClustersTableListClusterLink';
const editButton = 'remoteClusterTableRowEditButton';
const deleteButton = 'remoteClusterTableRowRemoveButton';
const deleteModalTitle = 'confirmModalTitleText';
const detailsTitle = 'remoteClusterDetailsFlyoutTitle';
const requestButton = 'remoteClustersRequestButton';
const requestTitle = 'remoteClusterRequestFlyoutTitle';
interface Payload {
persistent: {
cluster: {
remote: {
[k: string]: ClusterPayloadEs;
};
};
};
}
const getEmptyPayload = () =>
({
persistent: {
cluster: {
remote: {},
},
},
} as Payload);
const getPayloadClusterProxyMode = (name: string): Payload => {
const payload = getEmptyPayload();
payload.persistent.cluster.remote[name] = {
mode: 'proxy',
proxy_address: '127.0.0.1:9302',
server_name: 'test_server',
};
return payload;
};
const getPayloadClusterSniffMode = (name: string): Payload => {
const payload = getEmptyPayload();
payload.persistent.cluster.remote[name] = {
mode: 'sniff',
seeds: ['127.0.0.1:9301'],
};
return payload;
};
const getDeleteClusterPayload = (name: string): Payload => {
const payload = getEmptyPayload();
payload.persistent.cluster.remote[name] = {
skip_unavailable: null,
mode: null,
proxy_address: null,
proxy_socket_connections: null,
server_name: null,
seeds: null,
node_connections: null,
proxy: null,
};
return payload;
};
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['common', 'security']);
const testSubjects = getService('testSubjects');
const esClient = getService('es');
const a11y = getService('a11y');
const retry = getService('retry');
describe('Remote Clusters', () => {
beforeEach(async () => {
await PageObjects.common.navigateToApp('remoteClusters');
});
describe('Add remote cluster', () => {
it('renders the list view with empty prompt', async () => {
await retry.waitFor('empty prompt to be rendered', async () => {
return testSubjects.isDisplayed(emptyPrompt);
});
await a11y.testAppSnapshot();
});
it('renders add remote cluster form', async () => {
await retry.waitFor('add remote cluster button to be rendered', async () => {
return testSubjects.isDisplayed(createButton);
});
await testSubjects.click(createButton);
await retry.waitFor('add remote cluster form to be rendered', async () => {
return (await testSubjects.getVisibleText(pageTitle)) === 'Add remote cluster';
});
await a11y.testAppSnapshot();
});
it('renders request flyout', async () => {
await retry.waitFor('add remote cluster button to be rendered', async () => {
return testSubjects.isDisplayed(createButton);
});
await testSubjects.click(createButton);
await retry.waitFor('add remote cluster form to be rendered', async () => {
return (await testSubjects.getVisibleText(pageTitle)) === 'Add remote cluster';
});
await testSubjects.click(requestButton);
await retry.waitFor('request flyout to be rendered', async () => {
return (await testSubjects.getVisibleText(requestTitle)) === 'Request';
});
await a11y.testAppSnapshot();
});
});
const modes = ['sniff', 'proxy'];
modes.forEach((mode: string) => {
describe(`Edit remote cluster (${mode} mode)`, () => {
const clusterName = mode === 'sniff' ? 'clusterSniffMode' : 'clusterProxyMode';
const body =
mode === 'sniff'
? getPayloadClusterSniffMode(clusterName)
: getPayloadClusterProxyMode(clusterName);
before(async () => {
await esClient.cluster.putSettings({ body });
});
after(async () => {
await esClient.cluster.putSettings({ body: getDeleteClusterPayload(clusterName) });
});
it('renders the list view with remote clusters', async () => {
await retry.waitFor('remote clusters list to be rendered', async () => {
return testSubjects.isDisplayed(nameLink);
});
await a11y.testAppSnapshot();
});
it(`renders remote cluster details flyout (${mode} mode)`, async () => {
await retry.waitFor('remote clusters list to be rendered', async () => {
return testSubjects.isDisplayed(nameLink);
});
await testSubjects.click(nameLink);
await retry.waitFor('remote cluster details to be rendered', async () => {
return (await testSubjects.getVisibleText(detailsTitle)) === clusterName;
});
await a11y.testAppSnapshot();
});
it(`renders delete cluster modal (${mode} mode)`, async () => {
await retry.waitFor('remote clusters list to be rendered', async () => {
return testSubjects.isDisplayed(nameLink);
});
await testSubjects.click(deleteButton);
await retry.waitFor('delete cluster modal to be rendered', async () => {
return (
(await testSubjects.getVisibleText(deleteModalTitle)) ===
`Remove remote cluster '${clusterName}'?`
);
});
await a11y.testAppSnapshot();
});
it(`renders edit remote cluster form and request flyout (${mode} mode)`, async () => {
await retry.waitFor('edit remote cluster button to be rendered', async () => {
return testSubjects.isDisplayed(editButton);
});
await testSubjects.click(editButton);
await retry.waitFor('edit remote cluster form to be rendered', async () => {
return (await testSubjects.getVisibleText(pageTitle)) === 'Edit remote cluster';
});
await testSubjects.click(requestButton);
await retry.waitFor('request flyout to be rendered', async () => {
return (
(await testSubjects.getVisibleText(requestTitle)) === `Request for '${clusterName}'`
);
});
await a11y.testAppSnapshot();
});
});
});
});
}

View file

@ -36,6 +36,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
require.resolve('./apps/canvas'),
require.resolve('./apps/security_solution'),
require.resolve('./apps/ml_embeddables_in_dashboard'),
require.resolve('./apps/remote_clusters'),
],
pageObjects,