diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-01 15:08:56 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-01 15:08:56 +0300 |
commit | 50d66f5ece57dcfbe074d97703691a8d3c38f4ac (patch) | |
tree | c96aa5ffd1cb73c18e53356680cb9792d24c257b /spec | |
parent | cfec4ed6fe77e4150b1ea83b87f407aa0cca944c (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
30 files changed, 371 insertions, 237 deletions
diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb index 4d419f89aa3..feb0b0b992f 100644 --- a/spec/features/boards/new_issue_spec.rb +++ b/spec/features/boards/new_issue_spec.rb @@ -60,7 +60,7 @@ RSpec.describe 'Issue Boards new issue', :js do page.within(first('.board-new-issue-form')) do find('.form-control').set('bug') - click_button 'Submit issue' + click_button 'Create issue' end wait_for_requests @@ -85,7 +85,7 @@ RSpec.describe 'Issue Boards new issue', :js do page.within(first('.board-new-issue-form')) do find('.form-control').set('bug') - click_button 'Submit issue' + click_button 'Create issue' end wait_for_requests @@ -100,7 +100,7 @@ RSpec.describe 'Issue Boards new issue', :js do page.within(first('.board-new-issue-form')) do find('.form-control').set('new issue') - click_button 'Submit issue' + click_button 'Create issue' end wait_for_requests diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index 57e88fac013..977147c3c6b 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -7,10 +7,10 @@ RSpec.describe 'Project issue boards sidebar', :js do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :public) } - let_it_be(:issue) { create(:issue, project: project, relative_position: 1) } let_it_be(:board) { create(:board, project: project) } let_it_be(:list) { create(:list, board: board, position: 0) } - let(:card) { find('.board:nth-child(1)').first('.board-card') } + + let_it_be(:issue, reload: true) { create(:issue, project: project, relative_position: 1) } before do project.add_maintainer(user) @@ -18,41 +18,17 @@ RSpec.describe 'Project issue boards sidebar', :js do sign_in(user) visit project_board_path(project, board) - wait_for_requests - end - - it 'shows sidebar when clicking issue' do - click_card(card) - - expect(page).to have_selector('.issue-boards-sidebar') - end - - it 'closes sidebar when clicking issue' do - click_card(card) - expect(page).to have_selector('.issue-boards-sidebar') - - click_card(card) - - expect(page).not_to have_selector('.issue-boards-sidebar') + wait_for_requests end - it 'closes sidebar when clicking close button' do - click_card(card) + it_behaves_like 'issue boards sidebar' - expect(page).to have_selector('.issue-boards-sidebar') - - find("[data-testid='sidebar-drawer'] .gl-drawer-close-button").click - - expect(page).not_to have_selector('.issue-boards-sidebar') + def first_card + find('.board:nth-child(1)').first("[data-testid='board_card']") end - it 'shows issue details when sidebar is open' do - click_card(card) - - page.within('.issue-boards-sidebar') do - expect(page).to have_content(issue.title) - expect(page).to have_content(issue.to_reference) - end + def click_first_issue_card + click_card(first_card) end end diff --git a/spec/features/boards/sidebar_subscription_spec.rb b/spec/features/boards/sidebar_subscription_spec.rb deleted file mode 100644 index 598fec7514e..00000000000 --- a/spec/features/boards/sidebar_subscription_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Project issue boards sidebar subscription', :js do - include BoardHelpers - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project, :public) } - let_it_be(:issue1) { create(:issue, project: project, relative_position: 1) } - let_it_be(:issue2) { create(:issue, project: project, relative_position: 2) } - let_it_be(:subscription) { create(:subscription, user: user, project: project, subscribable: issue2, subscribed: true) } - let_it_be(:board) { create(:board, project: project) } - let_it_be(:list) { create(:list, board: board, position: 0) } - let(:card1) { find('.board:nth-child(1) .board-card:nth-of-type(1)') } - let(:card2) { find('.board:nth-child(1) .board-card:nth-of-type(2)') } - - before do - stub_feature_flags(graphql_board_lists: false) - - project.add_maintainer(user) - - sign_in(user) - - visit project_board_path(project, board) - wait_for_requests - end - - context 'subscription' do - it 'changes issue subscription' do - click_card(card1) - wait_for_requests - - page.within('.subscriptions') do - find('[data-testid="subscription-toggle"] button:not(.is-checked)').click - wait_for_requests - - expect(page).to have_css('[data-testid="subscription-toggle"] button.is-checked') - end - end - - it 'has checked subscription toggle when already subscribed' do - click_card(card2) - wait_for_requests - - page.within('.subscriptions') do - find('[data-testid="subscription-toggle"] button.is-checked').click - wait_for_requests - - expect(page).to have_css('[data-testid="subscription-toggle"] button:not(.is-checked)') - end - end - end -end diff --git a/spec/features/boards/sidebar_time_tracking_spec.rb b/spec/features/boards/sidebar_time_tracking_spec.rb deleted file mode 100644 index 3ac8b93692a..00000000000 --- a/spec/features/boards/sidebar_time_tracking_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Project issue boards sidebar time tracking', :js do - include BoardHelpers - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project, :public) } - let_it_be(:board) { create(:board, project: project) } - let_it_be(:list) { create(:list, board: board, position: 0) } - let!(:issue) { create(:issue, project: project, relative_position: 1) } - let(:card) { find('.board:nth-child(1)').first('.board-card') } - - let(:application_settings) { {} } - - before do - stub_feature_flags(graphql_board_lists: false) - - project.add_maintainer(user) - - sign_in(user) - - stub_application_setting(application_settings) - - visit project_board_path(project, board) - wait_for_requests - end - - context 'time tracking' do - let(:compare_meter_tooltip) { find('.time-tracking .time-tracking-content .compare-meter')['title'] } - - before do - issue.timelogs.create!(time_spent: 14400, user: user) - issue.update!(time_estimate: 128800) - - click_card(card) - end - - it 'shows time tracking progress bar' do - expect(compare_meter_tooltip).to eq('Time remaining: 3d 7h 46m') - end - - context 'when time_tracking_limit_to_hours is true' do - let(:application_settings) { { time_tracking_limit_to_hours: true } } - - it 'shows time tracking progress bar' do - expect(compare_meter_tooltip).to eq('Time remaining: 31h 46m') - end - end - end -end diff --git a/spec/features/groups/board_spec.rb b/spec/features/groups/board_spec.rb index aab3f5e68d5..b4c60ff4fa3 100644 --- a/spec/features/groups/board_spec.rb +++ b/spec/features/groups/board_spec.rb @@ -33,7 +33,7 @@ RSpec.describe 'Group Boards' do find('.gl-new-dropdown-item button').click end - click_button 'Submit issue' + click_button 'Create issue' expect(page).to have_content(issue_title) end diff --git a/spec/features/groups/navbar_spec.rb b/spec/features/groups/navbar_spec.rb index 710755ce306..021b1af54d4 100644 --- a/spec/features/groups/navbar_spec.rb +++ b/spec/features/groups/navbar_spec.rb @@ -68,7 +68,7 @@ RSpec.describe 'Group navbar' do before do stub_config(registry: { enabled: true }) - insert_container_nav(_('Kubernetes')) + insert_container_nav visit group_path(group) end @@ -80,7 +80,7 @@ RSpec.describe 'Group navbar' do before do stub_config(dependency_proxy: { enabled: true }) - insert_dependency_proxy_nav(_('Dependency Proxy')) + insert_dependency_proxy_nav visit group_path(group) end diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb index 4ff3827b240..7dc3ee63669 100644 --- a/spec/features/projects/navbar_spec.rb +++ b/spec/features/projects/navbar_spec.rb @@ -13,6 +13,8 @@ RSpec.describe 'Project navbar' do before do insert_package_nav(_('Operations')) + insert_infrastructure_registry_nav + stub_config(registry: { enabled: false }) project.add_maintainer(user) sign_in(user) @@ -60,7 +62,7 @@ RSpec.describe 'Project navbar' do before do stub_config(registry: { enabled: true }) - insert_container_nav(_('Operations')) + insert_container_nav visit project_path(project) end diff --git a/spec/features/users/terms_spec.rb b/spec/features/users/terms_spec.rb index 7500f2fe59a..8ba79d77c22 100644 --- a/spec/features/users/terms_spec.rb +++ b/spec/features/users/terms_spec.rb @@ -121,7 +121,7 @@ RSpec.describe 'Users > Terms' do enforce_terms - click_button 'Submit issue' + click_button 'Create issue' expect(current_path).to eq(terms_path) diff --git a/spec/frontend/boards/board_new_issue_deprecated_spec.js b/spec/frontend/boards/board_new_issue_deprecated_spec.js index 3903ad201b2..3beaf870bf5 100644 --- a/spec/frontend/boards/board_new_issue_deprecated_spec.js +++ b/spec/frontend/boards/board_new_issue_deprecated_spec.js @@ -111,7 +111,7 @@ describe('Issue boards new issue form', () => { describe('submit success', () => { it('creates new issue', () => { - wrapper.setData({ title: 'submit issue' }); + wrapper.setData({ title: 'create issue' }); return Vue.nextTick() .then(submitIssue) @@ -122,7 +122,7 @@ describe('Issue boards new issue form', () => { it('enables button after submit', () => { jest.spyOn(wrapper.vm, 'submit').mockImplementation(); - wrapper.setData({ title: 'submit issue' }); + wrapper.setData({ title: 'create issue' }); return Vue.nextTick() .then(submitIssue) @@ -132,7 +132,7 @@ describe('Issue boards new issue form', () => { }); it('clears title after submit', () => { - wrapper.setData({ title: 'submit issue' }); + wrapper.setData({ title: 'create issue' }); return Vue.nextTick() .then(submitIssue) @@ -143,17 +143,17 @@ describe('Issue boards new issue form', () => { it('sets detail issue after submit', () => { expect(boardsStore.detail.issue.title).toBe(undefined); - wrapper.setData({ title: 'submit issue' }); + wrapper.setData({ title: 'create issue' }); return Vue.nextTick() .then(submitIssue) .then(() => { - expect(boardsStore.detail.issue.title).toBe('submit issue'); + expect(boardsStore.detail.issue.title).toBe('create issue'); }); }); it('sets detail list after submit', () => { - wrapper.setData({ title: 'submit issue' }); + wrapper.setData({ title: 'create issue' }); return Vue.nextTick() .then(submitIssue) @@ -164,7 +164,7 @@ describe('Issue boards new issue form', () => { it('sets detail weight after submit', () => { boardsStore.weightFeatureAvailable = true; - wrapper.setData({ title: 'submit issue' }); + wrapper.setData({ title: 'create issue' }); return Vue.nextTick() .then(submitIssue) @@ -175,7 +175,7 @@ describe('Issue boards new issue form', () => { it('does not set detail weight after submit', () => { boardsStore.weightFeatureAvailable = false; - wrapper.setData({ title: 'submit issue' }); + wrapper.setData({ title: 'create issue' }); return Vue.nextTick() .then(submitIssue) diff --git a/spec/frontend/boards/components/board_new_issue_spec.js b/spec/frontend/boards/components/board_new_issue_spec.js index 737a18294bc..e6405bbcff3 100644 --- a/spec/frontend/boards/components/board_new_issue_spec.js +++ b/spec/frontend/boards/components/board_new_issue_spec.js @@ -86,7 +86,7 @@ describe('Issue boards new issue form', () => { describe('submit success', () => { it('creates new issue', async () => { - wrapper.setData({ title: 'submit issue' }); + wrapper.setData({ title: 'create issue' }); await vm.$nextTick(); await submitIssue(); @@ -95,7 +95,7 @@ describe('Issue boards new issue form', () => { it('enables button after submit', async () => { jest.spyOn(wrapper.vm, 'submit').mockImplementation(); - wrapper.setData({ title: 'submit issue' }); + wrapper.setData({ title: 'create issue' }); await vm.$nextTick(); await submitIssue(); @@ -103,7 +103,7 @@ describe('Issue boards new issue form', () => { }); it('clears title after submit', async () => { - wrapper.setData({ title: 'submit issue' }); + wrapper.setData({ title: 'create issue' }); await vm.$nextTick(); await submitIssue(); diff --git a/spec/frontend/members/components/avatars/user_avatar_spec.js b/spec/frontend/members/components/avatars/user_avatar_spec.js index 3f4d9155c5d..5cf3a4cdc13 100644 --- a/spec/frontend/members/components/avatars/user_avatar_spec.js +++ b/spec/frontend/members/components/avatars/user_avatar_spec.js @@ -1,31 +1,25 @@ import { GlAvatarLink, GlBadge } from '@gitlab/ui'; import { within } from '@testing-library/dom'; import { mount, createWrapper } from '@vue/test-utils'; -import Vue from 'vue'; -import Vuex from 'vuex'; import UserAvatar from '~/members/components/avatars/user_avatar.vue'; import { member as memberMock, member2faEnabled, orphanedMember } from '../../mock_data'; -Vue.use(Vuex); - describe('UserAvatar', () => { let wrapper; const { user } = memberMock; - const createComponent = (propsData = {}, state = {}) => { + const createComponent = (propsData = {}, provide = {}) => { wrapper = mount(UserAvatar, { propsData: { member: memberMock, isCurrentUser: false, ...propsData, }, - store: new Vuex.Store({ - state: { - canManageMembers: true, - ...state, - }, - }), + provide: { + canManageMembers: true, + ...provide, + }, }); }; diff --git a/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js b/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js index 14b437a8c4e..326a29747ef 100644 --- a/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js +++ b/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js @@ -10,10 +10,9 @@ localVue.use(Vuex); describe('MembersFilteredSearchBar', () => { let wrapper; - const createComponent = (state) => { + const createComponent = ({ state = {}, provide = {} } = {}) => { const store = new Vuex.Store({ state: { - sourceId: 1, filteredSearchBar: { show: true, tokens: ['two_factor'], @@ -21,13 +20,17 @@ describe('MembersFilteredSearchBar', () => { placeholder: 'Filter members', recentSearchesStorageKey: 'group_members', }, - canManageMembers: true, ...state, }, }); wrapper = shallowMount(MembersFilteredSearchBar, { localVue, + provide: { + sourceId: 1, + canManageMembers: true, + ...provide, + }, store, }); }; @@ -68,14 +71,18 @@ describe('MembersFilteredSearchBar', () => { describe('when `canManageMembers` is false', () => { it('excludes 2FA token', () => { createComponent({ - filteredSearchBar: { - show: true, - tokens: ['two_factor', 'with_inherited_permissions'], - searchParam: 'search', - placeholder: 'Filter members', - recentSearchesStorageKey: 'group_members', + state: { + filteredSearchBar: { + show: true, + tokens: ['two_factor', 'with_inherited_permissions'], + searchParam: 'search', + placeholder: 'Filter members', + recentSearchesStorageKey: 'group_members', + }, + }, + provide: { + canManageMembers: false, }, - canManageMembers: false, }); expect(findFilteredSearchBar().props('tokens')).toEqual([ diff --git a/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js b/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js index 357fad741e9..390e12bc0e5 100644 --- a/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js +++ b/spec/frontend/members/components/filter_sort/sort_dropdown_spec.js @@ -15,7 +15,6 @@ describe('SortDropdown', () => { const createComponent = (state) => { const store = new Vuex.Store({ state: { - sourceId: 1, tableSortableFields: ['account', 'granted', 'expires', 'maxRole', 'lastSignIn'], filteredSearchBar: { show: true, @@ -30,6 +29,9 @@ describe('SortDropdown', () => { wrapper = mount(SortDropdown, { localVue, + provide: { + sourceId: 1, + }, store, }); }; diff --git a/spec/frontend/members/components/table/members_table_cell_spec.js b/spec/frontend/members/components/table/members_table_cell_spec.js index b7dcd2a9fae..5375ee11736 100644 --- a/spec/frontend/members/components/table/members_table_cell_spec.js +++ b/spec/frontend/members/components/table/members_table_cell_spec.js @@ -42,21 +42,21 @@ describe('MembersTableCell', () => { const createStore = (state = {}) => { return new Vuex.Store({ - state: { - sourceId: 1, - currentUserId: 1, - ...state, - }, + state, }); }; let wrapper; - const createComponent = (propsData, state = {}) => { + const createComponent = (propsData, state) => { wrapper = mount(MembersTableCell, { localVue, propsData, store: createStore(state), + provide: { + sourceId: 1, + currentUserId: 1, + }, scopedSlots: { default: ` <wrapped-component diff --git a/spec/frontend/members/components/table/members_table_spec.js b/spec/frontend/members/components/table/members_table_spec.js index cf5811e72e7..0395dc39880 100644 --- a/spec/frontend/members/components/table/members_table_spec.js +++ b/spec/frontend/members/components/table/members_table_spec.js @@ -32,17 +32,20 @@ describe('MembersTable', () => { table: { 'data-qa-selector': 'members_list' }, tr: { 'data-qa-selector': 'member_row' }, }, - sourceId: 1, - currentUserId: 1, ...state, }, }); }; - const createComponent = (state) => { + const createComponent = (state, provide = {}) => { wrapper = mount(MembersTable, { localVue, store: createStore(state), + provide: { + sourceId: 1, + currentUserId: 1, + ...provide, + }, stubs: [ 'member-avatar', 'member-source', @@ -119,7 +122,7 @@ describe('MembersTable', () => { describe('when user is not logged in', () => { it('does not render the "Actions" field', () => { - createComponent({ currentUserId: null, tableFields: ['actions'] }); + createComponent({ tableFields: ['actions'] }, { currentUserId: null }); expect(within(wrapper.element).queryByTestId('col-actions')).toBe(null); }); diff --git a/spec/frontend/members/index_spec.js b/spec/frontend/members/index_spec.js index dd3b9ddd912..f40c08401d4 100644 --- a/spec/frontend/members/index_spec.js +++ b/spec/frontend/members/index_spec.js @@ -42,33 +42,6 @@ describe('initMembersApp', () => { expect(wrapper.find(MembersApp).exists()).toBe(true); }); - it('sets `currentUserId` in Vuex store', () => { - setup(); - - expect(vm.$store.state.currentUserId).toBe(123); - }); - - describe('when `gon.current_user_id` is not set (user is not logged in)', () => { - it('sets `currentUserId` as `null` in Vuex store', () => { - window.gon = {}; - setup(); - - expect(vm.$store.state.currentUserId).toBeNull(); - }); - }); - - it('parses and sets `data-source-id` as `sourceId` in Vuex store', () => { - setup(); - - expect(vm.$store.state.sourceId).toBe(234); - }); - - it('parses and sets `data-can-manage-members` as `canManageMembers` in Vuex store', () => { - setup(); - - expect(vm.$store.state.canManageMembers).toBe(true); - }); - it('parses and sets `members` in Vuex store', () => { setup(); diff --git a/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb b/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb index 2a4478ded6b..24f5299d357 100644 --- a/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb +++ b/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb @@ -23,10 +23,10 @@ RSpec.describe Gitlab::ErrorTracking::Processor::ContextPayloadProcessor do end it 'merges the context payload into event payload', :aggregate_failures do - expect(result_hash[:user]).to eq(ip_address: '127.0.0.1', username: 'root') + expect(result_hash[:user]).to include(ip_address: '127.0.0.1', username: 'root') expect(result_hash[:tags]) - .to eq(priority: 'high', + .to include(priority: 'high', locale: 'en', program: 'test', feature_category: 'feature_a', diff --git a/spec/lib/gitlab/legacy_github_import/importer_spec.rb b/spec/lib/gitlab/legacy_github_import/importer_spec.rb index 56074147854..9a4d7bd996e 100644 --- a/spec/lib/gitlab/legacy_github_import/importer_spec.rb +++ b/spec/lib/gitlab/legacy_github_import/importer_spec.rb @@ -290,7 +290,7 @@ RSpec.describe Gitlab::LegacyGithubImport::Importer do subject { described_class.new(project) } before do - project.update(import_type: 'gitea', import_url: "#{repo_root}/foo/group/project.git") + project.update!(import_type: 'gitea', import_url: "#{repo_root}/foo/group/project.git") end it_behaves_like 'Gitlab::LegacyGithubImport::Importer#execute' do diff --git a/spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb b/spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb index 4b1e0d2c144..454bab8846c 100644 --- a/spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb +++ b/spec/lib/gitlab/legacy_github_import/issue_formatter_spec.rb @@ -152,7 +152,7 @@ RSpec.describe Gitlab::LegacyGithubImport::IssueFormatter do context 'when importing a Gitea project' do before do - project.update(import_type: 'gitea') + project.update!(import_type: 'gitea') end it_behaves_like 'Gitlab::LegacyGithubImport::IssueFormatter#attributes' diff --git a/spec/lib/gitlab/legacy_github_import/milestone_formatter_spec.rb b/spec/lib/gitlab/legacy_github_import/milestone_formatter_spec.rb index 148b59dedab..64fcc46d304 100644 --- a/spec/lib/gitlab/legacy_github_import/milestone_formatter_spec.rb +++ b/spec/lib/gitlab/legacy_github_import/milestone_formatter_spec.rb @@ -92,7 +92,7 @@ RSpec.describe Gitlab::LegacyGithubImport::MilestoneFormatter do let(:iid_attr) { :id } before do - project.update(import_type: 'gitea') + project.update!(import_type: 'gitea') end it_behaves_like 'Gitlab::LegacyGithubImport::MilestoneFormatter#attributes' diff --git a/spec/lib/gitlab/legacy_github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/legacy_github_import/pull_request_formatter_spec.rb index 3e6b9340d0b..7d8875e36c3 100644 --- a/spec/lib/gitlab/legacy_github_import/pull_request_formatter_spec.rb +++ b/spec/lib/gitlab/legacy_github_import/pull_request_formatter_spec.rb @@ -260,7 +260,7 @@ RSpec.describe Gitlab::LegacyGithubImport::PullRequestFormatter do context 'when importing a Gitea project' do before do - project.update(import_type: 'gitea') + project.update!(import_type: 'gitea') end it_behaves_like 'Gitlab::LegacyGithubImport::PullRequestFormatter#attributes' diff --git a/spec/lib/gitlab/tracking/standard_context_spec.rb b/spec/lib/gitlab/tracking/standard_context_spec.rb index 561edbd38f8..dacd08cf12b 100644 --- a/spec/lib/gitlab/tracking/standard_context_spec.rb +++ b/spec/lib/gitlab/tracking/standard_context_spec.rb @@ -58,10 +58,16 @@ RSpec.describe Gitlab::Tracking::StandardContext do end context 'with extra data' do - subject { described_class.new(foo: 'bar') } + subject { described_class.new(extra_key_1: 'extra value 1', extra_key_2: 'extra value 2') } - it 'creates a Snowplow context with the given data' do - expect(snowplow_context.to_json.dig(:data, :foo)).to eq('bar') + it 'includes extra data in `extra` hash' do + expect(snowplow_context.to_json.dig(:data, :extra)).to eq(extra_key_1: 'extra value 1', extra_key_2: 'extra value 2') + end + end + + context 'without extra data' do + it 'contains an empty `extra` hash' do + expect(snowplow_context.to_json.dig(:data, :extra)).to be_empty end end diff --git a/spec/lib/gitlab/tracking_spec.rb b/spec/lib/gitlab/tracking_spec.rb index c1e69b94406..edc19df5e37 100644 --- a/spec/lib/gitlab/tracking_spec.rb +++ b/spec/lib/gitlab/tracking_spec.rb @@ -51,7 +51,7 @@ RSpec.describe Gitlab::Tracking do expect(Gitlab::Tracking::StandardContext) .to receive(:new) - .with(project: project, user: user, namespace: namespace) + .with(project: project, user: user, namespace: namespace, extra_key_1: 'extra value 1', extra_key_2: 'extra value 2') .and_call_original expect_any_instance_of(klass).to receive(:event) do |_, category, action, args| @@ -66,7 +66,8 @@ RSpec.describe Gitlab::Tracking do end described_class.event('category', 'action', label: 'label', property: 'property', value: 1.5, - context: [other_context], project: project, user: user, namespace: namespace) + context: [other_context], project: project, user: user, namespace: namespace, + extra_key_1: 'extra value 1', extra_key_2: 'extra value 2') end end diff --git a/spec/requests/api/ci/runner/jobs_request_post_spec.rb b/spec/requests/api/ci/runner/jobs_request_post_spec.rb index aced094e219..03412fe1b66 100644 --- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb +++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb @@ -490,6 +490,36 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do { 'id' => job.id, 'name' => job.name, 'token' => job.token }, { 'id' => job2.id, 'name' => job2.name, 'token' => job2.token }) end + + describe 'preloading job_artifacts_archive' do + context 'when the feature flag is disabled' do + before do + stub_feature_flags(preload_associations_jobs_request_api_endpoint: false) + end + + it 'queries the ci_job_artifacts table multiple times' do + expect { request_job }.to exceed_all_query_limit(1).for_model(::Ci::JobArtifact) + end + + it 'queries the ci_builds table more than five times' do + expect { request_job }.to exceed_all_query_limit(5).for_model(::Ci::Build) + end + end + + context 'when the feature flag is enabled' do + before do + stub_feature_flags(preload_associations_jobs_request_api_endpoint: true) + end + + it 'queries the ci_job_artifacts table once only' do + expect { request_job }.not_to exceed_all_query_limit(1).for_model(::Ci::JobArtifact) + end + + it 'queries the ci_builds table five times' do + expect { request_job }.not_to exceed_all_query_limit(5).for_model(::Ci::Build) + end + end + end end context 'when pipeline have jobs with artifacts' do diff --git a/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb b/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb index 380e20905c6..cad3d2e3373 100644 --- a/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb +++ b/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb @@ -268,4 +268,49 @@ RSpec.describe MergeRequestPollCachedWidgetEntity do end end end + + describe 'merge_pipeline' do + it 'returns nil' do + expect(subject[:merge_pipeline]).to be_nil + end + + context 'when is merged' do + let(:resource) { create(:merged_merge_request, source_project: project, merge_commit_sha: project.commit.id) } + let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.target_branch, sha: resource.merge_commit_sha) } + + before do + project.add_maintainer(user) + end + + it 'returns merge_pipeline' do + pipeline.reload + pipeline_payload = + MergeRequests::PipelineEntity + .represent(pipeline, request: request) + .as_json + + expect(subject[:merge_pipeline]).to eq(pipeline_payload) + end + + context 'when user cannot read pipelines on target project' do + before do + project.add_guest(user) + end + + it 'returns nil' do + expect(subject[:merge_pipeline]).to be_nil + end + end + + context 'when merge_request_cached_merge_pipeline_serializer is disabled' do + before do + stub_feature_flags(merge_request_cached_merge_pipeline_serializer: false) + end + + it 'returns nil' do + expect(subject[:merge_pipeline]).to be_nil + end + end + end + end end diff --git a/spec/serializers/merge_request_poll_widget_entity_spec.rb b/spec/serializers/merge_request_poll_widget_entity_spec.rb index 3bf4f613167..9618624f226 100644 --- a/spec/serializers/merge_request_poll_widget_entity_spec.rb +++ b/spec/serializers/merge_request_poll_widget_entity_spec.rb @@ -6,9 +6,9 @@ RSpec.describe MergeRequestPollWidgetEntity do include ProjectForksHelper using RSpec::Parameterized::TableSyntax - let(:project) { create :project, :repository } - let(:resource) { create(:merge_request, source_project: project, target_project: project) } - let(:user) { create(:user) } + let_it_be(:project) { create :project, :repository } + let_it_be(:resource) { create(:merge_request, source_project: project, target_project: project) } + let_it_be(:user) { create(:user) } let(:request) { double('request', current_user: user, project: project) } @@ -22,20 +22,33 @@ RSpec.describe MergeRequestPollWidgetEntity do end describe 'merge_pipeline' do + before do + stub_feature_flags(merge_request_cached_merge_pipeline_serializer: false) + end + it 'returns nil' do expect(subject[:merge_pipeline]).to be_nil end context 'when is merged' do - let(:resource) { create(:merged_merge_request, source_project: project, merge_commit_sha: project.commit.id) } - let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.target_branch, sha: resource.merge_commit_sha) } + let_it_be(:resource) { create(:merged_merge_request, source_project: project, merge_commit_sha: project.commit.id) } + let_it_be(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.target_branch, sha: resource.merge_commit_sha) } before do project.add_maintainer(user) end + context 'when user cannot read pipelines on target project' do + before do + project.team.truncate + end + + it 'returns nil' do + expect(subject[:merge_pipeline]).to be_nil + end + end + it 'returns merge_pipeline' do - pipeline.reload pipeline_payload = MergeRequests::PipelineEntity .represent(pipeline, request: request) @@ -44,9 +57,9 @@ RSpec.describe MergeRequestPollWidgetEntity do expect(subject[:merge_pipeline]).to eq(pipeline_payload) end - context 'when user cannot read pipelines on target project' do + context 'when merge_request_cached_merge_pipeline_serializer is enabled' do before do - project.add_guest(user) + stub_feature_flags(merge_request_cached_merge_pipeline_serializer: true) end it 'returns nil' do diff --git a/spec/support/helpers/navbar_structure_helper.rb b/spec/support/helpers/navbar_structure_helper.rb index e18a708e41c..826108a63a5 100644 --- a/spec/support/helpers/navbar_structure_helper.rb +++ b/spec/support/helpers/navbar_structure_helper.rb @@ -29,7 +29,7 @@ module NavbarStructureHelper ) end - def insert_container_nav(within) + def insert_container_nav insert_after_sub_nav_item( _('Package Registry'), within: _('Packages & Registries'), @@ -37,11 +37,19 @@ module NavbarStructureHelper ) end - def insert_dependency_proxy_nav(within) + def insert_dependency_proxy_nav insert_after_sub_nav_item( _('Package Registry'), within: _('Packages & Registries'), new_sub_nav_item_name: _('Dependency Proxy') ) end + + def insert_infrastructure_registry_nav + insert_after_sub_nav_item( + _('Package Registry'), + within: _('Packages & Registries'), + new_sub_nav_item_name: _('Infrastructure Registry') + ) + end end diff --git a/spec/support/matchers/exceed_query_limit.rb b/spec/support/matchers/exceed_query_limit.rb index 7a66eff3a41..b48c7f905b2 100644 --- a/spec/support/matchers/exceed_query_limit.rb +++ b/spec/support/matchers/exceed_query_limit.rb @@ -20,6 +20,11 @@ module ExceedQueryLimitHelpers self end + def for_model(model) + table = model.table_name if model < ActiveRecord::Base + for_query(/(FROM|UPDATE|INSERT INTO|DELETE FROM)\s+"#{table}"/) + end + def show_common_queries @show_common_queries = true self diff --git a/spec/support/shared_examples/features/sidebar_shared_examples.rb b/spec/support/shared_examples/features/sidebar_shared_examples.rb new file mode 100644 index 00000000000..558536a80c6 --- /dev/null +++ b/spec/support/shared_examples/features/sidebar_shared_examples.rb @@ -0,0 +1,165 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'issue boards sidebar' do + include MobileHelpers + + before do + first_card.click + end + + it 'shows sidebar when clicking issue' do + expect(page).to have_selector('.issue-boards-sidebar') + end + + it 'closes sidebar when clicking issue' do + expect(page).to have_selector('.issue-boards-sidebar') + + first_card.click + + expect(page).not_to have_selector('.issue-boards-sidebar') + end + + it 'shows issue details when sidebar is open', :aggregate_failures do + page.within('.issue-boards-sidebar') do + expect(page).to have_content(issue.title) + expect(page).to have_content(issue.to_reference) + end + end + + context 'when clicking close button' do + before do + find("[data-testid='sidebar-drawer'] .gl-drawer-close-button").click + end + + it 'unhighlights the active issue card' do + expect(first_card[:class]).not_to include('is-active') + expect(first_card[:class]).not_to include('multi-select') + end + + it 'closes sidebar when clicking close button' do + expect(page).not_to have_selector('.issue-boards-sidebar') + end + end + + context 'in notifications subscription' do + it 'displays notifications toggle', :aggregate_failures do + page.within('[data-testid="sidebar-notifications"]') do + expect(page).to have_selector('[data-testid="notification-subscribe-toggle"]') + expect(page).to have_content('Notifications') + expect(page).not_to have_content('Notifications have been disabled by the project or group owner') + end + end + + it 'shows toggle as on then as off as user toggles to subscribe and unsubscribe', :aggregate_failures do + toggle = find('[data-testid="notification-subscribe-toggle"]') + + toggle.click + + expect(toggle).to have_css("button.is-checked") + + toggle.click + + expect(toggle).not_to have_css("button.is-checked") + end + + context 'when notifications have been disabled' do + before do + project.update_attribute(:emails_disabled, true) + + refresh_and_click_first_card + end + + it 'displays a message that notifications have been disabled' do + page.within('[data-testid="sidebar-notifications"]') do + expect(page).not_to have_selector('[data-testid="notification-subscribe-toggle"]') + expect(page).to have_content('Notifications have been disabled by the project or group owner') + end + end + end + end + + context 'in time tracking' do + it 'displays time tracking feature with default message' do + page.within('[data-testid="time-tracker"]') do + expect(page).to have_content('Time tracking') + expect(page).to have_content('No estimate or time spent') + end + end + + context 'when only spent time is recorded' do + before do + issue.timelogs.create!(time_spent: 3600, user: user) + + refresh_and_click_first_card + end + + it 'shows the total time spent only' do + page.within('[data-testid="time-tracker"]') do + expect(page).to have_content('Spent: 1h') + expect(page).not_to have_content('Estimated') + end + end + end + + context 'when only estimated time is recorded' do + before do + issue.update!(time_estimate: 3600) + + refresh_and_click_first_card + end + + it 'shows the estimated time only', :aggregate_failures do + page.within('[data-testid="time-tracker"]') do + expect(page).to have_content('Estimated: 1h') + expect(page).not_to have_content('Spent') + end + end + end + + context 'when estimated and spent times are available' do + before do + issue.timelogs.create!(time_spent: 1800, user: user) + issue.update!(time_estimate: 3600) + + refresh_and_click_first_card + end + + it 'shows time tracking progress bar' do + page.within('[data-testid="time-tracker"]') do + expect(page).to have_selector('[data-testid="timeTrackingComparisonPane"]') + end + end + + it 'shows both estimated and spent time text', :aggregate_failures do + page.within('[data-testid="time-tracker"]') do + expect(page).to have_content('Spent 30m') + expect(page).to have_content('Est 1h') + end + end + end + + context 'when limitedToHours instance option is turned on' do + before do + # 3600+3600*24 = 1d 1h or 25h + issue.timelogs.create!(time_spent: 3600 + 3600 * 24, user: user) + stub_application_setting(time_tracking_limit_to_hours: true) + + refresh_and_click_first_card + end + + it 'shows the total time spent only' do + page.within('[data-testid="time-tracker"]') do + expect(page).to have_content('Spent: 25h') + end + end + end + end + + def refresh_and_click_first_card + page.refresh + + wait_for_requests + + first_card.click + end +end diff --git a/spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb b/spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb index 6d8d9ba0754..67d87fe3c2f 100644 --- a/spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb +++ b/spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb @@ -225,6 +225,16 @@ RSpec.describe ExceedQueryLimitHelpers do expect(test_matcher.actual_count).to eq(2) end + it 'can filter specific models' do + test_matcher = TestMatcher.new.for_model(TestQueries) + test_matcher.verify_count do + TestQueries.first + TestQueries.connection.execute('select 1') + end + + expect(test_matcher.actual_count).to eq(1) + end + it 'can ignore specific queries' do test_matcher = TestMatcher.new.ignoring(/foobar/) test_matcher.verify_count do |