diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-07 12:12:12 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-07 12:12:12 +0300 |
commit | b9bc4d88ea6b998e2cede0da904f36daa2c18007 (patch) | |
tree | 46a3d43aa85d18f1fe27cfccdad9e7cf53fda14f /spec | |
parent | 913224e81c5ee474f2d61962fed3c7e42b71c3f9 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/features/groups/show_spec.rb | 2 | ||||
-rw-r--r-- | spec/features/projects/user_sorts_projects_spec.rb | 4 | ||||
-rw-r--r-- | spec/frontend/groups/components/app_spec.js | 10 | ||||
-rw-r--r-- | spec/frontend/groups/components/overview_tabs_spec.js | 106 | ||||
-rw-r--r-- | spec/frontend/issuable/issuable_form_spec.js | 199 | ||||
-rw-r--r-- | spec/helpers/groups_helper_spec.rb | 23 | ||||
-rw-r--r-- | spec/workers/concerns/application_worker_spec.rb | 2 |
7 files changed, 265 insertions, 81 deletions
diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb index d814906a274..67310862516 100644 --- a/spec/features/groups/show_spec.rb +++ b/spec/features/groups/show_spec.rb @@ -331,6 +331,7 @@ RSpec.describe 'Group show page' do end it 'does not include structured markup in shared projects tab', :aggregate_failures, :js do + stub_feature_flags(group_overview_tabs_vue: false) other_project = create(:project, :public) other_project.project_group_links.create!(group: group) @@ -342,6 +343,7 @@ RSpec.describe 'Group show page' do end it 'does not include structured markup in archived projects tab', :aggregate_failures, :js do + stub_feature_flags(group_overview_tabs_vue: false) project.update!(archived: true) visit group_archived_path(group) diff --git a/spec/features/projects/user_sorts_projects_spec.rb b/spec/features/projects/user_sorts_projects_spec.rb index 7c970f7ee3d..b9b28398279 100644 --- a/spec/features/projects/user_sorts_projects_spec.rb +++ b/spec/features/projects/user_sorts_projects_spec.rb @@ -24,6 +24,7 @@ RSpec.describe 'User sorts projects and order persists' do end it "is set on the group_canonical_path" do + stub_feature_flags(group_overview_tabs_vue: false) visit(group_canonical_path(group)) within '[data-testid=group_sort_by_dropdown]' do @@ -32,6 +33,7 @@ RSpec.describe 'User sorts projects and order persists' do end it "is set on the details_group_path" do + stub_feature_flags(group_overview_tabs_vue: false) visit(details_group_path(group)) within '[data-testid=group_sort_by_dropdown]' do @@ -64,6 +66,7 @@ RSpec.describe 'User sorts projects and order persists' do context 'from group homepage', :js do before do + stub_feature_flags(group_overview_tabs_vue: false) sign_in(user) visit(group_canonical_path(group)) within '[data-testid=group_sort_by_dropdown]' do @@ -77,6 +80,7 @@ RSpec.describe 'User sorts projects and order persists' do context 'from group details', :js do before do + stub_feature_flags(group_overview_tabs_vue: false) sign_in(user) visit(details_group_path(group)) within '[data-testid=group_sort_by_dropdown]' do diff --git a/spec/frontend/groups/components/app_spec.js b/spec/frontend/groups/components/app_spec.js index 2796a561953..a4a7530184d 100644 --- a/spec/frontend/groups/components/app_spec.js +++ b/spec/frontend/groups/components/app_spec.js @@ -40,7 +40,7 @@ describe('AppComponent', () => { const store = new GroupsStore({ hideProjects: false }); const service = new GroupsService(mockEndpoint); - const createShallowComponent = ({ propsData = {}, provide = {} } = {}) => { + const createShallowComponent = ({ propsData = {} } = {}) => { store.state.pageInfo = mockPageInfo; wrapper = shallowMount(appComponent, { propsData: { @@ -53,10 +53,6 @@ describe('AppComponent', () => { mocks: { $toast, }, - provide: { - renderEmptyState: false, - ...provide, - }, }); vm = wrapper.vm; }; @@ -402,8 +398,7 @@ describe('AppComponent', () => { ({ action, groups, fromSearch, renderEmptyState, expected }) => { it(expected ? 'renders empty state' : 'does not render empty state', async () => { createShallowComponent({ - propsData: { action }, - provide: { renderEmptyState }, + propsData: { action, renderEmptyState }, }); vm.updateGroups(groups, fromSearch); @@ -420,7 +415,6 @@ describe('AppComponent', () => { it('renders legacy empty state', async () => { createShallowComponent({ propsData: { action: 'subgroups_and_projects' }, - provide: { renderEmptyState: false }, }); vm.updateGroups([], false); diff --git a/spec/frontend/groups/components/overview_tabs_spec.js b/spec/frontend/groups/components/overview_tabs_spec.js new file mode 100644 index 00000000000..c26254acf3d --- /dev/null +++ b/spec/frontend/groups/components/overview_tabs_spec.js @@ -0,0 +1,106 @@ +import { GlTab } from '@gitlab/ui'; +import { nextTick } from 'vue'; +import AxiosMockAdapter from 'axios-mock-adapter'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import OverviewTabs from '~/groups/components/overview_tabs.vue'; +import GroupsApp from '~/groups/components/app.vue'; +import GroupsStore from '~/groups/store/groups_store'; +import GroupsService from '~/groups/service/groups_service'; +import { + ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, + ACTIVE_TAB_SHARED, + ACTIVE_TAB_ARCHIVED, +} from '~/groups/constants'; +import axios from '~/lib/utils/axios_utils'; + +describe('OverviewTabs', () => { + let wrapper; + + const endpoints = { + subgroups_and_projects: '/groups/foobar/-/children.json', + shared: '/groups/foobar/-/shared_projects.json', + archived: '/groups/foobar/-/children.json?archived=only', + }; + + const createComponent = async () => { + wrapper = mountExtended(OverviewTabs, { + provide: { + endpoints, + }, + }); + + await nextTick(); + }; + + const findTabPanels = () => wrapper.findAllComponents(GlTab); + const findTab = (name) => wrapper.findByRole('tab', { name }); + + afterEach(() => { + wrapper.destroy(); + }); + + beforeEach(async () => { + // eslint-disable-next-line no-new + new AxiosMockAdapter(axios); + + await createComponent(); + }); + + it('renders `Subgroups and projects` tab with `GroupsApp` component', async () => { + const tabPanel = findTabPanels().at(0); + + expect(tabPanel.vm.$attrs).toMatchObject({ + title: OverviewTabs.i18n.subgroupsAndProjects, + lazy: false, + }); + expect(tabPanel.findComponent(GroupsApp).props()).toMatchObject({ + action: ACTIVE_TAB_SUBGROUPS_AND_PROJECTS, + store: new GroupsStore({ showSchemaMarkup: true }), + service: new GroupsService(endpoints[ACTIVE_TAB_SUBGROUPS_AND_PROJECTS]), + hideProjects: false, + renderEmptyState: true, + }); + }); + + it('renders `Shared projects` tab and renders `GroupsApp` component after clicking tab', async () => { + const tabPanel = findTabPanels().at(1); + + expect(tabPanel.vm.$attrs).toMatchObject({ + title: OverviewTabs.i18n.sharedProjects, + lazy: true, + }); + + await findTab(OverviewTabs.i18n.sharedProjects).trigger('click'); + + expect(tabPanel.findComponent(GroupsApp).props()).toMatchObject({ + action: ACTIVE_TAB_SHARED, + store: new GroupsStore(), + service: new GroupsService(endpoints[ACTIVE_TAB_SHARED]), + hideProjects: false, + renderEmptyState: false, + }); + + expect(tabPanel.vm.$attrs.lazy).toBe(false); + }); + + it('renders `Archived projects` tab and renders `GroupsApp` component after clicking tab', async () => { + const tabPanel = findTabPanels().at(2); + + expect(tabPanel.vm.$attrs).toMatchObject({ + title: OverviewTabs.i18n.archivedProjects, + lazy: true, + }); + + await findTab(OverviewTabs.i18n.archivedProjects).trigger('click'); + + expect(tabPanel.findComponent(GroupsApp).props()).toMatchObject({ + action: ACTIVE_TAB_ARCHIVED, + store: new GroupsStore(), + service: new GroupsService(endpoints[ACTIVE_TAB_ARCHIVED]), + hideProjects: false, + renderEmptyState: false, + }); + + expect(tabPanel.vm.$attrs.lazy).toBe(false); + }); +}); diff --git a/spec/frontend/issuable/issuable_form_spec.js b/spec/frontend/issuable/issuable_form_spec.js index d844f3394d5..f37d132743a 100644 --- a/spec/frontend/issuable/issuable_form_spec.js +++ b/spec/frontend/issuable/issuable_form_spec.js @@ -1,111 +1,168 @@ import $ from 'jquery'; +import Autosave from '~/autosave'; import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; import IssuableForm from '~/issuable/issuable_form'; import setWindowLocation from 'helpers/set_window_location_helper'; +jest.mock('~/autosave'); + +const createIssuable = (form) => { + return new IssuableForm(form); +}; + describe('IssuableForm', () => { + let $form; let instance; - const createIssuable = (form) => { - instance = new IssuableForm(form); - }; - beforeEach(() => { setHTMLFixture(` <form> <input name="[title]" /> + <textarea name="[description]"></textarea> </form> `); - createIssuable($('form')); + $form = $('form'); }); afterEach(() => { resetHTMLFixture(); + $form = null; + instance = null; }); - describe('initAutosave', () => { - it('creates autosave with the searchTerm included', () => { - setWindowLocation('https://gitlab.test/foo?bar=true'); - const autosave = instance.initAutosave(); + describe('autosave', () => { + let $title; + let $description; + + beforeEach(() => { + $title = $form.find('input[name*="[title]"]'); + $description = $form.find('textarea[name*="[description]"]'); + }); + + afterEach(() => { + $title = null; + $description = null; + }); - expect(autosave.key.includes('bar=true')).toBe(true); + describe('initAutosave', () => { + it('calls initAutosave', () => { + const initAutosave = jest.spyOn(IssuableForm.prototype, 'initAutosave'); + createIssuable($form); + + expect(initAutosave).toHaveBeenCalledTimes(1); + }); + + it('creates autosave with the searchTerm included', () => { + setWindowLocation('https://gitlab.test/foo?bar=true'); + createIssuable($form); + + expect(Autosave).toHaveBeenCalledWith( + $title, + ['/foo', 'bar=true', 'title'], + 'autosave//foo/bar=true=title', + ); + expect(Autosave).toHaveBeenCalledWith( + $description, + ['/foo', 'bar=true', 'description'], + 'autosave//foo/bar=true=description', + ); + }); + + it("creates autosave fields without the searchTerm if it's an issue new form", () => { + setWindowLocation('https://gitlab.test/issues/new?bar=true'); + $form.attr('data-new-issue-path', '/issues/new'); + createIssuable($form); + + expect(Autosave).toHaveBeenCalledWith( + $title, + ['/issues/new', '', 'title'], + 'autosave//issues/new/bar=true=title', + ); + expect(Autosave).toHaveBeenCalledWith( + $description, + ['/issues/new', '', 'description'], + 'autosave//issues/new/bar=true=description', + ); + }); }); - it("creates autosave fields without the searchTerm if it's an issue new form", () => { - setHTMLFixture(` - <form data-new-issue-path="/issues/new"> - <input name="[title]" /> - </form> - `); - createIssuable($('form')); + describe('resetAutosave', () => { + it('calls reset on title and description', () => { + instance = createIssuable($form); + + instance.resetAutosave(); - setWindowLocation('https://gitlab.test/issues/new?bar=true'); + expect(instance.autosaveTitle.reset).toHaveBeenCalledTimes(1); + expect(instance.autosaveDescription.reset).toHaveBeenCalledTimes(1); + }); - const autosave = instance.initAutosave(); + it('resets autosave when submit', () => { + const resetAutosave = jest.spyOn(IssuableForm.prototype, 'resetAutosave'); + createIssuable($form); - expect(autosave.key.includes('bar=true')).toBe(false); + $form.submit(); + + expect(resetAutosave).toHaveBeenCalledTimes(1); + }); + + it('resets autosave on elements with the .js-reset-autosave class', () => { + const resetAutosave = jest.spyOn(IssuableForm.prototype, 'resetAutosave'); + $form.append('<a class="js-reset-autosave">Cancel</a>'); + createIssuable($form); + + $form.find('.js-reset-autosave').trigger('click'); + + expect(resetAutosave).toHaveBeenCalledTimes(1); + }); }); }); - describe('resetAutosave', () => { - it('resets autosave on elements with the .js-reset-autosave class', () => { - setHTMLFixture(` - <form> - <input name="[title]" /> - <textarea name="[description]"></textarea> - <a class="js-reset-autosave">Cancel</a> - </form> - `); - const $form = $('form'); - const resetAutosave = jest.spyOn(IssuableForm.prototype, 'resetAutosave'); - createIssuable($form); - - $form.find('.js-reset-autosave').trigger('click'); - - expect(resetAutosave).toHaveBeenCalled(); + describe('wip', () => { + beforeEach(() => { + instance = createIssuable($form); }); - }); - describe('removeWip', () => { - it.each` - prefix - ${'draFT: '} - ${' [DRaft] '} - ${'drAft:'} - ${'[draFT]'} - ${'(draft) '} - ${' (DrafT)'} - ${'draft: [draft] (draft)'} - `('removes "$prefix" from the beginning of the title', ({ prefix }) => { - instance.titleField.val(`${prefix}The Issuable's Title Value`); - - instance.removeWip(); - - expect(instance.titleField.val()).toBe("The Issuable's Title Value"); + describe('removeWip', () => { + it.each` + prefix + ${'draFT: '} + ${' [DRaft] '} + ${'drAft:'} + ${'[draFT]'} + ${'(draft) '} + ${' (DrafT)'} + ${'draft: [draft] (draft)'} + `('removes "$prefix" from the beginning of the title', ({ prefix }) => { + instance.titleField.val(`${prefix}The Issuable's Title Value`); + + instance.removeWip(); + + expect(instance.titleField.val()).toBe("The Issuable's Title Value"); + }); }); - }); - describe('addWip', () => { - it("properly adds the work in progress prefix to the Issuable's title", () => { - instance.titleField.val("The Issuable's Title Value"); + describe('addWip', () => { + it("properly adds the work in progress prefix to the Issuable's title", () => { + instance.titleField.val("The Issuable's Title Value"); - instance.addWip(); + instance.addWip(); - expect(instance.titleField.val()).toBe("Draft: The Issuable's Title Value"); + expect(instance.titleField.val()).toBe("Draft: The Issuable's Title Value"); + }); }); - }); - describe('workInProgress', () => { - it.each` - title | expected - ${'draFT: something is happening'} | ${true} - ${'draft something is happening'} | ${false} - ${'something is happening to drafts'} | ${false} - ${'something is happening'} | ${false} - `('returns $expected with "$title"', ({ title, expected }) => { - instance.titleField.val(title); - - expect(instance.workInProgress()).toBe(expected); + describe('workInProgress', () => { + it.each` + title | expected + ${'draFT: something is happening'} | ${true} + ${'draft something is happening'} | ${false} + ${'something is happening to drafts'} | ${false} + ${'something is happening'} | ${false} + `('returns $expected with "$title"', ({ title, expected }) => { + instance.titleField.val(title); + + expect(instance.workInProgress()).toBe(expected); + }); }); }); }); diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 2c1061d2f1b..00e620832b3 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -520,6 +520,29 @@ RSpec.describe GroupsHelper do end end + describe '#group_overview_tabs_app_data' do + let_it_be(:group) { create(:group) } + let_it_be(:user) { create(:user) } + + before do + allow(helper).to receive(:current_user).and_return(user) + + allow(helper).to receive(:can?).with(user, :create_subgroup, group) { true } + allow(helper).to receive(:can?).with(user, :create_projects, group) { true } + end + + it 'returns expected hash' do + expect(helper.group_overview_tabs_app_data(group)).to match( + { + subgroups_and_projects_endpoint: including("/groups/#{group.path}/-/children.json"), + shared_projects_endpoint: including("/groups/#{group.path}/-/shared_projects.json"), + archived_projects_endpoint: including("/groups/#{group.path}/-/children.json?archived=only"), + current_group_visibility: group.visibility + }.merge(helper.group_overview_tabs_app_data(group)) + ) + end + end + describe "#enabled_git_access_protocol_options_for_group" do subject { helper.enabled_git_access_protocol_options_for_group } diff --git a/spec/workers/concerns/application_worker_spec.rb b/spec/workers/concerns/application_worker_spec.rb index 707fa0c9c78..5fde54b98f0 100644 --- a/spec/workers/concerns/application_worker_spec.rb +++ b/spec/workers/concerns/application_worker_spec.rb @@ -289,7 +289,6 @@ RSpec.describe ApplicationWorker do perform_action expect(worker.jobs.count).to eq args.count - expect(worker.jobs).to all(include('enqueued_at')) end end @@ -302,7 +301,6 @@ RSpec.describe ApplicationWorker do perform_action expect(worker.jobs.count).to eq args.count - expect(worker.jobs).to all(include('enqueued_at')) end end |