diff options
Diffstat (limited to 'spec')
12 files changed, 242 insertions, 76 deletions
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index fc159e1b70c..f4a5044c049 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -367,7 +367,8 @@ RSpec.describe Projects::MergeRequestsController do namespace_id: project.namespace, project_id: project, id: merge_request.iid, - merge_request: mr_params + merge_request: mr_params, + serializer: 'basic' }.merge(additional_params) put :update, params: params diff --git a/spec/frontend/environments/graphql/resolvers_spec.js b/spec/frontend/environments/graphql/resolvers_spec.js index 4d2a0818996..320e4794de0 100644 --- a/spec/frontend/environments/graphql/resolvers_spec.js +++ b/spec/frontend/environments/graphql/resolvers_spec.js @@ -1,6 +1,7 @@ import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import { resolvers } from '~/environments/graphql/resolvers'; +import pollIntervalQuery from '~/environments/graphql/queries/poll_interval.query.graphql'; import { TEST_HOST } from 'helpers/test_constants'; import { environmentsApp, resolvedEnvironmentsApp, folder, resolvedFolder } from './mock_data'; @@ -21,10 +22,27 @@ describe('~/frontend/environments/graphql/resolvers', () => { describe('environmentApp', () => { it('should fetch environments and map them to frontend data', async () => { - mock.onGet(ENDPOINT, { params: { nested: true } }).reply(200, environmentsApp); + const cache = { writeQuery: jest.fn() }; + mock.onGet(ENDPOINT, { params: { nested: true } }).reply(200, environmentsApp, {}); - const app = await mockResolvers.Query.environmentApp(); + const app = await mockResolvers.Query.environmentApp(null, null, { cache }); expect(app).toEqual(resolvedEnvironmentsApp); + expect(cache.writeQuery).toHaveBeenCalledWith({ + query: pollIntervalQuery, + data: { interval: undefined }, + }); + }); + it('should set the poll interval when there is one', async () => { + const cache = { writeQuery: jest.fn() }; + mock + .onGet(ENDPOINT, { params: { nested: true } }) + .reply(200, environmentsApp, { 'poll-interval': 3000 }); + + await mockResolvers.Query.environmentApp(null, null, { cache }); + expect(cache.writeQuery).toHaveBeenCalledWith({ + query: pollIntervalQuery, + data: { interval: 3000 }, + }); }); }); describe('folder', () => { @@ -42,7 +60,7 @@ describe('~/frontend/environments/graphql/resolvers', () => { it('should post to the stop environment path', async () => { mock.onPost(ENDPOINT).reply(200); - await mockResolvers.Mutations.stopEnvironment(null, { environment: { stopPath: ENDPOINT } }); + await mockResolvers.Mutation.stopEnvironment(null, { environment: { stopPath: ENDPOINT } }); expect(mock.history.post).toContainEqual( expect.objectContaining({ url: ENDPOINT, method: 'post' }), @@ -53,7 +71,7 @@ describe('~/frontend/environments/graphql/resolvers', () => { it('should post to the retry environment path', async () => { mock.onPost(ENDPOINT).reply(200); - await mockResolvers.Mutations.rollbackEnvironment(null, { + await mockResolvers.Mutation.rollbackEnvironment(null, { environment: { retryUrl: ENDPOINT }, }); @@ -66,7 +84,7 @@ describe('~/frontend/environments/graphql/resolvers', () => { it('should DELETE to the delete environment path', async () => { mock.onDelete(ENDPOINT).reply(200); - await mockResolvers.Mutations.deleteEnvironment(null, { + await mockResolvers.Mutation.deleteEnvironment(null, { environment: { deletePath: ENDPOINT }, }); @@ -79,7 +97,7 @@ describe('~/frontend/environments/graphql/resolvers', () => { it('should post to the auto stop path', async () => { mock.onPost(ENDPOINT).reply(200); - await mockResolvers.Mutations.cancelAutoStop(null, { + await mockResolvers.Mutation.cancelAutoStop(null, { environment: { autoStopPath: ENDPOINT }, }); diff --git a/spec/frontend/jira_connect/subscriptions/components/app_spec.js b/spec/frontend/jira_connect/subscriptions/components/app_spec.js index 8e464968453..47fe96262ee 100644 --- a/spec/frontend/jira_connect/subscriptions/components/app_spec.js +++ b/spec/frontend/jira_connect/subscriptions/components/app_spec.js @@ -5,6 +5,7 @@ import JiraConnectApp from '~/jira_connect/subscriptions/components/app.vue'; import AddNamespaceButton from '~/jira_connect/subscriptions/components/add_namespace_button.vue'; import SignInButton from '~/jira_connect/subscriptions/components/sign_in_button.vue'; import SubscriptionsList from '~/jira_connect/subscriptions/components/subscriptions_list.vue'; +import UserLink from '~/jira_connect/subscriptions/components/user_link.vue'; import createStore from '~/jira_connect/subscriptions/store'; import { SET_ALERT } from '~/jira_connect/subscriptions/store/mutation_types'; import { __ } from '~/locale'; @@ -12,6 +13,7 @@ import { mockSubscription } from '../mock_data'; jest.mock('~/jira_connect/subscriptions/utils', () => ({ retrieveAlert: jest.fn().mockReturnValue({ message: 'error message' }), + getGitlabSignInURL: jest.fn(), })); describe('JiraConnectApp', () => { @@ -83,6 +85,22 @@ describe('JiraConnectApp', () => { }); }, ); + + it('renders UserLink component', () => { + createComponent({ + provide: { + usersPath: '/user', + subscriptions: [], + }, + }); + + const userLink = wrapper.findComponent(UserLink); + expect(userLink.exists()).toBe(true); + expect(userLink.props()).toEqual({ + hasSubscriptions: false, + userSignedIn: false, + }); + }); }); describe('alert', () => { diff --git a/spec/frontend/jira_connect/subscriptions/components/user_link_spec.js b/spec/frontend/jira_connect/subscriptions/components/user_link_spec.js new file mode 100644 index 00000000000..b98a36269a3 --- /dev/null +++ b/spec/frontend/jira_connect/subscriptions/components/user_link_spec.js @@ -0,0 +1,91 @@ +import { GlSprintf } from '@gitlab/ui'; +import UserLink from '~/jira_connect/subscriptions/components/user_link.vue'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import waitForPromises from 'helpers/wait_for_promises'; + +jest.mock('~/jira_connect/subscriptions/utils', () => ({ + getGitlabSignInURL: jest.fn().mockImplementation((path) => Promise.resolve(path)), +})); + +describe('SubscriptionsList', () => { + let wrapper; + + const createComponent = (propsData = {}, { provide } = {}) => { + wrapper = shallowMountExtended(UserLink, { + propsData, + provide, + stubs: { + GlSprintf, + }, + }); + }; + + const findSignInLink = () => wrapper.findByTestId('sign-in-link'); + const findGitlabUserLink = () => wrapper.findByTestId('gitlab-user-link'); + const findSprintf = () => wrapper.findComponent(GlSprintf); + + afterEach(() => { + wrapper.destroy(); + }); + + describe.each` + userSignedIn | hasSubscriptions | expectGlSprintf | expectGlLink + ${true} | ${false} | ${true} | ${false} + ${false} | ${true} | ${false} | ${true} + ${true} | ${true} | ${true} | ${false} + ${false} | ${false} | ${false} | ${false} + `( + 'when `userSignedIn` is $userSignedIn and `hasSubscriptions` is $hasSubscriptions', + ({ userSignedIn, hasSubscriptions, expectGlSprintf, expectGlLink }) => { + it('renders template correctly', () => { + createComponent({ + userSignedIn, + hasSubscriptions, + }); + + expect(findSprintf().exists()).toBe(expectGlSprintf); + expect(findSignInLink().exists()).toBe(expectGlLink); + }); + }, + ); + + describe('sign in link', () => { + it('renders with correct href', async () => { + const mockUsersPath = '/user'; + createComponent( + { + userSignedIn: false, + hasSubscriptions: true, + }, + { provide: { usersPath: mockUsersPath } }, + ); + + await waitForPromises(); + + expect(findSignInLink().exists()).toBe(true); + expect(findSignInLink().attributes('href')).toBe(mockUsersPath); + }); + }); + + describe('gitlab user link', () => { + window.gon = { current_username: 'root' }; + + beforeEach(() => { + createComponent( + { + userSignedIn: true, + hasSubscriptions: true, + }, + { provide: { gitlabUserPath: '/root' } }, + ); + }); + + it('renders with correct href', () => { + expect(findGitlabUserLink().attributes('href')).toBe('/root'); + }); + + it('contains GitLab user handle', () => { + expect(findGitlabUserLink().text()).toBe('@root'); + }); + }); +}); diff --git a/spec/frontend/jira_connect/subscriptions/index_spec.js b/spec/frontend/jira_connect/subscriptions/index_spec.js deleted file mode 100644 index b97918a198e..00000000000 --- a/spec/frontend/jira_connect/subscriptions/index_spec.js +++ /dev/null @@ -1,36 +0,0 @@ -import { initJiraConnect } from '~/jira_connect/subscriptions'; -import { getGitlabSignInURL } from '~/jira_connect/subscriptions/utils'; - -jest.mock('~/jira_connect/subscriptions/utils'); - -describe('initJiraConnect', () => { - const mockInitialHref = 'https://gitlab.com'; - - beforeEach(() => { - setFixtures(` - <a class="js-jira-connect-sign-in" href="${mockInitialHref}">Sign In</a> - <a class="js-jira-connect-sign-in" href="${mockInitialHref}">Another Sign In</a> - `); - }); - - const assertSignInLinks = (expectedLink) => { - Array.from(document.querySelectorAll('.js-jira-connect-sign-in')).forEach((el) => { - expect(el.getAttribute('href')).toBe(expectedLink); - }); - }; - - describe('Sign in links', () => { - it('are updated on initialization', async () => { - const mockSignInLink = `https://gitlab.com?return_to=${encodeURIComponent('/test/location')}`; - getGitlabSignInURL.mockResolvedValue(mockSignInLink); - - // assert the initial state - assertSignInLinks(mockInitialHref); - - await initJiraConnect(); - - // assert the update has occurred - assertSignInLinks(mockSignInLink); - }); - }); -}); diff --git a/spec/helpers/jira_connect_helper_spec.rb b/spec/helpers/jira_connect_helper_spec.rb index 55a5c724665..0f78185dc7d 100644 --- a/spec/helpers/jira_connect_helper_spec.rb +++ b/spec/helpers/jira_connect_helper_spec.rb @@ -19,7 +19,9 @@ RSpec.describe JiraConnectHelper do is_expected.to include( :groups_path, :subscriptions_path, - :users_path + :users_path, + :subscriptions, + :gitlab_user_path ) end @@ -32,6 +34,10 @@ RSpec.describe JiraConnectHelper do expect(subject[:groups_path]).to include("#{skip_groups_param}=#{subscription.namespace.id}") end + + it 'assigns gitlab_user_path to nil' do + expect(subject[:gitlab_user_path]).to be_nil + end end context 'user is logged in' do @@ -42,6 +48,10 @@ RSpec.describe JiraConnectHelper do it 'assigns users_path to nil' do expect(subject[:users_path]).to be_nil end + + it 'assigns gitlab_user_path correctly' do + expect(subject[:gitlab_user_path]).to eq(user_path(user)) + end end end end diff --git a/spec/models/merge_request_assignee_spec.rb b/spec/models/merge_request_assignee_spec.rb index 5bb8e7184a3..58b802de8e0 100644 --- a/spec/models/merge_request_assignee_spec.rb +++ b/spec/models/merge_request_assignee_spec.rb @@ -3,9 +3,10 @@ require 'spec_helper' RSpec.describe MergeRequestAssignee do + let(:assignee) { create(:user) } let(:merge_request) { create(:merge_request) } - subject { merge_request.merge_request_assignees.build(assignee: create(:user)) } + subject { merge_request.merge_request_assignees.build(assignee: assignee) } describe 'associations' do it { is_expected.to belong_to(:merge_request).class_name('MergeRequest') } @@ -41,4 +42,13 @@ RSpec.describe MergeRequestAssignee do it_behaves_like 'having unique enum values' it_behaves_like 'having reviewer state' + + describe 'syncs to reviewer state' do + before do + reviewer = merge_request.merge_request_reviewers.build(reviewer: assignee) + reviewer.update!(state: :reviewed) + end + + it { is_expected.to have_attributes(state: 'reviewed') } + end end diff --git a/spec/models/merge_request_reviewer_spec.rb b/spec/models/merge_request_reviewer_spec.rb index d69d60c94f0..d99fd4afb0f 100644 --- a/spec/models/merge_request_reviewer_spec.rb +++ b/spec/models/merge_request_reviewer_spec.rb @@ -3,14 +3,24 @@ require 'spec_helper' RSpec.describe MergeRequestReviewer do + let(:reviewer) { create(:user) } let(:merge_request) { create(:merge_request) } - subject { merge_request.merge_request_reviewers.build(reviewer: create(:user)) } + subject { merge_request.merge_request_reviewers.build(reviewer: reviewer) } it_behaves_like 'having unique enum values' it_behaves_like 'having reviewer state' + describe 'syncs to assignee state' do + before do + assignee = merge_request.merge_request_assignees.build(assignee: reviewer) + assignee.update!(state: :reviewed) + end + + it { is_expected.to have_attributes(state: 'reviewed') } + end + describe 'associations' do it { is_expected.to belong_to(:merge_request).class_name('MergeRequest') } it { is_expected.to belong_to(:reviewer).class_name('User').inverse_of(:merge_request_reviewers) } diff --git a/spec/services/merge_requests/toggle_attention_requested_service_spec.rb b/spec/services/merge_requests/toggle_attention_requested_service_spec.rb index e2455a71eef..e5ba7bcefae 100644 --- a/spec/services/merge_requests/toggle_attention_requested_service_spec.rb +++ b/spec/services/merge_requests/toggle_attention_requested_service_spec.rb @@ -19,6 +19,8 @@ RSpec.describe MergeRequests::ToggleAttentionRequestedService do allow(NotificationService).to receive(:new) { notification_service } allow(service).to receive(:todo_service).and_return(todo_service) allow(service).to receive(:notification_service).and_return(notification_service) + allow(SystemNoteService).to receive(:request_attention) + allow(SystemNoteService).to receive(:remove_attention_request) project.add_developer(current_user) project.add_developer(user) @@ -93,6 +95,12 @@ RSpec.describe MergeRequests::ToggleAttentionRequestedService do service.execute end + + it 'creates a request attention system note' do + expect(SystemNoteService).to receive(:request_attention).with(merge_request, merge_request.project, current_user, assignee_user) + + service.execute + end end context 'assignee is the same as reviewer' do @@ -132,6 +140,12 @@ RSpec.describe MergeRequests::ToggleAttentionRequestedService do service.execute end + + it 'creates a remove attention request system note' do + expect(SystemNoteService).to receive(:remove_attention_request).with(merge_request, merge_request.project, current_user, user) + + service.execute + end end end end diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 11c6dbe92e7..3ec2c71b20c 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -146,6 +146,30 @@ RSpec.describe SystemNoteService do end end + describe '.request_attention' do + let(:user) { double } + + it 'calls IssuableService' do + expect_next_instance_of(::SystemNotes::IssuablesService) do |service| + expect(service).to receive(:request_attention).with(user) + end + + described_class.request_attention(noteable, project, author, user) + end + end + + describe '.remove_attention_request' do + let(:user) { double } + + it 'calls IssuableService' do + expect_next_instance_of(::SystemNotes::IssuablesService) do |service| + expect(service).to receive(:remove_attention_request).with(user) + end + + described_class.remove_attention_request(noteable, project, author, user) + end + end + describe '.merge_when_pipeline_succeeds' do it 'calls MergeRequestsService' do sha = double diff --git a/spec/services/system_notes/issuables_service_spec.rb b/spec/services/system_notes/issuables_service_spec.rb index 43760e296bc..7e53e66303b 100644 --- a/spec/services/system_notes/issuables_service_spec.rb +++ b/spec/services/system_notes/issuables_service_spec.rb @@ -199,6 +199,42 @@ RSpec.describe ::SystemNotes::IssuablesService do end end + describe '#request_attention' do + subject { service.request_attention(user) } + + let(:user) { create(:user) } + + it_behaves_like 'a system note' do + let(:action) { 'attention_requested' } + end + + context 'when attention requested' do + it_behaves_like 'a note with overridable created_at' + + it 'sets the note text' do + expect(subject.note).to eq "requested attention from @#{user.username}" + end + end + end + + describe '#remove_attention_request' do + subject { service.remove_attention_request(user) } + + let(:user) { create(:user) } + + it_behaves_like 'a system note' do + let(:action) { 'attention_request_removed' } + end + + context 'when attention request is removed' do + it_behaves_like 'a note with overridable created_at' + + it 'sets the note text' do + expect(subject.note).to eq "removed attention request from @#{user.username}" + end + end + end + describe '#change_title' do let(:noteable) { create(:issue, project: project, title: 'Lorem ipsum') } diff --git a/spec/views/jira_connect/subscriptions/index.html.haml_spec.rb b/spec/views/jira_connect/subscriptions/index.html.haml_spec.rb deleted file mode 100644 index 0a4d283a983..00000000000 --- a/spec/views/jira_connect/subscriptions/index.html.haml_spec.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'jira_connect/subscriptions/index.html.haml' do - let(:user) { build_stubbed(:user) } - - before do - allow(view).to receive(:current_user).and_return(user) - assign(:subscriptions, create_list(:jira_connect_subscription, 1)) - end - - context 'when the user is signed in' do - it 'shows link to user profile' do - render - - expect(rendered).to have_link(user.to_reference) - end - end - - context 'when the user is not signed in' do - let(:user) { nil } - - it 'shows "Sign in" link' do - render - - expect(rendered).to have_link('Sign in to GitLab') - end - end -end |