diff options
Diffstat (limited to 'spec/frontend/observability')
-rw-r--r-- | spec/frontend/observability/client_spec.js | 233 | ||||
-rw-r--r-- | spec/frontend/observability/index_spec.js | 64 | ||||
-rw-r--r-- | spec/frontend/observability/observability_app_spec.js | 201 | ||||
-rw-r--r-- | spec/frontend/observability/observability_container_spec.js | 6 | ||||
-rw-r--r-- | spec/frontend/observability/skeleton_spec.js | 86 |
5 files changed, 213 insertions, 377 deletions
diff --git a/spec/frontend/observability/client_spec.js b/spec/frontend/observability/client_spec.js index 056175eac07..68a53131539 100644 --- a/spec/frontend/observability/client_spec.js +++ b/spec/frontend/observability/client_spec.js @@ -12,7 +12,8 @@ describe('buildClient', () => { const tracingUrl = 'https://example.com/tracing'; const provisioningUrl = 'https://example.com/provisioning'; - + const servicesUrl = 'https://example.com/services'; + const operationsUrl = 'https://example.com/services/$SERVICE_NAME$/operations'; const FETCHING_TRACES_ERROR = 'traces are missing/invalid in the response'; beforeEach(() => { @@ -22,6 +23,8 @@ describe('buildClient', () => { client = buildClient({ tracingUrl, provisioningUrl, + servicesUrl, + operationsUrl, }); }); @@ -29,6 +32,27 @@ describe('buildClient', () => { axiosMock.restore(); }); + describe('buildClient', () => { + it('rejects if params are missing', () => { + const e = new Error( + 'missing required params. provisioningUrl, tracingUrl, servicesUrl, operationsUrl are required', + ); + expect(() => + buildClient({ tracingUrl: 'test', servicesUrl: 'test', operationsUrl: 'test' }), + ).toThrow(e); + expect(() => + buildClient({ provisioningUrl: 'test', servicesUrl: 'test', operationsUrl: 'test' }), + ).toThrow(e); + expect(() => + buildClient({ provisioningUrl: 'test', tracingUrl: 'test', operationsUrl: 'test' }), + ).toThrow(e); + expect(() => + buildClient({ provisioningUrl: 'test', tracingUrl: 'test', servicesUrl: 'test' }), + ).toThrow(e); + expect(() => buildClient({})).toThrow(e); + }); + }); + describe('isTracingEnabled', () => { it('returns true if requests succeedes', async () => { axiosMock.onGet(provisioningUrl).reply(200, { @@ -145,18 +169,18 @@ describe('buildClient', () => { describe('fetchTraces', () => { it('fetches traces from the tracing URL', async () => { - const mockTraces = [ - { - trace_id: 'trace-1', - duration_nano: 3000, - spans: [{ duration_nano: 1000 }, { duration_nano: 2000 }], - }, - { trace_id: 'trace-2', duration_nano: 3000, spans: [{ duration_nano: 2000 }] }, - ]; - - axiosMock.onGet(tracingUrl).reply(200, { - traces: mockTraces, - }); + const mockResponse = { + traces: [ + { + trace_id: 'trace-1', + duration_nano: 3000, + spans: [{ duration_nano: 1000 }, { duration_nano: 2000 }], + }, + { trace_id: 'trace-2', duration_nano: 3000, spans: [{ duration_nano: 2000 }] }, + ], + }; + + axiosMock.onGet(tracingUrl).reply(200, mockResponse); const result = await client.fetchTraces(); @@ -165,7 +189,7 @@ describe('buildClient', () => { withCredentials: true, params: new URLSearchParams(), }); - expect(result).toEqual(mockTraces); + expect(result).toEqual(mockResponse); }); it('rejects if traces are missing', async () => { @@ -197,28 +221,42 @@ describe('buildClient', () => { expect(getQueryParam()).toBe(''); }); + it('appends page_token if specified', async () => { + await client.fetchTraces({ pageToken: 'page-token' }); + + expect(getQueryParam()).toBe('page_token=page-token'); + }); + + it('appends page_size if specified', async () => { + await client.fetchTraces({ pageSize: 10 }); + + expect(getQueryParam()).toBe('page_size=10'); + }); + it('converts filter to proper query params', async () => { await client.fetchTraces({ - durationMs: [ - { operator: '>', value: '100' }, - { operator: '<', value: '1000' }, - ], - operation: [ - { operator: '=', value: 'op' }, - { operator: '!=', value: 'not-op' }, - ], - serviceName: [ - { operator: '=', value: 'service' }, - { operator: '!=', value: 'not-service' }, - ], - period: [{ operator: '=', value: '5m' }], - traceId: [ - { operator: '=', value: 'trace-id' }, - { operator: '!=', value: 'not-trace-id' }, - ], + filters: { + durationMs: [ + { operator: '>', value: '100' }, + { operator: '<', value: '1000' }, + ], + operation: [ + { operator: '=', value: 'op' }, + { operator: '!=', value: 'not-op' }, + ], + serviceName: [ + { operator: '=', value: 'service' }, + { operator: '!=', value: 'not-service' }, + ], + period: [{ operator: '=', value: '5m' }], + traceId: [ + { operator: '=', value: 'trace-id' }, + { operator: '!=', value: 'not-trace-id' }, + ], + }, }); expect(getQueryParam()).toBe( - 'gt[duration_nano]=100000<[duration_nano]=1000000' + + 'gt[duration_nano]=100000000<[duration_nano]=1000000000' + '&operation=op¬[operation]=not-op' + '&service_name=service¬[service_name]=not-service' + '&period=5m' + @@ -228,17 +266,21 @@ describe('buildClient', () => { it('handles repeated params', async () => { await client.fetchTraces({ - operation: [ - { operator: '=', value: 'op' }, - { operator: '=', value: 'op2' }, - ], + filters: { + operation: [ + { operator: '=', value: 'op' }, + { operator: '=', value: 'op2' }, + ], + }, }); expect(getQueryParam()).toBe('operation=op&operation=op2'); }); it('ignores unsupported filters', async () => { await client.fetchTraces({ - unsupportedFilter: [{ operator: '=', value: 'foo' }], + filters: { + unsupportedFilter: [{ operator: '=', value: 'foo' }], + }, }); expect(getQueryParam()).toBe(''); @@ -246,8 +288,10 @@ describe('buildClient', () => { it('ignores empty filters', async () => { await client.fetchTraces({ - durationMs: null, - traceId: undefined, + filters: { + durationMs: null, + traceId: undefined, + }, }); expect(getQueryParam()).toBe(''); @@ -255,28 +299,103 @@ describe('buildClient', () => { it('ignores unsupported operators', async () => { await client.fetchTraces({ - durationMs: [ - { operator: '*', value: 'foo' }, - { operator: '=', value: 'foo' }, - { operator: '!=', value: 'foo' }, - ], - operation: [ - { operator: '>', value: 'foo' }, - { operator: '<', value: 'foo' }, - ], - serviceName: [ - { operator: '>', value: 'foo' }, - { operator: '<', value: 'foo' }, - ], - period: [{ operator: '!=', value: 'foo' }], - traceId: [ - { operator: '>', value: 'foo' }, - { operator: '<', value: 'foo' }, - ], + filters: { + durationMs: [ + { operator: '*', value: 'foo' }, + { operator: '=', value: 'foo' }, + { operator: '!=', value: 'foo' }, + ], + operation: [ + { operator: '>', value: 'foo' }, + { operator: '<', value: 'foo' }, + ], + serviceName: [ + { operator: '>', value: 'foo' }, + { operator: '<', value: 'foo' }, + ], + period: [{ operator: '!=', value: 'foo' }], + traceId: [ + { operator: '>', value: 'foo' }, + { operator: '<', value: 'foo' }, + ], + }, }); expect(getQueryParam()).toBe(''); }); }); }); + + describe('fetchServices', () => { + it('fetches services from the services URL', async () => { + const mockResponse = { + services: [{ name: 'service-1' }, { name: 'service-2' }], + }; + + axiosMock.onGet(servicesUrl).reply(200, mockResponse); + + const result = await client.fetchServices(); + + expect(axios.get).toHaveBeenCalledTimes(1); + expect(axios.get).toHaveBeenCalledWith(servicesUrl, { + withCredentials: true, + }); + expect(result).toEqual(mockResponse.services); + }); + + it('rejects if services are missing', async () => { + axiosMock.onGet(servicesUrl).reply(200, {}); + + const e = 'failed to fetch services. invalid response'; + await expect(client.fetchServices()).rejects.toThrow(e); + expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e)); + }); + }); + + describe('fetchOperations', () => { + const serviceName = 'test-service'; + const parsedOperationsUrl = `https://example.com/services/${serviceName}/operations`; + + it('fetches operations from the operations URL', async () => { + const mockResponse = { + operations: [{ name: 'operation-1' }, { name: 'operation-2' }], + }; + + axiosMock.onGet(parsedOperationsUrl).reply(200, mockResponse); + + const result = await client.fetchOperations(serviceName); + + expect(axios.get).toHaveBeenCalledTimes(1); + expect(axios.get).toHaveBeenCalledWith(parsedOperationsUrl, { + withCredentials: true, + }); + expect(result).toEqual(mockResponse.operations); + }); + + it('rejects if serviceName is missing', async () => { + const e = 'fetchOperations() - serviceName is required.'; + await expect(client.fetchOperations()).rejects.toThrow(e); + expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e)); + }); + + it('rejects if operationUrl does not contain $SERVICE_NAME$', async () => { + client = buildClient({ + tracingUrl, + provisioningUrl, + servicesUrl, + operationsUrl: 'something', + }); + const e = 'fetchOperations() - operationsUrl must contain $SERVICE_NAME$'; + await expect(client.fetchOperations(serviceName)).rejects.toThrow(e); + expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e)); + }); + + it('rejects if operations are missing', async () => { + axiosMock.onGet(parsedOperationsUrl).reply(200, {}); + + const e = 'failed to fetch operations. invalid response'; + await expect(client.fetchOperations(serviceName)).rejects.toThrow(e); + expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e)); + }); + }); }); diff --git a/spec/frontend/observability/index_spec.js b/spec/frontend/observability/index_spec.js deleted file mode 100644 index 25eb048c62b..00000000000 --- a/spec/frontend/observability/index_spec.js +++ /dev/null @@ -1,64 +0,0 @@ -import { createWrapper } from '@vue/test-utils'; -import Vue, { nextTick } from 'vue'; -import renderObservability from '~/observability/index'; -import ObservabilityApp from '~/observability/components/observability_app.vue'; -import { SKELETON_VARIANTS_BY_ROUTE } from '~/observability/constants'; - -describe('renderObservability', () => { - let element; - let vueInstance; - let component; - - const OBSERVABILITY_ROUTES = Object.keys(SKELETON_VARIANTS_BY_ROUTE); - const SKELETON_VARIANTS = Object.values(SKELETON_VARIANTS_BY_ROUTE); - - beforeEach(() => { - element = document.createElement('div'); - element.setAttribute('id', 'js-observability-app'); - element.dataset.observabilityIframeSrc = 'https://observe.gitlab.com/'; - document.body.appendChild(element); - - vueInstance = renderObservability(); - component = createWrapper(vueInstance).findComponent(ObservabilityApp); - }); - - afterEach(() => { - element.remove(); - }); - - it('should return a Vue instance', () => { - expect(vueInstance).toEqual(expect.any(Vue)); - }); - - it('should render the ObservabilityApp component', () => { - expect(component.props('observabilityIframeSrc')).toBe('https://observe.gitlab.com/'); - }); - - describe('skeleton variant', () => { - it.each` - pathDescription | path | variant - ${'dashboards'} | ${OBSERVABILITY_ROUTES[0]} | ${SKELETON_VARIANTS[0]} - ${'explore'} | ${OBSERVABILITY_ROUTES[1]} | ${SKELETON_VARIANTS[1]} - ${'manage dashboards'} | ${OBSERVABILITY_ROUTES[2]} | ${SKELETON_VARIANTS[2]} - ${'any other'} | ${'unknown/route'} | ${SKELETON_VARIANTS[0]} - `( - 'renders the $variant skeleton variant for $pathDescription path', - async ({ path, variant }) => { - component.vm.$router.push(path); - await nextTick(); - - expect(component.props('skeletonVariant')).toBe(variant); - }, - ); - }); - - it('handle route-update events', () => { - component.vm.$router.push('/something?foo=bar'); - component.vm.$emit('route-update', { url: '/some_path' }); - expect(component.vm.$router.currentRoute.path).toBe('/something'); - expect(component.vm.$router.currentRoute.query).toEqual({ - foo: 'bar', - observability_path: '/some_path', - }); - }); -}); diff --git a/spec/frontend/observability/observability_app_spec.js b/spec/frontend/observability/observability_app_spec.js deleted file mode 100644 index 392992a5962..00000000000 --- a/spec/frontend/observability/observability_app_spec.js +++ /dev/null @@ -1,201 +0,0 @@ -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import { stubComponent } from 'helpers/stub_component'; -import ObservabilityApp from '~/observability/components/observability_app.vue'; -import ObservabilitySkeleton from '~/observability/components/skeleton/index.vue'; -import { - MESSAGE_EVENT_TYPE, - INLINE_EMBED_DIMENSIONS, - FULL_APP_DIMENSIONS, - SKELETON_VARIANT_EMBED, -} from '~/observability/constants'; - -import { darkModeEnabled } from '~/lib/utils/color_utils'; - -jest.mock('~/lib/utils/color_utils'); - -describe('ObservabilityApp', () => { - let wrapper; - - const $route = { - pathname: 'https://gitlab.com/gitlab-org/', - path: 'https://gitlab.com/gitlab-org/-/observability/dashboards', - query: { otherQuery: 100 }, - }; - - const mockSkeletonOnContentLoaded = jest.fn(); - - const findIframe = () => wrapper.findByTestId('observability-ui-iframe'); - - const TEST_IFRAME_SRC = 'https://observe.gitlab.com/9970/?groupId=14485840'; - - const TEST_USERNAME = 'test-user'; - - const mountComponent = (props) => { - wrapper = shallowMountExtended(ObservabilityApp, { - propsData: { - observabilityIframeSrc: TEST_IFRAME_SRC, - ...props, - }, - stubs: { - ObservabilitySkeleton: stubComponent(ObservabilitySkeleton, { - methods: { onContentLoaded: mockSkeletonOnContentLoaded }, - }), - }, - mocks: { - $route, - }, - }); - }; - - const dispatchMessageEvent = (message) => - window.dispatchEvent(new MessageEvent('message', message)); - - beforeEach(() => { - gon.current_username = TEST_USERNAME; - }); - - describe('iframe src', () => { - it('should render an iframe with observabilityIframeSrc, decorated with light theme and username', () => { - darkModeEnabled.mockReturnValueOnce(false); - mountComponent(); - const iframe = findIframe(); - - expect(iframe.exists()).toBe(true); - expect(iframe.attributes('src')).toBe( - `${TEST_IFRAME_SRC}&theme=light&username=${TEST_USERNAME}`, - ); - }); - - it('should render an iframe with observabilityIframeSrc decorated with dark theme and username', () => { - darkModeEnabled.mockReturnValueOnce(true); - mountComponent(); - const iframe = findIframe(); - - expect(iframe.exists()).toBe(true); - expect(iframe.attributes('src')).toBe( - `${TEST_IFRAME_SRC}&theme=dark&username=${TEST_USERNAME}`, - ); - }); - }); - - describe('iframe sandbox', () => { - it('should render an iframe with sandbox attributes', () => { - mountComponent(); - const iframe = findIframe(); - - expect(iframe.exists()).toBe(true); - expect(iframe.attributes('sandbox')).toBe('allow-same-origin allow-forms allow-scripts'); - }); - }); - - describe('iframe kiosk query param', () => { - it('when inlineEmbed, it should set the proper kiosk query parameter', () => { - mountComponent({ - inlineEmbed: true, - }); - - const iframe = findIframe(); - - expect(iframe.attributes('src')).toBe( - `${TEST_IFRAME_SRC}&theme=light&username=${TEST_USERNAME}&kiosk=inline-embed`, - ); - }); - }); - - describe('iframe size', () => { - it('should set the specified size', () => { - mountComponent({ - height: INLINE_EMBED_DIMENSIONS.HEIGHT, - width: INLINE_EMBED_DIMENSIONS.WIDTH, - }); - - const iframe = findIframe(); - - expect(iframe.attributes('width')).toBe(INLINE_EMBED_DIMENSIONS.WIDTH); - expect(iframe.attributes('height')).toBe(INLINE_EMBED_DIMENSIONS.HEIGHT); - }); - - it('should fallback to default size', () => { - mountComponent({}); - - const iframe = findIframe(); - - expect(iframe.attributes('width')).toBe(FULL_APP_DIMENSIONS.WIDTH); - expect(iframe.attributes('height')).toBe(FULL_APP_DIMENSIONS.HEIGHT); - }); - }); - - describe('skeleton variant', () => { - it('sets the specified skeleton variant', () => { - mountComponent({ skeletonVariant: SKELETON_VARIANT_EMBED }); - const props = wrapper.findComponent(ObservabilitySkeleton).props(); - - expect(props.variant).toBe(SKELETON_VARIANT_EMBED); - }); - - it('should have a default skeleton variant', () => { - mountComponent(); - const props = wrapper.findComponent(ObservabilitySkeleton).props(); - - expect(props.variant).toBe('dashboards'); - }); - }); - - describe('on GOUI_ROUTE_UPDATE', () => { - it('should emit a route-update event', () => { - mountComponent(); - - const payload = { url: '/explore' }; - dispatchMessageEvent({ - data: { type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, payload }, - origin: 'https://observe.gitlab.com', - }); - - expect(wrapper.emitted('route-update')[0]).toEqual([payload]); - }); - }); - - describe('on GOUI_LOADED', () => { - beforeEach(() => { - mountComponent(); - }); - - it('should call onContentLoaded method', () => { - dispatchMessageEvent({ - data: { type: MESSAGE_EVENT_TYPE.GOUI_LOADED }, - origin: 'https://observe.gitlab.com', - }); - expect(mockSkeletonOnContentLoaded).toHaveBeenCalled(); - }); - - it('should not call onContentLoaded method if origin is different', () => { - dispatchMessageEvent({ - data: { type: MESSAGE_EVENT_TYPE.GOUI_LOADED }, - origin: 'https://example.com', - }); - expect(mockSkeletonOnContentLoaded).not.toHaveBeenCalled(); - }); - - it('should not call onContentLoaded method if event type is different', () => { - dispatchMessageEvent({ - data: { type: 'UNKNOWN_EVENT' }, - origin: 'https://observe.gitlab.com', - }); - expect(mockSkeletonOnContentLoaded).not.toHaveBeenCalled(); - }); - }); - - describe('on unmount', () => { - it('should not emit any even on route update', () => { - mountComponent(); - wrapper.destroy(); - - dispatchMessageEvent({ - data: { type: MESSAGE_EVENT_TYPE.GOUI_ROUTE_UPDATE, payload: { url: '/explore' } }, - origin: 'https://observe.gitlab.com', - }); - - expect(wrapper.emitted('route-update')).toBeUndefined(); - }); - }); -}); diff --git a/spec/frontend/observability/observability_container_spec.js b/spec/frontend/observability/observability_container_spec.js index 1152df072d4..5d838756308 100644 --- a/spec/frontend/observability/observability_container_spec.js +++ b/spec/frontend/observability/observability_container_spec.js @@ -16,6 +16,8 @@ describe('ObservabilityContainer', () => { const OAUTH_URL = 'https://example.com/oauth'; const TRACING_URL = 'https://example.com/tracing'; const PROVISIONING_URL = 'https://example.com/provisioning'; + const SERVICES_URL = 'https://example.com/services'; + const OPERATIONS_URL = 'https://example.com/operations'; beforeEach(() => { jest.spyOn(console, 'error').mockImplementation(); @@ -27,6 +29,8 @@ describe('ObservabilityContainer', () => { oauthUrl: OAUTH_URL, tracingUrl: TRACING_URL, provisioningUrl: PROVISIONING_URL, + servicesUrl: SERVICES_URL, + operationsUrl: OPERATIONS_URL, }, stubs: { ObservabilitySkeleton: stubComponent(ObservabilitySkeleton, { @@ -93,6 +97,8 @@ describe('ObservabilityContainer', () => { expect(buildClient).toHaveBeenCalledWith({ provisioningUrl: PROVISIONING_URL, tracingUrl: TRACING_URL, + servicesUrl: SERVICES_URL, + operationsUrl: OPERATIONS_URL, }); expect(findIframe().exists()).toBe(false); }); diff --git a/spec/frontend/observability/skeleton_spec.js b/spec/frontend/observability/skeleton_spec.js index 979070cfb12..5501fa117e0 100644 --- a/spec/frontend/observability/skeleton_spec.js +++ b/spec/frontend/observability/skeleton_spec.js @@ -3,32 +3,16 @@ import { GlSkeletonLoader, GlAlert, GlLoadingIcon } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import Skeleton from '~/observability/components/skeleton/index.vue'; -import DashboardsSkeleton from '~/observability/components/skeleton/dashboards.vue'; -import ExploreSkeleton from '~/observability/components/skeleton/explore.vue'; -import ManageSkeleton from '~/observability/components/skeleton/manage.vue'; -import EmbedSkeleton from '~/observability/components/skeleton/embed.vue'; -import { - SKELETON_VARIANTS_BY_ROUTE, - DEFAULT_TIMERS, - SKELETON_VARIANT_EMBED, -} from '~/observability/constants'; +import { DEFAULT_TIMERS } from '~/observability/constants'; describe('Skeleton component', () => { let wrapper; - const SKELETON_VARIANTS = [...Object.values(SKELETON_VARIANTS_BY_ROUTE), 'spinner']; + const findSpinner = () => wrapper.findComponent(GlLoadingIcon); const findContentWrapper = () => wrapper.findByTestId('content-wrapper'); - const findExploreSkeleton = () => wrapper.findComponent(ExploreSkeleton); - - const findDashboardsSkeleton = () => wrapper.findComponent(DashboardsSkeleton); - - const findManageSkeleton = () => wrapper.findComponent(ManageSkeleton); - - const findEmbedSkeleton = () => wrapper.findComponent(EmbedSkeleton); - const findAlert = () => wrapper.findComponent(GlAlert); const mountComponent = ({ ...props } = {}) => { @@ -39,39 +23,39 @@ describe('Skeleton component', () => { describe('on mount', () => { beforeEach(() => { - mountComponent({ variant: 'explore' }); + mountComponent({ variant: 'spinner' }); }); describe('showing content', () => { it('shows the skeleton if content is not loaded within CONTENT_WAIT_MS', async () => { - expect(findExploreSkeleton().exists()).toBe(false); - expect(findContentWrapper().isVisible()).toBe(false); + expect(findSpinner().exists()).toBe(false); + expect(findContentWrapper().exists()).toBe(false); jest.advanceTimersByTime(DEFAULT_TIMERS.CONTENT_WAIT_MS); await nextTick(); - expect(findExploreSkeleton().exists()).toBe(true); - expect(findContentWrapper().isVisible()).toBe(false); + expect(findSpinner().exists()).toBe(true); + expect(findContentWrapper().exists()).toBe(false); }); it('does not show the skeleton if content loads within CONTENT_WAIT_MS', async () => { - expect(findExploreSkeleton().exists()).toBe(false); - expect(findContentWrapper().isVisible()).toBe(false); + expect(findSpinner().exists()).toBe(false); + expect(findContentWrapper().exists()).toBe(false); wrapper.vm.onContentLoaded(); await nextTick(); - expect(findContentWrapper().isVisible()).toBe(true); - expect(findExploreSkeleton().exists()).toBe(false); + expect(findContentWrapper().exists()).toBe(true); + expect(findSpinner().exists()).toBe(false); jest.advanceTimersByTime(DEFAULT_TIMERS.CONTENT_WAIT_MS); await nextTick(); - expect(findContentWrapper().isVisible()).toBe(true); - expect(findExploreSkeleton().exists()).toBe(false); + expect(findContentWrapper().exists()).toBe(true); + expect(findSpinner().exists()).toBe(false); }); it('hides the skeleton after content loads', async () => { @@ -79,15 +63,15 @@ describe('Skeleton component', () => { await nextTick(); - expect(findExploreSkeleton().exists()).toBe(true); - expect(findContentWrapper().isVisible()).toBe(false); + expect(findSpinner().exists()).toBe(true); + expect(findContentWrapper().exists()).toBe(false); wrapper.vm.onContentLoaded(); await nextTick(); - expect(findContentWrapper().isVisible()).toBe(true); - expect(findExploreSkeleton().exists()).toBe(false); + expect(findContentWrapper().exists()).toBe(true); + expect(findSpinner().exists()).toBe(false); }); }); @@ -99,7 +83,7 @@ describe('Skeleton component', () => { await nextTick(); expect(findAlert().exists()).toBe(true); - expect(findContentWrapper().isVisible()).toBe(false); + expect(findContentWrapper().exists()).toBe(false); }); it('shows the error dialog if content fails to load', async () => { @@ -110,7 +94,7 @@ describe('Skeleton component', () => { await nextTick(); expect(findAlert().exists()).toBe(true); - expect(findContentWrapper().isVisible()).toBe(false); + expect(findContentWrapper().exists()).toBe(false); }); it('does not show the error dialog if content has loaded within TIMEOUT_MS', async () => { @@ -120,36 +104,28 @@ describe('Skeleton component', () => { await nextTick(); expect(findAlert().exists()).toBe(false); - expect(findContentWrapper().isVisible()).toBe(true); + expect(findContentWrapper().exists()).toBe(true); }); }); }); describe('skeleton variant', () => { - it.each` - skeletonType | condition | variant - ${'dashboards'} | ${'variant is dashboards'} | ${SKELETON_VARIANTS[0]} - ${'explore'} | ${'variant is explore'} | ${SKELETON_VARIANTS[1]} - ${'manage'} | ${'variant is manage'} | ${SKELETON_VARIANTS[2]} - ${'embed'} | ${'variant is embed'} | ${SKELETON_VARIANT_EMBED} - ${'spinner'} | ${'variant is spinner'} | ${'spinner'} - ${'default'} | ${'variant is not manage, dashboards or explore'} | ${'unknown'} - `('should render $skeletonType skeleton if $condition', async ({ skeletonType, variant }) => { - mountComponent({ variant }); + it('shows only the spinner variant when variant is spinner', async () => { + mountComponent({ variant: 'spinner' }); jest.advanceTimersByTime(DEFAULT_TIMERS.CONTENT_WAIT_MS); await nextTick(); - const showsDefaultSkeleton = ![...SKELETON_VARIANTS, SKELETON_VARIANT_EMBED].includes( - variant, - ); - expect(findDashboardsSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[0]); - expect(findExploreSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[1]); - expect(findManageSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANTS[2]); - expect(findEmbedSkeleton().exists()).toBe(skeletonType === SKELETON_VARIANT_EMBED); + expect(findSpinner().exists()).toBe(true); + expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(false); + }); - expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(showsDefaultSkeleton); + it('shows only the default variant when variant is not spinner', async () => { + mountComponent({ variant: 'unknown' }); + jest.advanceTimersByTime(DEFAULT_TIMERS.CONTENT_WAIT_MS); + await nextTick(); - expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(variant === 'spinner'); + expect(findSpinner().exists()).toBe(false); + expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(true); }); }); |