diff options
Diffstat (limited to 'spec')
9 files changed, 562 insertions, 180 deletions
diff --git a/spec/fixtures/api/schemas/entities/merge_request_sidebar.json b/spec/fixtures/api/schemas/entities/merge_request_sidebar.json index 214b67a9a0f..9945de8a856 100644 --- a/spec/fixtures/api/schemas/entities/merge_request_sidebar.json +++ b/spec/fixtures/api/schemas/entities/merge_request_sidebar.json @@ -2,6 +2,7 @@ "type": "object", "properties" : { "id": { "type": "integer" }, + "iid": { "type": "integer" }, "type": { "type": "string" }, "author_id": { "type": "integer" }, "project_id": { "type": "integer" }, diff --git a/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js b/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js new file mode 100644 index 00000000000..452d4cd07cc --- /dev/null +++ b/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js @@ -0,0 +1,85 @@ +import { shallowMount } from '@vue/test-utils'; +import { joinPaths } from '~/lib/utils/url_utility'; +import { TEST_HOST } from 'helpers/test_constants'; +import AssigneeAvatarLink from '~/sidebar/components/assignees/assignee_avatar_link.vue'; +import AssigneeAvatar from '~/sidebar/components/assignees/assignee_avatar.vue'; +import userDataMock from '../../user_data_mock'; + +const TOOLTIP_PLACEMENT = 'bottom'; +const { name: USER_NAME, username: USER_USERNAME } = userDataMock(); +const TEST_ISSUABLE_TYPE = 'merge_request'; + +describe('AssigneeAvatarLink component', () => { + let wrapper; + + function createComponent(props = {}) { + const propsData = { + user: userDataMock(), + showLess: true, + rootPath: TEST_HOST, + tooltipPlacement: TOOLTIP_PLACEMENT, + singleUser: false, + issuableType: TEST_ISSUABLE_TYPE, + ...props, + }; + + wrapper = shallowMount(AssigneeAvatarLink, { + propsData, + sync: false, + }); + } + + afterEach(() => { + wrapper.destroy(); + }); + + const findTooltipText = () => wrapper.attributes('data-original-title'); + + it('has the root url present in the assigneeUrl method', () => { + createComponent(); + const assigneeUrl = joinPaths(TEST_HOST, USER_USERNAME); + + expect(wrapper.attributes().href).toEqual(assigneeUrl); + }); + + it('renders assignee avatar', () => { + createComponent(); + + expect(wrapper.find(AssigneeAvatar).props()).toEqual( + expect.objectContaining({ + issuableType: TEST_ISSUABLE_TYPE, + user: userDataMock(), + }), + ); + }); + + describe.each` + issuableType | tooltipHasName | canMerge | expected + ${'merge_request'} | ${true} | ${true} | ${USER_NAME} + ${'merge_request'} | ${true} | ${false} | ${`${USER_NAME} (cannot merge)`} + ${'merge_request'} | ${false} | ${true} | ${''} + ${'merge_request'} | ${false} | ${false} | ${'Cannot merge'} + ${'issue'} | ${true} | ${true} | ${USER_NAME} + ${'issue'} | ${true} | ${false} | ${USER_NAME} + ${'issue'} | ${false} | ${true} | ${''} + ${'issue'} | ${false} | ${false} | ${''} + `( + 'with $issuableType and tooltipHasName=$tooltipHasName and canMerge=$canMerge', + ({ issuableType, tooltipHasName, canMerge, expected }) => { + beforeEach(() => { + createComponent({ + issuableType, + tooltipHasName, + user: { + ...userDataMock(), + can_merge: canMerge, + }, + }); + }); + + it('sets tooltip', () => { + expect(findTooltipText()).toBe(expected); + }); + }, + ); +}); diff --git a/spec/frontend/sidebar/components/assignees/assignee_avatar_spec.js b/spec/frontend/sidebar/components/assignees/assignee_avatar_spec.js new file mode 100644 index 00000000000..d60ae17733b --- /dev/null +++ b/spec/frontend/sidebar/components/assignees/assignee_avatar_spec.js @@ -0,0 +1,78 @@ +import { shallowMount } from '@vue/test-utils'; +import AssigneeAvatar from '~/sidebar/components/assignees/assignee_avatar.vue'; +import { TEST_HOST } from 'helpers/test_constants'; +import userDataMock from '../../user_data_mock'; + +const TEST_AVATAR = `${TEST_HOST}/avatar.png`; +const TEST_DEFAULT_AVATAR_URL = `${TEST_HOST}/default/avatar/url.png`; + +describe('AssigneeAvatar', () => { + let origGon; + let wrapper; + + function createComponent(props = {}) { + const propsData = { + user: userDataMock(), + imgSize: 24, + issuableType: 'merge_request', + ...props, + }; + + wrapper = shallowMount(AssigneeAvatar, { + propsData, + sync: false, + }); + } + + beforeEach(() => { + origGon = window.gon; + window.gon = { default_avatar_url: TEST_DEFAULT_AVATAR_URL }; + }); + + afterEach(() => { + window.gon = origGon; + wrapper.destroy(); + }); + + const findImg = () => wrapper.find('img'); + + it('does not show warning icon if assignee can merge', () => { + createComponent(); + + expect(wrapper.find('.merge-icon').exists()).toBe(false); + }); + + it('shows warning icon if assignee cannot merge', () => { + createComponent({ + user: { + can_merge: false, + }, + }); + + expect(wrapper.find('.merge-icon').exists()).toBe(true); + }); + + it('does not show warning icon for issuableType = "issue"', () => { + createComponent({ + issuableType: 'issue', + }); + + expect(wrapper.find('.merge-icon').exists()).toBe(false); + }); + + it.each` + avatar | avatar_url | expected | desc + ${TEST_AVATAR} | ${null} | ${TEST_AVATAR} | ${'with avatar'} + ${null} | ${TEST_AVATAR} | ${TEST_AVATAR} | ${'with avatar_url'} + ${null} | ${null} | ${TEST_DEFAULT_AVATAR_URL} | ${'with no avatar'} + `('$desc', ({ avatar, avatar_url, expected }) => { + createComponent({ + user: { + avatar, + avatar_url, + }, + }); + + expect(findImg().attributes('src')).toEqual(expected); + }); +}); diff --git a/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js b/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js new file mode 100644 index 00000000000..ff0c8d181b5 --- /dev/null +++ b/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js @@ -0,0 +1,189 @@ +import { shallowMount } from '@vue/test-utils'; +import CollapsedAssigneeList from '~/sidebar/components/assignees/collapsed_assignee_list.vue'; +import CollapsedAssignee from '~/sidebar/components/assignees/collapsed_assignee.vue'; +import UsersMockHelper from 'helpers/user_mock_data_helper'; + +const DEFAULT_MAX_COUNTER = 99; + +describe('CollapsedAssigneeList component', () => { + let wrapper; + + function createComponent(props = {}) { + const propsData = { + users: [], + issuableType: 'merge_request', + ...props, + }; + + wrapper = shallowMount(CollapsedAssigneeList, { + propsData, + sync: false, + }); + } + + const findNoUsersIcon = () => wrapper.find('i[aria-label=None]'); + const findAvatarCounter = () => wrapper.find('.avatar-counter'); + const findAssignees = () => wrapper.findAll(CollapsedAssignee); + const getTooltipTitle = () => wrapper.attributes('data-original-title'); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('No assignees/users', () => { + beforeEach(() => { + createComponent({ + users: [], + }); + }); + + it('has no users', () => { + expect(findNoUsersIcon().exists()).toBe(true); + }); + }); + + describe('One assignee/user', () => { + let users; + + beforeEach(() => { + users = UsersMockHelper.createNumberRandomUsers(1); + }); + + it('should not show no users icon', () => { + createComponent({ users }); + + expect(findNoUsersIcon().exists()).toBe(false); + }); + + it('has correct "cannot merge" tooltip when user cannot merge', () => { + users[0].can_merge = false; + + createComponent({ users }); + + expect(getTooltipTitle()).toContain('cannot merge'); + }); + + it('does not have "merge" word in tooltip if user can merge', () => { + users[0].can_merge = true; + + createComponent({ users }); + + expect(getTooltipTitle()).not.toContain('merge'); + }); + }); + + describe('More than one assignees/users', () => { + let users; + + beforeEach(() => { + users = UsersMockHelper.createNumberRandomUsers(2); + + createComponent({ users }); + }); + + it('has multiple-users class', () => { + expect(wrapper.classes('multiple-users')).toBe(true); + }); + + it('does not display an avatar count', () => { + expect(findAvatarCounter().exists()).toBe(false); + }); + + it('returns just two collapsed users', () => { + expect(findAssignees().length).toBe(2); + }); + }); + + describe('More than two assignees/users', () => { + let users; + let userNames; + + beforeEach(() => { + users = UsersMockHelper.createNumberRandomUsers(3); + userNames = users.map(x => x.name).join(', '); + }); + + describe('default', () => { + beforeEach(() => { + createComponent({ users }); + }); + + it('does display an avatar count', () => { + expect(findAvatarCounter().exists()).toBe(true); + expect(findAvatarCounter().text()).toEqual('+2'); + }); + + it('returns one collapsed users', () => { + expect(findAssignees().length).toBe(1); + }); + }); + + it('has corrent "no one can merge" tooltip when no one can merge', () => { + users[0].can_merge = false; + users[1].can_merge = false; + users[2].can_merge = false; + + createComponent({ + users, + }); + + expect(getTooltipTitle()).toEqual(`${userNames} (no one can merge)`); + }); + + it('has correct "cannot merge" tooltip when one user can merge', () => { + users[0].can_merge = true; + users[1].can_merge = false; + users[2].can_merge = false; + + createComponent({ + users, + }); + + expect(getTooltipTitle()).toEqual(`${userNames} (1/3 can merge)`); + }); + + it('has correct "cannot merge" tooltip when more than one user can merge', () => { + users[0].can_merge = false; + users[1].can_merge = true; + users[2].can_merge = true; + + createComponent({ + users, + }); + + expect(getTooltipTitle()).toEqual(`${userNames} (2/3 can merge)`); + }); + + it('does not have "merge" in tooltip if everyone can merge', () => { + users[0].can_merge = true; + users[1].can_merge = true; + users[2].can_merge = true; + + createComponent({ + users, + }); + + expect(getTooltipTitle()).toEqual(userNames); + }); + + it('displays the correct avatar count', () => { + users = UsersMockHelper.createNumberRandomUsers(5); + + createComponent({ + users, + }); + + expect(findAvatarCounter().text()).toEqual(`+${users.length - 1}`); + }); + + it('displays the correct avatar count via a computed property if more than default max counter', () => { + users = UsersMockHelper.createNumberRandomUsers(100); + + createComponent({ + users, + }); + + expect(findAvatarCounter().text()).toEqual(`${DEFAULT_MAX_COUNTER}+`); + }); + }); +}); diff --git a/spec/frontend/sidebar/components/assignees/collapsed_assignee_spec.js b/spec/frontend/sidebar/components/assignees/collapsed_assignee_spec.js new file mode 100644 index 00000000000..f9ca7bc1ecb --- /dev/null +++ b/spec/frontend/sidebar/components/assignees/collapsed_assignee_spec.js @@ -0,0 +1,49 @@ +import { shallowMount } from '@vue/test-utils'; +import CollapsedAssignee from '~/sidebar/components/assignees/collapsed_assignee.vue'; +import AssigneeAvatar from '~/sidebar/components/assignees/assignee_avatar.vue'; +import userDataMock from '../../user_data_mock'; + +const TEST_USER = userDataMock(); +const TEST_ISSUABLE_TYPE = 'merge_request'; + +describe('CollapsedAssignee assignee component', () => { + let wrapper; + + function createComponent(props = {}) { + const propsData = { + user: userDataMock(), + issuableType: TEST_ISSUABLE_TYPE, + ...props, + }; + + wrapper = shallowMount(CollapsedAssignee, { + propsData, + sync: false, + }); + } + + afterEach(() => { + wrapper.destroy(); + }); + + it('has author name', () => { + createComponent(); + + expect( + wrapper + .find('.author') + .text() + .trim(), + ).toEqual(TEST_USER.name); + }); + + it('has assignee avatar', () => { + createComponent(); + + expect(wrapper.find(AssigneeAvatar).props()).toEqual({ + imgSize: 24, + user: TEST_USER, + issuableType: TEST_ISSUABLE_TYPE, + }); + }); +}); diff --git a/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js b/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js new file mode 100644 index 00000000000..6398351834c --- /dev/null +++ b/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js @@ -0,0 +1,103 @@ +import { mount } from '@vue/test-utils'; +import UncollapsedAssigneeList from '~/sidebar/components/assignees/uncollapsed_assignee_list.vue'; +import AssigneeAvatarLink from '~/sidebar/components/assignees/assignee_avatar_link.vue'; +import { TEST_HOST } from 'helpers/test_constants'; +import userDataMock from '../../user_data_mock'; +import UsersMockHelper from '../../../helpers/user_mock_data_helper'; + +const DEFAULT_RENDER_COUNT = 5; + +describe('UncollapsedAssigneeList component', () => { + let wrapper; + + function createComponent(props = {}) { + const propsData = { + users: [], + rootPath: TEST_HOST, + ...props, + }; + + wrapper = mount(UncollapsedAssigneeList, { + sync: false, + propsData, + }); + } + + afterEach(() => { + wrapper.destroy(); + }); + + const findMoreButton = () => wrapper.find('.user-list-more button'); + + describe('One assignee/user', () => { + let user; + + beforeEach(() => { + user = userDataMock(); + + createComponent({ + users: [user], + }); + }); + + it('only has one user', () => { + expect(wrapper.findAll(AssigneeAvatarLink).length).toBe(1); + }); + + it('calls the AssigneeAvatarLink with the proper props', () => { + expect(wrapper.find(AssigneeAvatarLink).exists()).toBe(true); + expect(wrapper.find(AssigneeAvatarLink).props().tooltipPlacement).toEqual('left'); + }); + + it('Shows one user with avatar, username and author name', () => { + expect(wrapper.text()).toContain(user.name); + expect(wrapper.text()).toContain(`@${user.username}`); + }); + }); + + describe('n+ more label', () => { + describe('when users count is rendered users', () => { + beforeEach(() => { + createComponent({ + users: UsersMockHelper.createNumberRandomUsers(DEFAULT_RENDER_COUNT), + }); + }); + + it('does not show more label', () => { + expect(findMoreButton().exists()).toBe(false); + }); + }); + + describe('when more than rendered users', () => { + beforeEach(() => { + createComponent({ + users: UsersMockHelper.createNumberRandomUsers(DEFAULT_RENDER_COUNT + 1), + }); + }); + + it('shows "+1 more" label', () => { + expect(findMoreButton().text()).toBe('+ 1 more'); + }); + + it('shows truncated users', () => { + expect(wrapper.findAll(AssigneeAvatarLink).length).toBe(DEFAULT_RENDER_COUNT); + }); + + describe('when more button is clicked', () => { + beforeEach(() => { + findMoreButton().trigger('click'); + + return wrapper.vm.$nextTick(); + }); + + it('shows "show less" label', () => { + expect(findMoreButton().text()).toBe('- show less'); + }); + + it('shows all users', () => { + expect(wrapper.findAll(AssigneeAvatarLink).length).toBe(DEFAULT_RENDER_COUNT + 1); + }); + }); + }); + }); +}); diff --git a/spec/frontend/sidebar/user_data_mock.js b/spec/frontend/sidebar/user_data_mock.js new file mode 100644 index 00000000000..8ad70bb3499 --- /dev/null +++ b/spec/frontend/sidebar/user_data_mock.js @@ -0,0 +1,9 @@ +export default () => ({ + avatar_url: 'mock_path', + id: 1, + name: 'Root', + state: 'active', + username: 'root', + web_url: '', + can_merge: true, +}); diff --git a/spec/javascripts/sidebar/assignees_spec.js b/spec/javascripts/sidebar/assignees_spec.js index 4ae2141d5f0..a1df5389a38 100644 --- a/spec/javascripts/sidebar/assignees_spec.js +++ b/spec/javascripts/sidebar/assignees_spec.js @@ -94,115 +94,9 @@ describe('Assignee component', () => { expect(assignee.querySelector('.author').innerText.trim()).toEqual(UsersMock.user.name); }); - - it('Shows one user with avatar, username and author name', () => { - component = new AssigneeComponent({ - propsData: { - rootPath: 'http://localhost:3000/', - users: [UsersMock.user], - editable: true, - }, - }).$mount(); - - expect(component.$el.querySelector('.author-link')).not.toBeNull(); - // The image - expect(component.$el.querySelector('.author-link img').getAttribute('src')).toEqual( - UsersMock.user.avatar, - ); - // Author name - expect(component.$el.querySelector('.author-link .author').innerText.trim()).toEqual( - UsersMock.user.name, - ); - // Username - expect(component.$el.querySelector('.author-link .username').innerText.trim()).toEqual( - `@${UsersMock.user.username}`, - ); - }); - - it('has the root url present in the assigneeUrl method', () => { - component = new AssigneeComponent({ - propsData: { - rootPath: 'http://localhost:3000/', - users: [UsersMock.user], - editable: true, - }, - }).$mount(); - - expect(component.assigneeUrl(UsersMock.user).indexOf('http://localhost:3000/')).not.toEqual( - -1, - ); - }); - - it('has correct "cannot merge" tooltip when user cannot merge', () => { - const user = Object.assign({}, UsersMock.user, { can_merge: false }); - - component = new AssigneeComponent({ - propsData: { - rootPath: 'http://localhost:3000/', - users: [user], - editable: true, - issuableType: 'merge_request', - }, - }).$mount(); - - expect(component.mergeNotAllowedTooltipMessage).toEqual('Cannot merge'); - }); }); describe('Two or more assignees/users', () => { - it('has correct "cannot merge" tooltip when one user can merge', () => { - const users = UsersMockHelper.createNumberRandomUsers(3); - users[0].can_merge = true; - users[1].can_merge = false; - users[2].can_merge = false; - - component = new AssigneeComponent({ - propsData: { - rootPath: 'http://localhost:3000/', - users, - editable: true, - issuableType: 'merge_request', - }, - }).$mount(); - - expect(component.mergeNotAllowedTooltipMessage).toEqual('1/3 can merge'); - }); - - it('has correct "cannot merge" tooltip when no user can merge', () => { - const users = UsersMockHelper.createNumberRandomUsers(2); - users[0].can_merge = false; - users[1].can_merge = false; - - component = new AssigneeComponent({ - propsData: { - rootPath: 'http://localhost:3000/', - users, - editable: true, - issuableType: 'merge_request', - }, - }).$mount(); - - expect(component.mergeNotAllowedTooltipMessage).toEqual('No one can merge'); - }); - - it('has correct "cannot merge" tooltip when more than one user can merge', () => { - const users = UsersMockHelper.createNumberRandomUsers(3); - users[0].can_merge = false; - users[1].can_merge = true; - users[2].can_merge = true; - - component = new AssigneeComponent({ - propsData: { - rootPath: 'http://localhost:3000/', - users, - editable: true, - issuableType: 'merge_request', - }, - }).$mount(); - - expect(component.mergeNotAllowedTooltipMessage).toEqual('2/3 can merge'); - }); - it('has no "cannot merge" tooltip when every user can merge', () => { const users = UsersMockHelper.createNumberRandomUsers(2); users[0].can_merge = true; @@ -217,7 +111,7 @@ describe('Assignee component', () => { }, }).$mount(); - expect(component.mergeNotAllowedTooltipMessage).toEqual(null); + expect(component.collapsedTooltipTitle).not.toContain('cannot merge'); }); it('displays two assignee icons when collapsed', () => { @@ -295,8 +189,12 @@ describe('Assignee component', () => { expect(component.$el.querySelector('.user-list-more')).toBe(null); }); - it('sets tooltip container to body', () => { - const users = UsersMockHelper.createNumberRandomUsers(2); + it('shows sorted assignee where "can merge" users are sorted first', () => { + const users = UsersMockHelper.createNumberRandomUsers(3); + users[0].can_merge = false; + users[1].can_merge = false; + users[2].can_merge = true; + component = new AssigneeComponent({ propsData: { rootPath: 'http://localhost:3000', @@ -305,98 +203,46 @@ describe('Assignee component', () => { }, }).$mount(); - expect(component.$el.querySelector('.user-link').getAttribute('data-container')).toBe('body'); + expect(component.sortedAssigness[0].can_merge).toBe(true); }); - it('Shows the "show-less" assignees label', done => { - const users = UsersMockHelper.createNumberRandomUsers(6); + it('passes the sorted assignees to the uncollapsed-assignee-list', () => { + const users = UsersMockHelper.createNumberRandomUsers(3); + users[0].can_merge = false; + users[1].can_merge = false; + users[2].can_merge = true; + component = new AssigneeComponent({ propsData: { rootPath: 'http://localhost:3000', users, - editable: true, + editable: false, }, }).$mount(); - expect(component.$el.querySelectorAll('.user-item').length).toEqual( - component.defaultRenderCount, - ); - - expect(component.$el.querySelector('.user-list-more')).not.toBe(null); - const usersLabelExpectation = users.length - component.defaultRenderCount; + const userItems = component.$el.querySelectorAll('.user-list .user-item a'); - expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim()).not.toBe( - `+${usersLabelExpectation} more`, - ); - component.toggleShowLess(); - Vue.nextTick(() => { - expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim()).toBe( - '- show less', - ); - done(); - }); + expect(userItems.length).toBe(3); + expect(userItems[0].dataset.originalTitle).toBe(users[2].name); }); - it('Shows the "show-less" when "n+ more " label is clicked', done => { - const users = UsersMockHelper.createNumberRandomUsers(6); - component = new AssigneeComponent({ - propsData: { - rootPath: 'http://localhost:3000', - users, - editable: true, - }, - }).$mount(); - - component.$el.querySelector('.user-list-more .btn-link').click(); - Vue.nextTick(() => { - expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim()).toBe( - '- show less', - ); - done(); - }); - }); + it('passes the sorted assignees to the collapsed-assignee-list', () => { + const users = UsersMockHelper.createNumberRandomUsers(3); + users[0].can_merge = false; + users[1].can_merge = false; + users[2].can_merge = true; - it('gets the count of avatar via a computed property ', () => { - const users = UsersMockHelper.createNumberRandomUsers(6); component = new AssigneeComponent({ propsData: { rootPath: 'http://localhost:3000', users, - editable: true, + editable: false, }, }).$mount(); - expect(component.sidebarAvatarCounter).toEqual(`+${users.length - 1}`); - }); + const collapsedButton = component.$el.querySelector('.sidebar-collapsed-user button'); - describe('n+ more label', () => { - beforeEach(() => { - const users = UsersMockHelper.createNumberRandomUsers(6); - component = new AssigneeComponent({ - propsData: { - rootPath: 'http://localhost:3000', - users, - editable: true, - }, - }).$mount(); - }); - - it('shows "+1 more" label', () => { - expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim()).toBe( - '+ 1 more', - ); - }); - - it('shows "show less" label', done => { - component.toggleShowLess(); - - Vue.nextTick(() => { - expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim()).toBe( - '- show less', - ); - done(); - }); - }); + expect(collapsedButton.innerText.trim()).toBe(users[2].name); }); }); }); diff --git a/spec/serializers/merge_request_sidebar_basic_entity_spec.rb b/spec/serializers/merge_request_sidebar_basic_entity_spec.rb new file mode 100644 index 00000000000..b364b1a3306 --- /dev/null +++ b/spec/serializers/merge_request_sidebar_basic_entity_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe MergeRequestSidebarBasicEntity do + let(:project) { create :project, :repository } + let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } + let(:user) { create(:user) } + + let(:request) { double('request', current_user: user, project: project) } + + let(:entity) { described_class.new(merge_request, request: request).as_json } + + describe '#current_user' do + it 'contains attributes related to the current user' do + expect(entity[:current_user].keys).to contain_exactly( + :id, :name, :username, :state, :avatar_url, :web_url, :todo, + :can_edit, :can_move, :can_admin_label, :can_merge + ) + end + end +end |