diff options
Diffstat (limited to 'spec/frontend/groups')
7 files changed, 254 insertions, 11 deletions
diff --git a/spec/frontend/groups/components/invite_members_banner_spec.js b/spec/frontend/groups/components/invite_members_banner_spec.js new file mode 100644 index 00000000000..95003b211fd --- /dev/null +++ b/spec/frontend/groups/components/invite_members_banner_spec.js @@ -0,0 +1,144 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlBanner } from '@gitlab/ui'; +import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; +import { setCookie, parseBoolean } from '~/lib/utils/common_utils'; +import InviteMembersBanner from '~/groups/components/invite_members_banner.vue'; + +jest.mock('~/lib/utils/common_utils'); + +const isDismissedKey = 'invite_99_1'; +const title = 'Collaborate with your team'; +const body = + "We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge"; +const svgPath = '/illustrations/background'; +const inviteMembersPath = 'groups/members'; +const buttonText = 'Invite your colleagues'; +const trackLabel = 'invite_members_banner'; + +const createComponent = (stubs = {}) => { + return shallowMount(InviteMembersBanner, { + provide: { + svgPath, + inviteMembersPath, + isDismissedKey, + trackLabel, + }, + stubs, + }); +}; + +describe('InviteMembersBanner', () => { + let wrapper; + let trackingSpy; + + beforeEach(() => { + document.body.dataset.page = 'any:page'; + trackingSpy = mockTracking('_category_', undefined, jest.spyOn); + }); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + unmockTracking(); + }); + + describe('tracking', () => { + beforeEach(() => { + wrapper = createComponent({ GlBanner }); + }); + + const trackCategory = undefined; + const displayEvent = 'invite_members_banner_displayed'; + const buttonClickEvent = 'invite_members_banner_button_clicked'; + const dismissEvent = 'invite_members_banner_dismissed'; + + it('sends the displayEvent when the banner is displayed', () => { + expect(trackingSpy).toHaveBeenCalledWith(trackCategory, displayEvent, { + label: trackLabel, + }); + }); + + it('sets the button attributes for the buttonClickEvent', () => { + const button = wrapper.find(`[href='${wrapper.vm.inviteMembersPath}']`); + + expect(button.attributes()).toMatchObject({ + 'data-track-event': buttonClickEvent, + 'data-track-label': trackLabel, + }); + }); + + it('sends the dismissEvent when the banner is dismissed', () => { + wrapper.find(GlBanner).vm.$emit('close'); + + expect(trackingSpy).toHaveBeenCalledWith(trackCategory, dismissEvent, { + label: trackLabel, + }); + }); + }); + + describe('rendering', () => { + const findBanner = () => { + return wrapper.find(GlBanner); + }; + + beforeEach(() => { + wrapper = createComponent(); + }); + + it('uses the svgPath for the banner svgpath', () => { + expect(findBanner().attributes('svgpath')).toBe(svgPath); + }); + + it('uses the title from options for title', () => { + expect(findBanner().attributes('title')).toBe(title); + }); + + it('includes the body text from options', () => { + expect(findBanner().html()).toContain(body); + }); + + it('uses the button_text text from options for buttontext', () => { + expect(findBanner().attributes('buttontext')).toBe(buttonText); + }); + + it('uses the href from inviteMembersPath for buttonlink', () => { + expect(findBanner().attributes('buttonlink')).toBe(inviteMembersPath); + }); + }); + + describe('dismissing', () => { + const findButton = () => { + return wrapper.find('button'); + }; + + beforeEach(() => { + wrapper = createComponent({ GlBanner }); + + findButton().trigger('click'); + }); + + it('sets iDismissed to true', () => { + expect(wrapper.vm.isDismissed).toBe(true); + }); + + it('sets the cookie with the isDismissedKey', () => { + expect(setCookie).toHaveBeenCalledWith(isDismissedKey, true); + }); + }); + + describe('when a dismiss cookie exists', () => { + beforeEach(() => { + parseBoolean.mockReturnValue(true); + + wrapper = createComponent({ GlBanner }); + }); + + it('sets isDismissed to true', () => { + expect(wrapper.vm.isDismissed).toBe(true); + }); + + it('does not render the banner', () => { + expect(wrapper.contains(GlBanner)).toBe(false); + }); + }); +}); diff --git a/spec/frontend/groups/components/item_actions_spec.js b/spec/frontend/groups/components/item_actions_spec.js index c0dc1a816e6..f5df8c180d5 100644 --- a/spec/frontend/groups/components/item_actions_spec.js +++ b/spec/frontend/groups/components/item_actions_spec.js @@ -57,8 +57,8 @@ describe('ItemActionsComponent', () => { expect(editBtn.getAttribute('href')).toBe(group.editPath); expect(editBtn.getAttribute('aria-label')).toBe('Edit group'); expect(editBtn.dataset.originalTitle).toBe('Edit group'); - expect(editBtn.querySelectorAll('svg use').length).not.toBe(0); - expect(editBtn.querySelector('svg use').getAttribute('xlink:href')).toContain('#settings'); + expect(editBtn.querySelectorAll('svg').length).not.toBe(0); + expect(editBtn.querySelector('svg').getAttribute('data-testid')).toBe('settings-icon'); newVm.$destroy(); }); @@ -75,8 +75,8 @@ describe('ItemActionsComponent', () => { expect(leaveBtn.getAttribute('href')).toBe(group.leavePath); expect(leaveBtn.getAttribute('aria-label')).toBe('Leave this group'); expect(leaveBtn.dataset.originalTitle).toBe('Leave this group'); - expect(leaveBtn.querySelectorAll('svg use').length).not.toBe(0); - expect(leaveBtn.querySelector('svg use').getAttribute('xlink:href')).toContain('#leave'); + expect(leaveBtn.querySelectorAll('svg').length).not.toBe(0); + expect(leaveBtn.querySelector('svg').getAttribute('data-testid')).toBe('leave-icon'); newVm.$destroy(); }); diff --git a/spec/frontend/groups/components/item_caret_spec.js b/spec/frontend/groups/components/item_caret_spec.js index bfe27be9b51..4ff7482414c 100644 --- a/spec/frontend/groups/components/item_caret_spec.js +++ b/spec/frontend/groups/components/item_caret_spec.js @@ -27,12 +27,12 @@ describe('ItemCaretComponent', () => { it('should render caret down icon if `isGroupOpen` prop is `true`', () => { vm = createComponent(true); - expect(vm.$el.querySelector('svg use').getAttribute('xlink:href')).toContain('angle-down'); + expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('angle-down-icon'); }); it('should render caret right icon if `isGroupOpen` prop is `false`', () => { vm = createComponent(); - expect(vm.$el.querySelector('svg use').getAttribute('xlink:href')).toContain('angle-right'); + expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('angle-right-icon'); }); }); }); diff --git a/spec/frontend/groups/components/item_stats_value_spec.js b/spec/frontend/groups/components/item_stats_value_spec.js index da6f145fa19..11246390444 100644 --- a/spec/frontend/groups/components/item_stats_value_spec.js +++ b/spec/frontend/groups/components/item_stats_value_spec.js @@ -72,7 +72,7 @@ describe('ItemStatsValueComponent', () => { }); it('renders element icon correctly', () => { - expect(vm.$el.querySelector('svg use').getAttribute('xlink:href')).toContain('folder'); + expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('folder-icon'); }); it('renders value count correctly', () => { diff --git a/spec/frontend/groups/components/item_type_icon_spec.js b/spec/frontend/groups/components/item_type_icon_spec.js index 251b5b5ff4c..477c413ddcd 100644 --- a/spec/frontend/groups/components/item_type_icon_spec.js +++ b/spec/frontend/groups/components/item_type_icon_spec.js @@ -27,12 +27,12 @@ describe('ItemTypeIconComponent', () => { vm = createComponent(ITEM_TYPE.GROUP, true); - expect(vm.$el.querySelector('use').getAttribute('xlink:href')).toContain('folder-open'); + expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('folder-open-icon'); vm.$destroy(); vm = createComponent(ITEM_TYPE.GROUP); - expect(vm.$el.querySelector('use').getAttribute('xlink:href')).toContain('folder'); + expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('folder-o-icon'); vm.$destroy(); }); @@ -41,12 +41,12 @@ describe('ItemTypeIconComponent', () => { vm = createComponent(ITEM_TYPE.PROJECT); - expect(vm.$el.querySelector('use').getAttribute('xlink:href')).toContain('bookmark'); + expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('bookmark-icon'); vm.$destroy(); vm = createComponent(ITEM_TYPE.GROUP); - expect(vm.$el.querySelector('use').getAttribute('xlink:href')).not.toContain('bookmark'); + expect(vm.$el.querySelector('svg').getAttribute('data-testid')).not.toBe('bookmark-icon'); vm.$destroy(); }); }); diff --git a/spec/frontend/groups/members/index_spec.js b/spec/frontend/groups/members/index_spec.js new file mode 100644 index 00000000000..70fce0d60fb --- /dev/null +++ b/spec/frontend/groups/members/index_spec.js @@ -0,0 +1,66 @@ +import { createWrapper } from '@vue/test-utils'; +import initGroupMembersApp from '~/groups/members'; +import GroupMembersApp from '~/groups/members/components/app.vue'; +import { membersJsonString, membersParsed } from './mock_data'; + +describe('initGroupMembersApp', () => { + let el; + let vm; + let wrapper; + + const setup = () => { + vm = initGroupMembersApp(el); + wrapper = createWrapper(vm); + }; + + beforeEach(() => { + el = document.createElement('div'); + el.setAttribute('data-members', membersJsonString); + el.setAttribute('data-group-id', '234'); + + window.gon = { current_user_id: 123 }; + + document.body.appendChild(el); + }); + + afterEach(() => { + document.body.innerHTML = ''; + el = null; + + wrapper.destroy(); + wrapper = null; + }); + + it('renders `GroupMembersApp`', () => { + setup(); + + expect(wrapper.find(GroupMembersApp).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-group-id` as `sourceId` in Vuex store', () => { + setup(); + + expect(vm.$store.state.sourceId).toBe(234); + }); + + it('parses and sets `members` in Vuex store', () => { + setup(); + + expect(vm.$store.state.members).toEqual(membersParsed); + }); +}); diff --git a/spec/frontend/groups/members/mock_data.js b/spec/frontend/groups/members/mock_data.js new file mode 100644 index 00000000000..b84c9c6d446 --- /dev/null +++ b/spec/frontend/groups/members/mock_data.js @@ -0,0 +1,33 @@ +export const membersJsonString = + '[{"requested_at":null,"can_update":true,"can_remove":true,"can_override":false,"access_level":{"integer_value":50,"string_value":"Owner"},"source":{"id":323,"name":"My group / my subgroup","web_url":"http://127.0.0.1:3000/groups/my-group/my-subgroup"},"user":{"id":1,"name":"Administrator","username":"root","web_url":"http://127.0.0.1:3000/root","avatar_url":"https://www.gravatar.com/avatar/4816142ef496f956a277bedf1a40607b?s=80\u0026d=identicon","blocked":false,"two_factor_enabled":false},"id":524,"created_at":"2020-08-21T21:33:27.631Z","expires_at":null,"using_license":false,"group_sso":false,"group_managed_account":false}]'; + +export const membersParsed = [ + { + requestedAt: null, + canUpdate: true, + canRemove: true, + canOverride: false, + accessLevel: { integerValue: 50, stringValue: 'Owner' }, + source: { + id: 323, + name: 'My group / my subgroup', + webUrl: 'http://127.0.0.1:3000/groups/my-group/my-subgroup', + }, + user: { + id: 1, + name: 'Administrator', + username: 'root', + webUrl: 'http://127.0.0.1:3000/root', + avatarUrl: + 'https://www.gravatar.com/avatar/4816142ef496f956a277bedf1a40607b?s=80&d=identicon', + blocked: false, + twoFactorEnabled: false, + }, + id: 524, + createdAt: '2020-08-21T21:33:27.631Z', + expiresAt: null, + usingLicense: false, + groupSso: false, + groupManagedAccount: false, + }, +]; |