diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-31 21:09:40 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-08-31 21:09:40 +0300 |
commit | e33402e375d7c05441d1ba6ac5030efb8a9c9537 (patch) | |
tree | 7367bd7ddcedea4d2f08294b6e6a80261fe75062 /spec/frontend | |
parent | 532c924885ebec865e0c87f484eadaf2828910e2 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
9 files changed, 185 insertions, 68 deletions
diff --git a/spec/frontend/blob/line_highlighter_spec.js b/spec/frontend/blob/line_highlighter_spec.js index de39a8f688a..c7a86d6230a 100644 --- a/spec/frontend/blob/line_highlighter_spec.js +++ b/spec/frontend/blob/line_highlighter_spec.js @@ -72,6 +72,15 @@ describe('LineHighlighter', () => { expect(utils.scrollToElement).toHaveBeenCalledWith('#L5', expect.anything()); }); + it('does not scroll to the first highlighted line when disableScroll is `true`', () => { + jest.spyOn(utils, 'scrollToElement'); + const highlighter = new LineHighlighter(); + const scrollEnabled = false; + highlighter.highlightHash('#L5-25', scrollEnabled); + + expect(utils.scrollToElement).not.toHaveBeenCalled(); + }); + it('discards click events', () => { const clickSpy = jest.fn(); diff --git a/spec/frontend/tracking/internal_events_spec.js b/spec/frontend/tracking/internal_events_spec.js index ca244c25b06..264dee37e43 100644 --- a/spec/frontend/tracking/internal_events_spec.js +++ b/spec/frontend/tracking/internal_events_spec.js @@ -6,6 +6,7 @@ import { GITLAB_INTERNAL_EVENT_CATEGORY, SERVICE_PING_SCHEMA, LOAD_INTERNAL_EVENTS_SELECTOR, + USER_CONTEXT_SCHEMA, } from '~/tracking/constants'; import * as utils from '~/tracking/utils'; import { Tracker } from '~/tracking/tracker'; @@ -145,4 +146,88 @@ describe('InternalEvents', () => { }); }); }); + + describe('initBrowserSDK', () => { + beforeEach(() => { + window.glClient = { + setDocumentTitle: jest.fn(), + page: jest.fn(), + }; + window.gl = { + environment: 'testing', + key: 'value', + }; + window.gl.snowplowStandardContext = { + schema: 'iglu:com.gitlab/gitlab_standard', + data: { + environment: 'testing', + key: 'value', + google_analytics_id: '', + source: 'gitlab-javascript', + extra: {}, + }, + }; + }); + + it('should not call setDocumentTitle or page methods when window.glClient is undefined', () => { + window.glClient = undefined; + + InternalEvents.initBrowserSDK(); + + expect(window.glClient?.setDocumentTitle).toBeUndefined(); + expect(window.glClient?.page).toBeUndefined(); + }); + + it('should call setDocumentTitle and page methods on window.glClient when it is defined', () => { + const mockStandardContext = window.gl.snowplowStandardContext; + const userContext = { + schema: USER_CONTEXT_SCHEMA, + data: mockStandardContext?.data, + }; + + InternalEvents.initBrowserSDK(); + + expect(window.glClient.setDocumentTitle).toHaveBeenCalledWith('GitLab'); + expect(window.glClient.page).toHaveBeenCalledWith({ + title: 'GitLab', + context: [userContext], + }); + }); + + it('should call page method with combined standard and experiment contexts', () => { + const mockStandardContext = window.gl.snowplowStandardContext; + const userContext = { + schema: USER_CONTEXT_SCHEMA, + data: mockStandardContext?.data, + }; + + InternalEvents.initBrowserSDK(); + + expect(window.glClient.page).toHaveBeenCalledWith({ + title: 'GitLab', + context: [userContext], + }); + }); + + it('should call setDocumentTitle and page methods with default data when window.gl is undefined', () => { + window.gl = undefined; + + InternalEvents.initBrowserSDK(); + + expect(window.glClient.setDocumentTitle).toHaveBeenCalledWith('GitLab'); + expect(window.glClient.page).toHaveBeenCalledWith({ + title: 'GitLab', + context: [ + { + schema: USER_CONTEXT_SCHEMA, + data: { + google_analytics_id: '', + source: 'gitlab-javascript', + extra: {}, + }, + }, + ], + }); + }); + }); }); diff --git a/spec/frontend/tracking/tracking_initialization_spec.js b/spec/frontend/tracking/tracking_initialization_spec.js index 3c512cf73a7..2dc3c6ab41c 100644 --- a/spec/frontend/tracking/tracking_initialization_spec.js +++ b/spec/frontend/tracking/tracking_initialization_spec.js @@ -1,6 +1,6 @@ import { TRACKING_CONTEXT_SCHEMA } from '~/experimentation/constants'; import { getExperimentData, getAllExperimentContexts } from '~/experimentation/utils'; -import Tracking, { initUserTracking, initDefaultTrackers } from '~/tracking'; +import Tracking, { initUserTracking, initDefaultTrackers, InternalEvents } from '~/tracking'; import getStandardContext from '~/tracking/get_standard_context'; jest.mock('~/experimentation/utils', () => ({ @@ -15,6 +15,9 @@ describe('Tracking', () => { let trackLoadEventsSpy; let enableFormTracking; let setAnonymousUrlsSpy; + let bindInternalEventDocumentSpy; + let trackInternalLoadEventsSpy; + let initBrowserSDKSpy; beforeAll(() => { window.gl = window.gl || {}; @@ -74,6 +77,15 @@ describe('Tracking', () => { .spyOn(Tracking, 'enableFormTracking') .mockImplementation(() => null); setAnonymousUrlsSpy = jest.spyOn(Tracking, 'setAnonymousUrls').mockImplementation(() => null); + bindInternalEventDocumentSpy = jest + .spyOn(InternalEvents, 'bindInternalEventDocument') + .mockImplementation(() => null); + trackInternalLoadEventsSpy = jest + .spyOn(InternalEvents, 'trackInternalLoadEvents') + .mockImplementation(() => null); + initBrowserSDKSpy = jest + .spyOn(InternalEvents, 'initBrowserSDK') + .mockImplementation(() => null); }); it('should activate features based on what has been enabled', () => { @@ -117,6 +129,21 @@ describe('Tracking', () => { expect(setAnonymousUrlsSpy).toHaveBeenCalled(); }); + it('binds the document event handling for intenral events', () => { + initDefaultTrackers(); + expect(bindInternalEventDocumentSpy).toHaveBeenCalled(); + }); + + it('tracks page loaded events for internal events', () => { + initDefaultTrackers(); + expect(trackInternalLoadEventsSpy).toHaveBeenCalled(); + }); + + it('calls initBrowserSDKSpy', () => { + initDefaultTrackers(); + expect(initBrowserSDKSpy).toHaveBeenCalled(); + }); + describe('when there are experiment contexts', () => { const experimentContexts = [ { diff --git a/spec/frontend/vue_merge_request_widget/deployment/deployment_actions_spec.js b/spec/frontend/vue_merge_request_widget/deployment/deployment_actions_spec.js index b901b80e8bf..6f5e08a0829 100644 --- a/spec/frontend/vue_merge_request_widget/deployment/deployment_actions_spec.js +++ b/spec/frontend/vue_merge_request_widget/deployment/deployment_actions_spec.js @@ -2,7 +2,6 @@ import { mount } from '@vue/test-utils'; import waitForPromises from 'helpers/wait_for_promises'; import { createAlert } from '~/alert'; import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal'; -import { visitUrl } from '~/lib/utils/url_utility'; import { CREATED, MANUAL_DEPLOY, @@ -20,6 +19,7 @@ import { deploymentMockData, playDetails, retryDetails, + mockRedeployProps, } from './deployment_mock_data'; jest.mock('~/alert'); @@ -36,7 +36,6 @@ describe('DeploymentAction component', () => { const findStopButton = () => wrapper.find('.js-stop-env'); const findDeployButton = () => wrapper.find('.js-manual-deploy-action'); - const findManualRedeployButton = () => wrapper.find('.js-manual-redeploy-action'); const findRedeployButton = () => wrapper.find('.js-redeploy-action'); beforeEach(() => { @@ -78,23 +77,25 @@ describe('DeploymentAction component', () => { expect(findDeployButton().exists()).toBe(false); }); }); - - describe('when there is no retry_path in details', () => { - it('the manual redeploy button does not appear', () => { - expect(findManualRedeployButton().exists()).toBe(false); - }); - }); }); describe('when conditions are met', () => { describe.each` - configConst | computedDeploymentStatus | displayConditionChanges | finderFn | endpoint - ${STOPPING} | ${CREATED} | ${{}} | ${findStopButton} | ${deploymentMockData.stop_url} - ${DEPLOYING} | ${MANUAL_DEPLOY} | ${playDetails} | ${findDeployButton} | ${playDetails.playable_build.play_path} - ${REDEPLOYING} | ${FAILED} | ${retryDetails} | ${findManualRedeployButton} | ${retryDetails.playable_build.retry_path} + configConst | computedDeploymentStatus | displayConditionChanges | finderFn | endpoint | props + ${STOPPING} | ${CREATED} | ${{}} | ${findStopButton} | ${deploymentMockData.stop_url} | ${{}} + ${DEPLOYING} | ${MANUAL_DEPLOY} | ${playDetails} | ${findDeployButton} | ${playDetails.playable_build.play_path} | ${{}} + ${REDEPLOYING} | ${FAILED} | ${{}} | ${findRedeployButton} | ${retryDetails.playable_build.retry_path} | ${mockRedeployProps} + ${REDEPLOYING} | ${SUCCESS} | ${{}} | ${findRedeployButton} | ${retryDetails.playable_build.retry_path} | ${mockRedeployProps} `( '$configConst action', - ({ configConst, computedDeploymentStatus, displayConditionChanges, finderFn, endpoint }) => { + ({ + configConst, + computedDeploymentStatus, + displayConditionChanges, + finderFn, + endpoint, + props, + }) => { describe(`${configConst} action`, () => { beforeEach(() => { factory({ @@ -103,6 +104,7 @@ describe('DeploymentAction component', () => { deployment: { ...deploymentMockData, details: displayConditionChanges, + ...props, }, }, }); @@ -163,25 +165,6 @@ describe('DeploymentAction component', () => { expect(createAlert).not.toHaveBeenCalled(); }); - describe('response includes redirect_url', () => { - const url = '/root/example'; - beforeEach(async () => { - executeActionSpy.mockResolvedValueOnce({ - data: { redirect_url: url }, - }); - - await waitForPromises(); - - confirmAction.mockResolvedValueOnce(true); - finderFn().trigger('click'); - }); - - it('calls visit url with the redirect_url', () => { - expect(visitUrl).toHaveBeenCalled(); - expect(visitUrl).toHaveBeenCalledWith(url); - }); - }); - describe('it should call the executeAction method', () => { beforeEach(async () => { jest.spyOn(wrapper.vm, 'executeAction').mockImplementation(); @@ -234,7 +217,7 @@ describe('DeploymentAction component', () => { ); }); - describe('with the reviewAppsRedeployMrWidget feature flag turned on', () => { + describe('redeploy action', () => { beforeEach(() => { factory({ propsData: { @@ -246,11 +229,6 @@ describe('DeploymentAction component', () => { environment_available: false, }, }, - provide: { - glFeatures: { - reviewAppsRedeployMrWidget: true, - }, - }, }); }); @@ -304,24 +282,6 @@ describe('DeploymentAction component', () => { expect(createAlert).not.toHaveBeenCalled(); }); - describe('response includes redirect_url', () => { - const url = '/root/example'; - beforeEach(async () => { - executeActionSpy.mockResolvedValueOnce({ - data: { redirect_url: url }, - }); - - await waitForPromises(); - - confirmAction.mockResolvedValueOnce(true); - findRedeployButton().trigger('click'); - }); - - it('does not call visit url', () => { - expect(visitUrl).not.toHaveBeenCalled(); - }); - }); - describe('it should call the executeAction method', () => { beforeEach(async () => { jest.spyOn(wrapper.vm, 'executeAction').mockImplementation(); diff --git a/spec/frontend/vue_merge_request_widget/deployment/deployment_mock_data.js b/spec/frontend/vue_merge_request_widget/deployment/deployment_mock_data.js index 374fe4e1b95..2c6a40c6e16 100644 --- a/spec/frontend/vue_merge_request_widget/deployment/deployment_mock_data.js +++ b/spec/frontend/vue_merge_request_widget/deployment/deployment_mock_data.js @@ -74,4 +74,9 @@ const retryDetails = { }, }; -export { actionButtonMocks, deploymentMockData, playDetails, retryDetails }; +const mockRedeployProps = { + retry_url: retryDetails.playable_build.retry_path, + environment_available: false, +}; + +export { actionButtonMocks, deploymentMockData, playDetails, retryDetails, mockRedeployProps }; diff --git a/spec/frontend/vue_merge_request_widget/deployment/deployment_spec.js b/spec/frontend/vue_merge_request_widget/deployment/deployment_spec.js index 234491c531a..0a96feb184f 100644 --- a/spec/frontend/vue_merge_request_widget/deployment/deployment_spec.js +++ b/spec/frontend/vue_merge_request_widget/deployment/deployment_spec.js @@ -10,7 +10,12 @@ import { import DeploymentComponent from '~/vue_merge_request_widget/components/deployment/deployment.vue'; import DeploymentInfo from '~/vue_merge_request_widget/components/deployment/deployment_info.vue'; import DeploymentViewButton from '~/vue_merge_request_widget/components/deployment/deployment_view_button.vue'; -import { deploymentMockData, playDetails, retryDetails } from './deployment_mock_data'; +import { + deploymentMockData, + playDetails, + retryDetails, + mockRedeployProps, +} from './deployment_mock_data'; describe('Deployment component', () => { let wrapper; @@ -46,7 +51,6 @@ describe('Deployment component', () => { }; const defaultGroup = ['.js-deploy-url', '.js-stop-env']; const manualDeployGroup = ['.js-manual-deploy-action', ...defaultGroup]; - const manualRedeployGroup = ['.js-manual-redeploy-action', ...defaultGroup]; describe.each` status | previous | deploymentDetails | text | actionButtons @@ -62,7 +66,7 @@ describe('Deployment component', () => { ${SUCCESS} | ${true} | ${noDetails} | ${'Deployed to'} | ${defaultGroup} ${SUCCESS} | ${false} | ${deployDetail} | ${'Deployed to'} | ${defaultGroup} ${SUCCESS} | ${false} | ${noDetails} | ${'Deployed to'} | ${defaultGroup} - ${FAILED} | ${true} | ${retryDetail} | ${'Failed to deploy to'} | ${manualRedeployGroup} + ${FAILED} | ${true} | ${retryDetail} | ${'Failed to deploy to'} | ${defaultGroup} ${FAILED} | ${true} | ${noDetails} | ${'Failed to deploy to'} | ${defaultGroup} ${FAILED} | ${false} | ${retryDetail} | ${'Failed to deploy to'} | ${noActions} ${FAILED} | ${false} | ${noDetails} | ${'Failed to deploy to'} | ${noActions} @@ -139,6 +143,27 @@ describe('Deployment component', () => { } }, ); + + describe('redeploy action', () => { + beforeEach(() => { + factory({ + propsData: { + showMetrics: false, + deployment: { + ...deploymentMockData, + ...mockRedeployProps, + }, + }, + }); + }); + + it('shows only the redeploy button', () => { + expect(wrapper.find('.js-redeploy-action').exists()).toBe(true); + expect(wrapper.find('.js-deploy-url').exists()).toBe(false); + expect(wrapper.find('.js-stop-env').exists()).toBe(false); + expect(wrapper.find('.js-manual-deploy-action').exists()).toBe(false); + }); + }); }); describe('hasExternalUrls', () => { diff --git a/spec/frontend/vue_shared/components/source_viewer/components/chunk_new_spec.js b/spec/frontend/vue_shared/components/source_viewer/components/chunk_new_spec.js index 1154c930e5d..852598b13dc 100644 --- a/spec/frontend/vue_shared/components/source_viewer/components/chunk_new_spec.js +++ b/spec/frontend/vue_shared/components/source_viewer/components/chunk_new_spec.js @@ -35,6 +35,7 @@ describe('Chunk component', () => { await nextTick(); expect(findContent().exists()).toBe(true); + expect(wrapper.emitted('appear')).toHaveLength(1); }); }); diff --git a/spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js b/spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js index 431ede17954..1a498d0c5b1 100644 --- a/spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js +++ b/spec/frontend/vue_shared/components/source_viewer/source_viewer_new_spec.js @@ -58,7 +58,8 @@ describe('Source Viewer component', () => { describe('hash highlighting', () => { it('calls highlightHash with expected parameter', () => { - expect(lineHighlighter.highlightHash).toHaveBeenCalledWith(hash); + const scrollEnabled = false; + expect(lineHighlighter.highlightHash).toHaveBeenCalledWith(hash, scrollEnabled); }); }); }); diff --git a/spec/frontend/vue_shared/components/source_viewer/source_viewer_spec.js b/spec/frontend/vue_shared/components/source_viewer/source_viewer_spec.js index 7998b4c17a1..2043f36443d 100644 --- a/spec/frontend/vue_shared/components/source_viewer/source_viewer_spec.js +++ b/spec/frontend/vue_shared/components/source_viewer/source_viewer_spec.js @@ -1,6 +1,4 @@ import hljs from 'highlight.js/lib/core'; -import Vue from 'vue'; -import VueRouter from 'vue-router'; import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; @@ -25,11 +23,10 @@ import LineHighlighter from '~/blob/line_highlighter'; import eventHub from '~/notes/event_hub'; import Tracking from '~/tracking'; -jest.mock('~/blob/line_highlighter'); +const lineHighlighter = new LineHighlighter(); +jest.mock('~/blob/line_highlighter', () => jest.fn().mockReturnValue({ highlightHash: jest.fn() })); jest.mock('highlight.js/lib/core'); jest.mock('~/vue_shared/components/source_viewer/plugins/index'); -Vue.use(VueRouter); -const router = new VueRouter(); const mockAxios = new MockAdapter(axios); const generateContent = (content, totalLines = 1, delimiter = '\n') => { @@ -45,6 +42,7 @@ const execImmediately = (callback) => callback(); describe('Source Viewer component', () => { let wrapper; const language = 'docker'; + const selectedRangeHash = '#L1-2'; const mappedLanguage = ROUGE_TO_HLJS_LANGUAGE_MAP[language]; const chunk1 = generateContent('// Some source code 1', 70); const chunk2 = generateContent('// Some source code 2', 70); @@ -61,8 +59,8 @@ describe('Source Viewer component', () => { const createComponent = async (blob = {}) => { wrapper = shallowMountExtended(SourceViewer, { - router, propsData: { blob: { ...DEFAULT_BLOB_DATA, ...blob }, currentRef, projectPath }, + mocks: { $route: { hash: selectedRangeHash } }, }); await waitForPromises(); }; @@ -271,6 +269,12 @@ describe('Source Viewer component', () => { it('instantiates the lineHighlighter class', () => { expect(LineHighlighter).toHaveBeenCalledWith({ scrollBehavior: 'auto' }); }); + + it('highlights the range when chunk appears', () => { + findChunks().at(0).vm.$emit('appear'); + const scrollEnabled = false; + expect(lineHighlighter.highlightHash).toHaveBeenCalledWith(selectedRangeHash, scrollEnabled); + }); }); describe('Codeowners validation', () => { |