diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-02 18:08:48 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-02 18:08:48 +0000 |
commit | fa06c9a675d9c028905276e7d0a11aacc9f8f8ac (patch) | |
tree | e84c88aa04b4a94a144cd2d3b4d1a6fd632828b7 /spec/frontend | |
parent | 6f998d352988f93f875db862353e814e95db1fe3 (diff) | |
download | gitlab-ce-fa06c9a675d9c028905276e7d0a11aacc9f8f8ac.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
25 files changed, 218 insertions, 225 deletions
diff --git a/spec/frontend/authentication/two_factor_auth/index_spec.js b/spec/frontend/authentication/two_factor_auth/index_spec.js index f5345139021..0ff9d60f409 100644 --- a/spec/frontend/authentication/two_factor_auth/index_spec.js +++ b/spec/frontend/authentication/two_factor_auth/index_spec.js @@ -1,5 +1,6 @@ import { getByTestId, fireEvent } from '@testing-library/dom'; import { createWrapper } from '@vue/test-utils'; +import setWindowLocation from 'helpers/set_window_location_helper'; import { initRecoveryCodes, initClose2faSuccessMessage } from '~/authentication/two_factor_auth'; import RecoveryCodes from '~/authentication/two_factor_auth/components/recovery_codes.vue'; import * as urlUtils from '~/lib/utils/url_utility'; @@ -53,8 +54,7 @@ describe('initClose2faSuccessMessage', () => { describe('when alert is closed', () => { beforeEach(() => { - delete window.location; - window.location = new URL( + setWindowLocation( 'https://localhost/-/profile/account?two_factor_auth_enabled_successfully=true', ); diff --git a/spec/frontend/authentication/webauthn/error_spec.js b/spec/frontend/authentication/webauthn/error_spec.js index 26f1ca5e27d..9b71f77dde2 100644 --- a/spec/frontend/authentication/webauthn/error_spec.js +++ b/spec/frontend/authentication/webauthn/error_spec.js @@ -1,3 +1,4 @@ +import setWindowLocation from 'helpers/set_window_location_helper'; import WebAuthnError from '~/authentication/webauthn/error'; describe('WebAuthnError', () => { @@ -17,19 +18,8 @@ describe('WebAuthnError', () => { }); describe('SecurityError', () => { - const { location } = window; - - beforeEach(() => { - delete window.location; - window.location = {}; - }); - - afterEach(() => { - window.location = location; - }); - it('returns a descriptive error if https is disabled', () => { - window.location.protocol = 'http:'; + setWindowLocation('http://localhost'); const expectedMessage = 'WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details.'; @@ -39,7 +29,7 @@ describe('WebAuthnError', () => { }); it('returns a generic error if https is enabled', () => { - window.location.protocol = 'https:'; + setWindowLocation('https://localhost'); const expectedMessage = 'There was a problem communicating with your device.'; expect( diff --git a/spec/frontend/authentication/webauthn/register_spec.js b/spec/frontend/authentication/webauthn/register_spec.js index 43cd3d7ca34..0f8ea2b635f 100644 --- a/spec/frontend/authentication/webauthn/register_spec.js +++ b/spec/frontend/authentication/webauthn/register_spec.js @@ -1,4 +1,5 @@ import $ from 'jquery'; +import setWindowLocation from 'helpers/set_window_location_helper'; import waitForPromises from 'helpers/wait_for_promises'; import WebAuthnRegister from '~/authentication/webauthn/register'; import MockWebAuthnDevice from './mock_webauthn_device'; @@ -50,17 +51,14 @@ describe('WebAuthnRegister', () => { }); describe('when unsupported', () => { - const { location, PublicKeyCredential } = window; + const { PublicKeyCredential } = window; beforeEach(() => { - delete window.location; delete window.credentials; - window.location = {}; window.PublicKeyCredential = undefined; }); afterEach(() => { - window.location = location; window.PublicKeyCredential = PublicKeyCredential; }); @@ -69,7 +67,7 @@ describe('WebAuthnRegister', () => { ${false} | ${'WebAuthn only works with HTTPS-enabled websites'} ${true} | ${'Please use a supported browser, e.g. Chrome (67+) or Firefox'} `('when https is $httpsEnabled', ({ httpsEnabled, expectedText }) => { - window.location.protocol = httpsEnabled ? 'https:' : 'http:'; + setWindowLocation(`${httpsEnabled ? 'https:' : 'http:'}//localhost`); component.start(); expect(findMessage().text()).toContain(expectedText); diff --git a/spec/frontend/boards/board_card_inner_spec.js b/spec/frontend/boards/board_card_inner_spec.js index 87f9a68f5dd..555767dd549 100644 --- a/spec/frontend/boards/board_card_inner_spec.js +++ b/spec/frontend/boards/board_card_inner_spec.js @@ -1,6 +1,7 @@ import { GlLabel, GlLoadingIcon, GlTooltip } from '@gitlab/ui'; import { range } from 'lodash'; import Vuex from 'vuex'; +import setWindowLocation from 'helpers/set_window_location_helper'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import BoardBlockedIcon from '~/boards/components/board_blocked_icon.vue'; import BoardCardInner from '~/boards/components/board_card_inner.vue'; @@ -363,8 +364,6 @@ describe('Board card component', () => { describe('filterByLabel method', () => { beforeEach(() => { - delete window.location; - wrapper.setProps({ updateFilters: true, }); @@ -373,7 +372,7 @@ describe('Board card component', () => { describe('when selected label is not in the filter', () => { beforeEach(() => { jest.spyOn(wrapper.vm, 'performSearch').mockImplementation(() => {}); - window.location = { search: '' }; + setWindowLocation('?'); wrapper.vm.filterByLabel(label1); }); @@ -394,7 +393,7 @@ describe('Board card component', () => { describe('when selected label is already in the filter', () => { beforeEach(() => { jest.spyOn(wrapper.vm, 'performSearch').mockImplementation(() => {}); - window.location = { search: '?label_name[]=testing%20123' }; + setWindowLocation('?label_name[]=testing%20123'); wrapper.vm.filterByLabel(label1); }); diff --git a/spec/frontend/boards/components/board_form_spec.js b/spec/frontend/boards/components/board_form_spec.js index 3966c3e6b87..52f1907654a 100644 --- a/spec/frontend/boards/components/board_form_spec.js +++ b/spec/frontend/boards/components/board_form_spec.js @@ -1,5 +1,6 @@ import { GlModal } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; +import setWindowLocation from 'helpers/set_window_location_helper'; import { TEST_HOST } from 'helpers/test_constants'; import waitForPromises from 'helpers/wait_for_promises'; @@ -75,10 +76,6 @@ describe('BoardForm', () => { }); }; - beforeEach(() => { - delete window.location; - }); - afterEach(() => { wrapper.destroy(); wrapper = null; @@ -244,7 +241,7 @@ describe('BoardForm', () => { updateBoard: { board: { id: 'gid://gitlab/Board/321', webPath: 'test-path' } }, }, }); - window.location = new URL('https://test/boards/1'); + setWindowLocation('https://test/boards/1'); createComponent({ canAdminBoard: true, currentPage: formType.edit }); findInput().trigger('keyup.enter', { metaKey: true }); @@ -270,7 +267,7 @@ describe('BoardForm', () => { updateBoard: { board: { id: 'gid://gitlab/Board/321', webPath: 'test-path' } }, }, }); - window.location = new URL('https://test/boards/1?group_by=epic'); + setWindowLocation('https://test/boards/1?group_by=epic'); createComponent({ canAdminBoard: true, currentPage: formType.edit }); findInput().trigger('keyup.enter', { metaKey: true }); diff --git a/spec/frontend/clusters/clusters_bundle_spec.js b/spec/frontend/clusters/clusters_bundle_spec.js index 42990334f0a..2a0610b1b0a 100644 --- a/spec/frontend/clusters/clusters_bundle_spec.js +++ b/spec/frontend/clusters/clusters_bundle_spec.js @@ -1,5 +1,6 @@ import MockAdapter from 'axios-mock-adapter'; import { loadHTMLFixture } from 'helpers/fixtures'; +import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; import { setTestTimeout } from 'helpers/timeout'; import Clusters from '~/clusters/clusters_bundle'; import axios from '~/lib/utils/axios_utils'; @@ -8,6 +9,8 @@ import initProjectSelectDropdown from '~/project_select'; jest.mock('~/lib/utils/poll'); jest.mock('~/project_select'); +useMockLocationHelper(); + describe('Clusters', () => { setTestTimeout(1000); @@ -55,20 +58,6 @@ describe('Clusters', () => { }); describe('updateContainer', () => { - const { location } = window; - - beforeEach(() => { - delete window.location; - window.location = { - reload: jest.fn(), - hash: location.hash, - }; - }); - - afterEach(() => { - window.location = location; - }); - describe('when creating cluster', () => { it('should show the creating container', () => { cluster.updateContainer(null, 'creating'); diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js index b5eb3e1713c..bc06990e03a 100644 --- a/spec/frontend/diffs/components/app_spec.js +++ b/spec/frontend/diffs/components/app_spec.js @@ -4,6 +4,7 @@ import MockAdapter from 'axios-mock-adapter'; import Mousetrap from 'mousetrap'; import Vue, { nextTick } from 'vue'; import Vuex from 'vuex'; +import setWindowLocation from 'helpers/set_window_location_helper'; import { TEST_HOST } from 'spec/test_constants'; import App from '~/diffs/components/app.vue'; import CommitWidget from '~/diffs/components/commit_widget.vue'; @@ -428,12 +429,10 @@ describe('diffs/components/app', () => { jest.spyOn(wrapper.vm, 'refetchDiffData').mockImplementation(() => {}); jest.spyOn(wrapper.vm, 'adjustView').mockImplementation(() => {}); }; - let location; + const location = window.location.href; beforeAll(() => { - location = window.location; - delete window.location; - window.location = COMMIT_URL; + setWindowLocation(COMMIT_URL); document.title = 'My Title'; }); @@ -442,7 +441,7 @@ describe('diffs/components/app', () => { }); afterAll(() => { - window.location = location; + setWindowLocation(location); }); it('when the commit changes and the app is not loading it should update the history, refetch the diff data, and update the view', async () => { diff --git a/spec/frontend/diffs/components/compare_versions_spec.js b/spec/frontend/diffs/components/compare_versions_spec.js index 1697ea3e952..1c0cb1193fa 100644 --- a/spec/frontend/diffs/components/compare_versions_spec.js +++ b/spec/frontend/diffs/components/compare_versions_spec.js @@ -220,7 +220,7 @@ describe('CompareVersions', () => { describe('prev commit', () => { beforeAll(() => { - setWindowLocation(`${TEST_HOST}?commit_id=${mrCommit.id}`); + setWindowLocation(`?commit_id=${mrCommit.id}`); }); beforeEach(() => { @@ -255,7 +255,7 @@ describe('CompareVersions', () => { describe('next commit', () => { beforeAll(() => { - setWindowLocation(`${TEST_HOST}?commit_id=${mrCommit.id}`); + setWindowLocation(`?commit_id=${mrCommit.id}`); }); beforeEach(() => { diff --git a/spec/frontend/editor/source_editor_extension_base_spec.js b/spec/frontend/editor/source_editor_extension_base_spec.js index 352db9d0d51..2c06ae03892 100644 --- a/spec/frontend/editor/source_editor_extension_base_spec.js +++ b/spec/frontend/editor/source_editor_extension_base_spec.js @@ -1,5 +1,6 @@ import { Range } from 'monaco-editor'; import { useFakeRequestAnimationFrame } from 'helpers/fake_request_animation_frame'; +import setWindowLocation from 'helpers/set_window_location_helper'; import { ERROR_INSTANCE_REQUIRED_FOR_EXTENSION, EDITOR_TYPE_CODE, @@ -152,12 +153,7 @@ describe('The basis for an Source Editor extension', () => { useFakeRequestAnimationFrame(); beforeEach(() => { - delete window.location; - window.location = new URL(`https://localhost`); - }); - - afterEach(() => { - window.location.hash = ''; + setWindowLocation('https://localhost'); }); it.each` diff --git a/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js b/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js index a3b91cb20bb..3f47fa024bc 100644 --- a/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js +++ b/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js @@ -1,11 +1,23 @@ import { GlFilteredSearchToken } from '@gitlab/ui'; import { shallowMount, createLocalVue } from '@vue/test-utils'; import Vuex from 'vuex'; +import setWindowLocation from 'helpers/set_window_location_helper'; +import { redirectTo } from '~/lib/utils/url_utility'; import MembersFilteredSearchBar from '~/members/components/filter_sort/members_filtered_search_bar.vue'; import { MEMBER_TYPES } from '~/members/constants'; import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; +jest.mock('~/lib/utils/url_utility', () => { + const urlUtility = jest.requireActual('~/lib/utils/url_utility'); + + return { + __esModule: true, + ...urlUtility, + redirectTo: jest.fn(), + }; +}); + const localVue = createLocalVue(); localVue.use(Vuex); @@ -113,12 +125,11 @@ describe('MembersFilteredSearchBar', () => { describe('when filters are set via query params', () => { beforeEach(() => { - delete window.location; - window.location = new URL('https://localhost'); + setWindowLocation('https://localhost'); }); it('parses and passes tokens to `FilteredSearchBar` component as `initialFilterValue` prop', () => { - window.location.search = '?two_factor=enabled&token_not_available=foobar'; + setWindowLocation('?two_factor=enabled&token_not_available=foobar'); createComponent(); @@ -134,7 +145,7 @@ describe('MembersFilteredSearchBar', () => { }); it('parses and passes search param to `FilteredSearchBar` component as `initialFilterValue` prop', () => { - window.location.search = '?search=foobar'; + setWindowLocation('?search=foobar'); createComponent(); @@ -149,7 +160,7 @@ describe('MembersFilteredSearchBar', () => { }); it('parses and passes search param with multiple words to `FilteredSearchBar` component as `initialFilterValue` prop', () => { - window.location.search = '?search=foo+bar+baz'; + setWindowLocation('?search=foo+bar+baz'); createComponent(); @@ -166,8 +177,7 @@ describe('MembersFilteredSearchBar', () => { describe('when filter bar is submitted', () => { beforeEach(() => { - delete window.location; - window.location = new URL('https://localhost'); + setWindowLocation('https://localhost'); }); it('adds correct filter query params', () => { @@ -177,7 +187,7 @@ describe('MembersFilteredSearchBar', () => { { type: 'two_factor', value: { data: 'enabled', operator: '=' } }, ]); - expect(window.location.href).toBe('https://localhost/?two_factor=enabled'); + expect(redirectTo).toHaveBeenCalledWith('https://localhost/?two_factor=enabled'); }); it('adds search query param', () => { @@ -188,7 +198,9 @@ describe('MembersFilteredSearchBar', () => { { type: 'filtered-search-term', value: { data: 'foobar' } }, ]); - expect(window.location.href).toBe('https://localhost/?two_factor=enabled&search=foobar'); + expect(redirectTo).toHaveBeenCalledWith( + 'https://localhost/?two_factor=enabled&search=foobar', + ); }); it('adds search query param with multiple words', () => { @@ -199,11 +211,13 @@ describe('MembersFilteredSearchBar', () => { { type: 'filtered-search-term', value: { data: 'foo bar baz' } }, ]); - expect(window.location.href).toBe('https://localhost/?two_factor=enabled&search=foo+bar+baz'); + expect(redirectTo).toHaveBeenCalledWith( + 'https://localhost/?two_factor=enabled&search=foo+bar+baz', + ); }); it('adds sort query param', () => { - window.location.search = '?sort=name_asc'; + setWindowLocation('?sort=name_asc'); createComponent(); @@ -212,13 +226,13 @@ describe('MembersFilteredSearchBar', () => { { type: 'filtered-search-term', value: { data: 'foobar' } }, ]); - expect(window.location.href).toBe( + expect(redirectTo).toHaveBeenCalledWith( 'https://localhost/?two_factor=enabled&search=foobar&sort=name_asc', ); }); it('adds active tab query param', () => { - window.location.search = '?tab=invited'; + setWindowLocation('?tab=invited'); createComponent(); @@ -226,7 +240,7 @@ describe('MembersFilteredSearchBar', () => { { type: 'filtered-search-term', value: { data: 'foobar' } }, ]); - expect(window.location.href).toBe('https://localhost/?search=foobar&tab=invited'); + expect(redirectTo).toHaveBeenCalledWith('https://localhost/?search=foobar&tab=invited'); }); }); }); diff --git a/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js b/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js index 4b335755980..d0684acd487 100644 --- a/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js +++ b/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js @@ -1,6 +1,7 @@ import { GlSorting, GlSortingItem } from '@gitlab/ui'; import { mount, createLocalVue } from '@vue/test-utils'; import Vuex from 'vuex'; +import setWindowLocation from 'helpers/set_window_location_helper'; import * as urlUtilities from '~/lib/utils/url_utility'; import SortDropdown from '~/members/components/filter_sort/sort_dropdown.vue'; import { MEMBER_TYPES } from '~/members/constants'; @@ -52,17 +53,16 @@ describe('SortDropdown', () => { .findAll(GlSortingItem) .wrappers.find((dropdownItemWrapper) => dropdownItemWrapper.text() === text); - describe('dropdown options', () => { - beforeEach(() => { - delete window.location; - window.location = new URL(URL_HOST); - }); + beforeEach(() => { + setWindowLocation(URL_HOST); + }); + describe('dropdown options', () => { it('adds dropdown items for all the sortable fields', () => { const URL_FILTER_PARAMS = '?two_factor=enabled&search=foobar'; const EXPECTED_BASE_URL = `${URL_HOST}${URL_FILTER_PARAMS}&sort=`; - window.location.search = URL_FILTER_PARAMS; + setWindowLocation(URL_FILTER_PARAMS); const expectedDropdownItems = [ { @@ -94,7 +94,7 @@ describe('SortDropdown', () => { }); it('checks selected sort option', () => { - window.location.search = '?sort=access_level_asc'; + setWindowLocation('?sort=access_level_asc'); createComponent(); @@ -103,11 +103,6 @@ describe('SortDropdown', () => { }); describe('dropdown toggle', () => { - beforeEach(() => { - delete window.location; - window.location = new URL(URL_HOST); - }); - it('defaults to sorting by "Account" in ascending order', () => { createComponent(); @@ -116,7 +111,7 @@ describe('SortDropdown', () => { }); it('sets text as selected sort option', () => { - window.location.search = '?sort=access_level_asc'; + setWindowLocation('?sort=access_level_asc'); createComponent(); @@ -126,15 +121,12 @@ describe('SortDropdown', () => { describe('sort direction toggle', () => { beforeEach(() => { - delete window.location; - window.location = new URL(URL_HOST); - - jest.spyOn(urlUtilities, 'visitUrl'); + jest.spyOn(urlUtilities, 'visitUrl').mockImplementation(); }); describe('when current sort direction is ascending', () => { beforeEach(() => { - window.location.search = '?sort=access_level_asc'; + setWindowLocation('?sort=access_level_asc'); createComponent(); }); @@ -152,7 +144,7 @@ describe('SortDropdown', () => { describe('when current sort direction is descending', () => { beforeEach(() => { - window.location.search = '?sort=access_level_desc'; + setWindowLocation('?sort=access_level_desc'); createComponent(); }); diff --git a/spec/frontend/members/components/members_tabs_spec.js b/spec/frontend/members/components/members_tabs_spec.js index 33d8eebf7eb..68f25bcb619 100644 --- a/spec/frontend/members/components/members_tabs_spec.js +++ b/spec/frontend/members/components/members_tabs_spec.js @@ -1,6 +1,7 @@ import { GlTabs } from '@gitlab/ui'; import Vue, { nextTick } from 'vue'; import Vuex from 'vuex'; +import setWindowLocation from 'helpers/set_window_location_helper'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import MembersApp from '~/members/components/app.vue'; import MembersTabs from '~/members/components/members_tabs.vue'; @@ -90,8 +91,7 @@ describe('MembersTabs', () => { const findActiveTab = () => wrapper.findByRole('tab', { selected: true }); beforeEach(() => { - delete window.location; - window.location = new URL('https://localhost'); + setWindowLocation('https://localhost'); }); afterEach(() => { @@ -151,7 +151,7 @@ describe('MembersTabs', () => { describe('when url param matches `filteredSearchBar.searchParam`', () => { beforeEach(() => { - window.location.search = '?search_groups=foo+bar'; + setWindowLocation('?search_groups=foo+bar'); }); it('shows tab that corresponds to search param', async () => { diff --git a/spec/frontend/members/components/table/members_table_spec.js b/spec/frontend/members/components/table/members_table_spec.js index 6e7d9bc6b6e..6885da53b26 100644 --- a/spec/frontend/members/components/table/members_table_spec.js +++ b/spec/frontend/members/components/table/members_table_spec.js @@ -6,6 +6,7 @@ import { } from '@testing-library/dom'; import { mount, createLocalVue, createWrapper } from '@vue/test-utils'; import Vuex from 'vuex'; +import setWindowLocation from 'helpers/set_window_location_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import CreatedAt from '~/members/components/table/created_at.vue'; import ExpirationDatepicker from '~/members/components/table/expiration_datepicker.vue'; @@ -243,12 +244,8 @@ describe('MembersTable', () => { }); describe('when required pagination data is provided', () => { - beforeEach(() => { - delete window.location; - }); - it('renders `gl-pagination` component with correct props', () => { - window.location = new URL(url); + setWindowLocation(url); createComponent(); @@ -268,7 +265,7 @@ describe('MembersTable', () => { }); it('uses `pagination.paramName` to generate the pagination links', () => { - window.location = new URL(url); + setWindowLocation(url); createComponent({ pagination: { @@ -283,7 +280,7 @@ describe('MembersTable', () => { }); it('removes any url params defined as `null` in the `params` attribute', () => { - window.location = new URL(`${url}&search_groups=foo`); + setWindowLocation(`${url}&search_groups=foo`); createComponent({ pagination: { diff --git a/spec/frontend/members/utils_spec.js b/spec/frontend/members/utils_spec.js index 9740e1c2edb..a157cfa1c1d 100644 --- a/spec/frontend/members/utils_spec.js +++ b/spec/frontend/members/utils_spec.js @@ -1,3 +1,4 @@ +import setWindowLocation from 'helpers/set_window_location_helper'; import { DEFAULT_SORT, MEMBER_TYPES } from '~/members/constants'; import { generateBadges, @@ -150,21 +151,18 @@ describe('Members Utils', () => { describe('parseSortParam', () => { beforeEach(() => { - delete window.location; - window.location = new URL(URL_HOST); + setWindowLocation(URL_HOST); }); describe('when `sort` param is not present', () => { it('returns default sort options', () => { - window.location.search = ''; - expect(parseSortParam(['account'])).toEqual(DEFAULT_SORT); }); }); describe('when field passed in `sortableFields` argument does not have `sort` key defined', () => { it('returns default sort options', () => { - window.location.search = '?sort=source_asc'; + setWindowLocation('?sort=source_asc'); expect(parseSortParam(['source'])).toEqual(DEFAULT_SORT); }); @@ -182,7 +180,7 @@ describe('Members Utils', () => { ${'oldest_sign_in'} | ${{ sortByKey: 'lastSignIn', sortDesc: true }} `('when `sort` query string param is `$sortParam`', ({ sortParam, expected }) => { it(`returns ${JSON.stringify(expected)}`, async () => { - window.location.search = `?sort=${sortParam}`; + setWindowLocation(`?sort=${sortParam}`); expect(parseSortParam(['account', 'granted', 'expires', 'maxRole', 'lastSignIn'])).toEqual( expected, @@ -193,8 +191,7 @@ describe('Members Utils', () => { describe('buildSortHref', () => { beforeEach(() => { - delete window.location; - window.location = new URL(URL_HOST); + setWindowLocation(URL_HOST); }); describe('when field passed in `sortBy` argument does not have `sort` key defined', () => { @@ -225,7 +222,7 @@ describe('Members Utils', () => { describe('when filter params are set', () => { it('merges the `sort` param with the filter params', () => { - window.location.search = '?two_factor=enabled&with_inherited_permissions=exclude'; + setWindowLocation('?two_factor=enabled&with_inherited_permissions=exclude'); expect( buildSortHref({ @@ -240,7 +237,7 @@ describe('Members Utils', () => { describe('when search param is set', () => { it('merges the `sort` param with the search param', () => { - window.location.search = '?search=foobar'; + setWindowLocation('?search=foobar'); expect( buildSortHref({ diff --git a/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js b/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js index dbb9fd5f603..f2116c1f478 100644 --- a/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js +++ b/spec/frontend/monitoring/components/dashboard_actions_menu_spec.js @@ -301,9 +301,6 @@ describe('Actions menu', () => { }); it('redirects to the newly created dashboard', () => { - delete window.location; - window.location = new URL('https://localhost'); - const newDashboard = dashboardGitResponse[1]; const newDashboardUrl = 'root/sandbox/-/metrics/dashboard.yml'; diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/frontend/monitoring/components/dashboard_spec.js index 7ca1b97d849..f899580b3df 100644 --- a/spec/frontend/monitoring/components/dashboard_spec.js +++ b/spec/frontend/monitoring/components/dashboard_spec.js @@ -1,5 +1,6 @@ import MockAdapter from 'axios-mock-adapter'; import VueDraggable from 'vuedraggable'; +import setWindowLocation from 'helpers/set_window_location_helper'; import { TEST_HOST } from 'helpers/test_constants'; import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper'; import createFlash from '~/flash'; @@ -226,32 +227,25 @@ describe('Dashboard', () => { }); describe('when the URL contains a reference to a panel', () => { - let location; + const location = window.location.href; - const setSearch = (search) => { - window.location = { ...location, search }; + const setSearch = (searchParams) => { + setWindowLocation(`?${objectToQuery(searchParams)}`); }; - beforeEach(() => { - location = window.location; - delete window.location; - }); - afterEach(() => { - window.location = location; + setWindowLocation(location); }); it('when the URL points to a panel it expands', () => { const panelGroup = metricsDashboardViewModel.panelGroups[0]; const panel = panelGroup.panels[0]; - setSearch( - objectToQuery({ - group: panelGroup.group, - title: panel.title, - y_label: panel.y_label, - }), - ); + setSearch({ + group: panelGroup.group, + title: panel.title, + y_label: panel.y_label, + }); createMountedWrapper({ hasMetrics: true }); setupStoreWithData(store); @@ -268,7 +262,7 @@ describe('Dashboard', () => { }); it('when the URL does not link to any panel, no panel is expanded', () => { - setSearch(''); + setSearch(); createMountedWrapper({ hasMetrics: true }); setupStoreWithData(store); @@ -285,13 +279,11 @@ describe('Dashboard', () => { const panelGroup = metricsDashboardViewModel.panelGroups[0]; const panel = panelGroup.panels[0]; - setSearch( - objectToQuery({ - group: panelGroup.group, - title: 'incorrect', - y_label: panel.y_label, - }), - ); + setSearch({ + group: panelGroup.group, + title: 'incorrect', + y_label: panel.y_label, + }); createMountedWrapper({ hasMetrics: true }); setupStoreWithData(store); diff --git a/spec/frontend/packages/details/components/app_spec.js b/spec/frontend/packages/details/components/app_spec.js index 3132ec61942..377e7e05f09 100644 --- a/spec/frontend/packages/details/components/app_spec.js +++ b/spec/frontend/packages/details/components/app_spec.js @@ -2,6 +2,7 @@ import { GlEmptyState } from '@gitlab/ui'; import { mount, createLocalVue } from '@vue/test-utils'; import { nextTick } from 'vue'; import Vuex from 'vuex'; +import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; import stubChildren from 'helpers/stub_children'; import AdditionalMetadata from '~/packages/details/components/additional_metadata.vue'; @@ -30,6 +31,8 @@ import { const localVue = createLocalVue(); localVue.use(Vuex); +useMockLocationHelper(); + describe('PackagesApp', () => { let wrapper; let store; @@ -37,7 +40,6 @@ describe('PackagesApp', () => { const deletePackage = jest.fn(); const deletePackageFile = jest.fn(); const defaultProjectName = 'bar'; - const { location } = window; function createComponent({ packageEntity = mavenPackage, @@ -100,14 +102,8 @@ describe('PackagesApp', () => { const findInstallationCommands = () => wrapper.find(InstallationCommands); const findPackageFiles = () => wrapper.find(PackageFiles); - beforeEach(() => { - delete window.location; - window.location = { replace: jest.fn() }; - }); - afterEach(() => { wrapper.destroy(); - window.location = location; }); it('renders the app and displays the package title', async () => { diff --git a/spec/frontend/packages/list/components/packages_list_app_spec.js b/spec/frontend/packages/list/components/packages_list_app_spec.js index 4de2dd0789e..b94192c531c 100644 --- a/spec/frontend/packages/list/components/packages_list_app_spec.js +++ b/spec/frontend/packages/list/components/packages_list_app_spec.js @@ -1,6 +1,7 @@ import { GlEmptyState, GlSprintf, GlLink } from '@gitlab/ui'; import { shallowMount, createLocalVue } from '@vue/test-utils'; import Vuex from 'vuex'; +import setWindowLocation from 'helpers/set_window_location_helper'; import createFlash from '~/flash'; import * as commonUtils from '~/lib/utils/common_utils'; import PackageListApp from '~/packages/list/components/packages_list_app.vue'; @@ -233,21 +234,17 @@ describe('packages_list_app', () => { }); describe('delete alert handling', () => { - const { location } = window.location; + const originalLocation = window.location.href; const search = `?${SHOW_DELETE_SUCCESS_ALERT}=true`; beforeEach(() => { createStore(); jest.spyOn(commonUtils, 'historyReplaceState').mockImplementation(() => {}); - delete window.location; - window.location = { - href: `foo_bar_baz${search}`, - search, - }; + setWindowLocation(search); }); afterEach(() => { - window.location = location; + setWindowLocation(originalLocation); }); it(`creates a flash if the query string contains ${SHOW_DELETE_SUCCESS_ALERT}`, () => { @@ -262,11 +259,11 @@ describe('packages_list_app', () => { it('calls historyReplaceState with a clean url', () => { mountComponent(); - expect(commonUtils.historyReplaceState).toHaveBeenCalledWith('foo_bar_baz'); + expect(commonUtils.historyReplaceState).toHaveBeenCalledWith(originalLocation); }); it(`does nothing if the query string does not contain ${SHOW_DELETE_SUCCESS_ALERT}`, () => { - window.location.search = ''; + setWindowLocation('?'); mountComponent(); expect(createFlash).not.toHaveBeenCalled(); diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js index 2b3acbf99f3..0504a42dfcf 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/details/additional_metadata_spec.js @@ -1,17 +1,35 @@ import { GlLink, GlSprintf } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import { mavenPackage, conanPackage, nugetPackage, npmPackage } from 'jest/packages/mock_data'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import { + conanMetadata, + mavenMetadata, + nugetMetadata, + packageData, +} from 'jest/packages_and_registries/package_registry/mock_data'; import component from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue'; +import { + PACKAGE_TYPE_NUGET, + PACKAGE_TYPE_CONAN, + PACKAGE_TYPE_MAVEN, + PACKAGE_TYPE_NPM, +} from '~/packages_and_registries/package_registry/constants'; import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; +const mavenPackage = { packageType: PACKAGE_TYPE_MAVEN, metadata: mavenMetadata() }; +const conanPackage = { packageType: PACKAGE_TYPE_CONAN, metadata: conanMetadata() }; +const nugetPackage = { packageType: PACKAGE_TYPE_NUGET, metadata: nugetMetadata() }; +const npmPackage = { packageType: PACKAGE_TYPE_NPM, metadata: {} }; + describe('Package Additional Metadata', () => { let wrapper; const defaultProps = { - packageEntity: { ...mavenPackage }, + packageEntity: { + ...packageData(mavenPackage), + }, }; const mountComponent = (props) => { - wrapper = shallowMount(component, { + wrapper = shallowMountExtended(component, { propsData: { ...defaultProps, ...props }, stubs: { DetailsRow, @@ -25,14 +43,14 @@ describe('Package Additional Metadata', () => { wrapper = null; }); - const findTitle = () => wrapper.find('[data-testid="title"]'); - const findMainArea = () => wrapper.find('[data-testid="main"]'); - const findNugetSource = () => wrapper.find('[data-testid="nuget-source"]'); - const findNugetLicense = () => wrapper.find('[data-testid="nuget-license"]'); - const findConanRecipe = () => wrapper.find('[data-testid="conan-recipe"]'); - const findMavenApp = () => wrapper.find('[data-testid="maven-app"]'); - const findMavenGroup = () => wrapper.find('[data-testid="maven-group"]'); - const findElementLink = (container) => container.find(GlLink); + const findTitle = () => wrapper.findByTestId('title'); + const findMainArea = () => wrapper.findByTestId('main'); + const findNugetSource = () => wrapper.findByTestId('nuget-source'); + const findNugetLicense = () => wrapper.findByTestId('nuget-license'); + const findConanRecipe = () => wrapper.findByTestId('conan-recipe'); + const findMavenApp = () => wrapper.findByTestId('maven-app'); + const findMavenGroup = () => wrapper.findByTestId('maven-group'); + const findElementLink = (container) => container.findComponent(GlLink); it('has the correct title', () => { mountComponent(); @@ -43,27 +61,21 @@ describe('Package Additional Metadata', () => { expect(title.text()).toBe('Additional Metadata'); }); - describe.each` - packageEntity | visible | metadata - ${mavenPackage} | ${true} | ${'maven_metadatum'} - ${conanPackage} | ${true} | ${'conan_metadatum'} - ${nugetPackage} | ${true} | ${'nuget_metadatum'} - ${npmPackage} | ${false} | ${null} - `('Component visibility', ({ packageEntity, visible, metadata }) => { - it(`Is ${visible} that the component markup is visible when the package is ${packageEntity.package_type}`, () => { + it.each` + packageEntity | visible | packageType + ${mavenPackage} | ${true} | ${PACKAGE_TYPE_MAVEN} + ${conanPackage} | ${true} | ${PACKAGE_TYPE_CONAN} + ${nugetPackage} | ${true} | ${PACKAGE_TYPE_NUGET} + ${npmPackage} | ${false} | ${PACKAGE_TYPE_NPM} + `( + `It is $visible that the component is visible when the package is $packageType`, + ({ packageEntity, visible }) => { mountComponent({ packageEntity }); expect(findTitle().exists()).toBe(visible); expect(findMainArea().exists()).toBe(visible); - }); - - it(`The component is hidden if ${metadata} is missing`, () => { - mountComponent({ packageEntity: { ...packageEntity, [metadata]: null } }); - - expect(findTitle().exists()).toBe(false); - expect(findMainArea().exists()).toBe(false); - }); - }); + }, + ); describe('nuget metadata', () => { beforeEach(() => { @@ -71,15 +83,15 @@ describe('Package Additional Metadata', () => { }); it.each` - name | finderFunction | text | link | icon - ${'source'} | ${findNugetSource} | ${'Source project located at project-foo-url'} | ${'project_url'} | ${'project'} - ${'license'} | ${findNugetLicense} | ${'License information located at license-foo-url'} | ${'license_url'} | ${'license'} + name | finderFunction | text | link | icon + ${'source'} | ${findNugetSource} | ${'Source project located at projectUrl'} | ${'projectUrl'} | ${'project'} + ${'license'} | ${findNugetLicense} | ${'License information located at licenseUrl'} | ${'licenseUrl'} | ${'license'} `('$name element', ({ finderFunction, text, link, icon }) => { const element = finderFunction(); expect(element.exists()).toBe(true); expect(element.text()).toBe(text); expect(element.props('icon')).toBe(icon); - expect(findElementLink(element).attributes('href')).toBe(nugetPackage.nuget_metadatum[link]); + expect(findElementLink(element).attributes('href')).toBe(nugetPackage.metadata[link]); }); }); @@ -89,8 +101,8 @@ describe('Package Additional Metadata', () => { }); it.each` - name | finderFunction | text | icon - ${'recipe'} | ${findConanRecipe} | ${'Recipe: conan-package/1.0.0@conan+conan-package/stable'} | ${'information-o'} + name | finderFunction | text | icon + ${'recipe'} | ${findConanRecipe} | ${'Recipe: package-8/1.0.0@gitlab-org+gitlab-test/stable'} | ${'information-o'} `('$name element', ({ finderFunction, text, icon }) => { const element = finderFunction(); expect(element.exists()).toBe(true); @@ -105,9 +117,9 @@ describe('Package Additional Metadata', () => { }); it.each` - name | finderFunction | text | icon - ${'app'} | ${findMavenApp} | ${'App name: test-app'} | ${'information-o'} - ${'group'} | ${findMavenGroup} | ${'App group: com.test.app'} | ${'information-o'} + name | finderFunction | text | icon + ${'app'} | ${findMavenApp} | ${'App name: appName'} | ${'information-o'} + ${'group'} | ${findMavenGroup} | ${'App group: appGroup'} | ${'information-o'} `('$name element', ({ finderFunction, text, icon }) => { const element = finderFunction(); expect(element.exists()).toBe(true); diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/app_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/app_spec.js index 4be4733b3b0..e6d12f5e479 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/app_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/details/app_spec.js @@ -5,6 +5,7 @@ import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; import createFlash from '~/flash'; +import AdditionalMetadata from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue'; import PackagesApp from '~/packages_and_registries/package_registry/components/details/app.vue'; import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue'; import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue'; @@ -48,6 +49,7 @@ describe('PackagesApp', () => { const findEmptyState = () => wrapper.findComponent(GlEmptyState); const findPackageTitle = () => wrapper.findComponent(PackageTitle); const findPackageHistory = () => wrapper.findComponent(PackageHistory); + const findAdditionalMetadata = () => wrapper.findComponent(AdditionalMetadata); afterEach(() => { wrapper.destroy(); @@ -95,4 +97,15 @@ describe('PackagesApp', () => { projectName: provide.projectName, }); }); + + it('renders additional metadata and has the right props', async () => { + createComponent(); + + await waitForPromises(); + + expect(findAdditionalMetadata().exists()).toBe(true); + expect(findAdditionalMetadata().props()).toMatchObject({ + packageEntity: expect.objectContaining(packageData()), + }); + }); }); diff --git a/spec/frontend/packages_and_registries/package_registry/mock_data.js b/spec/frontend/packages_and_registries/package_registry/mock_data.js index 9de3dee0738..d1b81aa8b5f 100644 --- a/spec/frontend/packages_and_registries/package_registry/mock_data.js +++ b/spec/frontend/packages_and_registries/package_registry/mock_data.js @@ -58,10 +58,49 @@ export const packageData = (extend) => ({ ...extend, }); +export const conanMetadata = () => ({ + packageChannel: 'stable', + packageUsername: 'gitlab-org+gitlab-test', + recipe: 'package-8/1.0.0@gitlab-org+gitlab-test/stable', + recipePath: 'package-8/1.0.0/gitlab-org+gitlab-test/stable', +}); + +export const composerMetadata = () => ({ + targetSha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0', + composerJson: { + license: 'MIT', + version: '1.0.0', + }, +}); + +export const pypyMetadata = () => ({ + requiredPython: '1.0.0', +}); + +export const mavenMetadata = () => ({ + appName: 'appName', + appGroup: 'appGroup', + appVersion: 'appVersion', + path: 'path', +}); + +export const nugetMetadata = () => ({ + iconUrl: 'iconUrl', + licenseUrl: 'licenseUrl', + projectUrl: 'projectUrl', +}); + export const packageDetailsQuery = () => ({ data: { package: { ...packageData(), + metadata: { + ...conanMetadata(), + ...composerMetadata(), + ...pypyMetadata(), + ...mavenMetadata(), + ...nugetMetadata(), + }, tags: { nodes: packageTags(), __typename: 'PackageTagConnection', diff --git a/spec/frontend/persistent_user_callout_spec.js b/spec/frontend/persistent_user_callout_spec.js index 1e51ddf909a..1db255106ed 100644 --- a/spec/frontend/persistent_user_callout_spec.js +++ b/spec/frontend/persistent_user_callout_spec.js @@ -1,4 +1,5 @@ import MockAdapter from 'axios-mock-adapter'; +import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; import waitForPromises from 'helpers/wait_for_promises'; import createFlash from '~/flash'; import axios from '~/lib/utils/axios_utils'; @@ -166,6 +167,8 @@ describe('PersistentUserCallout', () => { let mockAxios; let persistentUserCallout; + useMockLocationHelper(); + beforeEach(() => { const fixture = createFollowLinkFixture(); const container = fixture.querySelector('.container'); @@ -174,9 +177,6 @@ describe('PersistentUserCallout', () => { persistentUserCallout = new PersistentUserCallout(container); jest.spyOn(persistentUserCallout.container, 'remove').mockImplementation(() => {}); - - delete window.location; - window.location = { assign: jest.fn() }; }); afterEach(() => { diff --git a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js index b0d1a69ee56..0c5c08d7190 100644 --- a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js +++ b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js @@ -2,6 +2,7 @@ import { GlAlert, GlButton, GlLoadingIcon, GlTabs } from '@gitlab/ui'; import { shallowMount, createLocalVue } from '@vue/test-utils'; import VueApollo from 'vue-apollo'; import createMockApollo from 'helpers/mock_apollo_helper'; +import setWindowLocation from 'helpers/set_window_location_helper'; import waitForPromises from 'helpers/wait_for_promises'; import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue'; import TextEditor from '~/pipeline_editor/components/editor/text_editor.vue'; @@ -348,15 +349,14 @@ describe('Pipeline editor app component', () => { }); describe('when a template parameter is present in the URL', () => { - const { location } = window; + const originalLocation = window.location.href; beforeEach(() => { - delete window.location; - window.location = new URL('https://localhost?template=Android'); + setWindowLocation('?template=Android'); }); afterEach(() => { - window.location = location; + setWindowLocation(originalLocation); }); it('renders the given template', async () => { diff --git a/spec/frontend/profile/preferences/components/profile_preferences_spec.js b/spec/frontend/profile/preferences/components/profile_preferences_spec.js index f1172a73d36..4d2dcf83d3b 100644 --- a/spec/frontend/profile/preferences/components/profile_preferences_spec.js +++ b/spec/frontend/profile/preferences/components/profile_preferences_spec.js @@ -1,6 +1,7 @@ import { GlButton } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import { nextTick } from 'vue'; +import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import createFlash from '~/flash'; import IntegrationView from '~/profile/preferences/components/integration_view.vue'; @@ -19,6 +20,8 @@ import { jest.mock('~/flash'); const expectedUrl = '/foo'; +useMockLocationHelper(); + describe('ProfilePreferences component', () => { let wrapper; const defaultProvide = { @@ -174,8 +177,6 @@ describe('ProfilePreferences component', () => { }); describe('theme changes', () => { - const { location } = window; - let themeInput; let form; @@ -197,18 +198,6 @@ describe('ProfilePreferences component', () => { form.dispatchEvent(successEvent); } - beforeAll(() => { - delete window.location; - window.location = { - ...location, - reload: jest.fn(), - }; - }); - - afterAll(() => { - window.location = location; - }); - beforeEach(() => { setupBody(); themeInput = createThemeInput(); diff --git a/spec/frontend/snippets/components/snippet_header_spec.js b/spec/frontend/snippets/components/snippet_header_spec.js index 585614a6b79..e77bae79f68 100644 --- a/spec/frontend/snippets/components/snippet_header_spec.js +++ b/spec/frontend/snippets/components/snippet_header_spec.js @@ -1,12 +1,15 @@ import { GlButton, GlModal } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import { ApolloMutation } from 'vue-apollo'; +import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; import waitForPromises from 'helpers/wait_for_promises'; import { Blob, BinaryBlob } from 'jest/blob/components/mock_data'; import { differenceInMilliseconds } from '~/lib/utils/datetime_utility'; import SnippetHeader from '~/snippets/components/snippet_header.vue'; import DeleteSnippetMutation from '~/snippets/mutations/deleteSnippet.mutation.graphql'; +useMockLocationHelper(); + describe('Snippet header component', () => { let wrapper; let snippet; @@ -200,19 +203,6 @@ describe('Snippet header component', () => { }); describe('Delete mutation', () => { - const { location } = window; - - beforeEach(() => { - delete window.location; - window.location = { - pathname: '', - }; - }); - - afterEach(() => { - window.location = location; - }); - it('dispatches a mutation to delete the snippet with correct variables', () => { createComponent(); wrapper.vm.deleteSnippet(); |