[APM] Correctly format url when linking to other apps (#67446)

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Dario Gieselaar 2020-05-29 14:07:58 +02:00 committed by GitHub
parent 84ed5096f3
commit d9ac0489a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 130 additions and 17 deletions

View file

@ -105,10 +105,11 @@ export const TransactionActionMenu: FunctionComponent<Props> = ({
if (app === 'uptime' || app === 'metrics' || app === 'logs') {
event.preventDefault();
const search = parsed.search || '';
const path = `${rest.join('/')}${search}`;
core.application.navigateToApp(app, {
path: `${rest.join('/')}${
parsed.search ? `&${parsed.search}` : ''
}`,
path,
});
}
},

View file

@ -6,6 +6,7 @@
import React from 'react';
import { render, fireEvent, act } from '@testing-library/react';
import { merge, tail } from 'lodash';
import { TransactionActionMenu } from '../TransactionActionMenu';
import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
import * as Transactions from './mockData';
@ -16,13 +17,43 @@ import {
import * as hooks from '../../../../hooks/useFetcher';
import { LicenseContext } from '../../../../context/LicenseContext';
import { License } from '../../../../../../licensing/common/license';
import { MockApmPluginContextWrapper } from '../../../../context/ApmPluginContext/MockApmPluginContext';
import {
MockApmPluginContextWrapper,
mockApmPluginContextValue,
} from '../../../../context/ApmPluginContext/MockApmPluginContext';
import * as apmApi from '../../../../services/rest/createCallApmApi';
import { ApmPluginContextValue } from '../../../../context/ApmPluginContext';
const renderTransaction = async (transaction: Record<string, any>) => {
const getMock = () => {
return (merge({}, mockApmPluginContextValue, {
core: {
application: {
navigateToApp: jest.fn(),
},
http: {
basePath: {
remove: jest.fn((path: string) => {
return tail(path.split('/')).join('/');
}),
},
},
},
}) as unknown) as ApmPluginContextValue;
};
const renderTransaction = async (
transaction: Record<string, any>,
mock: ApmPluginContextValue = getMock()
) => {
const rendered = render(
<TransactionActionMenu transaction={transaction as Transaction} />,
{ wrapper: MockApmPluginContextWrapper }
{
wrapper: ({ children }: { children?: React.ReactNode }) => (
<MockApmPluginContextWrapper value={mock}>
{children}
</MockApmPluginContextWrapper>
),
}
);
fireEvent.click(rendered.getByText('Actions'));
@ -49,11 +80,21 @@ describe('TransactionActionMenu component', () => {
});
it('should always render the trace logs link', async () => {
const { queryByText } = await renderTransaction(
Transactions.transactionWithMinimalData
const mock = getMock();
const { queryByText, getByText } = await renderTransaction(
Transactions.transactionWithMinimalData,
mock
);
expect(queryByText('Trace logs')).not.toBeNull();
fireEvent.click(getByText('Trace logs'));
expect(mock.core.application.navigateToApp).toHaveBeenCalledWith('logs', {
path:
'link-to/logs?time=1545092070952&filter=trace.id:%228b60bd32ecc6e1506735a8b6cfcf175c%22%20OR%208b60bd32ecc6e1506735a8b6cfcf175c',
});
});
it('should not render the pod links when there is no pod id', async () => {
@ -66,12 +107,33 @@ describe('TransactionActionMenu component', () => {
});
it('should render the pod links when there is a pod id', async () => {
const { queryByText } = await renderTransaction(
Transactions.transactionWithKubernetesData
const mock = getMock();
const { queryByText, getByText } = await renderTransaction(
Transactions.transactionWithKubernetesData,
mock
);
expect(queryByText('Pod logs')).not.toBeNull();
expect(queryByText('Pod metrics')).not.toBeNull();
fireEvent.click(getByText('Pod logs'));
expect(mock.core.application.navigateToApp).toHaveBeenCalledWith('logs', {
path: 'link-to/pod-logs/pod123456abcdef?time=1545092070952',
});
(mock.core.application.navigateToApp as jest.Mock).mockClear();
fireEvent.click(getByText('Pod metrics'));
expect(mock.core.application.navigateToApp).toHaveBeenCalledWith(
'metrics',
{
path:
'link-to/pod-detail/pod123456abcdef?from=1545091770952&to=1545092370952',
}
);
});
it('should not render the container links when there is no container id', async () => {
@ -84,12 +146,33 @@ describe('TransactionActionMenu component', () => {
});
it('should render the container links when there is a container id', async () => {
const { queryByText } = await renderTransaction(
Transactions.transactionWithContainerData
const mock = getMock();
const { queryByText, getByText } = await renderTransaction(
Transactions.transactionWithContainerData,
mock
);
expect(queryByText('Container logs')).not.toBeNull();
expect(queryByText('Container metrics')).not.toBeNull();
fireEvent.click(getByText('Container logs'));
expect(mock.core.application.navigateToApp).toHaveBeenCalledWith('logs', {
path: 'link-to/container-logs/container123456abcdef?time=1545092070952',
});
(mock.core.application.navigateToApp as jest.Mock).mockClear();
fireEvent.click(getByText('Container metrics'));
expect(mock.core.application.navigateToApp).toHaveBeenCalledWith(
'metrics',
{
path:
'link-to/container-detail/container123456abcdef?from=1545091770952&to=1545092370952',
}
);
});
it('should not render the host links when there is no hostname', async () => {
@ -102,12 +185,32 @@ describe('TransactionActionMenu component', () => {
});
it('should render the host links when there is a hostname', async () => {
const { queryByText } = await renderTransaction(
Transactions.transactionWithHostData
const mock = getMock();
const { queryByText, getByText } = await renderTransaction(
Transactions.transactionWithHostData,
mock
);
expect(queryByText('Host logs')).not.toBeNull();
expect(queryByText('Host metrics')).not.toBeNull();
fireEvent.click(getByText('Host logs'));
expect(mock.core.application.navigateToApp).toHaveBeenCalledWith('logs', {
path: 'link-to/host-logs/227453131a17?time=1545092070952',
});
(mock.core.application.navigateToApp as jest.Mock).mockClear();
fireEvent.click(getByText('Host metrics'));
expect(mock.core.application.navigateToApp).toHaveBeenCalledWith(
'metrics',
{
path:
'link-to/host-detail/227453131a17?from=1545091770952&to=1545092370952',
}
);
});
it('should not render the uptime link if there is no url available', async () => {
@ -127,11 +230,20 @@ describe('TransactionActionMenu component', () => {
});
it('should render the uptime link if there is a url with a domain', async () => {
const { queryByText } = await renderTransaction(
Transactions.transactionWithUrlAndDomain
const mock = getMock();
const { queryByText, getByText } = await renderTransaction(
Transactions.transactionWithUrlAndDomain,
mock
);
expect(queryByText('Status')).not.toBeNull();
fireEvent.click(getByText('Status'));
expect(mock.core.application.navigateToApp).toHaveBeenCalledWith('uptime', {
path: '?search=url.domain:%22example.com%22',
});
});
it('should match the snapshot', async () => {

View file

@ -62,7 +62,7 @@ export const getSections = ({
const uptimeLink = url.format({
pathname: basePath.prepend('/app/uptime'),
hash: `/?${fromQuery(
search: `?${fromQuery(
pick(
{
dateRangeStart: urlParams.rangeFrom,