diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-09-01 18:09:54 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-09-01 18:09:54 +0300 |
commit | e1faff6544efe7f1b31e0e73312e7b832c00e6a4 (patch) | |
tree | c0dfc1987a15afd55e5a9819bc91ea9399e6a6e7 /spec/frontend | |
parent | 02f6aecd47c847bb2a7d101678813fe5077ae299 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
12 files changed, 0 insertions, 1148 deletions
diff --git a/spec/frontend/tracing/components/trace_utils_spec.js b/spec/frontend/tracing/components/trace_utils_spec.js deleted file mode 100644 index ba2e360b0fc..00000000000 --- a/spec/frontend/tracing/components/trace_utils_spec.js +++ /dev/null @@ -1,163 +0,0 @@ -import _ from 'lodash'; -import { - mapTraceToTreeRoot, - durationNanoToMs, - formatDurationMs, - formatTraceDuration, - assignColorToServices, -} from '~/tracing/components/trace_utils'; - -describe('trace_utils', () => { - describe('durationNanoToMs', () => { - it('converts a duration value from nano to ms', () => { - expect(durationNanoToMs(1000000001)).toBe(1000000); - }); - }); - - describe('formatDurationMs', () => { - it('formats a duration ms value', () => { - expect(formatDurationMs(1000)).toBe('1000 ms'); - }); - }); - - describe('formatTraceDuration', () => { - it('formats the trace duration nano value', () => { - expect(formatTraceDuration(1000000001)).toBe('1000000 ms'); - }); - }); - - describe('assignColorToService', () => { - it('should assign the right palette', () => { - const trace = { duration_nane: 100000, spans: [] }; - trace.spans = _.times(31).map((i) => ({ - timestamp: '2023-08-07T15:03:32.199806Z', - span_id: `SPAN-${i}`, - trace_id: 'TRACE-1', - service_name: `service-${i}`, - operation: 'op', - duration_nano: 100000, - parent_span_id: '', - })); - - expect(assignColorToServices(trace)).toEqual({ - 'service-0': 'blue-500', - 'service-1': 'orange-500', - 'service-2': 'aqua-500', - 'service-3': 'green-500', - 'service-4': 'magenta-500', - 'service-5': 'blue-600', - 'service-6': 'orange-600', - 'service-7': 'aqua-600', - 'service-8': 'green-600', - 'service-9': 'magenta-600', - 'service-10': 'blue-700', - 'service-11': 'orange-700', - 'service-12': 'aqua-700', - 'service-13': 'green-700', - 'service-14': 'magenta-700', - 'service-15': 'blue-800', - 'service-16': 'orange-800', - 'service-17': 'aqua-800', - 'service-18': 'green-800', - 'service-19': 'magenta-800', - 'service-20': 'blue-900', - 'service-21': 'orange-900', - 'service-22': 'aqua-900', - 'service-23': 'green-900', - 'service-24': 'magenta-900', - 'service-25': 'blue-950', - 'service-26': 'orange-950', - 'service-27': 'aqua-950', - 'service-28': 'green-950', - 'service-29': 'magenta-950', - // restart pallete - 'service-30': 'blue-500', - }); - }); - }); - - describe('mapTraceToTreeRoot', () => { - it('should map a trace data to tree data and return the root node', () => { - const trace = { - spans: [ - { - timestamp: '2023-08-07T15:03:32.199806Z', - span_id: 'SPAN-1', - trace_id: 'TRACE-1', - service_name: 'tracegen', - operation: 'lets-go', - duration_nano: 100120000, - parent_span_id: '', - }, - { - timestamp: '2023-08-07T15:03:32.199871Z', - span_id: 'SPAN-2', - trace_id: 'TRACE-1', - service_name: 'tracegen', - operation: 'okey-dokey', - duration_nano: 100055000, - parent_span_id: 'SPAN-1', - }, - { - timestamp: '2023-08-07T15:03:53.199871Z', - span_id: 'SPAN-3', - trace_id: 'TRACE-1', - service_name: 'tracegen', - operation: 'okey-dokey', - duration_nano: 50027500, - parent_span_id: 'SPAN-2', - }, - { - timestamp: '2023-08-07T15:03:53.199871Z', - span_id: 'SPAN-4', - trace_id: 'TRACE-1', - service_name: 'fake-service-2', - operation: 'okey-dokey', - duration_nano: 50027500, - parent_span_id: 'SPAN-2', - }, - ], - duration_nano: 3000000, - }; - - expect(mapTraceToTreeRoot(trace)).toEqual({ - durationMs: 100120, - operation: 'lets-go', - service: 'tracegen', - spanId: 'SPAN-1', - startTimeMs: 0, - timestamp: '2023-08-07T15:03:32.199806Z', - children: [ - { - durationMs: 100055, - operation: 'okey-dokey', - service: 'tracegen', - spanId: 'SPAN-2', - startTimeMs: 0, - timestamp: '2023-08-07T15:03:32.199871Z', - children: [ - { - children: [], - durationMs: 50028, - operation: 'okey-dokey', - service: 'tracegen', - spanId: 'SPAN-3', - startTimeMs: 21000, - timestamp: '2023-08-07T15:03:53.199871Z', - }, - { - children: [], - durationMs: 50028, - operation: 'okey-dokey', - service: 'fake-service-2', - spanId: 'SPAN-4', - startTimeMs: 21000, - timestamp: '2023-08-07T15:03:53.199871Z', - }, - ], - }, - ], - }); - }); - }); -}); diff --git a/spec/frontend/tracing/components/tracing_details_chart_spec.js b/spec/frontend/tracing/components/tracing_details_chart_spec.js deleted file mode 100644 index 5062cbc5d9d..00000000000 --- a/spec/frontend/tracing/components/tracing_details_chart_spec.js +++ /dev/null @@ -1,61 +0,0 @@ -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import TracingDetailsChart from '~/tracing/components/tracing_details_chart.vue'; -import TracingDetailsSpansChart from '~/tracing/components/tracing_details_spans_chart.vue'; -import { - mapTraceToTreeRoot, - assignColorToServices, - durationNanoToMs, -} from '~/tracing/components/trace_utils'; - -jest.mock('~/tracing/components/trace_utils'); - -describe('TracingDetailsChart', () => { - let wrapper; - - const mockTrace = { - timestamp: '2023-08-07T15:03:32.199806Z', - trace_id: 'dabb7ae1-2501-8e57-18e1-30ab21a9ab19', - service_name: 'tracegen', - operation: 'lets-go', - statusCode: 'STATUS_CODE_UNSET', - duration_nano: 100120000, - spans: [ - { - timestamp: '2023-08-07T15:03:32.199806Z', - span_id: 'A1FB81EB031B09E8', - trace_id: 'dabb7ae1-2501-8e57-18e1-30ab21a9ab19', - service_name: 'tracegen', - operation: 'lets-go', - duration_nano: 100120000, - parent_span_id: '', - statusCode: 'STATUS_CODE_UNSET', - }, - ], - }; - - beforeEach(() => { - mapTraceToTreeRoot.mockReturnValue(mockTrace.spans[0]); - assignColorToServices.mockReturnValue({ tracegen: 'red' }); - durationNanoToMs.mockReturnValue(100); - - wrapper = shallowMountExtended(TracingDetailsChart, { - propsData: { - trace: mockTrace, - }, - }); - }); - - it('renders the TracingDetailsSpansChart component', () => { - expect(wrapper.findComponent(TracingDetailsSpansChart).exists()).toBe(true); - }); - - it('passes the correct props to the TracingDetailsSpansChart component', () => { - const tracingDetailsSpansChart = wrapper.findComponent(TracingDetailsSpansChart); - - expect(mapTraceToTreeRoot).toHaveBeenCalledWith(mockTrace); - - expect(tracingDetailsSpansChart.props('spans')).toEqual([mockTrace.spans[0]]); - expect(tracingDetailsSpansChart.props('traceDurationMs')).toBe(100); - expect(tracingDetailsSpansChart.props('serviceToColor')).toEqual({ tracegen: 'red' }); - }); -}); diff --git a/spec/frontend/tracing/components/tracing_details_header_spec.js b/spec/frontend/tracing/components/tracing_details_header_spec.js deleted file mode 100644 index 579b8babfe4..00000000000 --- a/spec/frontend/tracing/components/tracing_details_header_spec.js +++ /dev/null @@ -1,42 +0,0 @@ -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import TracingDetailsHeader from '~/tracing/components/tracing_details_header.vue'; - -describe('TracingDetailsHeader', () => { - let wrapper; - - beforeEach(() => { - wrapper = shallowMountExtended(TracingDetailsHeader, { - propsData: { - trace: { - service_name: 'Service', - operation: 'Operation', - timestamp: 1692021937219, - duration_nano: 1000000, - totalSpans: 10, - }, - }, - }); - }); - - it('renders the correct title', () => { - expect(wrapper.find('h1').text()).toBe('Service : Operation'); - }); - - it('renders the correct trace date', () => { - expect(wrapper.findByTestId('trace-date-card').text()).toMatchInterpolatedText( - 'Trace Start Aug 14, 2023 14:05:37 UTC', - ); - }); - - it('renders the correct trace duration', () => { - expect(wrapper.findByTestId('trace-duration-card').text()).toMatchInterpolatedText( - 'Duration 1000 ms', - ); - }); - - it('renders the correct total spans', () => { - expect(wrapper.findByTestId('trace-spans-card').text()).toMatchInterpolatedText( - 'Total Spans 10', - ); - }); -}); diff --git a/spec/frontend/tracing/components/tracing_details_span_chart_spec.js b/spec/frontend/tracing/components/tracing_details_span_chart_spec.js deleted file mode 100644 index aaa02aef406..00000000000 --- a/spec/frontend/tracing/components/tracing_details_span_chart_spec.js +++ /dev/null @@ -1,181 +0,0 @@ -import { GlButton, GlTruncate } from '@gitlab/ui'; -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import TracingDetailsSpansChart from '~/tracing/components/tracing_details_spans_chart.vue'; - -describe('TracingDetailsSpansChart', () => { - const mockSpans = [ - { - operation: 'operation-1', - service: 'service-1', - startTimeMs: 100, - durationMs: 150, - children: [ - { - operation: 'operation-3', - service: 'service-3', - startTimeMs: 0, - durationMs: 100, - children: [], - }, - ], - }, - { - operation: 'operation-2', - service: 'service-2', - startTimeMs: 100, - durationMs: 200, - children: [], - }, - ]; - - const mockProps = { - spans: mockSpans, - traceDurationMs: 300, - serviceToColor: { - 'service-1': 'blue-500', - 'service-2': 'orange-500', - }, - }; - - let wrapper; - - const getSpan = (index, depth = 0) => wrapper.findByTestId(`span-container-${depth}-${index}`); - const getSpanDetails = (index, depth = 0) => - getSpan(index, depth).find('[data-testid="span-details"]'); - - const getToggleButton = (index, depth = 0) => - getSpanDetails(index, depth).findComponent(GlButton); - - const getSpanDuration = (index, depth = 0) => - getSpan(index, depth).find('[data-testid="span-duration"]'); - - const getSpanDurationBar = (index, depth = 0) => - getSpanDuration(index, depth).find('[data-testid="span-duration-bar"]'); - - beforeEach(() => { - wrapper = shallowMountExtended(TracingDetailsSpansChart, { - propsData: { - ...mockProps, - }, - }); - }); - - it('renders the correct number of spans', () => { - expect(wrapper.findAll('[data-testid^="span-container-"]')).toHaveLength( - mockProps.spans.length, - ); - }); - - it('renders tracing-details-spans-chart only if span has children', () => { - const childrenChart = getSpan(0).findComponent(TracingDetailsSpansChart); - - expect(childrenChart.exists()).toBe(true); - expect(childrenChart.props('depth')).toBe(1); - expect(childrenChart.props('traceDurationMs')).toBe(mockProps.traceDurationMs); - expect(childrenChart.props('serviceToColor')).toBe(mockProps.serviceToColor); - expect(childrenChart.props('spans')).toBe(mockProps.spans[0].children); - - // span with no children - expect(getSpan(1).findComponent(TracingDetailsSpansChart).exists()).toBe(false); - }); - - it('toggle the children spans when clicking the expand button', async () => { - await getToggleButton(0).vm.$emit('click'); - - expect(getToggleButton(0).props('icon')).toBe('chevron-up'); - expect(getSpan(0).findComponent(TracingDetailsSpansChart).exists()).toBe(false); - - await getToggleButton(0).vm.$emit('click'); - - expect(getToggleButton(0).props('icon')).toBe('chevron-down'); - expect(getSpan(0).findComponent(TracingDetailsSpansChart).exists()).toBe(true); - }); - - it('reset the expanded state when the spans change', async () => { - await getToggleButton(0).vm.$emit('click'); - expect(getSpan(0).findComponent(TracingDetailsSpansChart).exists()).toBe(false); - - await wrapper.setProps({ spans: [...mockSpans] }); - expect(getSpan(0).findComponent(TracingDetailsSpansChart).exists()).toBe(true); - }); - - describe('span details', () => { - it('renders the spans details with left padding based on depth', () => { - wrapper = shallowMountExtended(TracingDetailsSpansChart, { - propsData: { - ...mockProps, - depth: 2, - }, - }); - expect(getSpanDetails(0, 2).element.style.paddingLeft).toBe('32px'); - }); - - it('renders span operation and service name', () => { - const textContents = getSpanDetails(0).findAllComponents(GlTruncate); - expect(textContents.at(0).props('text')).toBe('operation-1'); - expect(textContents.at(1).props('text')).toBe('service-1'); - }); - - it('renders the expanded button', () => { - expect(getToggleButton(0).props('icon')).toBe('chevron-down'); - }); - }); - - describe('span duration', () => { - it('renders the duration value', () => { - expect( - wrapper.findByTestId('span-container-0-0').find('[data-testid="span-duration"]').text(), - ).toBe('150 ms'); - }); - - it('renders the proper color based on service', () => { - expect( - wrapper - .findByTestId('span-container-0-0') - .find('[data-testid="span-duration-bar"]') - .classes(), - ).toContain('gl-bg-data-viz-blue-500'); - }); - - it('renders the bar with the proper style', () => { - expect(getSpanDuration(0).element.style.marginLeft).toBe('33%'); - expect( - getSpanDurationBar(0).find('[data-testid="span-duration-bar"]').element.style.width, - ).toBe('50%'); - }); - - it('bar width should not be less than 0.5% and not bigger than 100%', () => { - wrapper = shallowMountExtended(TracingDetailsSpansChart, { - propsData: { - serviceToColor: { - 'service-1': 'blue-500', - 'service-2': 'orange-500', - }, - traceDurationMs: 300, - spans: [ - { - operation: 'operation-1', - service: 'service-1', - startTimeMs: 0, - durationMs: 1, - children: [], - }, - { - operation: 'operation-2', - service: 'service-2', - startTimeMs: 0, - durationMs: 310, - children: [], - }, - ], - }, - }); - expect( - getSpanDurationBar(0).find('[data-testid="span-duration-bar"]').element.style.width, - ).toBe('0.5%'); - expect( - getSpanDurationBar(1).find('[data-testid="span-duration-bar"]').element.style.width, - ).toBe('100%'); - }); - }); -}); diff --git a/spec/frontend/tracing/components/tracing_details_spec.js b/spec/frontend/tracing/components/tracing_details_spec.js deleted file mode 100644 index 1b0a450d7fa..00000000000 --- a/spec/frontend/tracing/components/tracing_details_spec.js +++ /dev/null @@ -1,111 +0,0 @@ -import { GlLoadingIcon } from '@gitlab/ui'; -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import TracingDetails from '~/tracing/components/tracing_details.vue'; -import waitForPromises from 'helpers/wait_for_promises'; -import { createAlert } from '~/alert'; -import { visitUrl, isSafeURL } from '~/lib/utils/url_utility'; -import TracingDetailsChart from '~/tracing/components/tracing_details_chart.vue'; -import TracingDetailsHeader from '~/tracing/components/tracing_details_header.vue'; - -jest.mock('~/alert'); -jest.mock('~/lib/utils/url_utility'); - -describe('TracingDetails', () => { - let wrapper; - let observabilityClientMock; - - const TRACE_ID = 'test-trace-id'; - const TRACING_INDEX_URL = 'https://www.gitlab.com/flightjs/Flight/-/tracing'; - - const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); - const findTraceDetails = () => wrapper.findComponentByTestId('trace-details'); - - const props = { - traceId: TRACE_ID, - tracingIndexUrl: TRACING_INDEX_URL, - }; - - const mountComponent = async () => { - wrapper = shallowMountExtended(TracingDetails, { - propsData: { - ...props, - observabilityClient: observabilityClientMock, - }, - }); - await waitForPromises(); - }; - - beforeEach(() => { - isSafeURL.mockReturnValue(true); - - observabilityClientMock = { - isTracingEnabled: jest.fn(), - fetchTrace: jest.fn(), - }; - }); - - it('renders the loading indicator while checking if tracing is enabled', () => { - mountComponent(); - - expect(findLoadingIcon().exists()).toBe(true); - expect(observabilityClientMock.isTracingEnabled).toHaveBeenCalled(); - }); - - describe('when tracing is enabled', () => { - const mockTrace = { traceId: 'test-trace-id', foo: 'bar' }; - beforeEach(async () => { - observabilityClientMock.isTracingEnabled.mockResolvedValueOnce(true); - observabilityClientMock.fetchTrace.mockResolvedValueOnce(mockTrace); - - await mountComponent(); - }); - - it('fetches the trace and renders the trace details', () => { - expect(observabilityClientMock.isTracingEnabled).toHaveBeenCalled(); - expect(observabilityClientMock.fetchTrace).toHaveBeenCalled(); - expect(findLoadingIcon().exists()).toBe(false); - expect(findTraceDetails().exists()).toBe(true); - }); - - it('renders the correct components', () => { - const details = findTraceDetails(); - expect(details.findComponent(TracingDetailsChart).exists()).toBe(true); - expect(details.findComponent(TracingDetailsHeader).exists()).toBe(true); - }); - }); - - describe('when tracing is not enabled', () => { - beforeEach(async () => { - observabilityClientMock.isTracingEnabled.mockResolvedValueOnce(false); - - await mountComponent(); - }); - - it('redirects to tracingIndexUrl', () => { - expect(visitUrl).toHaveBeenCalledWith(props.tracingIndexUrl); - }); - }); - - describe('error handling', () => { - it('if isTracingEnabled fails, it renders an alert and empty page', async () => { - observabilityClientMock.isTracingEnabled.mockRejectedValueOnce('error'); - - await mountComponent(); - - expect(createAlert).toHaveBeenCalledWith({ message: 'Failed to load trace details.' }); - expect(findLoadingIcon().exists()).toBe(false); - expect(findTraceDetails().exists()).toBe(false); - }); - - it('if fetchTrace fails, it renders an alert and empty page', async () => { - observabilityClientMock.isTracingEnabled.mockReturnValueOnce(true); - observabilityClientMock.fetchTrace.mockRejectedValueOnce('error'); - - await mountComponent(); - - expect(createAlert).toHaveBeenCalledWith({ message: 'Failed to load trace details.' }); - expect(findLoadingIcon().exists()).toBe(false); - expect(findTraceDetails().exists()).toBe(false); - }); - }); -}); diff --git a/spec/frontend/tracing/components/tracing_empty_state_spec.js b/spec/frontend/tracing/components/tracing_empty_state_spec.js deleted file mode 100644 index d91c62a1dad..00000000000 --- a/spec/frontend/tracing/components/tracing_empty_state_spec.js +++ /dev/null @@ -1,39 +0,0 @@ -import { GlButton, GlEmptyState } from '@gitlab/ui'; -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import TracingEmptyState from '~/tracing/components/tracing_empty_state.vue'; - -describe('TracingEmptyState', () => { - let wrapper; - - const findEnableButton = () => wrapper.findComponent(GlButton); - - beforeEach(() => { - wrapper = shallowMountExtended(TracingEmptyState); - }); - - it('renders the component properly', () => { - expect(wrapper.exists()).toBe(true); - }); - - it('displays the correct title', () => { - const { title } = wrapper.findComponent(GlEmptyState).props(); - expect(title).toBe('Get started with Tracing'); - }); - - it('displays the correct description', () => { - const description = wrapper.find('span').text(); - expect(description).toBe('Monitor your applications with GitLab Distributed Tracing.'); - }); - - it('displays the enable button', () => { - const enableButton = findEnableButton(); - expect(enableButton.exists()).toBe(true); - expect(enableButton.text()).toBe('Enable'); - }); - - it('emits enable-tracing when enable button is clicked', () => { - findEnableButton().vm.$emit('click'); - - expect(wrapper.emitted('enable-tracing')).toHaveLength(1); - }); -}); diff --git a/spec/frontend/tracing/components/tracing_list_filtered_search_spec.js b/spec/frontend/tracing/components/tracing_list_filtered_search_spec.js deleted file mode 100644 index ad15dd4a371..00000000000 --- a/spec/frontend/tracing/components/tracing_list_filtered_search_spec.js +++ /dev/null @@ -1,38 +0,0 @@ -import { GlFilteredSearch } from '@gitlab/ui'; -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; - -import TracingListFilteredSearch from '~/tracing/components/tracing_list_filtered_search.vue'; - -describe('TracingListFilteredSearch', () => { - let wrapper; - const initialFilters = [ - { type: 'period', value: '1h' }, - { type: 'service_name', value: 'example-service' }, - ]; - beforeEach(() => { - wrapper = shallowMountExtended(TracingListFilteredSearch, { - propsData: { - initialFilters, - }, - }); - }); - - it('renders the component', () => { - expect(wrapper.exists()).toBe(true); - }); - - it('sets initialFilters prop correctly', () => { - expect(wrapper.findComponent(GlFilteredSearch).props('value')).toEqual(initialFilters); - }); - - it('emits submit event on filtered search submit', () => { - wrapper - .findComponent(GlFilteredSearch) - .vm.$emit('submit', { filters: [{ type: 'period', value: '1h' }] }); - - expect(wrapper.emitted('submit')).toHaveLength(1); - expect(wrapper.emitted('submit')[0][0]).toEqual({ - filters: [{ type: 'period', value: '1h' }], - }); - }); -}); diff --git a/spec/frontend/tracing/components/tracing_list_spec.js b/spec/frontend/tracing/components/tracing_list_spec.js deleted file mode 100644 index 63f1d09e5c0..00000000000 --- a/spec/frontend/tracing/components/tracing_list_spec.js +++ /dev/null @@ -1,216 +0,0 @@ -import { GlLoadingIcon } from '@gitlab/ui'; -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import TracingList from '~/tracing/components/tracing_list.vue'; -import TracingEmptyState from '~/tracing/components/tracing_empty_state.vue'; -import TracingTableList from '~/tracing/components/tracing_table_list.vue'; -import waitForPromises from 'helpers/wait_for_promises'; -import { createAlert } from '~/alert'; -import * as urlUtility from '~/lib/utils/url_utility'; -import { - queryToFilterObj, - filterObjToQuery, - filterObjToFilterToken, - filterTokensToFilterObj, -} from '~/tracing/filters'; -import FilteredSearch from '~/tracing/components/tracing_list_filtered_search.vue'; -import UrlSync from '~/vue_shared/components/url_sync.vue'; -import setWindowLocation from 'helpers/set_window_location_helper'; - -jest.mock('~/alert'); -jest.mock('~/tracing/filters'); - -describe('TracingList', () => { - let wrapper; - let observabilityClientMock; - - const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); - const findEmptyState = () => wrapper.findComponent(TracingEmptyState); - const findTableList = () => wrapper.findComponent(TracingTableList); - const findFilteredSearch = () => wrapper.findComponent(FilteredSearch); - const findUrlSync = () => wrapper.findComponent(UrlSync); - - const mountComponent = async () => { - wrapper = shallowMountExtended(TracingList, { - propsData: { - observabilityClient: observabilityClientMock, - }, - }); - await waitForPromises(); - }; - - beforeEach(() => { - observabilityClientMock = { - isTracingEnabled: jest.fn(), - enableTraces: jest.fn(), - fetchTraces: jest.fn(), - }; - }); - - it('renders the loading indicator while checking if tracing is enabled', () => { - mountComponent(); - expect(findLoadingIcon().exists()).toBe(true); - expect(findEmptyState().exists()).toBe(false); - expect(findTableList().exists()).toBe(false); - expect(findFilteredSearch().exists()).toBe(false); - expect(findUrlSync().exists()).toBe(false); - expect(observabilityClientMock.isTracingEnabled).toHaveBeenCalled(); - }); - - describe('when tracing is enabled', () => { - const mockTraces = ['trace1', 'trace2']; - beforeEach(async () => { - observabilityClientMock.isTracingEnabled.mockResolvedValueOnce(true); - observabilityClientMock.fetchTraces.mockResolvedValueOnce(mockTraces); - - await mountComponent(); - }); - - it('fetches the traces and renders the trace list with filtered search', () => { - expect(observabilityClientMock.isTracingEnabled).toHaveBeenCalled(); - expect(observabilityClientMock.fetchTraces).toHaveBeenCalled(); - expect(findLoadingIcon().exists()).toBe(false); - expect(findEmptyState().exists()).toBe(false); - expect(findTableList().exists()).toBe(true); - expect(findFilteredSearch().exists()).toBe(true); - expect(findUrlSync().exists()).toBe(true); - expect(findTableList().props('traces')).toBe(mockTraces); - }); - - it('calls fetchTraces method when TracingTableList emits reload event', () => { - observabilityClientMock.fetchTraces.mockClear(); - observabilityClientMock.fetchTraces.mockResolvedValueOnce(['trace1']); - - findTableList().vm.$emit('reload'); - - expect(observabilityClientMock.fetchTraces).toHaveBeenCalledTimes(1); - }); - - it('on trace selection it redirects to the details url', () => { - setWindowLocation('base_path'); - const visitUrlMock = jest.spyOn(urlUtility, 'visitUrl').mockReturnValue({}); - - findTableList().vm.$emit('trace-selected', { traceId: 'test-trace-id' }); - - expect(visitUrlMock).toHaveBeenCalledTimes(1); - expect(visitUrlMock).toHaveBeenCalledWith('/base_path/test-trace-id'); - }); - }); - - describe('filtered search', () => { - let mockFilterObj; - let mockFilterToken; - let mockQuery; - let mockUpdatedFilterObj; - - beforeEach(async () => { - observabilityClientMock.isTracingEnabled.mockResolvedValue(true); - observabilityClientMock.fetchTraces.mockResolvedValue([]); - - setWindowLocation('?trace-id=foo'); - - mockFilterObj = { mock: 'filter-obj' }; - queryToFilterObj.mockReturnValue(mockFilterObj); - - mockFilterToken = ['mock-token']; - filterObjToFilterToken.mockReturnValue(mockFilterToken); - - mockQuery = { mock: 'query' }; - filterObjToQuery.mockReturnValueOnce(mockQuery); - - mockUpdatedFilterObj = { mock: 'filter-obj-upd' }; - filterTokensToFilterObj.mockReturnValue(mockUpdatedFilterObj); - - await mountComponent(); - }); - - it('renders FilteredSeach with initial filters parsed from window.location', () => { - expect(queryToFilterObj).toHaveBeenCalledWith('?trace-id=foo'); - expect(filterObjToFilterToken).toHaveBeenCalledWith(mockFilterObj); - expect(findFilteredSearch().props('initialFilters')).toBe(mockFilterToken); - }); - - it('renders UrlSync and sets query prop', () => { - expect(filterObjToQuery).toHaveBeenCalledWith(mockFilterObj); - expect(findUrlSync().props('query')).toBe(mockQuery); - }); - - it('process filters on search submit', async () => { - const mockUpdatedQuery = { mock: 'updated-query' }; - filterObjToQuery.mockReturnValueOnce(mockUpdatedQuery); - const mockFilters = { mock: 'some-filter' }; - - findFilteredSearch().vm.$emit('submit', mockFilters); - await waitForPromises(); - - expect(filterTokensToFilterObj).toHaveBeenCalledWith(mockFilters); - expect(filterObjToQuery).toHaveBeenCalledWith(mockUpdatedFilterObj); - expect(findUrlSync().props('query')).toBe(mockUpdatedQuery); - }); - - it('fetches traces with filters', () => { - expect(observabilityClientMock.fetchTraces).toHaveBeenCalledWith(mockFilterObj); - - findFilteredSearch().vm.$emit('submit', {}); - - expect(observabilityClientMock.fetchTraces).toHaveBeenLastCalledWith(mockUpdatedFilterObj); - }); - }); - - describe('when tracing is not enabled', () => { - beforeEach(async () => { - observabilityClientMock.isTracingEnabled.mockResolvedValueOnce(false); - observabilityClientMock.fetchTraces.mockResolvedValueOnce([]); - - await mountComponent(); - }); - - it('renders TracingEmptyState', () => { - expect(findEmptyState().exists()).toBe(true); - }); - - it('calls enableTracing when TracingEmptyState emits enable-tracing', () => { - findEmptyState().vm.$emit('enable-tracing'); - - expect(observabilityClientMock.enableTraces).toHaveBeenCalled(); - }); - }); - - describe('error handling', () => { - it('if isTracingEnabled fails, it renders an alert and empty page', async () => { - observabilityClientMock.isTracingEnabled.mockRejectedValueOnce('error'); - - await mountComponent(); - - expect(createAlert).toHaveBeenCalledWith({ message: 'Failed to load page.' }); - expect(findLoadingIcon().exists()).toBe(false); - expect(findEmptyState().exists()).toBe(false); - expect(findTableList().exists()).toBe(false); - }); - - it('if fetchTraces fails, it renders an alert and empty list', async () => { - observabilityClientMock.fetchTraces.mockRejectedValueOnce('error'); - observabilityClientMock.isTracingEnabled.mockReturnValueOnce(true); - - await mountComponent(); - - expect(createAlert).toHaveBeenCalledWith({ message: 'Failed to load traces.' }); - expect(findTableList().exists()).toBe(true); - expect(findTableList().props('traces')).toEqual([]); - }); - - it('if enableTraces fails, it renders an alert and empty-state', async () => { - observabilityClientMock.isTracingEnabled.mockReturnValueOnce(false); - observabilityClientMock.enableTraces.mockRejectedValueOnce('error'); - - await mountComponent(); - - findEmptyState().vm.$emit('enable-tracing'); - await waitForPromises(); - - expect(createAlert).toHaveBeenCalledWith({ message: 'Failed to enable tracing.' }); - expect(findLoadingIcon().exists()).toBe(false); - expect(findEmptyState().exists()).toBe(true); - expect(findTableList().exists()).toBe(false); - }); - }); -}); diff --git a/spec/frontend/tracing/components/tracing_table_list_spec.js b/spec/frontend/tracing/components/tracing_table_list_spec.js deleted file mode 100644 index 1930ebe6b4e..00000000000 --- a/spec/frontend/tracing/components/tracing_table_list_spec.js +++ /dev/null @@ -1,77 +0,0 @@ -import { nextTick } from 'vue'; -import { mountExtended } from 'helpers/vue_test_utils_helper'; -import TracingTableList from '~/tracing/components/tracing_table_list.vue'; - -describe('TracingTableList', () => { - let wrapper; - const mockTraces = [ - { - timestamp: '2023-07-10T15:02:30.677538Z', - service_name: 'tracegen', - operation: 'lets-go', - duration_nano: 150000, - }, - { - timestamp: '2023-07-10T15:02:30.677538Z', - service_name: 'tracegen', - operation: 'lets-go', - duration_nano: 200000, - }, - ]; - - const mountComponent = ({ traces = mockTraces } = {}) => { - wrapper = mountExtended(TracingTableList, { - propsData: { - traces, - }, - }); - }; - - const getRows = () => wrapper.findComponent({ name: 'GlTable' }).find('tbody').findAll('tr'); - const getRow = (idx) => getRows().at(idx); - const getCells = (trIdx) => getRows().at(trIdx).findAll('td'); - - const getCell = (trIdx, tdIdx) => { - return getCells(trIdx).at(tdIdx); - }; - - const selectRow = async (idx) => { - getRow(idx).trigger('click'); - await nextTick(); - }; - - it('renders traces as table', () => { - mountComponent(); - - const rows = wrapper.findAll('table tbody tr'); - - expect(rows.length).toBe(mockTraces.length); - - mockTraces.forEach((trace, i) => { - expect(getCells(i).length).toBe(4); - expect(getCell(i, 0).text()).toBe('Jul 10, 2023 3:02pm UTC'); - expect(getCell(i, 1).text()).toBe(trace.service_name); - expect(getCell(i, 2).text()).toBe(trace.operation); - expect(getCell(i, 3).text()).toBe(`${trace.duration_nano / 1000} ms`); - }); - }); - - it('emits trace-selected on row selection', async () => { - mountComponent(); - - await selectRow(0); - expect(wrapper.emitted('trace-selected')).toHaveLength(1); - expect(wrapper.emitted('trace-selected')[0][0]).toEqual({ trace_id: mockTraces[0].trace_id }); - }); - - it('renders the empty state when no traces are provided', () => { - mountComponent({ traces: [] }); - - expect(getCell(0, 0).text()).toContain('No traces to display'); - const link = getCell(0, 0).findComponent({ name: 'GlLink' }); - expect(link.text()).toBe('Check again'); - - link.trigger('click'); - expect(wrapper.emitted('reload')).toHaveLength(1); - }); -}); diff --git a/spec/frontend/tracing/details_index_spec.js b/spec/frontend/tracing/details_index_spec.js deleted file mode 100644 index e0d368b6cb7..00000000000 --- a/spec/frontend/tracing/details_index_spec.js +++ /dev/null @@ -1,42 +0,0 @@ -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import DetailsIndex from '~/tracing/details_index.vue'; -import TracingDetails from '~/tracing/components/tracing_details.vue'; -import ObservabilityContainer from '~/observability/components/observability_container.vue'; - -describe('DetailsIndex', () => { - const props = { - traceId: 'test-trace-id', - tracingIndexUrl: 'https://example.com/tracing/index', - oauthUrl: 'https://example.com/oauth', - tracingUrl: 'https://example.com/tracing', - provisioningUrl: 'https://example.com/provisioning', - }; - - let wrapper; - - const mountComponent = () => { - wrapper = shallowMountExtended(DetailsIndex, { - propsData: props, - }); - }; - - it('renders ObservabilityContainer component', () => { - mountComponent(); - - const observabilityContainer = wrapper.findComponent(ObservabilityContainer); - expect(observabilityContainer.exists()).toBe(true); - expect(observabilityContainer.props('oauthUrl')).toBe(props.oauthUrl); - expect(observabilityContainer.props('tracingUrl')).toBe(props.tracingUrl); - expect(observabilityContainer.props('provisioningUrl')).toBe(props.provisioningUrl); - }); - - it('renders TracingList component inside ObservabilityContainer', () => { - mountComponent(); - - const observabilityContainer = wrapper.findComponent(ObservabilityContainer); - const detailsCmp = observabilityContainer.findComponent(TracingDetails); - expect(detailsCmp.exists()).toBe(true); - expect(detailsCmp.props('traceId')).toBe(props.traceId); - expect(detailsCmp.props('tracingIndexUrl')).toBe(props.tracingIndexUrl); - }); -}); diff --git a/spec/frontend/tracing/filters_spec.js b/spec/frontend/tracing/filters_spec.js deleted file mode 100644 index ee396326f45..00000000000 --- a/spec/frontend/tracing/filters_spec.js +++ /dev/null @@ -1,141 +0,0 @@ -import { - filterToQueryObject, - urlQueryToFilter, - prepareTokens, - processFilters, -} from '~/vue_shared/components/filtered_search_bar/filtered_search_utils'; -import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; - -import { - PERIOD_FILTER_TOKEN_TYPE, - SERVICE_NAME_FILTER_TOKEN_TYPE, - OPERATION_FILTER_TOKEN_TYPE, - TRACE_ID_FILTER_TOKEN_TYPE, - DURATION_MS_FILTER_TOKEN_TYPE, - queryToFilterObj, - filterObjToQuery, - filterObjToFilterToken, - filterTokensToFilterObj, -} from '~/tracing/filters'; - -jest.mock('~/vue_shared/components/filtered_search_bar/filtered_search_utils'); - -describe('utils', () => { - describe('queryToFilterObj', () => { - it('should build a filter obj', () => { - const url = 'http://example.com/'; - urlQueryToFilter.mockReturnValue({ - period: '7d', - service: 'my_service', - operation: 'my_operation', - trace_id: 'my_trace_id', - durationMs: '500', - [FILTERED_SEARCH_TERM]: 'test', - }); - - const filterObj = queryToFilterObj(url); - - expect(urlQueryToFilter).toHaveBeenCalledWith(url, { - customOperators: [ - { operator: '>', prefix: 'gt' }, - { operator: '<', prefix: 'lt' }, - ], - filteredSearchTermKey: 'search', - }); - expect(filterObj).toEqual({ - period: '7d', - service: 'my_service', - operation: 'my_operation', - traceId: 'my_trace_id', - durationMs: '500', - search: 'test', - }); - }); - }); - - describe('filterObjToQuery', () => { - it('should convert filter object to URL query', () => { - filterToQueryObject.mockReturnValue('mockquery'); - - const query = filterObjToQuery({ - period: '7d', - serviceName: 'my_service', - operation: 'my_operation', - traceId: 'my_trace_id', - durationMs: '500', - search: 'test', - }); - - expect(filterToQueryObject).toHaveBeenCalledWith( - { - period: '7d', - service: 'my_service', - operation: 'my_operation', - trace_id: 'my_trace_id', - durationMs: '500', - 'filtered-search-term': 'test', - }, - { - customOperators: [ - { applyOnlyToKey: 'durationMs', operator: '>', prefix: 'gt' }, - { applyOnlyToKey: 'durationMs', operator: '<', prefix: 'lt' }, - ], - filteredSearchTermKey: 'search', - }, - ); - expect(query).toBe('mockquery'); - }); - }); - - describe('filterObjToFilterToken', () => { - it('should convert filter object to filter tokens', () => { - const mockTokens = []; - prepareTokens.mockReturnValue(mockTokens); - - const tokens = filterObjToFilterToken({ - period: '7d', - serviceName: 'my_service', - operation: 'my_operation', - traceId: 'my_trace_id', - durationMs: '500', - search: 'test', - }); - - expect(prepareTokens).toHaveBeenCalledWith({ - [PERIOD_FILTER_TOKEN_TYPE]: '7d', - [SERVICE_NAME_FILTER_TOKEN_TYPE]: 'my_service', - [OPERATION_FILTER_TOKEN_TYPE]: 'my_operation', - [TRACE_ID_FILTER_TOKEN_TYPE]: 'my_trace_id', - [DURATION_MS_FILTER_TOKEN_TYPE]: '500', - [FILTERED_SEARCH_TERM]: 'test', - }); - expect(tokens).toBe(mockTokens); - }); - }); - - describe('filterTokensToFilterObj', () => { - it('should convert filter tokens to filter object', () => { - const mockTokens = []; - processFilters.mockReturnValue({ - [SERVICE_NAME_FILTER_TOKEN_TYPE]: 'my_service', - [PERIOD_FILTER_TOKEN_TYPE]: '7d', - [OPERATION_FILTER_TOKEN_TYPE]: 'my_operation', - [TRACE_ID_FILTER_TOKEN_TYPE]: 'my_trace_id', - [DURATION_MS_FILTER_TOKEN_TYPE]: '500', - [FILTERED_SEARCH_TERM]: 'test', - }); - - const filterObj = filterTokensToFilterObj(mockTokens); - - expect(processFilters).toHaveBeenCalledWith(mockTokens); - expect(filterObj).toEqual({ - serviceName: 'my_service', - period: '7d', - operation: 'my_operation', - traceId: 'my_trace_id', - durationMs: '500', - search: 'test', - }); - }); - }); -}); diff --git a/spec/frontend/tracing/list_index_spec.js b/spec/frontend/tracing/list_index_spec.js deleted file mode 100644 index a5759035c2f..00000000000 --- a/spec/frontend/tracing/list_index_spec.js +++ /dev/null @@ -1,37 +0,0 @@ -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import ListIndex from '~/tracing/list_index.vue'; -import TracingList from '~/tracing/components/tracing_list.vue'; -import ObservabilityContainer from '~/observability/components/observability_container.vue'; - -describe('ListIndex', () => { - const props = { - oauthUrl: 'https://example.com/oauth', - tracingUrl: 'https://example.com/tracing', - provisioningUrl: 'https://example.com/provisioning', - }; - - let wrapper; - - const mountComponent = () => { - wrapper = shallowMountExtended(ListIndex, { - propsData: props, - }); - }; - - it('renders ObservabilityContainer component', () => { - mountComponent(); - - const observabilityContainer = wrapper.findComponent(ObservabilityContainer); - expect(observabilityContainer.exists()).toBe(true); - expect(observabilityContainer.props('oauthUrl')).toBe(props.oauthUrl); - expect(observabilityContainer.props('tracingUrl')).toBe(props.tracingUrl); - expect(observabilityContainer.props('provisioningUrl')).toBe(props.provisioningUrl); - }); - - it('renders TracingList component inside ObservabilityContainer', () => { - mountComponent(); - - const observabilityContainer = wrapper.findComponent(ObservabilityContainer); - expect(observabilityContainer.findComponent(TracingList).exists()).toBe(true); - }); -}); |