Commit 3e333282 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch...

Merge branch '326251-experiment-cleanup-invite_members_version_b-in-assignee-dropdown' into 'master'

Remove invite_members_version_b experiment [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!60426
parents 9d4f4b20 2c660711
<script>
import { GlModal, GlLink } from '@gitlab/ui';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import { s__, __ } from '~/locale';
import { OPEN_MODAL, MODAL_ID } from '../constants';
import eventHub from '../event_hub';
export default {
cancelProps: {
text: __('Got it'),
attributes: [
{
variant: 'info',
},
],
},
modalId: MODAL_ID,
components: {
GlLink,
GlModal,
},
props: {
membersPath: {
type: String,
required: false,
default: '',
},
},
i18n: {
modalTitle: s__("InviteMember|Oops, this feature isn't ready yet"),
bodyTopMessage: s__(
"InviteMember|We're working to allow everyone to invite new members, making it easier for teams to get started with GitLab",
),
bodyMiddleMessage: s__(
'InviteMember|Until then, ask an owner to invite new project members for you',
),
linkText: s__('InviteMember|See who can invite members for you'),
},
mounted() {
eventHub.$on(OPEN_MODAL, this.openModal);
},
methods: {
openModal() {
this.$root.$emit(BV_SHOW_MODAL, MODAL_ID);
},
},
};
</script>
<template>
<gl-modal :modal-id="$options.modalId" size="sm" :action-cancel="$options.cancelProps">
<template #modal-title>
{{ $options.i18n.modalTitle }}
<gl-emoji
class="gl-vertical-align-baseline font-size-inherit gl-mr-1"
data-name="sweat_smile"
/>
</template>
<p>{{ $options.i18n.bodyTopMessage }}</p>
<p>{{ $options.i18n.bodyMiddleMessage }}</p>
<gl-link
:href="membersPath"
data-track-event="click_who_can_invite_link"
data-track-label="invite_members_message"
>{{ $options.i18n.linkText }}</gl-link
>
</gl-modal>
</template>
<script>
import { GlLink } from '@gitlab/ui';
import { OPEN_MODAL } from '../constants';
import eventHub from '../event_hub';
export default {
components: {
GlLink,
},
props: {
displayText: {
type: String,
required: false,
default: '',
},
event: {
type: String,
required: false,
default: '',
},
label: {
type: String,
required: false,
default: '',
},
},
methods: {
openModal() {
eventHub.$emit(OPEN_MODAL);
},
},
};
</script>
<template>
<gl-link
data-is-link="true"
:data-track-event="event"
:data-track-label="label"
@click="openModal"
>{{ displayText }}
</gl-link>
</template>
export const OPEN_MODAL = 'openModal';
export const MODAL_ID = 'invite-member-modal';
import createEventHub from '~/helpers/event_hub_factory';
export default createEventHub();
import { GlToast } from '@gitlab/ui';
import Vue from 'vue';
import { isInIssuePage, isInDesignPage } from '~/lib/utils/common_utils';
import InviteMemberModal from './components/invite_member_modal.vue';
Vue.use(GlToast);
const isAssigneesWidgetShown =
(isInIssuePage() || isInDesignPage()) && gon.features.issueAssigneesWidget;
export default function initInviteMembersModal() {
const el = document.querySelector('.js-invite-member-modal');
if (!el || isAssigneesWidgetShown) {
return false;
}
const { membersPath } = el.dataset;
return new Vue({
el,
render: (createElement) =>
createElement(InviteMemberModal, {
props: { membersPath },
}),
});
}
import Vue from 'vue';
import InviteMemberTrigger from './components/invite_member_trigger.vue';
export default function initInviteMembersTrigger() {
const el = document.querySelector('.js-invite-member-trigger');
if (!el) {
return false;
}
return new Vue({
el,
render: (createElement) =>
createElement(InviteMemberTrigger, {
props: { ...el.dataset },
}),
});
}
import loadAwardsHandler from '~/awards_handler'; import loadAwardsHandler from '~/awards_handler';
import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable'; import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import initIssuableSidebar from '~/init_issuable_sidebar'; import initIssuableSidebar from '~/init_issuable_sidebar';
import initInviteMemberModal from '~/invite_member/init_invite_member_modal';
import initInviteMemberTrigger from '~/invite_member/init_invite_member_trigger';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import { IssuableType } from '~/issuable_show/constants'; import { IssuableType } from '~/issuable_show/constants';
...@@ -58,7 +56,5 @@ export default function initShowIssue() { ...@@ -58,7 +56,5 @@ export default function initShowIssue() {
} else { } else {
loadAwardsHandler(); loadAwardsHandler();
} }
initInviteMemberModal();
initInviteMemberTrigger();
} }
} }
...@@ -3,8 +3,6 @@ import loadAwardsHandler from '~/awards_handler'; ...@@ -3,8 +3,6 @@ import loadAwardsHandler from '~/awards_handler';
import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable'; import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import initPipelines from '~/commit/pipelines/pipelines_bundle'; import initPipelines from '~/commit/pipelines/pipelines_bundle';
import initIssuableSidebar from '~/init_issuable_sidebar'; import initIssuableSidebar from '~/init_issuable_sidebar';
import initInviteMemberModal from '~/invite_member/init_invite_member_modal';
import initInviteMemberTrigger from '~/invite_member/init_invite_member_trigger';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import { handleLocationHash } from '~/lib/utils/common_utils'; import { handleLocationHash } from '~/lib/utils/common_utils';
...@@ -28,8 +26,6 @@ export default function initMergeRequestShow() { ...@@ -28,8 +26,6 @@ export default function initMergeRequestShow() {
} else { } else {
loadAwardsHandler(); loadAwardsHandler();
} }
initInviteMemberModal();
initInviteMemberTrigger();
initInviteMembersModal(); initInviteMembersModal();
initInviteMembersTrigger(); initInviteMembersTrigger();
......
...@@ -47,9 +47,6 @@ export default { ...@@ -47,9 +47,6 @@ export default {
directlyInviteMembers: { directlyInviteMembers: {
default: false, default: false,
}, },
indirectlyInviteMembers: {
default: false,
},
}, },
props: { props: {
iid: { iid: {
...@@ -444,7 +441,7 @@ export default { ...@@ -444,7 +441,7 @@ export default {
</template> </template>
<template #footer> <template #footer>
<gl-dropdown-item> <gl-dropdown-item>
<sidebar-invite-members v-if="directlyInviteMembers || indirectlyInviteMembers" /> <sidebar-invite-members v-if="directlyInviteMembers" />
</gl-dropdown-item> </gl-dropdown-item>
</template> </template>
</multi-select-dropdown> </multi-select-dropdown>
......
<script> <script>
import InviteMemberModal from '~/invite_member/components/invite_member_modal.vue';
import InviteMemberTrigger from '~/invite_member/components/invite_member_trigger.vue';
import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue'; import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
import { __ } from '~/locale'; import { __ } from '~/locale';
export default { export default {
displayText: __('Invite members'), displayText: __('Invite members'),
dataTrackLabel: 'edit_assignee', dataTrackLabel: 'edit_assignee',
dataTrackEvent: 'click_invite_members',
components: { components: {
InviteMemberTrigger,
InviteMemberModal,
InviteMembersTrigger, InviteMembersTrigger,
}, },
inject: {
projectMembersPath: {
default: '',
},
directlyInviteMembers: {
default: false,
},
},
computed: {
trackEvent() {
return this.directlyInviteMembers ? 'click_invite_members' : 'click_invite_members_version_b';
},
},
}; };
</script> </script>
<template> <template>
<div> <invite-members-trigger
<invite-members-trigger trigger-element="anchor"
v-if="directlyInviteMembers" :display-text="$options.displayText"
trigger-element="anchor" :event="$options.dataTrackEvent"
:display-text="$options.displayText" :label="$options.dataTrackLabel"
:event="trackEvent" classes="gl-display-block gl-pl-6 gl-hover-text-decoration-none gl-hover-text-blue-800!"
:label="$options.dataTrackLabel" />
classes="gl-display-block gl-pl-6 gl-hover-text-decoration-none gl-hover-text-blue-800!"
/>
<template v-else>
<invite-member-trigger
:display-text="$options.displayText"
:event="trackEvent"
:label="$options.dataTrackLabel"
class="gl-display-block gl-pl-6 gl-hover-text-decoration-none gl-hover-text-blue-800!"
/>
<invite-member-modal :members-path="projectMembersPath" />
</template>
</div>
</template> </template>
...@@ -86,7 +86,7 @@ function mountAssigneesComponent() { ...@@ -86,7 +86,7 @@ function mountAssigneesComponent() {
if (!el) return; if (!el) return;
const { id, iid, fullPath, editable, projectMembersPath } = getSidebarOptions(); const { id, iid, fullPath, editable } = getSidebarOptions();
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new Vue({ new Vue({
el, el,
...@@ -96,9 +96,7 @@ function mountAssigneesComponent() { ...@@ -96,9 +96,7 @@ function mountAssigneesComponent() {
}, },
provide: { provide: {
canUpdate: editable, canUpdate: editable,
projectMembersPath,
directlyInviteMembers: el.hasAttribute('data-directly-invite-members'), directlyInviteMembers: el.hasAttribute('data-directly-invite-members'),
indirectlyInviteMembers: el.hasAttribute('data-indirectly-invite-members'),
}, },
render: (createElement) => render: (createElement) =>
createElement('sidebar-assignees-widget', { createElement('sidebar-assignees-widget', {
......
...@@ -56,8 +56,6 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -56,8 +56,6 @@ class Projects::IssuesController < Projects::ApplicationController
push_frontend_feature_flag(:confidential_notes, @project, default_enabled: :yaml) push_frontend_feature_flag(:confidential_notes, @project, default_enabled: :yaml)
push_frontend_feature_flag(:issue_assignees_widget, @project, default_enabled: :yaml) push_frontend_feature_flag(:issue_assignees_widget, @project, default_enabled: :yaml)
record_experiment_user(:invite_members_version_b)
experiment(:invite_members_in_comment, namespace: @project.root_ancestor) do |experiment_instance| experiment(:invite_members_in_comment, namespace: @project.root_ancestor) do |experiment_instance|
experiment_instance.exclude! unless helpers.can_import_members? experiment_instance.exclude! unless helpers.can_import_members?
......
...@@ -47,8 +47,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -47,8 +47,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:users_expanding_widgets_usage_data, @project, default_enabled: :yaml) push_frontend_feature_flag(:users_expanding_widgets_usage_data, @project, default_enabled: :yaml)
push_frontend_feature_flag(:diff_settings_usage_data, default_enabled: :yaml) push_frontend_feature_flag(:diff_settings_usage_data, default_enabled: :yaml)
record_experiment_user(:invite_members_version_b)
experiment(:invite_members_in_comment, namespace: @project.root_ancestor) do |experiment_instance| experiment(:invite_members_in_comment, namespace: @project.root_ancestor) do |experiment_instance|
experiment_instance.exclude! unless helpers.can_import_members? experiment_instance.exclude! unless helpers.can_import_members?
......
...@@ -17,20 +17,6 @@ module InviteMembersHelper ...@@ -17,20 +17,6 @@ module InviteMembersHelper
end end
end end
def indirectly_invite_members?
strong_memoize(:indirectly_invite_members) do
experiment_enabled?(:invite_members_version_b) && !can_import_members?
end
end
def show_invite_members_track_event
if directly_invite_members?
'show_invite_members'
elsif indirectly_invite_members?
'show_invite_members_version_b'
end
end
def invite_group_members?(group) def invite_group_members?(group)
experiment_enabled?(:invite_members_empty_group_version_a) && Ability.allowed?(current_user, :admin_group_member, group) experiment_enabled?(:invite_members_empty_group_version_a) && Ability.allowed?(current_user, :admin_group_member, group)
end end
......
...@@ -390,8 +390,7 @@ module IssuablesHelper ...@@ -390,8 +390,7 @@ module IssuablesHelper
severity: issuable[:severity], severity: issuable[:severity],
timeTrackingLimitToHours: Gitlab::CurrentSettings.time_tracking_limit_to_hours, timeTrackingLimitToHours: Gitlab::CurrentSettings.time_tracking_limit_to_hours,
createNoteEmail: issuable[:create_note_email], createNoteEmail: issuable[:create_note_email],
issuableType: issuable[:type], issuableType: issuable[:type]
projectMembersPath: project_project_members_path(@project, sort: :access_level_desc)
} }
end end
......
- issuable_type = issuable_sidebar[:type] - issuable_type = issuable_sidebar[:type]
- dropdown_options = assignees_dropdown_options(issuable_type) - dropdown_options = assignees_dropdown_options(issuable_type)
#js-vue-sidebar-assignees{ data: { field: issuable_type, signed_in: signed_in, max_assignees: dropdown_options[:data][:"max-select"], directly_invite_members: directly_invite_members?, indirectly_invite_members: indirectly_invite_members? } } #js-vue-sidebar-assignees{ data: { field: issuable_type,
signed_in: signed_in,
max_assignees: dropdown_options[:data][:"max-select"],
directly_invite_members: directly_invite_members? } }
.title.hide-collapsed .title.hide-collapsed
= _('Assignee') = _('Assignee')
= loading_icon(css_class: 'gl-vertical-align-text-bottom') = loading_icon(css_class: 'gl-vertical-align-text-bottom')
...@@ -39,12 +42,12 @@ ...@@ -39,12 +42,12 @@
- data['max-select'] = dropdown_options[:data][:'max-select'] if dropdown_options[:data][:'max-select'] - data['max-select'] = dropdown_options[:data][:'max-select'] if dropdown_options[:data][:'max-select']
- options[:data].merge!(data) - options[:data].merge!(data)
- if directly_invite_members? || indirectly_invite_members? - if directly_invite_members?
- options[:dropdown_class] += ' dropdown-extended-height' - options[:dropdown_class] += ' dropdown-extended-height'
- options[:footer_content] = true - options[:footer_content] = true
- options[:wrapper_class] = 'js-sidebar-assignee-dropdown' - options[:wrapper_class] = 'js-sidebar-assignee-dropdown'
- options[:toggle_class] += ' js-invite-members-track' - options[:toggle_class] += ' js-invite-members-track'
- data['track-event'] = show_invite_members_track_event - data['track-event'] = 'show_invite_members'
- options[:data].merge!(data) - options[:data].merge!(data)
- invite_text = _('Invite Members') - invite_text = _('Invite Members')
- track_label = 'edit_assignee' - track_label = 'edit_assignee'
...@@ -52,15 +55,9 @@ ...@@ -52,15 +55,9 @@
= dropdown_tag(title, options: options) do = dropdown_tag(title, options: options) do
%ul.dropdown-footer-list %ul.dropdown-footer-list
%li %li
- if directly_invite_members? .js-invite-members-trigger{ data: { trigger_element: 'anchor',
.js-invite-members-trigger{ data: { trigger_element: 'anchor', display_text: invite_text,
display_text: invite_text, event: 'click_invite_members',
event: 'click_invite_members', label: track_label } }
label: track_label } }
- else
.js-invite-member-trigger{ data: { display_text: invite_text, event: 'click_invite_members_version_b', label: track_label } }
- else - else
= dropdown_tag(title, options: options) = dropdown_tag(title, options: options)
- if indirectly_invite_members?
.js-invite-member-modal{ data: { members_path: project_project_members_path(@project, sort: :access_level_desc) } }
---
title: Remove invite_members_version_b experiment
merge_request: 60426
author:
type: other
---
name: invite_members_version_b_experiment_percentage
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43900
rollout_issue_url: https://gitlab.com/gitlab-org/growth/team-tasks/-/issues/214
milestone: '13.5'
type: experiment
group: group::expansion
default_enabled: false
...@@ -34,10 +34,6 @@ ...@@ -34,10 +34,6 @@
module Gitlab module Gitlab
module Experimentation module Experimentation
EXPERIMENTS = { EXPERIMENTS = {
invite_members_version_b: {
tracking_category: 'Growth::Expansion::Experiment::InviteMembersVersionB',
use_backwards_compatible_subject_index: true
},
invite_members_empty_group_version_a: { invite_members_empty_group_version_a: {
tracking_category: 'Growth::Expansion::Experiment::InviteMembersEmptyGroupVersionA', tracking_category: 'Growth::Expansion::Experiment::InviteMembersEmptyGroupVersionA',
use_backwards_compatible_subject_index: true use_backwards_compatible_subject_index: true
......
...@@ -17865,24 +17865,12 @@ msgstr "" ...@@ -17865,24 +17865,12 @@ msgstr ""
msgid "InviteMember|Invited users will be added with developer level permissions. %{linkStart}View the documentation%{linkEnd} to see how to change this later." msgid "InviteMember|Invited users will be added with developer level permissions. %{linkStart}View the documentation%{linkEnd} to see how to change this later."
msgstr "" msgstr ""
msgid "InviteMember|Oops, this feature isn't ready yet"
msgstr ""
msgid "InviteMember|See who can invite members for you"
msgstr ""
msgid "InviteMember|Send invitations" msgid "InviteMember|Send invitations"
msgstr "" msgstr ""
msgid "InviteMember|Skip this for now" msgid "InviteMember|Skip this for now"
msgstr "" msgstr ""
msgid "InviteMember|Until then, ask an owner to invite new project members for you"
msgstr ""
msgid "InviteMember|We're working to allow everyone to invite new members, making it easier for teams to get started with GitLab"
msgstr ""
msgid "InviteReminderEmail|%{inviter} is still waiting for you to join GitLab" msgid "InviteReminderEmail|%{inviter} is still waiting for you to join GitLab"
msgstr "" msgstr ""
......
...@@ -130,30 +130,7 @@ RSpec.describe 'Issue Sidebar' do ...@@ -130,30 +130,7 @@ RSpec.describe 'Issue Sidebar' do
end end
end end
context 'when invite_members_version_b experiment is enabled' do context 'when user cannot invite members in assignee dropdown' do
before do
stub_experiment_for_subject(invite_members_version_b: true)
end
it 'shows a link for inviting members and follows through to modal' do
project.add_developer(user)
visit_issue(project, issue2)
open_assignees_dropdown
page.within '.dropdown-menu-user' do
expect(page).to have_link('Invite members', href: '#')
expect(page).to have_selector('[data-track-event="click_invite_members_version_b"]')
expect(page).to have_selector('[data-track-label="edit_assignee"]')
end
click_link 'Invite members'
expect(page).to have_content("Oops, this feature isn't ready yet")
end
end
context 'when invite_members_version_b experiment is disabled' do
it 'shows author in assignee dropdown and no invite link' do it 'shows author in assignee dropdown and no invite link' do
project.add_developer(user) project.add_developer(user)
visit_issue(project, issue2) visit_issue(project, issue2)
......
import { GlLink, GlModal } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { stubComponent } from 'helpers/stub_component';
import { mockTracking, unmockTracking, triggerEvent } from 'helpers/tracking_helper';
import InviteMemberModal from '~/invite_member/components/invite_member_modal.vue';
const memberPath = 'member_path';
const GlEmoji = { template: '<img />' };
const createComponent = () => {
return shallowMount(InviteMemberModal, {
propsData: {
membersPath: memberPath,
},
stubs: {
GlEmoji,
GlModal: stubComponent(GlModal, {
template: '<div><slot name="modal-title"></slot><slot></slot></div>',
}),
},
});
};
describe('InviteMemberModal', () => {
let wrapper;
beforeEach(() => {
wrapper = createComponent();
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
const findLink = () => wrapper.find(GlLink);
describe('rendering the modal', () => {
it('renders the modal with the correct title', () => {
expect(wrapper.text()).toContain("Oops, this feature isn't ready yet");
});
describe('rendering the see who link', () => {
it('renders the correct link', () => {
expect(findLink().attributes('href')).toBe(memberPath);
});
});
});
describe('tracking', () => {
let trackingSpy;
afterEach(() => {
unmockTracking();
});
it('send an event when go to pipelines is clicked', () => {
trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
triggerEvent(findLink().element);
expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_who_can_invite_link', {
label: 'invite_members_message',
});
});
});
});
const triggerProvides = {
displayText: 'Invite member',
event: 'click_invite_members_version_b',
label: 'edit_assignee',
};
export default triggerProvides;
import { GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { mockTracking, unmockTracking, triggerEvent } from 'helpers/tracking_helper';
import InviteMemberTrigger from '~/invite_member/components/invite_member_trigger.vue';
import triggerProvides from './invite_member_trigger_mock_data';
const createComponent = () => {
return shallowMount(InviteMemberTrigger, { propsData: triggerProvides });
};
describe('InviteMemberTrigger', () => {
let wrapper;
beforeEach(() => {
wrapper = createComponent();
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
const findLink = () => wrapper.find(GlLink);
describe('displayText', () => {
it('includes the correct displayText for the link', () => {
expect(findLink().text()).toBe(triggerProvides.displayText);
});
});
describe('tracking', () => {
let trackingSpy;
afterEach(() => {
unmockTracking();
});
it('send an event when go to pipelines is clicked', () => {
trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
triggerEvent(findLink().element);
expect(trackingSpy).toHaveBeenCalledWith('_category_', triggerProvides.event, {
label: triggerProvides.label,
});
});
});
});
...@@ -533,7 +533,7 @@ describe('Sidebar assignees widget', () => { ...@@ -533,7 +533,7 @@ describe('Sidebar assignees widget', () => {
expect(findInviteMembersLink().exists()).toBe(false); expect(findInviteMembersLink().exists()).toBe(false);
}); });
it('does not render invite members link if `directlyInviteMembers` and `indirectlyInviteMembers` were not passed', async () => { it('does not render invite members link if `directlyInviteMembers` was not passed', async () => {
createComponent(); createComponent();
await waitForPromises(); await waitForPromises();
expect(findInviteMembersLink().exists()).toBe(false); expect(findInviteMembersLink().exists()).toBe(false);
...@@ -548,14 +548,4 @@ describe('Sidebar assignees widget', () => { ...@@ -548,14 +548,4 @@ describe('Sidebar assignees widget', () => {
await waitForPromises(); await waitForPromises();
expect(findInviteMembersLink().exists()).toBe(true); expect(findInviteMembersLink().exists()).toBe(true);
}); });
it('renders invite members link if `indirectlyInviteMembers` is true', async () => {
createComponent({
provide: {
indirectlyInviteMembers: true,
},
});
await waitForPromises();
expect(findInviteMembersLink().exists()).toBe(true);
});
}); });
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import InviteMemberModal from '~/invite_member/components/invite_member_modal.vue';
import InviteMemberTrigger from '~/invite_member/components/invite_member_trigger.vue';
import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue'; import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
import SidebarInviteMembers from '~/sidebar/components/assignees/sidebar_invite_members.vue'; import SidebarInviteMembers from '~/sidebar/components/assignees/sidebar_invite_members.vue';
const testProjectMembersPath = 'test-path';
describe('Sidebar invite members component', () => { describe('Sidebar invite members component', () => {
let wrapper; let wrapper;
const findDirectInviteLink = () => wrapper.findComponent(InviteMembersTrigger); const findDirectInviteLink = () => wrapper.findComponent(InviteMembersTrigger);
const findIndirectInviteLink = () => wrapper.findComponent(InviteMemberTrigger);
const findInviteModal = () => wrapper.findComponent(InviteMemberModal);
const createComponent = ({ directlyInviteMembers = false } = {}) => { const createComponent = () => {
wrapper = shallowMount(SidebarInviteMembers, { wrapper = shallowMount(SidebarInviteMembers);
provide: {
directlyInviteMembers,
projectMembersPath: testProjectMembersPath,
},
});
}; };
afterEach(() => { afterEach(() => {
...@@ -28,32 +17,11 @@ describe('Sidebar invite members component', () => { ...@@ -28,32 +17,11 @@ describe('Sidebar invite members component', () => {
describe('when directly inviting members', () => { describe('when directly inviting members', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ directlyInviteMembers: true }); createComponent();
}); });
it('renders a direct link to project members path', () => { it('renders a direct link to project members path', () => {
expect(findDirectInviteLink().exists()).toBe(true); expect(findDirectInviteLink().exists()).toBe(true);
}); });
it('does not render invite members trigger and modal components', () => {
expect(findIndirectInviteLink().exists()).toBe(false);
expect(findInviteModal().exists()).toBe(false);
});
});
describe('when indirectly inviting members', () => {
beforeEach(() => {
createComponent();
});
it('does not render a direct link to project members path', () => {
expect(findDirectInviteLink().exists()).toBe(false);
});
it('does not render invite members trigger and modal components', () => {
expect(findIndirectInviteLink().exists()).toBe(true);
expect(findInviteModal().exists()).toBe(true);
expect(findInviteModal().props('membersPath')).toBe(testProjectMembersPath);
});
}); });
}); });
...@@ -12,21 +12,6 @@ RSpec.describe InviteMembersHelper do ...@@ -12,21 +12,6 @@ RSpec.describe InviteMembersHelper do
helper.extend(Gitlab::Experimentation::ControllerConcern) helper.extend(Gitlab::Experimentation::ControllerConcern)
end end
describe '#show_invite_members_track_event' do
it 'shows values when can directly invite members' do
allow(helper).to receive(:directly_invite_members?).and_return(true)
expect(helper.show_invite_members_track_event).to eq 'show_invite_members'
end
it 'shows values when can indirectly invite members' do
allow(helper).to receive(:directly_invite_members?).and_return(false)
allow(helper).to receive(:indirectly_invite_members?).and_return(true)
expect(helper.show_invite_members_track_event).to eq 'show_invite_members_version_b'
end
end
context 'with project' do context 'with project' do
before do before do
assign(:project, project) assign(:project, project)
...@@ -87,38 +72,6 @@ RSpec.describe InviteMembersHelper do ...@@ -87,38 +72,6 @@ RSpec.describe InviteMembersHelper do
end end
end end
end end
describe "#indirectly_invite_members?" do
context 'when a user is a developer' do
before do
allow(helper).to receive(:current_user) { developer }
end
it 'returns false' do
allow(helper).to receive(:experiment_enabled?).with(:invite_members_version_b) { false }
expect(helper.indirectly_invite_members?).to eq false
end
it 'returns true' do
allow(helper).to receive(:experiment_enabled?).with(:invite_members_version_b) { true }
expect(helper.indirectly_invite_members?).to eq true
end
end
context 'when a user is an owner' do
before do
allow(helper).to receive(:current_user) { owner }
end
it 'returns false' do
allow(helper).to receive(:experiment_enabled?).with(:invite_members_version_b) { true }
expect(helper.indirectly_invite_members?).to eq false
end
end
end
end end
context 'with group' do context 'with group' do
......
...@@ -7,7 +7,6 @@ require 'spec_helper' ...@@ -7,7 +7,6 @@ require 'spec_helper'
RSpec.describe Gitlab::Experimentation::EXPERIMENTS do RSpec.describe Gitlab::Experimentation::EXPERIMENTS do
it 'temporarily ensures we know what experiments exist for backwards compatibility' do it 'temporarily ensures we know what experiments exist for backwards compatibility' do
expected_experiment_keys = [ expected_experiment_keys = [
:invite_members_version_b,
:invite_members_empty_group_version_a, :invite_members_empty_group_version_a,
:contact_sales_btn_in_app :contact_sales_btn_in_app
] ]
......
...@@ -22,32 +22,7 @@ RSpec.shared_examples 'issuable invite members experiments' do ...@@ -22,32 +22,7 @@ RSpec.shared_examples 'issuable invite members experiments' do
end end
end end
context 'when invite_members_version_b experiment is enabled' do context 'when user cannot invite members in assignee dropdown' do
before do
stub_experiment_for_subject(invite_members_version_b: true)
end
it 'shows a link for inviting members and follows through to modal' do
project.add_developer(user)
visit issuable_path
find('.block.assignee .edit-link').click
wait_for_requests
page.within '.dropdown-menu-user' do
expect(page).to have_link('Invite Members', href: '#')
expect(page).to have_selector('[data-track-event="click_invite_members_version_b"]')
expect(page).to have_selector('[data-track-label="edit_assignee"]')
end
click_link 'Invite Members'
expect(page).to have_content("Oops, this feature isn't ready yet")
end
end
context 'when invite_members_version_b experiment is disabled' do
it 'shows author in assignee dropdown and no invite link' do it 'shows author in assignee dropdown and no invite link' do
project.add_developer(user) project.add_developer(user)
visit issuable_path visit issuable_path
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment