diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-17 18:09:28 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-17 18:09:28 +0300 |
commit | 6535cf9c79362862c31ea7d26c61541b84db18d9 (patch) | |
tree | 6d646edcf11d38e8ac23bceed1340ff8907b850d /spec | |
parent | 9a8f801d7352b7965fe690a599410fb50005ce67 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
48 files changed, 706 insertions, 533 deletions
diff --git a/spec/controllers/concerns/metrics_dashboard_spec.rb b/spec/controllers/concerns/metrics_dashboard_spec.rb index 8a4d8828aaa..83546403ce5 100644 --- a/spec/controllers/concerns/metrics_dashboard_spec.rb +++ b/spec/controllers/concerns/metrics_dashboard_spec.rb @@ -155,6 +155,7 @@ RSpec.describe MetricsDashboard do '.gitlab/dashboards/errors.yml' => dashboard_yml } end + let_it_be(:project) { create(:project, :custom_repo, files: dashboards) } before do diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb index 3ae9a2b7555..8d1008b98a6 100644 --- a/spec/features/groups/milestone_spec.rb +++ b/spec/features/groups/milestone_spec.rb @@ -83,6 +83,7 @@ RSpec.describe 'Group milestones' do description: 'Lorem Ipsum is simply dummy text' ) end + let_it_be(:active_project_milestone2) { create(:milestone, project: other_project, state: 'active', title: 'v1.1') } let_it_be(:closed_project_milestone1) { create(:milestone, project: project, state: 'closed', title: 'v2.0') } let_it_be(:closed_project_milestone2) { create(:milestone, project: other_project, state: 'closed', title: 'v2.0') } diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb index 697fccaca34..d0340dfc880 100644 --- a/spec/features/profiles/user_edit_profile_spec.rb +++ b/spec/features/profiles/user_edit_profile_spec.rb @@ -20,6 +20,10 @@ RSpec.describe 'User edit profile' do wait_for_requests end + def toggle_busy_status + find('[data-testid="user-availability-checkbox"]').set(true) + end + it 'changes user profile' do fill_in 'user_skype', with: 'testskype' fill_in 'user_linkedin', with: 'testlinkedin' @@ -180,20 +184,51 @@ RSpec.describe 'User edit profile' do expect(page).to have_emoji('speech_balloon') end end + + it 'sets the users status to busy' do + busy_status = find('[data-testid="user-availability-checkbox"]') + + expect(busy_status.checked?).to eq(false) + + toggle_busy_status + submit_settings + visit profile_path + + expect(busy_status.checked?).to eq(true) + end + + context 'with set_user_availability_status feature flag disabled' do + before do + stub_feature_flags(set_user_availability_status: false) + visit root_path(user) + end + + it 'does not display the availability checkbox' do + expect(page).not_to have_css('[data-testid="user-availability-checkbox"]') + end + end end context 'user menu' do let(:issue) { create(:issue, project: project)} let(:project) { create(:project) } - def open_user_status_modal + def open_modal(button_text) find('.header-user-dropdown-toggle').click page.within ".header-user" do - click_button 'Set status' + click_button button_text end end + def open_user_status_modal + open_modal 'Set status' + end + + def open_edit_status_modal + open_modal 'Edit status' + end + def set_user_status_in_modal page.within "#set-user-status-modal" do click_button 'Set status' @@ -246,6 +281,19 @@ RSpec.describe 'User edit profile' do end end + it 'sets the users status to busy' do + open_user_status_modal + busy_status = find('[data-testid="user-availability-checkbox"]') + + expect(busy_status.checked?).to eq(false) + + toggle_busy_status + set_user_status_in_modal + open_edit_status_modal + + expect(busy_status.checked?).to eq(true) + end + it 'opens the emoji modal again after closing it' do open_user_status_modal select_emoji('biohazard', true) @@ -307,11 +355,7 @@ RSpec.describe 'User edit profile' do expect(page).to have_content user_status.message end - find('.header-user-dropdown-toggle').click - - page.within ".header-user" do - click_button 'Edit status' - end + open_edit_status_modal find('.js-clear-user-status-button').click set_user_status_in_modal @@ -333,11 +377,7 @@ RSpec.describe 'User edit profile' do expect(page).to have_content user_status.message end - find('.header-user-dropdown-toggle').click - - page.within ".header-user" do - click_button 'Edit status' - end + open_edit_status_modal page.within "#set-user-status-modal" do click_button 'Remove status' @@ -357,6 +397,19 @@ RSpec.describe 'User edit profile' do expect(page).to have_emoji('speech_balloon') end end + + context 'with set_user_availability_status feature flag disabled' do + before do + stub_feature_flags(set_user_availability_status: false) + visit root_path(user) + end + + it 'does not display the availability checkbox' do + open_user_status_modal + + expect(page).not_to have_css('[data-testid="user-availability-checkbox"]') + end + end end context 'User time preferences', :js do diff --git a/spec/finders/merge_requests/by_approvals_finder_spec.rb b/spec/finders/merge_requests/by_approvals_finder_spec.rb index 0e1856879f1..5c56e610c0b 100644 --- a/spec/finders/merge_requests/by_approvals_finder_spec.rb +++ b/spec/finders/merge_requests/by_approvals_finder_spec.rb @@ -13,6 +13,7 @@ RSpec.describe MergeRequests::ByApprovalsFinder do create(:approval, merge_request: mr, user: first_user) end end + let_it_be(:merge_request_with_both_approvals) do create(:merge_request).tap do |mr| create(:approval, merge_request: mr, user: first_user) diff --git a/spec/fixtures/api/schemas/internal/pages/lookup_path.json b/spec/fixtures/api/schemas/internal/pages/lookup_path.json index a7793d679be..9d81ea495f1 100644 --- a/spec/fixtures/api/schemas/internal/pages/lookup_path.json +++ b/spec/fixtures/api/schemas/internal/pages/lookup_path.json @@ -15,7 +15,11 @@ "required": ["type", "path"], "properties" : { "type": { "type": "string", "enum": ["file", "zip"] }, - "path": { "type": "string" } + "path": { "type": "string" }, + "global_id": { "type": "string" }, + "sha256": { "type": "string" }, + "file_size": { "type": "integer" }, + "file_count": { "type": ["integer", "null"] } }, "additionalProperties": false }, diff --git a/spec/frontend/alerts_settings/alerts_integrations_list_spec.js b/spec/frontend/alerts_settings/alerts_integrations_list_spec.js index 051caf0e49d..90bb38f0c2b 100644 --- a/spec/frontend/alerts_settings/alerts_integrations_list_spec.js +++ b/spec/frontend/alerts_settings/alerts_integrations_list_spec.js @@ -1,5 +1,6 @@ import { GlTable, GlIcon, GlButton } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; +import { useMockIntersectionObserver } from 'helpers/mock_dom_observer'; import Tracking from '~/tracking'; import AlertIntegrationsList, { i18n, @@ -23,6 +24,7 @@ const mockIntegrations = [ describe('AlertIntegrationsList', () => { let wrapper; + const { trigger: triggerIntersection } = useMockIntersectionObserver(); function mountComponent({ data = {}, props = {} } = {}) { wrapper = mount(AlertIntegrationsList, { @@ -100,12 +102,23 @@ describe('AlertIntegrationsList', () => { describe('Snowplow tracking', () => { beforeEach(() => { - jest.spyOn(Tracking, 'event'); mountComponent(); + jest.spyOn(Tracking, 'event'); + }); + + it('should NOT track alert list page views when list is collapsed', () => { + triggerIntersection(wrapper.vm.$el, { entry: { isIntersecting: false } }); + + expect(Tracking.event).not.toHaveBeenCalled(); }); - it('should track alert list page views', () => { + it('should track alert list page views only once when list is expanded', () => { + triggerIntersection(wrapper.vm.$el, { entry: { isIntersecting: true } }); + triggerIntersection(wrapper.vm.$el, { entry: { isIntersecting: true } }); + triggerIntersection(wrapper.vm.$el, { entry: { isIntersecting: true } }); + const { category, action } = trackAlertIntegrationsViewsOptions; + expect(Tracking.event).toHaveBeenCalledTimes(1); expect(Tracking.event).toHaveBeenCalledWith(category, action); }); }); diff --git a/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js b/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js index c24a76f1df0..7384cf9a095 100644 --- a/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js +++ b/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js @@ -3,6 +3,7 @@ import { mount, createLocalVue } from '@vue/test-utils'; import createMockApollo from 'jest/helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; import { GlLoadingIcon, GlAlert } from '@gitlab/ui'; +import { useMockIntersectionObserver } from 'helpers/mock_dom_observer'; import AlertsSettingsWrapper from '~/alerts_settings/components/alerts_settings_wrapper.vue'; import AlertsSettingsFormOld from '~/alerts_settings/components/alerts_settings_form_old.vue'; import AlertsSettingsFormNew from '~/alerts_settings/components/alerts_settings_form_new.vue'; @@ -47,6 +48,7 @@ describe('AlertsSettingsWrapper', () => { let wrapper; let fakeApollo; let destroyIntegrationHandler; + useMockIntersectionObserver(); const findLoader = () => wrapper.find(IntegrationsList).find(GlLoadingIcon); const findIntegrations = () => wrapper.find(IntegrationsList).findAll('table tbody tr'); diff --git a/spec/frontend/gfm_auto_complete_spec.js b/spec/frontend/gfm_auto_complete_spec.js index 8da4320d993..e7025955e8e 100644 --- a/spec/frontend/gfm_auto_complete_spec.js +++ b/spec/frontend/gfm_auto_complete_spec.js @@ -378,6 +378,7 @@ describe('GfmAutoComplete', () => { username: 'my-group', title: '', icon: '', + availabilityStatus: '', }), ).toBe('<li>IMG my-group <small></small> </li>'); }); @@ -389,6 +390,7 @@ describe('GfmAutoComplete', () => { username: 'my-group', title: '', icon: '<i class="icon"/>', + availabilityStatus: '', }), ).toBe('<li>IMG my-group <small></small> <i class="icon"/></li>'); }); @@ -400,9 +402,24 @@ describe('GfmAutoComplete', () => { username: 'my-group', title: 'MyGroup+', icon: '<i class="icon"/>', + availabilityStatus: '', }), ).toBe('<li>IMG my-group <small>MyGroup+</small> <i class="icon"/></li>'); }); + + it('should add user availability status if availabilityStatus is set', () => { + expect( + GfmAutoComplete.Members.templateFunction({ + avatarTag: 'IMG', + username: 'my-group', + title: '', + icon: '<i class="icon"/>', + availabilityStatus: '<span class="gl-text-gray-500"> (Busy)</span>', + }), + ).toBe( + '<li>IMG my-group <small><span class="gl-text-gray-500"> (Busy)</span></small> <i class="icon"/></li>', + ); + }); }); describe('labels', () => { diff --git a/spec/frontend/notes/components/note_header_spec.js b/spec/frontend/notes/components/note_header_spec.js index 1cc4a2fa853..69aab0d051e 100644 --- a/spec/frontend/notes/components/note_header_spec.js +++ b/spec/frontend/notes/components/note_header_spec.js @@ -1,7 +1,9 @@ import { shallowMount, createLocalVue } from '@vue/test-utils'; import { nextTick } from 'vue'; import Vuex from 'vuex'; +import { GlSprintf } from '@gitlab/ui'; import NoteHeader from '~/notes/components/note_header.vue'; +import { AVAILABILITY_STATUS } from '~/set_status_modal/utils'; const localVue = createLocalVue(); localVue.use(Vuex); @@ -28,6 +30,9 @@ describe('NoteHeader component', () => { path: '/root', state: 'active', username: 'root', + status: { + availability: '', + }, }; const createComponent = props => { @@ -37,6 +42,7 @@ describe('NoteHeader component', () => { actions, }), propsData: { ...props }, + stubs: { GlSprintf }, }); }; @@ -97,6 +103,12 @@ describe('NoteHeader component', () => { expect(wrapper.find('.js-user-link').exists()).toBe(true); }); + it('renders busy status if author availability is set', () => { + createComponent({ author: { ...author, status: { availability: AVAILABILITY_STATUS.BUSY } } }); + + expect(wrapper.find('.js-user-link').text()).toContain('(Busy)'); + }); + it('renders deleted user text if author is not passed as a prop', () => { createComponent(); diff --git a/spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js b/spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js new file mode 100644 index 00000000000..fad23aa05a4 --- /dev/null +++ b/spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js @@ -0,0 +1,257 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlModal, GlFormCheckbox } from '@gitlab/ui'; +import { initEmojiMock } from 'helpers/emoji'; +import Api from '~/api'; +import { deprecatedCreateFlash as createFlash } from '~/flash'; +import SetStatusModalWrapper, { + AVAILABILITY_STATUS, +} from '~/set_status_modal/set_status_modal_wrapper.vue'; + +jest.mock('~/api'); +jest.mock('~/flash'); + +describe('SetStatusModalWrapper', () => { + let wrapper; + let mockEmoji; + const $toast = { + show: jest.fn(), + }; + + const defaultEmoji = 'speech_balloon'; + const defaultMessage = "They're comin' in too fast!"; + + const defaultProps = { + currentEmoji: defaultEmoji, + currentMessage: defaultMessage, + defaultEmoji, + canSetUserAvailability: true, + }; + + const createComponent = (props = {}) => { + return shallowMount(SetStatusModalWrapper, { + propsData: { + ...defaultProps, + ...props, + }, + mocks: { + $toast, + }, + }); + }; + + const findModal = () => wrapper.find(GlModal); + const findFormField = field => wrapper.find(`[name="user[status][${field}]"]`); + const findClearStatusButton = () => wrapper.find('.js-clear-user-status-button'); + const findNoEmojiPlaceholder = () => wrapper.find('.js-no-emoji-placeholder'); + const findToggleEmojiButton = () => wrapper.find('.js-toggle-emoji-menu'); + const findAvailabilityCheckbox = () => wrapper.find(GlFormCheckbox); + + const initModal = ({ mockOnUpdateSuccess = true, mockOnUpdateFailure = true } = {}) => { + const modal = findModal(); + // mock internal emoji methods + wrapper.vm.showEmojiMenu = jest.fn(); + wrapper.vm.hideEmojiMenu = jest.fn(); + if (mockOnUpdateSuccess) wrapper.vm.onUpdateSuccess = jest.fn(); + if (mockOnUpdateFailure) wrapper.vm.onUpdateFail = jest.fn(); + + modal.vm.$emit('shown'); + return wrapper.vm.$nextTick(); + }; + + beforeEach(async () => { + mockEmoji = await initEmojiMock(); + wrapper = createComponent(); + return initModal(); + }); + + afterEach(() => { + wrapper.destroy(); + mockEmoji.restore(); + }); + + describe('with minimum props', () => { + it('sets the hidden status emoji field', () => { + const field = findFormField('emoji'); + expect(field.exists()).toBe(true); + expect(field.element.value).toBe(defaultEmoji); + }); + + it('sets the message field', () => { + const field = findFormField('message'); + expect(field.exists()).toBe(true); + expect(field.element.value).toBe(defaultMessage); + }); + + it('sets the availability field to false', () => { + const field = findAvailabilityCheckbox(); + expect(field.exists()).toBe(true); + expect(field.element.checked).toBeUndefined(); + }); + + it('has a clear status button', () => { + expect(findClearStatusButton().isVisible()).toBe(true); + }); + + it('clicking the toggle emoji button displays the emoji list', () => { + expect(wrapper.vm.showEmojiMenu).not.toHaveBeenCalled(); + findToggleEmojiButton().trigger('click'); + expect(wrapper.vm.showEmojiMenu).toHaveBeenCalled(); + }); + }); + + describe('with no currentMessage set', () => { + beforeEach(async () => { + mockEmoji = await initEmojiMock(); + wrapper = createComponent({ currentMessage: '' }); + return initModal(); + }); + + it('does not set the message field', () => { + expect(findFormField('message').element.value).toBe(''); + }); + + it('hides the clear status button', () => { + expect(findClearStatusButton().isVisible()).toBe(false); + }); + + it('shows the placeholder emoji', () => { + expect(findNoEmojiPlaceholder().isVisible()).toBe(true); + }); + }); + + describe('with no currentEmoji set', () => { + beforeEach(async () => { + mockEmoji = await initEmojiMock(); + wrapper = createComponent({ currentEmoji: '' }); + return initModal(); + }); + + it('does not set the hidden status emoji field', () => { + expect(findFormField('emoji').element.value).toBe(''); + }); + + it('hides the placeholder emoji', () => { + expect(findNoEmojiPlaceholder().isVisible()).toBe(false); + }); + + describe('with no currentMessage set', () => { + beforeEach(async () => { + mockEmoji = await initEmojiMock(); + wrapper = createComponent({ currentEmoji: '', currentMessage: '' }); + return initModal(); + }); + + it('shows the placeholder emoji', () => { + expect(findNoEmojiPlaceholder().isVisible()).toBe(true); + }); + }); + }); + + describe('update status', () => { + describe('succeeds', () => { + beforeEach(() => { + jest.spyOn(Api, 'postUserStatus').mockResolvedValue(); + }); + + it('clicking "removeStatus" clears the emoji and message fields', async () => { + findModal().vm.$emit('cancel'); + await wrapper.vm.$nextTick(); + + expect(findFormField('message').element.value).toBe(''); + expect(findFormField('emoji').element.value).toBe(''); + }); + + it('clicking "setStatus" submits the user status', async () => { + findModal().vm.$emit('ok'); + await wrapper.vm.$nextTick(); + + // set the availability status + findAvailabilityCheckbox().vm.$emit('input', true); + + findModal().vm.$emit('ok'); + await wrapper.vm.$nextTick(); + + const commonParams = { emoji: defaultEmoji, message: defaultMessage }; + + expect(Api.postUserStatus).toHaveBeenCalledTimes(2); + expect(Api.postUserStatus).toHaveBeenNthCalledWith(1, { + availability: AVAILABILITY_STATUS.NOT_SET, + ...commonParams, + }); + expect(Api.postUserStatus).toHaveBeenNthCalledWith(2, { + availability: AVAILABILITY_STATUS.BUSY, + ...commonParams, + }); + }); + + it('calls the "onUpdateSuccess" handler', async () => { + findModal().vm.$emit('ok'); + await wrapper.vm.$nextTick(); + + expect(wrapper.vm.onUpdateSuccess).toHaveBeenCalled(); + }); + }); + + describe('success message', () => { + beforeEach(async () => { + mockEmoji = await initEmojiMock(); + wrapper = createComponent({ currentEmoji: '', currentMessage: '' }); + jest.spyOn(Api, 'postUserStatus').mockResolvedValue(); + return initModal({ mockOnUpdateSuccess: false }); + }); + + it('displays a toast success message', async () => { + findModal().vm.$emit('ok'); + await wrapper.vm.$nextTick(); + + expect($toast.show).toHaveBeenCalledWith('Status updated', { + position: 'top-center', + type: 'success', + }); + }); + }); + + describe('with errors', () => { + beforeEach(() => { + jest.spyOn(Api, 'postUserStatus').mockRejectedValue(); + }); + + it('calls the "onUpdateFail" handler', async () => { + findModal().vm.$emit('ok'); + await wrapper.vm.$nextTick(); + + expect(wrapper.vm.onUpdateFail).toHaveBeenCalled(); + }); + }); + + describe('error message', () => { + beforeEach(async () => { + mockEmoji = await initEmojiMock(); + wrapper = createComponent({ currentEmoji: '', currentMessage: '' }); + jest.spyOn(Api, 'postUserStatus').mockRejectedValue(); + return initModal({ mockOnUpdateFailure: false }); + }); + + it('flashes an error message', async () => { + findModal().vm.$emit('ok'); + await wrapper.vm.$nextTick(); + + expect(createFlash).toHaveBeenCalledWith( + "Sorry, we weren't able to set your status. Please try again later.", + ); + }); + }); + }); + + describe('with canSetUserAvailability=false', () => { + beforeEach(async () => { + mockEmoji = await initEmojiMock(); + wrapper = createComponent({ canSetUserAvailability: false }); + return initModal(); + }); + + it('hides the set availability checkbox', () => { + expect(findAvailabilityCheckbox().exists()).toBe(false); + }); + }); +}); diff --git a/spec/frontend/set_status_modal/user_availability_status_spec.js b/spec/frontend/set_status_modal/user_availability_status_spec.js new file mode 100644 index 00000000000..95ca0251ce0 --- /dev/null +++ b/spec/frontend/set_status_modal/user_availability_status_spec.js @@ -0,0 +1,31 @@ +import { shallowMount } from '@vue/test-utils'; +import UserAvailabilityStatus from '~/set_status_modal/components/user_availability_status.vue'; +import { AVAILABILITY_STATUS } from '~/set_status_modal/utils'; + +describe('UserAvailabilityStatus', () => { + let wrapper; + + const createComponent = (props = {}) => { + return shallowMount(UserAvailabilityStatus, { + propsData: { + ...props, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + describe('with availability status', () => { + it(`set to ${AVAILABILITY_STATUS.BUSY}`, () => { + wrapper = createComponent({ availability: AVAILABILITY_STATUS.BUSY }); + expect(wrapper.text()).toContain('(Busy)'); + }); + + it(`set to ${AVAILABILITY_STATUS.NOT_SET}`, () => { + wrapper = createComponent({ availability: AVAILABILITY_STATUS.NOT_SET }); + expect(wrapper.html()).toBe(''); + }); + }); +}); diff --git a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js index c208d7b0226..7d58a865ba3 100644 --- a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js +++ b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js @@ -1,6 +1,8 @@ import { GlDeprecatedSkeletonLoading as GlSkeletonLoading, GlSprintf, GlIcon } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import UserPopover from '~/vue_shared/components/user_popover/user_popover.vue'; +import UserAvailabilityStatus from '~/set_status_modal/components/user_availability_status.vue'; +import { AVAILABILITY_STATUS } from '~/set_status_modal/utils'; const DEFAULT_PROPS = { user: { @@ -34,6 +36,7 @@ describe('User Popover Component', () => { const findByTestId = testid => wrapper.find(`[data-testid="${testid}"]`); const findUserStatus = () => wrapper.find('.js-user-status'); const findTarget = () => document.querySelector('.js-user-link'); + const findAvailabilityStatus = () => wrapper.find(UserAvailabilityStatus); const createWrapper = (props = {}, options = {}) => { wrapper = shallowMount(UserPopover, { @@ -43,7 +46,8 @@ describe('User Popover Component', () => { ...props, }, stubs: { - 'gl-sprintf': GlSprintf, + GlSprintf, + UserAvailabilityStatus, }, ...options, }); @@ -199,6 +203,30 @@ describe('User Popover Component', () => { expect(findUserStatus().exists()).toBe(false); }); + + it('should show the busy status if user set to busy', () => { + const user = { + ...DEFAULT_PROPS.user, + status: { availability: AVAILABILITY_STATUS.BUSY }, + }; + + createWrapper({ user }); + + expect(findAvailabilityStatus().exists()).toBe(true); + expect(wrapper.text()).toContain(user.name); + expect(wrapper.text()).toContain('(Busy)'); + }); + + it('should hide the busy status for any other status', () => { + const user = { + ...DEFAULT_PROPS.user, + status: { availability: AVAILABILITY_STATUS.NOT_SET }, + }; + + createWrapper({ user }); + + expect(wrapper.text()).not.toContain('(Busy)'); + }); }); describe('security bot', () => { diff --git a/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb b/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb index ae3097c1d9e..deb5ff584cf 100644 --- a/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb +++ b/spec/graphql/resolvers/merge_request_pipelines_resolver_spec.rb @@ -14,6 +14,7 @@ RSpec.describe Resolvers::MergeRequestPipelinesResolver do sha: merge_request.diff_head_sha ) end + let_it_be(:other_project_pipeline) { create(:ci_pipeline, project: merge_request.source_project, ref: 'other-ref') } let_it_be(:other_pipeline) { create(:ci_pipeline) } let(:current_user) { create(:user) } diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index 302ab0cc137..6c5855eeb91 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -9,6 +9,7 @@ RSpec.describe MarkupHelper do project.add_maintainer(user) user end + let_it_be(:issue) { create(:issue, project: project) } let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let_it_be(:snippet) { create(:project_snippet, project: project) } diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index c213ad7ee59..99cdee6dbb2 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -221,4 +221,42 @@ RSpec.describe PageLayoutHelper do end end end + + describe '#user_status_properties' do + using RSpec::Parameterized::TableSyntax + + let(:user) { build(:user) } + + availability_types = Types::AvailabilityEnum.enum + + where(:message, :emoji, :availability) do + "Some message" | UserStatus::DEFAULT_EMOJI | availability_types[:busy] + "Some message" | UserStatus::DEFAULT_EMOJI | availability_types[:not_set] + "Some message" | "basketball" | availability_types[:busy] + "Some message" | "basketball" | availability_types[:not_set] + "Some message" | "" | availability_types[:busy] + "Some message" | "" | availability_types[:not_set] + "" | UserStatus::DEFAULT_EMOJI | availability_types[:busy] + "" | UserStatus::DEFAULT_EMOJI | availability_types[:not_set] + "" | "basketball" | availability_types[:busy] + "" | "basketball" | availability_types[:not_set] + "" | "" | availability_types[:busy] + "" | "" | availability_types[:not_set] + end + + with_them do + it "sets the default user status fields" do + user.status = UserStatus.new(message: message, emoji: emoji, availability: availability) + result = { + can_set_user_availability: true, + current_availability: availability, + current_emoji: emoji, + current_message: message, + default_emoji: UserStatus::DEFAULT_EMOJI + } + + expect(helper.user_status_properties(user)).to eq(result) + end + end + end end diff --git a/spec/helpers/profiles_helper_spec.rb b/spec/helpers/profiles_helper_spec.rb index 61b7ff94edb..9687d038162 100644 --- a/spec/helpers/profiles_helper_spec.rb +++ b/spec/helpers/profiles_helper_spec.rb @@ -80,6 +80,38 @@ RSpec.describe ProfilesHelper do end end + describe "#user_status_set_to_busy?" do + using RSpec::Parameterized::TableSyntax + + where(:availability, :result) do + "busy" | true + "not_set" | false + "" | false + nil | false + end + + with_them do + it { expect(helper.user_status_set_to_busy?(OpenStruct.new(availability: availability))).to eq(result) } + end + end + + describe "#show_status_emoji?" do + using RSpec::Parameterized::TableSyntax + + where(:message, :emoji, :result) do + "Some message" | UserStatus::DEFAULT_EMOJI | true + "Some message" | "" | true + "" | "basketball" | true + "" | "basketball" | true + "" | UserStatus::DEFAULT_EMOJI | false + "" | UserStatus::DEFAULT_EMOJI | false + end + + with_them do + it { expect(helper.show_status_emoji?(OpenStruct.new(message: message, emoji: emoji))).to eq(result) } + end + end + def stub_cas_omniauth_provider provider = OpenStruct.new( 'name' => 'cas3', diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb index 6b658a475b1..9481d756c16 100644 --- a/spec/helpers/todos_helper_spec.rb +++ b/spec/helpers/todos_helper_spec.rb @@ -12,6 +12,7 @@ RSpec.describe TodosHelper do project: issue.project, note: 'I am note, hear me roar') end + let_it_be(:design_todo) do create(:todo, :mentioned, user: user, @@ -20,6 +21,7 @@ RSpec.describe TodosHelper do author: author, note: note) end + let_it_be(:alert_todo) do alert = create(:alert_management_alert, iid: 1001) create(:todo, target: alert) diff --git a/spec/lib/banzai/reference_parser/design_parser_spec.rb b/spec/lib/banzai/reference_parser/design_parser_spec.rb index 92d3a4aaad2..a9cb2952c26 100644 --- a/spec/lib/banzai/reference_parser/design_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/design_parser_spec.rb @@ -29,9 +29,11 @@ RSpec.describe Banzai::ReferenceParser::DesignParser do let_it_be(:other_project_link) do design_link(create(:design, :with_versions)) end + let_it_be(:public_link) do design_link(create(:design, :with_versions, issue: create(:issue, project: public_project))) end + let_it_be(:public_but_confidential_link) do design_link(create(:design, :with_versions, issue: create(:issue, :confidential, project: public_project))) end diff --git a/spec/lib/gitlab/chat/output_spec.rb b/spec/lib/gitlab/chat/output_spec.rb index 38e17c39fad..34f6bc0904c 100644 --- a/spec/lib/gitlab/chat/output_spec.rb +++ b/spec/lib/gitlab/chat/output_spec.rb @@ -8,62 +8,67 @@ RSpec.describe Gitlab::Chat::Output do end let(:output) { described_class.new(build) } + let(:trace) { Gitlab::Ci::Trace.new(build) } + + before do + trace.set("\e[0KRunning with gitlab-runner 13.4.0~beta.108.g2ed41114 (2ed41114) +\e[0;m\e[0K on GDK local runner g_XWCUS4 +\e[0;msection_start:1604068171:resolve_secrets\r\e[0K\e[0K\e[36;1mResolving secrets\e[0;m +\e[0;msection_end:1604068171:resolve_secrets\r\e[0Ksection_start:1604068171:prepare_executor\r\e[0K\e[0K\e[36;1mPreparing the \"docker\" executor\e[0;m +\e[0;m\e[0KUsing Docker executor with image ubuntu:20.04 ... +\e[0;m\e[0KUsing locally found image version due to if-not-present pull policy +\e[0;m\e[0KUsing docker image sha256:d70eaf7277eada08fca944de400e7e4dd97b1262c06ed2b1011500caa4decaf1 for ubuntu:20.04 with digest ubuntu@sha256:fff16eea1a8ae92867721d90c59a75652ea66d29c05294e6e2f898704bdb8cf1 ... +\e[0;msection_end:1604068172:prepare_executor\r\e[0Ksection_start:1604068172:prepare_script\r\e[0K\e[0K\e[36;1mPreparing environment\e[0;m +\e[0;mRunning on runner-gxwcus4-project-21-concurrent-0 via MacBook-Pro.local... +section_end:1604068173:prepare_script\r\e[0Ksection_start:1604068173:get_sources\r\e[0K\e[0K\e[36;1mGetting source from Git repository\e[0;m +\e[0;m\e[32;1mFetching changes with git depth set to 50...\e[0;m +Initialized empty Git repository in /builds/267388-group-1/playground/.git/ +\e[32;1mCreated fresh repository.\e[0;m +\e[32;1mChecking out 6c8eb7f4 as master...\e[0;m + +\e[32;1mSkipping Git submodules setup\e[0;m +section_end:1604068175:get_sources\r\e[0Ksection_start:1604068175:step_script\r\e[0K\e[0K\e[36;1mExecuting \"step_script\" stage of the job script\e[0;m +\e[0;m\e[32;1m$ echo \"success!\"\e[0;m +success! +section_end:1604068175:step_script\r\e[0Ksection_start:1604068175:chat_reply\r\033[0K +Chat Reply +section_end:1604068176:chat_reply\r\033[0K\e[32;1mJob succeeded +\e[0;m") + end describe '#to_s' do - it 'returns the build output as a String' do - trace = Gitlab::Ci::Trace.new(build) - - trace.set("echo hello\nhello") - - allow(build) - .to receive(:trace) - .and_return(trace) - - allow(output) - .to receive(:read_offset_and_length) - .and_return([0, 13]) - - expect(output.to_s).to eq('he') + it 'returns the chat reply as a String' do + expect(output.to_s).to eq("Chat Reply") end - end - describe '#read_offset_and_length' do context 'without the chat_reply trace section' do - it 'falls back to using the build_script trace section' do - expect(output) - .to receive(:find_build_trace_section) - .with('chat_reply') - .and_return(nil) - - expect(output) - .to receive(:find_build_trace_section) - .with('build_script') - .and_return({ name: 'build_script', byte_start: 1, byte_end: 4 }) - - expect(output.read_offset_and_length).to eq([1, 3]) + before do + trace.set(trace.raw.gsub('chat_reply', 'not_found')) end - end - context 'without the build_script trace section' do - it 'raises MissingBuildSectionError' do - expect { output.read_offset_and_length } - .to raise_error(described_class::MissingBuildSectionError) + it 'falls back to using the step_script trace section' do + expect(output.to_s).to eq("\e[0;m\e[32;1m$ echo \"success!\"\e[0;m\nsuccess!") end - end - - context 'with the chat_reply trace section' do - it 'returns the read offset and length as an Array' do - trace = Gitlab::Ci::Trace.new(build) - - allow(build) - .to receive(:trace) - .and_return(trace) - - allow(trace) - .to receive(:extract_sections) - .and_return([{ name: 'chat_reply', byte_start: 1, byte_end: 4 }]) - expect(output.read_offset_and_length).to eq([1, 3]) + context 'without the step_script trace section' do + before do + trace.set(trace.raw.gsub('step_script', 'build_script')) + end + + it 'falls back to using the build_script trace section' do + expect(output.to_s).to eq("\e[0;m\e[32;1m$ echo \"success!\"\e[0;m\nsuccess!") + end + + context 'without the build_script trace section' do + before do + trace.set(trace.raw.gsub('build_script', 'not_found')) + end + + it 'raises MissingBuildSectionError' do + expect { output.to_s } + .to raise_error(described_class::MissingBuildSectionError) + end + end end end end diff --git a/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb b/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb index 949cfb5a34d..762687beedb 100644 --- a/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb +++ b/spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb @@ -19,6 +19,7 @@ RSpec.describe Gitlab::ImportExport::JSON::StreamingSerializer do group: group, approvals_before_merge: 1) end + let_it_be(:issue) do create(:issue, assignees: [user], diff --git a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb index b6a396afd61..fd3b71deb37 100644 --- a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb @@ -973,6 +973,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do create(:project, :builds_disabled, :issues_disabled, { name: 'project', path: 'project' }) end + let(:shared) { project.import_export_shared } let(:project_tree_restorer) { described_class.new(user: user, shared: shared, project: project) } diff --git a/spec/lib/gitlab/relative_positioning/mover_spec.rb b/spec/lib/gitlab/relative_positioning/mover_spec.rb index dafd34585a8..cbb15ae876d 100644 --- a/spec/lib/gitlab/relative_positioning/mover_spec.rb +++ b/spec/lib/gitlab/relative_positioning/mover_spec.rb @@ -32,6 +32,7 @@ RSpec.describe RelativePositioning::Mover do let_it_be(:one_free_space_set) do indices.drop(1).map { |iid| create(:issue, project: one_free_space, iid: iid.succ) } end + let_it_be(:three_sibs_set) do [1, 2, 3].map { |iid| create(:issue, iid: iid, project: three_sibs) } end diff --git a/spec/migrations/reseed_merge_trains_enabled_spec.rb b/spec/migrations/reseed_merge_trains_enabled_spec.rb new file mode 100644 index 00000000000..71ef0b47da9 --- /dev/null +++ b/spec/migrations/reseed_merge_trains_enabled_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' +require Rails.root.join('db', 'migrate', '20201112195322_reseed_merge_trains_enabled.rb') + +RSpec.describe ReseedMergeTrainsEnabled do + describe 'migrate' do + let(:project_ci_cd_settings) { table(:project_ci_cd_settings) } + let(:projects) { table(:projects) } + let(:namespaces) { table(:namespaces) } + + context 'when on Gitlab.com' do + before do + namespace = namespaces.create!(name: 'hello', path: 'hello/') + project1 = projects.create!(namespace_id: namespace.id) + project2 = projects.create!(namespace_id: namespace.id) + project_ci_cd_settings.create!(project_id: project1.id, merge_pipelines_enabled: true) + project_ci_cd_settings.create!(project_id: project2.id, merge_pipelines_enabled: false) + end + + it 'updates merge_trains_enabled to true for where merge_pipelines_enabled is true' do + expect { migrate! }.to change(project_ci_cd_settings.where(merge_trains_enabled: true), :count).by(1) + end + end + end +end diff --git a/spec/models/pages/lookup_path_spec.rb b/spec/models/pages/lookup_path_spec.rb index bd890a71dfd..f8ebc237577 100644 --- a/spec/models/pages/lookup_path_spec.rb +++ b/spec/models/pages/lookup_path_spec.rb @@ -65,11 +65,18 @@ RSpec.describe Pages::LookupPath do project.pages_metadatum.update!(pages_deployment: deployment) end - it 'uses deployment from object storage', :aggregate_failures do + it 'uses deployment from object storage' do Timecop.freeze do - expect(source[:type]).to eq('zip') - expect(source[:path]).to eq(deployment.file.url(expire_at: 1.day.from_now)) - expect(source[:path]).to include("Expires=86400") + expect(source).to( + eq({ + type: 'zip', + path: deployment.file.url(expire_at: 1.day.from_now), + global_id: "gid://gitlab/PagesDeployment/#{deployment.id}", + sha256: deployment.file_sha256, + file_size: deployment.size, + file_count: deployment.file_count + }) + ) end end @@ -78,10 +85,18 @@ RSpec.describe Pages::LookupPath do deployment.file.migrate!(::ObjectStorage::Store::LOCAL) end - it 'uses file protocol', :aggregate_failures do + it 'uses file protocol' do Timecop.freeze do - expect(source[:type]).to eq('zip') - expect(source[:path]).to eq('file://' + deployment.file.path) + expect(source).to( + eq({ + type: 'zip', + path: 'file://' + deployment.file.path, + global_id: "gid://gitlab/PagesDeployment/#{deployment.id}", + sha256: deployment.file_sha256, + file_size: deployment.size, + file_count: deployment.file_count + }) + ) end end @@ -110,11 +125,18 @@ RSpec.describe Pages::LookupPath do project.mark_pages_as_deployed(artifacts_archive: artifacts_archive) end - it 'uses artifacts object storage', :aggregate_failures do + it 'uses artifacts object storage' do Timecop.freeze do - expect(source[:type]).to eq('zip') - expect(source[:path]).to eq(artifacts_archive.file.url(expire_at: 1.day.from_now)) - expect(source[:path]).to include("Expires=86400") + expect(source).to( + eq({ + type: 'zip', + path: artifacts_archive.file.url(expire_at: 1.day.from_now), + global_id: "gid://gitlab/Ci::JobArtifact/#{artifacts_archive.id}", + sha256: artifacts_archive.file_sha256, + file_size: artifacts_archive.size, + file_count: nil + }) + ) end end @@ -123,8 +145,16 @@ RSpec.describe Pages::LookupPath do it 'uses file protocol', :aggregate_failures do Timecop.freeze do - expect(source[:type]).to eq('zip') - expect(source[:path]).to eq('file://' + artifacts_archive.file.path) + expect(source).to( + eq({ + type: 'zip', + path: 'file://' + artifacts_archive.file.path, + global_id: "gid://gitlab/Ci::JobArtifact/#{artifacts_archive.id}", + sha256: artifacts_archive.file_sha256, + file_size: artifacts_archive.size, + file_count: nil + }) + ) end end diff --git a/spec/requests/api/admin/instance_clusters_spec.rb b/spec/requests/api/admin/instance_clusters_spec.rb index 9d0661089a9..1052080aad4 100644 --- a/spec/requests/api/admin/instance_clusters_spec.rb +++ b/spec/requests/api/admin/instance_clusters_spec.rb @@ -13,6 +13,7 @@ RSpec.describe ::API::Admin::InstanceClusters do user: admin_user, projects: [project]) end + let(:project_cluster_id) { project_cluster.id } describe "GET /admin/clusters" do diff --git a/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb b/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb index ca5a9165760..72ec2b8e070 100644 --- a/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb +++ b/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb @@ -17,6 +17,7 @@ RSpec.describe 'Getting Metrics Dashboard Annotations' do let_it_be(:to_old_annotation) do create(:metrics_dashboard_annotation, environment: environment, starting_at: Time.parse(from).advance(minutes: -5), dashboard_path: path) end + let_it_be(:to_new_annotation) do create(:metrics_dashboard_annotation, environment: environment, starting_at: to.advance(minutes: 5), dashboard_path: path) end diff --git a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb index 634ce58da96..713b26a6a9b 100644 --- a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb +++ b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb @@ -20,6 +20,7 @@ RSpec.describe 'Updating an image DiffNote' do position_type: 'image' ) end + let_it_be(:updated_body) { 'Updated body' } let_it_be(:updated_width) { 50 } let_it_be(:updated_height) { 100 } diff --git a/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb b/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb index 1b654e660e3..4bce3c7fe0f 100644 --- a/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb +++ b/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb @@ -14,6 +14,7 @@ RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha) create(:design_version, issue: issue, created_designs: create_list(:design, 3, issue: issue)) end + let_it_be(:version) do create(:design_version, issue: issue, modified_designs: old_version.designs, diff --git a/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb b/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb index 640ac95cd86..ee0085718b3 100644 --- a/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb +++ b/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb @@ -11,12 +11,15 @@ RSpec.describe 'Getting versions related to an issue' do let_it_be(:version_a) do create(:design_version, issue: issue) end + let_it_be(:version_b) do create(:design_version, issue: issue) end + let_it_be(:version_c) do create(:design_version, issue: issue) end + let_it_be(:version_d) do create(:design_version, issue: issue) end diff --git a/spec/requests/api/graphql/project/jira_import_spec.rb b/spec/requests/api/graphql/project/jira_import_spec.rb index 1cc30b95162..98a3f08baa6 100644 --- a/spec/requests/api/graphql/project/jira_import_spec.rb +++ b/spec/requests/api/graphql/project/jira_import_spec.rb @@ -19,6 +19,7 @@ RSpec.describe 'query Jira import data' do total_issue_count: 4 ) end + let_it_be(:jira_import2) do create( :jira_import_state, :finished, @@ -31,6 +32,7 @@ RSpec.describe 'query Jira import data' do total_issue_count: 3 ) end + let(:query) do %( query { diff --git a/spec/requests/api/graphql/user/group_member_query_spec.rb b/spec/requests/api/graphql/user/group_member_query_spec.rb index 3a16d962214..e47cef8cc37 100644 --- a/spec/requests/api/graphql/user/group_member_query_spec.rb +++ b/spec/requests/api/graphql/user/group_member_query_spec.rb @@ -19,6 +19,7 @@ RSpec.describe 'GroupMember' do } HEREDOC end + let_it_be(:query) do graphql_query_for('user', { id: member.user.to_global_id.to_s }, query_graphql_field("groupMemberships", {}, fields)) end diff --git a/spec/requests/api/graphql/user/project_member_query_spec.rb b/spec/requests/api/graphql/user/project_member_query_spec.rb index 0790e148caf..01827e94d5d 100644 --- a/spec/requests/api/graphql/user/project_member_query_spec.rb +++ b/spec/requests/api/graphql/user/project_member_query_spec.rb @@ -19,6 +19,7 @@ RSpec.describe 'ProjectMember' do } HEREDOC end + let_it_be(:query) do graphql_query_for('user', { id: member.user.to_global_id.to_s }, query_graphql_field("projectMemberships", {}, fields)) end diff --git a/spec/requests/api/graphql/user_query_spec.rb b/spec/requests/api/graphql/user_query_spec.rb index d64fd3868c2..738e120549e 100644 --- a/spec/requests/api/graphql/user_query_spec.rb +++ b/spec/requests/api/graphql/user_query_spec.rb @@ -32,22 +32,27 @@ RSpec.describe 'getting user information' do create(:merge_request, :unique_branches, :unique_author, source_project: project_a, assignees: [user]) end + let_it_be(:assigned_mr_b) do create(:merge_request, :unique_branches, :unique_author, source_project: project_b, assignees: [user]) end + let_it_be(:assigned_mr_c) do create(:merge_request, :unique_branches, :unique_author, source_project: project_b, assignees: [user]) end + let_it_be(:authored_mr) do create(:merge_request, :unique_branches, source_project: project_a, author: user) end + let_it_be(:authored_mr_b) do create(:merge_request, :unique_branches, source_project: project_b, author: user) end + let_it_be(:authored_mr_c) do create(:merge_request, :unique_branches, source_project: project_b, author: user) diff --git a/spec/requests/api/internal/pages_spec.rb b/spec/requests/api/internal/pages_spec.rb index 7f17f22b007..9a63e2a8ed5 100644 --- a/spec/requests/api/internal/pages_spec.rb +++ b/spec/requests/api/internal/pages_spec.rb @@ -191,6 +191,7 @@ RSpec.describe API::Internal::Pages do expect(json_response['certificate']).to eq(pages_domain.certificate) expect(json_response['key']).to eq(pages_domain.key) + deployment = project.pages_metadatum.pages_deployment expect(json_response['lookup_paths']).to eq( [ { @@ -200,7 +201,11 @@ RSpec.describe API::Internal::Pages do 'prefix' => '/', 'source' => { 'type' => 'zip', - 'path' => project.pages_metadatum.pages_deployment.file.url(expire_at: 1.day.from_now) + 'path' => deployment.file.url(expire_at: 1.day.from_now), + 'global_id' => "gid://gitlab/PagesDeployment/#{deployment.id}", + 'sha256' => deployment.file_sha256, + 'file_size' => deployment.size, + 'file_count' => deployment.file_count } } ] @@ -227,6 +232,7 @@ RSpec.describe API::Internal::Pages do expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('internal/pages/virtual_domain') + deployment = project.pages_metadatum.pages_deployment expect(json_response['lookup_paths']).to eq( [ { @@ -236,7 +242,11 @@ RSpec.describe API::Internal::Pages do 'prefix' => '/myproject/', 'source' => { 'type' => 'zip', - 'path' => project.pages_metadatum.pages_deployment.file.url(expire_at: 1.day.from_now) + 'path' => deployment.file.url(expire_at: 1.day.from_now), + 'global_id' => "gid://gitlab/PagesDeployment/#{deployment.id}", + 'sha256' => deployment.file_sha256, + 'file_size' => deployment.size, + 'file_count' => deployment.file_count } } ] @@ -268,6 +278,7 @@ RSpec.describe API::Internal::Pages do expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('internal/pages/virtual_domain') + deployment = project.pages_metadatum.pages_deployment expect(json_response['lookup_paths']).to eq( [ { @@ -277,7 +288,11 @@ RSpec.describe API::Internal::Pages do 'prefix' => '/', 'source' => { 'type' => 'zip', - 'path' => project.pages_metadatum.pages_deployment.file.url(expire_at: 1.day.from_now) + 'path' => deployment.file.url(expire_at: 1.day.from_now), + 'global_id' => "gid://gitlab/PagesDeployment/#{deployment.id}", + 'sha256' => deployment.file_sha256, + 'file_size' => deployment.size, + 'file_count' => deployment.file_count } } ] diff --git a/spec/requests/api/issues/get_project_issues_spec.rb b/spec/requests/api/issues/get_project_issues_spec.rb index 4228ca2d5fd..da0bae8d5e7 100644 --- a/spec/requests/api/issues/get_project_issues_spec.rb +++ b/spec/requests/api/issues/get_project_issues_spec.rb @@ -54,11 +54,13 @@ RSpec.describe API::Issues do let_it_be(:label) do create(:label, title: 'label', color: '#FFAABB', project: project) end + let!(:label_link) { create(:label_link, label: label, target: issue) } let(:milestone) { create(:milestone, title: '1.0.0', project: project) } let_it_be(:empty_milestone) do create(:milestone, title: '2.0.0', project: project) end + let!(:note) { create(:note_on_issue, author: user, project: project, noteable: issue) } let(:no_milestone_title) { 'None' } diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb index b8cbddd9ed4..0fe68be027c 100644 --- a/spec/requests/api/issues/issues_spec.rb +++ b/spec/requests/api/issues/issues_spec.rb @@ -54,11 +54,13 @@ RSpec.describe API::Issues do let_it_be(:label) do create(:label, title: 'label', color: '#FFAABB', project: project) end + let!(:label_link) { create(:label_link, label: label, target: issue) } let(:milestone) { create(:milestone, title: '1.0.0', project: project) } let_it_be(:empty_milestone) do create(:milestone, title: '2.0.0', project: project) end + let!(:note) { create(:note_on_issue, author: user, project: project, noteable: issue) } let(:no_milestone_title) { 'None' } diff --git a/spec/requests/api/issues/post_projects_issues_spec.rb b/spec/requests/api/issues/post_projects_issues_spec.rb index a7fe4d4509a..5b3e2363669 100644 --- a/spec/requests/api/issues/post_projects_issues_spec.rb +++ b/spec/requests/api/issues/post_projects_issues_spec.rb @@ -53,11 +53,13 @@ RSpec.describe API::Issues do let_it_be(:label) do create(:label, title: 'label', color: '#FFAABB', project: project) end + let!(:label_link) { create(:label_link, label: label, target: issue) } let(:milestone) { create(:milestone, title: '1.0.0', project: project) } let_it_be(:empty_milestone) do create(:milestone, title: '2.0.0', project: project) end + let!(:note) { create(:note_on_issue, author: user, project: project, noteable: issue) } let(:no_milestone_title) { 'None' } diff --git a/spec/requests/projects/metrics/dashboards/builder_spec.rb b/spec/requests/projects/metrics/dashboards/builder_spec.rb index e59ed591f63..002acca2135 100644 --- a/spec/requests/projects/metrics/dashboards/builder_spec.rb +++ b/spec/requests/projects/metrics/dashboards/builder_spec.rb @@ -32,6 +32,7 @@ RSpec.describe 'Projects::Metrics::Dashboards::BuilderController' do label: Legend Label YML end + let_it_be(:invalid_panel_yml) do <<~YML --- diff --git a/spec/rubocop/cop/line_break_around_conditional_block_spec.rb b/spec/rubocop/cop/line_break_around_conditional_block_spec.rb deleted file mode 100644 index 0a26ef49e35..00000000000 --- a/spec/rubocop/cop/line_break_around_conditional_block_spec.rb +++ /dev/null @@ -1,454 +0,0 @@ -# frozen_string_literal: true - -require 'fast_spec_helper' -require 'rubocop' -require 'rubocop/rspec/support' -require_relative '../../../rubocop/cop/line_break_around_conditional_block' - -RSpec.describe RuboCop::Cop::LineBreakAroundConditionalBlock, type: :rubocop do - include CopHelper - - subject(:cop) { described_class.new } - - shared_examples 'examples with conditional' do |conditional| - it "flags violation for #{conditional} without line break before" do - source = <<~RUBY - do_something - #{conditional} condition - do_something_more - end - RUBY - inspect_source(source) - - expect(cop.offenses.size).to eq(1) - offense = cop.offenses.first - - expect(offense.line).to eq(2) - expect(cop.highlights).to eq(["#{conditional} condition\n do_something_more\nend"]) - expect(offense.message).to eq('Add a line break around conditional blocks') - end - - it "flags violation for #{conditional} without line break after" do - source = <<~RUBY - #{conditional} condition - do_something - end - do_something_more - RUBY - inspect_source(source) - - expect(cop.offenses.size).to eq(1) - offense = cop.offenses.first - - expect(offense.line).to eq(1) - expect(cop.highlights).to eq(["#{conditional} condition\n do_something\nend"]) - expect(offense.message).to eq('Add a line break around conditional blocks') - end - - it "doesn't flag violation for #{conditional} with line break before and after" do - source = <<~RUBY - #{conditional} condition - do_something - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by a method definition" do - source = <<~RUBY - def a_method - #{conditional} condition - do_something - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by a class definition" do - source = <<~RUBY - class Foo - #{conditional} condition - do_something - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by a module definition" do - source = <<~RUBY - module Foo - #{conditional} condition - do_something - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by a begin definition" do - source = <<~RUBY - begin - #{conditional} condition - do_something - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by an assign/begin definition" do - source = <<~RUBY - @project ||= begin - #{conditional} condition - do_something - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by a block definition" do - source = <<~RUBY - on_block(param_a) do |item| - #{conditional} condition - do_something - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by a block definition with a comment" do - source = <<~RUBY - on_block(param_a) do |item| # a short comment - #{conditional} condition - do_something - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by a block definition using brackets" do - source = <<~RUBY - on_block(param_a) { |item| - #{conditional} condition - do_something - end - } - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by a comment" do - source = <<~RUBY - # a short comment - #{conditional} condition - do_something - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by an assignment" do - source = <<~RUBY - foo = - #{conditional} condition - do_something - else - do_something_more - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by a multiline comment" do - source = <<~RUBY - =begin - a multiline comment - =end - #{conditional} condition - do_something - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by another conditional" do - source = <<~RUBY - #{conditional} condition_a - #{conditional} condition_b - do_something - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by an else" do - source = <<~RUBY - if condition_a - do_something - else - #{conditional} condition_b - do_something_extra - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by an elsif" do - source = <<~RUBY - if condition_a - do_something - elsif condition_b - #{conditional} condition_c - do_something_extra - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by an ensure" do - source = <<~RUBY - def a_method - ensure - #{conditional} condition_c - do_something_extra - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by a when" do - source = <<~RUBY - case field - when value - #{conditional} condition_c - do_something_extra - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} followed by a comment" do - source = <<~RUBY - #{conditional} condition - do_something - end - # a short comment - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} followed by an end" do - source = <<~RUBY - class Foo - - #{conditional} condition - do_something - end - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} followed by an else" do - source = <<~RUBY - #{conditional} condition_a - #{conditional} condition_b - do_something - end - else - do_something_extra - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} followed by a when" do - source = <<~RUBY - case - when condition_a - #{conditional} condition_b - do_something - end - when condition_c - do_something_extra - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} followed by an elsif" do - source = <<~RUBY - if condition_a - #{conditional} condition_b - do_something - end - elsif condition_c - do_something_extra - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} preceded by a rescue" do - source = <<~RUBY - def a_method - do_something - rescue - #{conditional} condition - do_something - end - end - RUBY - - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{conditional} followed by a rescue" do - source = <<~RUBY - def a_method - #{conditional} condition - do_something - end - rescue - do_something_extra - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end - - it "autocorrects #{conditional} without line break before" do - source = <<~RUBY - do_something - #{conditional} condition - do_something_more - end - RUBY - autocorrected = autocorrect_source(source) - - expected_source = <<~RUBY - do_something - - #{conditional} condition - do_something_more - end - RUBY - expect(autocorrected).to eql(expected_source) - end - - it "autocorrects #{conditional} without line break after" do - source = <<~RUBY - #{conditional} condition - do_something - end - do_something_more - RUBY - autocorrected = autocorrect_source(source) - - expected_source = <<~RUBY - #{conditional} condition - do_something - end - - do_something_more - RUBY - expect(autocorrected).to eql(expected_source) - end - - it "autocorrects #{conditional} without line break before and after" do - source = <<~RUBY - do_something - #{conditional} condition - do_something_more - end - do_something_extra - RUBY - autocorrected = autocorrect_source(source) - - expected_source = <<~RUBY - do_something - - #{conditional} condition - do_something_more - end - - do_something_extra - RUBY - expect(autocorrected).to eql(expected_source) - end - end - - %w[if unless].each do |example| - it_behaves_like 'examples with conditional', example - end - - it "doesn't flag violation for if with elsif" do - source = <<~RUBY - if condition - do_something - elsif another_condition - do_something_more - end - RUBY - inspect_source(source) - - expect(cop.offenses).to be_empty - end -end diff --git a/spec/services/admin/propagate_integration_service_spec.rb b/spec/services/admin/propagate_integration_service_spec.rb index 5df6e5e50ff..13320528e4f 100644 --- a/spec/services/admin/propagate_integration_service_spec.rb +++ b/spec/services/admin/propagate_integration_service_spec.rb @@ -18,6 +18,7 @@ RSpec.describe Admin::PropagateIntegrationService do let_it_be(:inherited_integration) do create(:jira_service, project: create(:project), inherit_from_id: instance_integration.id) end + let_it_be(:different_type_inherited_integration) do create(:redmine_service, project: project, inherit_from_id: instance_integration.id) end diff --git a/spec/services/alert_management/create_alert_issue_service_spec.rb b/spec/services/alert_management/create_alert_issue_service_spec.rb index f2be317a13d..2834322be7b 100644 --- a/spec/services/alert_management/create_alert_issue_service_spec.rb +++ b/spec/services/alert_management/create_alert_issue_service_spec.rb @@ -12,6 +12,7 @@ RSpec.describe AlertManagement::CreateAlertIssueService do 'generatorURL' => 'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1' } end + let_it_be(:generic_alert, reload: true) { create(:alert_management_alert, :triggered, project: project, payload: payload) } let_it_be(:prometheus_alert, reload: true) { create(:alert_management_alert, :triggered, :prometheus, project: project, payload: payload) } let(:alert) { generic_alert } diff --git a/spec/services/metrics/dashboard/panel_preview_service_spec.rb b/spec/services/metrics/dashboard/panel_preview_service_spec.rb index d58dee3e7a3..2877d22d1f3 100644 --- a/spec/services/metrics/dashboard/panel_preview_service_spec.rb +++ b/spec/services/metrics/dashboard/panel_preview_service_spec.rb @@ -11,6 +11,7 @@ RSpec.describe Metrics::Dashboard::PanelPreviewService do title: test panel YML end + let_it_be(:dashboard) do { panel_groups: [ diff --git a/spec/services/notes/destroy_service_spec.rb b/spec/services/notes/destroy_service_spec.rb index f0e5b29ac9b..0859c28cbe7 100644 --- a/spec/services/notes/destroy_service_spec.rb +++ b/spec/services/notes/destroy_service_spec.rb @@ -41,6 +41,7 @@ RSpec.describe Notes::DestroyService do create(:merge_request, source_project: repo_project, target_project: repo_project) end + let_it_be(:note) do create(:diff_note_on_merge_request, project: repo_project, noteable: merge_request) diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 546b8fa1443..f9a89c6281e 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -848,6 +848,7 @@ RSpec.describe NotificationService, :mailer do noteable: design, note: "Hello #{member_and_mentioned.to_reference}, G'day #{non_member_and_mentioned.to_reference}") end + let_it_be(:note_2) do create(:diff_note_on_design, noteable: design, author: member_and_author_of_second_note) end diff --git a/spec/support/shared_contexts/design_management_shared_contexts.rb b/spec/support/shared_contexts/design_management_shared_contexts.rb index 3ff6a521338..e6ae7e03664 100644 --- a/spec/support/shared_contexts/design_management_shared_contexts.rb +++ b/spec/support/shared_contexts/design_management_shared_contexts.rb @@ -18,12 +18,14 @@ RSpec.shared_context 'four designs in three versions' do modified_designs: [], deleted_designs: []) end + let_it_be(:second_version) do create(:design_version, issue: issue, created_designs: [design_b, design_c, design_d], modified_designs: [design_a], deleted_designs: []) end + let_it_be(:third_version) do create(:design_version, issue: issue, created_designs: [], diff --git a/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb index 010c445d8df..88c31bf9cfd 100644 --- a/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb +++ b/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb @@ -23,6 +23,7 @@ RSpec.shared_context 'MergeRequestsFinder multiple projects with merge requests # We cannot use `let_it_be` here otherwise we get: # Failure/Error: allow(RepositoryForkWorker).to receive(:perform_async).and_return(true) # The use of doubles or partial doubles from rspec-mocks outside of the per-test lifecycle is not supported. + let!(:project2) do allow_gitaly_n_plus_1 do fork_project(project1, user) @@ -40,9 +41,11 @@ RSpec.shared_context 'MergeRequestsFinder multiple projects with merge requests let_it_be(:project4, reload: true) do allow_gitaly_n_plus_1 { create(:project, :repository, group: subgroup) } end + let_it_be(:project5, reload: true) do allow_gitaly_n_plus_1 { create(:project, group: subgroup) } end + let_it_be(:project6, reload: true) do allow_gitaly_n_plus_1 { create(:project, group: subgroup) } end diff --git a/spec/support/shared_contexts/requests/api/graphql/jira_import/jira_projects_context.rb b/spec/support/shared_contexts/requests/api/graphql/jira_import/jira_projects_context.rb index edc5b313220..de40b926a1c 100644 --- a/spec/support/shared_contexts/requests/api/graphql/jira_import/jira_projects_context.rb +++ b/spec/support/shared_contexts/requests/api/graphql/jira_import/jira_projects_context.rb @@ -116,6 +116,7 @@ RSpec.shared_context 'Jira projects request context' do "uuid": "14935009-f8aa-481e-94bc-f7251f320b0e" }]' end + let_it_be(:empty_jira_projects_json) do '{ "self": "https://your-domain.atlassian.net/rest/api/2/project/search?startAt=0&maxResults=2", diff --git a/spec/uploaders/gitlab_uploader_spec.rb b/spec/uploaders/gitlab_uploader_spec.rb index 72845b47a53..4e661e458ad 100644 --- a/spec/uploaders/gitlab_uploader_spec.rb +++ b/spec/uploaders/gitlab_uploader_spec.rb @@ -141,5 +141,23 @@ RSpec.describe GitlabUploader do end end end + + describe '#url_or_file_path' do + let(:options) { { expire_at: 1.day.from_now } } + + it 'returns url when in remote storage' do + expect(subject).to receive(:file_storage?).and_return(false) + expect(subject).to receive(:url).with(options).and_return("http://example.com") + + expect(subject.url_or_file_path(options)).to eq("http://example.com") + end + + it 'returns url when in remote storage' do + expect(subject).to receive(:file_storage?).and_return(true) + expect(subject).to receive(:path).and_return("/tmp/file") + + expect(subject.url_or_file_path(options)).to eq("file:///tmp/file") + end + end end end |