From ad0fddbeb210f85248551b2f153866f1f6b1b31f Mon Sep 17 00:00:00 2001 From: jennypavlova Date: Thu, 28 Nov 2024 12:44:20 +0100 Subject: [PATCH 1/2] [Inventory] Change discover link to use entity definition (#201433) Closes #200595 ## Summary This PR changes the link to discover: - Pass a different data view (using the entity definition indices) - from Open in Discover to Explore in Discover ## Testing - To have the test data I used metricbeat (for the host entity) and synthtrace (for the other entities type) - Open the inventory page and expand an entity type - Click on the `...` in the actions column - Click on `Explore in Discover` The results should be filtered by the selected entity and the dataview should include the indices from the entity definition: https://github.com/user-attachments/assets/29bb46b4-719e-4874-b1aa-056ac28d234a https://github.com/user-attachments/assets/36c08b8b-f507-445e-a7b5-8eb1176beb90 With service type filter (should not persist) https://github.com/user-attachments/assets/ae6ef28a-e55a-4a32-9128-802ebea25607 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> (cherry picked from commit afc5e51e296eb499a17ad82de560d20c352cd2a9) --- .../src/format_request.test.ts | 29 +++++ .../src/format_request.ts | 16 ++- .../public/lib/entity_client.ts | 21 +++- .../inventory/e2e/cypress/e2e/home.cy.ts | 10 +- .../public/components/entities_grid/index.tsx | 19 +--- .../components/entity_actions/index.tsx | 96 ++++++++++------- .../index.tsx | 5 +- ...ry_data_view.ts => use_adhoc_data_view.ts} | 7 +- .../public/hooks/use_discover_redirect.ts | 101 +++++++----------- .../hooks/use_fetch_entity_definition.ts | 27 +++++ .../hooks/use_unified_search_context.ts | 5 +- .../inventory/tsconfig.json | 3 +- .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 15 files changed, 206 insertions(+), 136 deletions(-) create mode 100644 packages/kbn-server-route-repository-utils/src/format_request.test.ts rename x-pack/plugins/observability_solution/inventory/public/hooks/{use_adhoc_inventory_data_view.ts => use_adhoc_data_view.ts} (82%) create mode 100644 x-pack/plugins/observability_solution/inventory/public/hooks/use_fetch_entity_definition.ts diff --git a/packages/kbn-server-route-repository-utils/src/format_request.test.ts b/packages/kbn-server-route-repository-utils/src/format_request.test.ts new file mode 100644 index 0000000000000..e2ddcebebe68f --- /dev/null +++ b/packages/kbn-server-route-repository-utils/src/format_request.test.ts @@ -0,0 +1,29 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { formatRequest } from './format_request'; + +describe('formatRequest', () => { + it('should return the correct path if the optional or required param is provided', () => { + const pathParams = { param: 'testParam' }; + const resultOptionalEnd = formatRequest('GET /api/endpoint/{param?}', pathParams); + expect(resultOptionalEnd.pathname).toBe('/api/endpoint/testParam'); + const resultRequiredEnd = formatRequest('GET /api/endpoint/{param}', pathParams); + expect(resultRequiredEnd.pathname).toBe('/api/endpoint/testParam'); + }); + it('should return the correct path if the only an optional param is provided', () => { + const resultOptEnd = formatRequest('GET /api/endpoint/{id?}', { id: 123 }); + expect(resultOptEnd.pathname).toBe('/api/endpoint/123'); + }); + it('should return the correct path if the optional param is not provided', () => { + const pathParams = {}; + const resultEnd = formatRequest('GET /api/endpoint/{pathParamReq?}', pathParams); + expect(resultEnd.pathname).toBe('/api/endpoint'); + }); +}); diff --git a/packages/kbn-server-route-repository-utils/src/format_request.ts b/packages/kbn-server-route-repository-utils/src/format_request.ts index 7348003e3bd42..291ba67cf70fd 100644 --- a/packages/kbn-server-route-repository-utils/src/format_request.ts +++ b/packages/kbn-server-route-repository-utils/src/format_request.ts @@ -11,11 +11,23 @@ import { parseEndpoint } from './parse_endpoint'; export function formatRequest(endpoint: string, pathParams: Record = {}) { const { method, pathname: rawPathname, version } = parseEndpoint(endpoint); + const optionalReg = /(\/\{\w+\?\})/g; // /{param?} + + const optionalOrRequiredParamsReg = /(\/{)((.+?))(\})/g; + if (Object.keys(pathParams)?.length === 0) { + const pathname = rawPathname.replace(optionalOrRequiredParamsReg, ''); + return { method, pathname, version }; + } - // replace template variables with path params const pathname = Object.keys(pathParams).reduce((acc, paramName) => { - return acc.replace(`{${paramName}}`, pathParams[paramName]); + return acc + .replace(`{${paramName}}`, pathParams[paramName]) + .replace(`{${paramName}?}`, pathParams[paramName]); }, rawPathname); + if ((pathname.match(optionalReg) ?? [])?.length > 0) { + throw new Error(`Missing parameters: ${pathname.match(optionalReg)}`); + } + return { method, pathname, version }; } diff --git a/x-pack/plugins/entity_manager/public/lib/entity_client.ts b/x-pack/plugins/entity_manager/public/lib/entity_client.ts index 9db1c37888d4b..43530b27df7f7 100644 --- a/x-pack/plugins/entity_manager/public/lib/entity_client.ts +++ b/x-pack/plugins/entity_manager/public/lib/entity_client.ts @@ -13,8 +13,9 @@ import { isHttpFetchError, } from '@kbn/server-route-repository-client'; import { type KueryNode, nodeTypes, toKqlExpression } from '@kbn/es-query'; -import type { EntityInstance, EntityMetadata } from '@kbn/entities-schema'; +import type { EntityDefinition, EntityInstance, EntityMetadata } from '@kbn/entities-schema'; import { castArray } from 'lodash'; +import type { EntityDefinitionWithState } from '../../server/lib/entities/types'; import { DisableManagedEntityResponse, EnableManagedEntityResponse, @@ -87,6 +88,24 @@ export class EntityClient { } } + async getEntityDefinition( + id: string + ): Promise<{ definitions: EntityDefinition[] | EntityDefinitionWithState[] }> { + try { + return await this.repositoryClient('GET /internal/entities/definition/{id?}', { + params: { + path: { id }, + query: { page: 1, perPage: 1 }, + }, + }); + } catch (err) { + if (isHttpFetchError(err) && err.body?.statusCode === 403) { + throw new EntityManagerUnauthorizedError(err.body.message); + } + throw err; + } + } + asKqlFilter( entityInstance: { entity: Pick; diff --git a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts index fdb68826e9dc8..61a55bab3258f 100644 --- a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts +++ b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts @@ -217,16 +217,16 @@ describe('Home page', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); + cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); cy.visitKibana('/app/inventory'); cy.wait('@getEEMStatus'); cy.contains('container'); cy.getByTestSubj('inventoryGroupTitle_entity.type_container').click(); + cy.wait('@getEntities'); + // cy.getByTestSubj('inventoryEntityActionsButton').click(); cy.getByTestSubj('inventoryEntityActionsButton-foo').click(); - cy.getByTestSubj('inventoryEntityActionOpenInDiscover').click(); - cy.url().should( - 'include', - "query:'container.id:%20%22foo%22%20AND%20entity.definition_id%20:%20builtin*" - ); + cy.getByTestSubj('inventoryEntityActionExploreInDiscover').click(); + cy.url().should('include', "query:'container.id:%20%22foo%22"); }); }); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx index dd421d30a3a9c..541af76350723 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx @@ -14,7 +14,7 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedDate, FormattedMessage, FormattedTime } from '@kbn/i18n-react'; import { last } from 'lodash'; -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; import { EntityColumnIds, InventoryEntity } from '../../../common/entities'; import { BadgeFilterWithPopover } from '../badge_filter_with_popover'; @@ -22,7 +22,6 @@ import { getColumns } from './grid_columns'; import { AlertsBadge } from '../alerts_badge/alerts_badge'; import { EntityName } from './entity_name'; import { EntityActions } from '../entity_actions'; -import { useDiscoverRedirect } from '../../hooks/use_discover_redirect'; interface Props { loading: boolean; @@ -45,7 +44,7 @@ export function EntitiesGrid({ onChangePage, onChangeSort, }: Props) { - const { getDiscoverRedirectUrl } = useDiscoverRedirect(); + const [showActions, setShowActions] = useState(true); const onSort: EuiDataGridSorting['onSort'] = useCallback( (newSortingColumns) => { @@ -62,8 +61,6 @@ export function EntitiesGrid({ [entities] ); - const showActions = useMemo(() => !!getDiscoverRedirectUrl(), [getDiscoverRedirectUrl]); - const columnVisibility = useMemo( () => ({ visibleColumns: getColumns({ showAlertsColumn, showActions }).map(({ id }) => id), @@ -81,7 +78,6 @@ export function EntitiesGrid({ const columnEntityTableId = columnId as EntityColumnIds; const entityType = entity.entityType; - const discoverUrl = getDiscoverRedirectUrl(entity); switch (columnEntityTableId) { case 'alertsCount': @@ -119,19 +115,12 @@ export function EntitiesGrid({ case 'entityDisplayName': return ; case 'actions': - return ( - discoverUrl && ( - - ) - ); + return ; default: return null; } }, - [entities, getDiscoverRedirectUrl] + [entities] ); if (loading) { diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entity_actions/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_actions/index.tsx index 95a4050fba4e9..691ba4388ac63 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entity_actions/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_actions/index.tsx @@ -7,56 +7,70 @@ import { EuiButtonIcon, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React from 'react'; +import React, { type SetStateAction } from 'react'; import { useBoolean } from '@kbn/react-hooks'; +import type { Dispatch } from '@kbn/kibana-utils-plugin/common'; +import type { InventoryEntity } from '../../../common/entities'; +import { useDiscoverRedirect } from '../../hooks/use_discover_redirect'; interface Props { - discoverUrl: string; - entityIdentifyingValue?: string; + entity: InventoryEntity; + setShowActions: Dispatch>; } -export const EntityActions = ({ discoverUrl, entityIdentifyingValue }: Props) => { +export const EntityActions = ({ entity, setShowActions }: Props) => { const [isPopoverOpen, { toggle: togglePopover, off: closePopover }] = useBoolean(false); - const actionButtonTestSubject = entityIdentifyingValue - ? `inventoryEntityActionsButton-${entityIdentifyingValue}` + const actionButtonTestSubject = entity.entityDisplayName + ? `inventoryEntityActionsButton-${entity.entityDisplayName}` : 'inventoryEntityActionsButton'; - const actions = [ - - {i18n.translate('xpack.inventory.entityActions.discoverLink', { - defaultMessage: 'Open in discover', - })} - , - ]; + const { getDiscoverEntitiesRedirectUrl, isEntityDefinitionLoading } = useDiscoverRedirect(entity); + const discoverUrl = getDiscoverEntitiesRedirectUrl(); - return ( - <> - - } - closePopover={closePopover} + const actions: React.ReactElement[] = []; + + if (!discoverUrl && !isEntityDefinitionLoading) { + setShowActions(false); + return null; + } + + if (!isEntityDefinitionLoading) { + actions.push( + - - - + {i18n.translate('xpack.inventory.entityActions.exploreInDiscoverLink', { + defaultMessage: 'Explore in Discover', + })} + + ); + } + + return ( + + } + closePopover={closePopover} + > + + ); }; diff --git a/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx b/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx index f5a71e80bd9a3..d43cba80dd177 100644 --- a/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx @@ -7,7 +7,8 @@ import React, { createContext, useContext, type ReactChild } from 'react'; import { Subject } from 'rxjs'; import { DataView } from '@kbn/data-views-plugin/common'; -import { useAdHocInventoryDataView } from '../../hooks/use_adhoc_inventory_data_view'; +import { ENTITIES_LATEST_ALIAS } from '../../../common/entities'; +import { useAdHocDataView } from '../../hooks/use_adhoc_data_view'; interface InventorySearchBarContextType { searchBarContentSubject$: Subject<{ @@ -24,7 +25,7 @@ const InventorySearchBarContext = createContext({ }); export function InventorySearchBarContextProvider({ children }: { children: ReactChild }) { - const { dataView } = useAdHocInventoryDataView(); + const { dataView } = useAdHocDataView(ENTITIES_LATEST_ALIAS); return ( { +export const useDiscoverRedirect = (entity: InventoryEntity) => { const { services: { share, application, entityManager }, } = useKibana(); - - const { - dataView, - searchState: { query, filters, panelFilters }, - } = useUnifiedSearchContext(); - - const discoverLocator = share.url.locators.get('DISCOVER_APP_LOCATOR'); - - const getDiscoverEntitiesRedirectUrl = useCallback( - (entity?: InventoryEntity) => { - const entityKqlFilter = entity - ? entityManager.entityClient.asKqlFilter({ - entity: { - identity_fields: entity.entityIdentityFields, - }, - ...entity, - }) - : ''; - - const kueryWithEntityDefinitionFilters = [ - query.query, - entityKqlFilter, - `${ENTITY_DEFINITION_ID} : builtin*`, - ] - .filter(Boolean) - .join(' AND '); - - return application.capabilities.discover?.show - ? discoverLocator?.getRedirectUrl({ - indexPatternId: dataView?.id ?? '', - columns: ACTIVE_COLUMNS, - query: { query: kueryWithEntityDefinitionFilters, language: 'kuery' }, - filters: [...filters, ...panelFilters], - }) - : undefined; - }, - [ - application.capabilities.discover?.show, - dataView?.id, - discoverLocator, - entityManager.entityClient, - filters, - panelFilters, - query.query, - ] + const { entityDefinitions, isEntityDefinitionLoading } = useFetchEntityDefinition( + entity.entityDefinitionId ); - const getDiscoverRedirectUrl = useCallback( - (entity?: InventoryEntity) => getDiscoverEntitiesRedirectUrl(entity), - [getDiscoverEntitiesRedirectUrl] + const title = useMemo( + () => + !isEntityDefinitionLoading && entityDefinitions && entityDefinitions?.length > 0 + ? entityDefinitions[0]?.indexPatterns?.join(',') + : '', + [entityDefinitions, isEntityDefinitionLoading] ); - return { getDiscoverRedirectUrl }; + const { dataView } = useAdHocDataView(title); + + const discoverLocator = share.url.locators.get('DISCOVER_APP_LOCATOR'); + + const getDiscoverEntitiesRedirectUrl = useCallback(() => { + const entityKqlFilter = entity + ? entityManager.entityClient.asKqlFilter({ + entity: { + identity_fields: entity.entityIdentityFields, + }, + ...entity, + }) + : ''; + + return application.capabilities.discover?.show + ? discoverLocator?.getRedirectUrl({ + indexPatternId: dataView?.id ?? '', + query: { query: entityKqlFilter, language: 'kuery' }, + }) + : undefined; + }, [ + application.capabilities.discover?.show, + dataView?.id, + discoverLocator, + entity, + entityManager.entityClient, + ]); + + return { getDiscoverEntitiesRedirectUrl, isEntityDefinitionLoading }; }; diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_fetch_entity_definition.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_fetch_entity_definition.ts new file mode 100644 index 0000000000000..9f6a0232891b2 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_fetch_entity_definition.ts @@ -0,0 +1,27 @@ +/* + * 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 { useAbortableAsync } from '@kbn/observability-utils-browser/hooks/use_abortable_async'; +import { useKibana } from './use_kibana'; + +export const useFetchEntityDefinition = (id: string) => { + const { + services: { entityManager }, + } = useKibana(); + + const { value, loading } = useAbortableAsync( + ({ signal }) => { + return entityManager.entityClient.getEntityDefinition(id); + }, + [entityManager.entityClient, id] + ); + + return { + entityDefinitions: value?.definitions, + isEntityDefinitionLoading: loading, + }; +}; diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts index 94df3a035f3bb..3c520867540c9 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts @@ -13,13 +13,14 @@ import useEffectOnce from 'react-use/lib/useEffectOnce'; import deepEqual from 'fast-deep-equal'; import { i18n } from '@kbn/i18n'; import { useKibanaQuerySettings } from '@kbn/observability-shared-plugin/public'; -import { useAdHocInventoryDataView } from './use_adhoc_inventory_data_view'; +import { ENTITIES_LATEST_ALIAS } from '../../common/entities'; +import { useAdHocDataView } from './use_adhoc_data_view'; import { useUnifiedSearchUrl } from './use_unified_search_url'; import { useKibana } from './use_kibana'; function useUnifiedSearch() { const [isControlPanelsInitiated, setIsControlPanelsInitiated] = useState(false); - const { dataView } = useAdHocInventoryDataView(); + const { dataView } = useAdHocDataView(ENTITIES_LATEST_ALIAS); const [refreshSubject$] = useState>(new Subject()); const { searchState, setSearchState } = useUnifiedSearchUrl(); const kibanaQuerySettings = useKibanaQuerySettings(); diff --git a/x-pack/plugins/observability_solution/inventory/tsconfig.json b/x-pack/plugins/observability_solution/inventory/tsconfig.json index 5094201cc2975..b276c3e7e28b1 100644 --- a/x-pack/plugins/observability_solution/inventory/tsconfig.json +++ b/x-pack/plugins/observability_solution/inventory/tsconfig.json @@ -59,6 +59,7 @@ "@kbn/react-hooks", "@kbn/observability-utils-common", "@kbn/observability-utils-browser", - "@kbn/observability-utils-server" + "@kbn/observability-utils-server", + "@kbn/kibana-utils-plugin" ] } diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 8edc8b0798ab0..a0a4691a993fc 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -26190,7 +26190,6 @@ "xpack.inventory.entitiesGrid.euiDataGrid.lastSeenTooltip": "Horodatage des dernières données reçues pour l'entité (entity.lastSeenTimestamp)", "xpack.inventory.entitiesGrid.euiDataGrid.typeLabel": "Type", "xpack.inventory.entitiesGrid.euiDataGrid.typeTooltip": "Type d'entité (entity.type)", - "xpack.inventory.entityActions.discoverLink": "Ouvrir dans Discover", "xpack.inventory.featureRegistry.inventoryFeatureName": "Inventory", "xpack.inventory.home.serviceAlertsTable.tooltip.activeAlertsExplanation": "Alertes actives", "xpack.inventory.inventoryLinkTitle": "Inventory", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 551ed6ccfebaf..9d20c296b1a06 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -26162,7 +26162,6 @@ "xpack.inventory.entitiesGrid.euiDataGrid.lastSeenTooltip": "エンティティで最後に受信したデータのタイムスタンプ(entity.lastSeenTimestamp)", "xpack.inventory.entitiesGrid.euiDataGrid.typeLabel": "型", "xpack.inventory.entitiesGrid.euiDataGrid.typeTooltip": "エンティティのタイプ(entity.type)", - "xpack.inventory.entityActions.discoverLink": "Discoverで開く", "xpack.inventory.featureRegistry.inventoryFeatureName": "インベントリ", "xpack.inventory.home.serviceAlertsTable.tooltip.activeAlertsExplanation": "アクティブアラート", "xpack.inventory.inventoryLinkTitle": "インベントリ", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index e5f3e9cf95c8f..e1debb2b5e09e 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -26218,7 +26218,6 @@ "xpack.inventory.entitiesGrid.euiDataGrid.lastSeenTooltip": "上次接收的实体数据的时间戳 (entity.lastSeenTimestamp)", "xpack.inventory.entitiesGrid.euiDataGrid.typeLabel": "类型", "xpack.inventory.entitiesGrid.euiDataGrid.typeTooltip": "实体的类型 (entity.type)", - "xpack.inventory.entityActions.discoverLink": "在 Discover 中打开", "xpack.inventory.featureRegistry.inventoryFeatureName": "库存", "xpack.inventory.home.serviceAlertsTable.tooltip.activeAlertsExplanation": "活动告警", "xpack.inventory.inventoryLinkTitle": "库存", From d4253aaf4a933734742a7a464c5c6174ae3da90e Mon Sep 17 00:00:00 2001 From: Jenny Date: Fri, 29 Nov 2024 13:38:12 +0100 Subject: [PATCH 2/2] Add a version to a test --- .../src/format_request.test.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/kbn-server-route-repository-utils/src/format_request.test.ts b/packages/kbn-server-route-repository-utils/src/format_request.test.ts index e2ddcebebe68f..5c128cf57fefc 100644 --- a/packages/kbn-server-route-repository-utils/src/format_request.test.ts +++ b/packages/kbn-server-route-repository-utils/src/format_request.test.ts @@ -10,20 +10,21 @@ import { formatRequest } from './format_request'; describe('formatRequest', () => { + const version = 1; it('should return the correct path if the optional or required param is provided', () => { const pathParams = { param: 'testParam' }; - const resultOptionalEnd = formatRequest('GET /api/endpoint/{param?}', pathParams); + const resultOptionalEnd = formatRequest(`GET /api/endpoint/{param?} ${version}`, pathParams); expect(resultOptionalEnd.pathname).toBe('/api/endpoint/testParam'); - const resultRequiredEnd = formatRequest('GET /api/endpoint/{param}', pathParams); + const resultRequiredEnd = formatRequest(`GET /api/endpoint/{param} ${version}`, pathParams); expect(resultRequiredEnd.pathname).toBe('/api/endpoint/testParam'); }); it('should return the correct path if the only an optional param is provided', () => { - const resultOptEnd = formatRequest('GET /api/endpoint/{id?}', { id: 123 }); + const resultOptEnd = formatRequest(`GET /api/endpoint/{id?} ${version}`, { id: 123 }); expect(resultOptEnd.pathname).toBe('/api/endpoint/123'); }); it('should return the correct path if the optional param is not provided', () => { const pathParams = {}; - const resultEnd = formatRequest('GET /api/endpoint/{pathParamReq?}', pathParams); + const resultEnd = formatRequest(`GET /api/endpoint/{pathParamReq?} ${version}`, pathParams); expect(resultEnd.pathname).toBe('/api/endpoint'); }); });