diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-28 18:09:19 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-28 18:09:19 +0300 |
commit | 24623a974348595d33cc9be6881b285a026ff13b (patch) | |
tree | 20a28aa9b423a65c52ea5ca54c6fcb91dd9ddfd6 /spec/frontend | |
parent | 72ba138510cad0a8c4819ef0512153dd4dbced7f (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
8 files changed, 216 insertions, 30 deletions
diff --git a/spec/frontend/fixtures/groups.rb b/spec/frontend/fixtures/groups.rb index 9c22ff176ff..e69287c879b 100644 --- a/spec/frontend/fixtures/groups.rb +++ b/spec/frontend/fixtures/groups.rb @@ -2,24 +2,39 @@ require 'spec_helper' -RSpec.describe 'Groups (JavaScript fixtures)', type: :controller do +RSpec.describe 'Groups (JavaScript fixtures)', feature_category: :groups_and_projects do + include ApiHelpers include JavaScriptFixturesHelpers - let(:user) { create(:user) } - let(:group) { create(:group, name: 'frontend-fixtures-group', runners_token: 'runnerstoken:intabulasreferre') } + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group, name: 'frontend-fixtures-group', runners_token: 'runnerstoken:intabulasreferre') } + let_it_be(:projects) { create_list(:project, 2, namespace: group) } - before do - group.add_owner(user) - sign_in(user) - end + describe GroupsController, '(JavaScript fixtures)', type: :controller do + render_views - render_views + before do + group.add_owner(user) + sign_in(user) + end - describe GroupsController, '(JavaScript fixtures)', type: :controller do it 'groups/edit.html' do get :edit, params: { id: group } expect(response).to be_successful end end + + describe API::Groups, '(JavaScript fixtures)', type: :request do + before do + group.add_owner(user) + sign_in(user) + end + + it 'api/groups/projects/get.json' do + get api("/groups/#{group.id}/projects", user) + + expect(response).to be_successful + end + end end diff --git a/spec/frontend/groups/components/app_spec.js b/spec/frontend/groups/components/app_spec.js index b474745790e..e32c50db8bf 100644 --- a/spec/frontend/groups/components/app_spec.js +++ b/spec/frontend/groups/components/app_spec.js @@ -93,10 +93,9 @@ describe('AppComponent', () => { page: 2, filterGroupsBy: 'git', sortBy: 'created_desc', - archived: true, }) .then(() => { - expect(getGroupsSpy).toHaveBeenCalledWith(1, 2, 'git', 'created_desc', true); + expect(getGroupsSpy).toHaveBeenCalledWith(1, 2, 'git', 'created_desc'); }); }); @@ -154,7 +153,6 @@ describe('AppComponent', () => { filterGroupsBy: 'foobar', sortBy: null, updatePagination: true, - archived: null, }); return fetchPromise.then(() => { expect(vm.updateGroups).toHaveBeenCalledWith(mockSearchedGroups, true); @@ -177,7 +175,6 @@ describe('AppComponent', () => { page: 2, filterGroupsBy: null, sortBy: null, - archived: true, }); expect(vm.isLoading).toBe(true); @@ -186,7 +183,6 @@ describe('AppComponent', () => { filterGroupsBy: null, sortBy: null, updatePagination: true, - archived: true, }); return fetchPagePromise.then(() => { @@ -471,7 +467,7 @@ describe('AppComponent', () => { it('calls API with expected params', () => { emitFetchFilteredAndSortedGroups(); - expect(getGroupsSpy).toHaveBeenCalledWith(undefined, undefined, search, sort, undefined); + expect(getGroupsSpy).toHaveBeenCalledWith(undefined, undefined, search, sort); }); it('updates pagination', () => { diff --git a/spec/frontend/groups/components/overview_tabs_spec.js b/spec/frontend/groups/components/overview_tabs_spec.js index ca852f398d0..8db69295ac4 100644 --- a/spec/frontend/groups/components/overview_tabs_spec.js +++ b/spec/frontend/groups/components/overview_tabs_spec.js @@ -10,26 +10,29 @@ import SharedProjectsEmptyState from '~/groups/components/empty_states/shared_pr import ArchivedProjectsEmptyState from '~/groups/components/empty_states/archived_projects_empty_state.vue'; import GroupsStore from '~/groups/store/groups_store'; import GroupsService from '~/groups/service/groups_service'; +import ArchivedProjectsService from '~/groups/service/archived_projects_service'; import { createRouter } from '~/groups/init_overview_tabs'; import eventHub from '~/groups/event_hub'; import { ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED, - OVERVIEW_TABS_SORTING_ITEMS, + SORTING_ITEM_NAME, + SORTING_ITEM_UPDATED, + SORTING_ITEM_STARS, } from '~/groups/constants'; import axios from '~/lib/utils/axios_utils'; import waitForPromises from 'helpers/wait_for_promises'; Vue.component('GroupFolder', GroupFolderComponent); const router = createRouter(); -const [SORTING_ITEM_NAME, , SORTING_ITEM_UPDATED] = OVERVIEW_TABS_SORTING_ITEMS; describe('OverviewTabs', () => { let wrapper; let axiosMock; const defaultProvide = { + groupId: '1', endpoints: { subgroups_and_projects: '/groups/foobar/-/children.json', shared: '/groups/foobar/-/shared_projects.json', @@ -92,7 +95,10 @@ describe('OverviewTabs', () => { expect(tabPanel.findComponent(GroupsApp).props()).toMatchObject({ action: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, store: new GroupsStore({ showSchemaMarkup: true }), - service: new GroupsService(defaultProvide.endpoints[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS]), + service: new GroupsService( + defaultProvide.endpoints[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS], + defaultProvide.initialSort, + ), }); await waitForPromises(); @@ -115,7 +121,10 @@ describe('OverviewTabs', () => { expect(tabPanel.findComponent(GroupsApp).props()).toMatchObject({ action: ACTIVE_TAB_SHARED, store: new GroupsStore(), - service: new GroupsService(defaultProvide.endpoints[ACTIVE_TAB_SHARED]), + service: new GroupsService( + defaultProvide.endpoints[ACTIVE_TAB_SHARED], + defaultProvide.initialSort, + ), }); expect(tabPanel.vm.$attrs.lazy).toBe(false); @@ -140,7 +149,7 @@ describe('OverviewTabs', () => { expect(tabPanel.findComponent(GroupsApp).props()).toMatchObject({ action: ACTIVE_TAB_ARCHIVED, store: new GroupsStore(), - service: new GroupsService(defaultProvide.endpoints[ACTIVE_TAB_ARCHIVED]), + service: new ArchivedProjectsService(defaultProvide.groupId, defaultProvide.initialSort), }); expect(tabPanel.vm.$attrs.lazy).toBe(false); @@ -219,7 +228,7 @@ describe('OverviewTabs', () => { it(`pushes expected route when ${tabToClick} tab is clicked`, async () => { await findTab(tabToClick).trigger('click'); - expect(routerMock.push).toHaveBeenCalledWith(expectedRoute); + expect(routerMock.push).toHaveBeenCalledWith(expect.objectContaining(expectedRoute)); }); }); @@ -304,6 +313,52 @@ describe('OverviewTabs', () => { sharedAssertions({ search: '', sort: SORTING_ITEM_UPDATED.asc }); }); + describe('when tab is changed', () => { + describe('when selected sort is supported', () => { + beforeEach(async () => { + await createComponent({ + route: { + name: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, + params: { group: 'foo/bar/baz' }, + query: { sort: SORTING_ITEM_NAME.asc }, + }, + }); + }); + + it('adds sort query string', async () => { + await findTab(OverviewTabs.i18n[ACTIVE_TAB_ARCHIVED]).trigger('click'); + + expect(routerMock.push).toHaveBeenCalledWith( + expect.objectContaining({ + query: { sort: SORTING_ITEM_NAME.asc }, + }), + ); + }); + }); + + describe('when selected sort is not supported', () => { + beforeEach(async () => { + await createComponent({ + route: { + name: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, + params: { group: 'foo/bar/baz' }, + query: { sort: SORTING_ITEM_STARS.asc }, + }, + }); + }); + + it('defaults to sorting by name', async () => { + await findTab(OverviewTabs.i18n[ACTIVE_TAB_ARCHIVED]).trigger('click'); + + expect(routerMock.push).toHaveBeenCalledWith( + expect.objectContaining({ + query: { sort: SORTING_ITEM_NAME.asc }, + }), + ); + }); + }); + }); + describe('when sort direction is changed', () => { beforeEach(async () => { await setup(); diff --git a/spec/frontend/groups/service/archived_projects_service_spec.js b/spec/frontend/groups/service/archived_projects_service_spec.js new file mode 100644 index 00000000000..3aec9d57ee1 --- /dev/null +++ b/spec/frontend/groups/service/archived_projects_service_spec.js @@ -0,0 +1,90 @@ +import projects from 'test_fixtures/api/groups/projects/get.json'; +import ArchivedProjectsService from '~/groups/service/archived_projects_service'; +import Api from '~/api'; + +jest.mock('~/api'); + +describe('ArchivedProjectsService', () => { + const groupId = 1; + let service; + + beforeEach(() => { + service = new ArchivedProjectsService(groupId, 'name_asc'); + }); + + describe('getGroups', () => { + const headers = { 'x-next-page': '2', 'x-page': '1', 'x-per-page': '20' }; + const page = 2; + const query = 'git'; + const sort = 'created_asc'; + + beforeEach(() => { + Api.groupProjects.mockResolvedValueOnce({ data: projects, headers }); + }); + + it('returns promise the resolves with formatted project', async () => { + await expect(service.getGroups(undefined, page, query, sort)).resolves.toEqual({ + data: projects.map((project) => { + return { + id: project.id, + name: project.name, + full_name: project.name_with_namespace, + markdown_description: project.description_html, + visibility: project.visibility, + avatar_url: project.avatar_url, + relative_path: `/${project.path_with_namespace}`, + edit_path: null, + leave_path: null, + can_edit: false, + can_leave: false, + can_remove: false, + type: 'project', + permission: null, + children: [], + parent_id: project.namespace.id, + project_count: 0, + subgroup_count: 0, + number_users_with_delimiter: 0, + star_count: project.star_count, + updated_at: project.updated_at, + marked_for_deletion: project.marked_for_deletion_at !== null, + last_activity_at: project.last_activity_at, + }; + }), + headers, + }); + + expect(Api.groupProjects).toHaveBeenCalledWith(groupId, query, { + archived: true, + page, + order_by: 'created_at', + sort: 'asc', + }); + }); + + describe.each` + sortArgument | expectedOrderByParameter | expectedSortParameter + ${'name_asc'} | ${'name'} | ${'asc'} + ${'name_desc'} | ${'name'} | ${'desc'} + ${'created_asc'} | ${'created_at'} | ${'asc'} + ${'created_desc'} | ${'created_at'} | ${'desc'} + ${'latest_activity_asc'} | ${'last_activity_at'} | ${'asc'} + ${'latest_activity_desc'} | ${'last_activity_at'} | ${'desc'} + ${undefined} | ${'name'} | ${'asc'} + `( + 'when the sort argument is $sortArgument', + ({ sortArgument, expectedSortParameter, expectedOrderByParameter }) => { + it(`calls the API with sort parameter set to ${expectedSortParameter} and order_by parameter set to ${expectedOrderByParameter}`, () => { + service.getGroups(undefined, page, query, sortArgument); + + expect(Api.groupProjects).toHaveBeenCalledWith(groupId, query, { + archived: true, + page, + order_by: expectedOrderByParameter, + sort: expectedSortParameter, + }); + }); + }, + ); + }); +}); diff --git a/spec/frontend/groups/service/groups_service_spec.js b/spec/frontend/groups/service/groups_service_spec.js index e037a6df1e2..ef0a7fde70a 100644 --- a/spec/frontend/groups/service/groups_service_spec.js +++ b/spec/frontend/groups/service/groups_service_spec.js @@ -7,7 +7,7 @@ describe('GroupsService', () => { let service; beforeEach(() => { - service = new GroupsService(mockEndpoint); + service = new GroupsService(mockEndpoint, 'created_asc'); }); describe('getGroups', () => { @@ -17,17 +17,28 @@ describe('GroupsService', () => { page: 2, filter: 'git', sort: 'created_asc', - archived: true, }; - service.getGroups(55, 2, 'git', 'created_asc', true); + service.getGroups(55, 2, 'git', 'created_asc'); expect(axios.get).toHaveBeenCalledWith(mockEndpoint, { params: { parent_id: 55 } }); - service.getGroups(null, 2, 'git', 'created_asc', true); + service.getGroups(null, 2, 'git', 'created_asc'); expect(axios.get).toHaveBeenCalledWith(mockEndpoint, { params }); }); + + describe('when sort argument is undefined', () => { + it('calls API with `initialSort` argument', () => { + jest.spyOn(axios, 'get').mockResolvedValue(); + + service.getGroups(undefined, 2, 'git', undefined); + + expect(axios.get).toHaveBeenCalledWith(mockEndpoint, { + params: { sort: 'created_asc', filter: 'git', page: 2 }, + }); + }); + }); }); describe('leaveGroup', () => { diff --git a/spec/frontend/search/mock_data.js b/spec/frontend/search/mock_data.js index 7cf8633d749..eb57deb46b1 100644 --- a/spec/frontend/search/mock_data.js +++ b/spec/frontend/search/mock_data.js @@ -132,6 +132,13 @@ export const MOCK_NAVIGATION = { active: true, count: '2,430', }, + epics: { + label: 'Epics', + scope: 'epics', + link: '/search?scope=epics&search=et', + active: true, + count: '0', + }, merge_requests: { label: 'Merge requests', scope: 'merge_requests', @@ -496,6 +503,14 @@ export const MOCK_NAVIGATION_ITEMS = [ items: [], }, { + title: 'Epics', + icon: 'epic', + link: '/search?scope=epics&search=et', + is_active: true, + pill_count: '0', + items: [], + }, + { title: 'Merge requests', icon: 'merge-request', link: '/search?scope=merge_requests&search=et', @@ -505,7 +520,7 @@ export const MOCK_NAVIGATION_ITEMS = [ }, { title: 'Wiki', - icon: 'overview', + icon: 'book', link: '/search?scope=wiki_blobs&search=et', is_active: false, pill_count: '0', @@ -529,7 +544,7 @@ export const MOCK_NAVIGATION_ITEMS = [ }, { title: 'Milestones', - icon: 'tag', + icon: 'clock', link: '/search?scope=milestones&search=et', is_active: false, pill_count: '0', diff --git a/spec/frontend/search/sidebar/components/scope_legacy_navigation_spec.js b/spec/frontend/search/sidebar/components/scope_legacy_navigation_spec.js index 6a94da31a1b..786ad806ea6 100644 --- a/spec/frontend/search/sidebar/components/scope_legacy_navigation_spec.js +++ b/spec/frontend/search/sidebar/components/scope_legacy_navigation_spec.js @@ -7,6 +7,8 @@ import ScopeLegacyNavigation from '~/search/sidebar/components/scope_legacy_navi Vue.use(Vuex); +const MOCK_NAVIGATION_ENTRIES = Object.entries(MOCK_NAVIGATION); + describe('ScopeLegacyNavigation', () => { let wrapper; @@ -55,12 +57,12 @@ describe('ScopeLegacyNavigation', () => { }); it('renders all nav item components', () => { - expect(findGlNavItems()).toHaveLength(9); + expect(findGlNavItems()).toHaveLength(MOCK_NAVIGATION_ENTRIES.length); }); it('has all proper links', () => { const linkAtPosition = 3; - const { link } = MOCK_NAVIGATION[Object.keys(MOCK_NAVIGATION)[linkAtPosition]]; + const { link } = MOCK_NAVIGATION_ENTRIES[linkAtPosition][1]; expect(findGlNavItems().at(linkAtPosition).attributes('href')).toBe(link); }); diff --git a/spec/frontend/search/sidebar/components/scope_sidebar_navigation_spec.js b/spec/frontend/search/sidebar/components/scope_sidebar_navigation_spec.js index 4b71ff0bedc..86939bdc5d6 100644 --- a/spec/frontend/search/sidebar/components/scope_sidebar_navigation_spec.js +++ b/spec/frontend/search/sidebar/components/scope_sidebar_navigation_spec.js @@ -7,6 +7,8 @@ import { MOCK_QUERY, MOCK_NAVIGATION, MOCK_NAVIGATION_ITEMS } from '../../mock_d Vue.use(Vuex); +const MOCK_NAVIGATION_ENTRIES = Object.entries(MOCK_NAVIGATION); + describe('ScopeSidebarNavigation', () => { let wrapper; @@ -59,7 +61,7 @@ describe('ScopeSidebarNavigation', () => { }); it('renders all nav item components', () => { - expect(findNavItems()).toHaveLength(9); + expect(findNavItems()).toHaveLength(MOCK_NAVIGATION_ENTRIES.length); }); it('has all proper links', () => { |