Commit 1b93b0c3 authored by Serhii Yarynovskyi's avatar Serhii Yarynovskyi Committed by Simon Knox

Clean up forcibly_show_trial_status_popover experiment

forcibly_show_trial_status_popover experiment has been called unsuccessful
and should be removed and returned back to control behavior

Changelog: removed
parent c5a348be
...@@ -4,9 +4,7 @@ const CLICK_BUTTON_ACTION = 'click_button'; ...@@ -4,9 +4,7 @@ const CLICK_BUTTON_ACTION = 'click_button';
const RESIZE_EVENT_DEBOUNCE_MS = 150; const RESIZE_EVENT_DEBOUNCE_MS = 150;
export const RESIZE_EVENT = 'resize'; export const RESIZE_EVENT = 'resize';
export const EXPERIMENT_KEY = 'forcibly_show_trial_status_popover'; export const EXPERIMENT_KEY = 'group_contact_sales';
export const TRACKING_PROPERTY_WHEN_FORCED = 'forced';
export const TRACKING_PROPERTY_WHEN_VOLUNTARY = 'voluntary';
export const WIDGET = { export const WIDGET = {
i18n: { i18n: {
...@@ -21,11 +19,7 @@ export const WIDGET = { ...@@ -21,11 +19,7 @@ export const WIDGET = {
}, },
}, },
trackingEvents: { trackingEvents: {
widgetClick: { widgetClick: { action: 'click_link', label: 'trial_status_widget' },
action: 'click_link',
label: 'trial_status_widget',
property: TRACKING_PROPERTY_WHEN_VOLUNTARY,
},
}, },
}; };
...@@ -43,9 +37,7 @@ export const POPOVER = { ...@@ -43,9 +37,7 @@ export const POPOVER = {
}, },
trackingEvents: { trackingEvents: {
popoverShown: { action: 'popover_shown', label: 'trial_status_popover' }, popoverShown: { action: 'popover_shown', label: 'trial_status_popover' },
closeBtnClick: { action: CLICK_BUTTON_ACTION, label: 'close_popover' },
contactSalesBtnClick: { action: CLICK_BUTTON_ACTION, label: 'contact_sales' }, contactSalesBtnClick: { action: CLICK_BUTTON_ACTION, label: 'contact_sales' },
upgradeBtnClick: { action: CLICK_BUTTON_ACTION, label: 'upgrade_to_ultimate' },
compareBtnClick: { action: CLICK_BUTTON_ACTION, label: 'compare_all_plans' }, compareBtnClick: { action: CLICK_BUTTON_ACTION, label: 'compare_all_plans' },
}, },
resizeEventDebounceMS: RESIZE_EVENT_DEBOUNCE_MS, resizeEventDebounceMS: RESIZE_EVENT_DEBOUNCE_MS,
......
...@@ -5,17 +5,10 @@ import { debounce } from 'lodash'; ...@@ -5,17 +5,10 @@ import { debounce } from 'lodash';
import { removeTrialSuffix } from 'ee/billings/billings_util'; import { removeTrialSuffix } from 'ee/billings/billings_util';
import { shouldHandRaiseLeadButtonMount } from 'ee/hand_raise_leads/hand_raise_lead'; import { shouldHandRaiseLeadButtonMount } from 'ee/hand_raise_leads/hand_raise_lead';
import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue'; import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
import axios from '~/lib/utils/axios_utils';
import { formatDate } from '~/lib/utils/datetime_utility'; import { formatDate } from '~/lib/utils/datetime_utility';
import { sprintf } from '~/locale'; import { sprintf } from '~/locale';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
import { import { POPOVER, RESIZE_EVENT, EXPERIMENT_KEY } from './constants';
POPOVER,
RESIZE_EVENT,
EXPERIMENT_KEY,
TRACKING_PROPERTY_WHEN_FORCED,
TRACKING_PROPERTY_WHEN_VOLUNTARY,
} from './constants';
const { const {
i18n, i18n,
...@@ -41,18 +34,13 @@ export default { ...@@ -41,18 +34,13 @@ export default {
planName: {}, planName: {},
plansHref: {}, plansHref: {},
purchaseHref: {}, purchaseHref: {},
startInitiallyShown: { default: false },
targetId: {}, targetId: {},
trialEndDate: {}, trialEndDate: {},
userCalloutsPath: {},
userCalloutsFeatureId: {},
user: {}, user: {},
}, },
data() { data() {
return { return {
disabled: false, disabled: false,
forciblyShowing: false,
show: false,
}; };
}, },
i18n, i18n,
...@@ -69,27 +57,13 @@ export default { ...@@ -69,27 +57,13 @@ export default {
planName: removeTrialSuffix(this.planName), planName: removeTrialSuffix(this.planName),
}); });
}, },
trackingPropertyAndValue() {
return {
property: this.forciblyShowing
? TRACKING_PROPERTY_WHEN_FORCED
: TRACKING_PROPERTY_WHEN_VOLUNTARY,
value: this.daysRemaining,
};
},
}, },
created() { created() {
this.debouncedResize = debounce(() => this.onResize(), resizeEventDebounceMS); this.debouncedResize = debounce(() => this.updateDisabledState(), resizeEventDebounceMS);
window.addEventListener(RESIZE_EVENT, this.debouncedResize); window.addEventListener(RESIZE_EVENT, this.debouncedResize);
if (this.startInitiallyShown) {
this.forciblyShowing = true;
this.show = true;
this.onForciblyShown();
}
}, },
mounted() { mounted() {
this.onResize(); this.updateDisabledState();
}, },
beforeDestroy() { beforeDestroy() {
window.removeEventListener(RESIZE_EVENT, this.debouncedResize); window.removeEventListener(RESIZE_EVENT, this.debouncedResize);
...@@ -97,34 +71,15 @@ export default { ...@@ -97,34 +71,15 @@ export default {
methods: { methods: {
trackPageAction(eventName) { trackPageAction(eventName) {
const { action, ...options } = trackingEvents[eventName]; const { action, ...options } = trackingEvents[eventName];
this.track(action, { ...options, ...this.trackingPropertyAndValue }); this.track(action, { ...options });
},
onClose() {
this.forciblyShowing = false;
this.trackPageAction('closeBtnClick');
},
onForciblyShown() {
if (this.userCalloutsPath && this.userCalloutsFeatureId) {
axios
.post(this.userCalloutsPath, {
feature_name: this.userCalloutsFeatureId,
})
.catch((e) => {
// eslint-disable-next-line no-console, @gitlab/require-i18n-strings
console.error('Failed to dismiss trial status popover.', e);
});
}
}, },
onResize() { updateDisabledState() {
this.updateDisabledState(); this.disabled = disabledBreakpoints.includes(bp.getBreakpointSize());
}, },
onShown() { onShown() {
this.trackPageAction('popoverShown'); this.trackPageAction('popoverShown');
shouldHandRaiseLeadButtonMount(); shouldHandRaiseLeadButtonMount();
}, },
updateDisabledState() {
this.disabled = disabledBreakpoints.includes(bp.getBreakpointSize());
},
}, },
}; };
</script> </script>
...@@ -132,17 +87,13 @@ export default { ...@@ -132,17 +87,13 @@ export default {
<template> <template>
<gl-popover <gl-popover
ref="popover" ref="popover"
placement="rightbottom"
boundary="viewport"
:container="containerId" :container="containerId"
:target="targetId" :target="targetId"
:disabled="disabled" :disabled="disabled"
placement="rightbottom"
boundary="viewport"
:delay="{ hide: 400 }" :delay="{ hide: 400 }"
:show="show"
:triggers="forciblyShowing ? '' : 'hover focus'"
:show-close-button="startInitiallyShown"
@shown="onShown" @shown="onShown"
@close-button-clicked.prevent="onClose"
> >
<template #title> <template #title>
{{ $options.i18n.popoverTitle }} {{ $options.i18n.popoverTitle }}
...@@ -160,21 +111,20 @@ export default { ...@@ -160,21 +111,20 @@ export default {
<gitlab-experiment name="group_contact_sales"> <gitlab-experiment name="group_contact_sales">
<template #control> <template #control>
<gl-button <gl-button
ref="upgradeBtn" data-testid="upgrade-btn"
category="primary" category="primary"
variant="confirm" variant="confirm"
size="small" size="small"
class="gl-mb-0" class="gl-mb-0"
block block
:href="purchaseHref" :href="purchaseHref"
@click="trackPageAction('upgradeBtnClick')"
> >
<span class="gl-font-sm">{{ upgradeButtonTitle }}</span> <span class="gl-font-sm">{{ upgradeButtonTitle }}</span>
</gl-button> </gl-button>
</template> </template>
<template #candidate> <template #candidate>
<div data-testid="contactSalesBtn" @click="trackPageAction('contactSalesBtnClick')"> <div data-testid="contact-sales-btn" @click="trackPageAction('contactSalesBtnClick')">
<div <div
class="js-hand-raise-lead-button" class="js-hand-raise-lead-button"
:data-namespace-id="user.namespaceId" :data-namespace-id="user.namespaceId"
...@@ -196,7 +146,7 @@ export default { ...@@ -196,7 +146,7 @@ export default {
size="small" size="small"
class="gl-mb-0" class="gl-mb-0"
block block
data-testid="compareBtn" data-testid="compare-btn"
:title="$options.i18n.compareAllButtonTitle" :title="$options.i18n.compareAllButtonTitle"
@click="trackPageAction('compareBtnClick')" @click="trackPageAction('compareBtnClick')"
> >
......
...@@ -36,15 +36,19 @@ export default { ...@@ -36,15 +36,19 @@ export default {
methods: { methods: {
onWidgetClick() { onWidgetClick() {
const { action, ...options } = trackingEvents.widgetClick; const { action, ...options } = trackingEvents.widgetClick;
this.track(action, { ...options, value: this.daysRemaining }); this.track(action, { ...options });
}, },
}, },
}; };
</script> </script>
<template> <template>
<gl-link :id="containerId" :title="widgetTitle" :href="plansHref" @click="onWidgetClick"> <gl-link :id="containerId" :title="widgetTitle" :href="plansHref">
<div class="gl-display-flex gl-flex-direction-column gl-align-items-stretch gl-w-full"> <div
data-testid="widget-menu"
class="gl-display-flex gl-flex-direction-column gl-align-items-stretch gl-w-full"
@click="onWidgetClick"
>
<span class="gl-display-flex gl-align-items-center"> <span class="gl-display-flex gl-align-items-center">
<span class="nav-icon-container svg-container"> <span class="nav-icon-container svg-container">
<img :src="navIconImagePath" width="16" class="svg" /> <img :src="navIconImagePath" width="16" class="svg" />
......
...@@ -42,11 +42,8 @@ export const initTrialStatusPopover = () => { ...@@ -42,11 +42,8 @@ export const initTrialStatusPopover = () => {
planName, planName,
plansHref, plansHref,
purchaseHref, purchaseHref,
startInitiallyShown,
targetId, targetId,
trialEndDate, trialEndDate,
userCalloutsPath,
userCalloutsFeatureId,
namespaceId, namespaceId,
userName, userName,
firstName, firstName,
...@@ -64,11 +61,8 @@ export const initTrialStatusPopover = () => { ...@@ -64,11 +61,8 @@ export const initTrialStatusPopover = () => {
planName, planName,
plansHref, plansHref,
purchaseHref, purchaseHref,
startInitiallyShown: startInitiallyShown !== undefined,
targetId, targetId,
trialEndDate: new Date(trialEndDate), trialEndDate: new Date(trialEndDate),
userCalloutsPath,
userCalloutsFeatureId,
user: { user: {
namespaceId, namespaceId,
userName, userName,
......
...@@ -6,11 +6,6 @@ ...@@ -6,11 +6,6 @@
# the codebase) could trigger the need to extract these patterns into a single, # the codebase) could trigger the need to extract these patterns into a single,
# reusable, sharable helper. # reusable, sharable helper.
module TrialStatusWidgetHelper module TrialStatusWidgetHelper
D14_CALLOUT_RANGE = (7..14).freeze # between 14 & 7 days remaining
D3_CALLOUT_RANGE = (0..3).freeze # between 3 & 0 days remaining
D14_CALLOUT_ID = 'trial_status_reminder_d14'
D3_CALLOUT_ID = 'trial_status_reminder_d3'
def trial_status_popover_data_attrs(group) def trial_status_popover_data_attrs(group)
hand_raise_attrs = experiment(:group_contact_sales, namespace: group.root_ancestor, user: current_user, sticky_to: current_user) do |e| hand_raise_attrs = experiment(:group_contact_sales, namespace: group.root_ancestor, user: current_user, sticky_to: current_user) do |e|
e.control { {} } e.control { {} }
...@@ -23,11 +18,8 @@ module TrialStatusWidgetHelper ...@@ -23,11 +18,8 @@ module TrialStatusWidgetHelper
days_remaining: group.trial_days_remaining, # for experiment tracking days_remaining: group.trial_days_remaining, # for experiment tracking
group_name: group.name, group_name: group.name,
purchase_href: ultimate_subscription_path_for_group(group), purchase_href: ultimate_subscription_path_for_group(group),
start_initially_shown: force_popover_to_be_shown?(group),
target_id: base_attrs[:container_id], target_id: base_attrs[:container_id],
trial_end_date: group.trial_ends_on, trial_end_date: group.trial_ends_on
user_callouts_path: callouts_path,
user_callouts_feature_id: current_user_callout_feature_id(group.trial_days_remaining)
) )
end end
...@@ -49,32 +41,6 @@ module TrialStatusWidgetHelper ...@@ -49,32 +41,6 @@ module TrialStatusWidgetHelper
group.trial_active? && can?(current_user, :admin_namespace, group) group.trial_active? && can?(current_user, :admin_namespace, group)
end end
def force_popover_to_be_shown?(group)
force_popover = false
experiment(:forcibly_show_trial_status_popover, group: group) do |e|
e.candidate do
force_popover = !dismissed_feature_callout?(
current_user_callout_feature_id(group.trial_days_remaining)
)
end
e.publish_to_database
end
force_popover
end
def current_user_callout_feature_id(days_remaining)
return D14_CALLOUT_ID if D14_CALLOUT_RANGE.cover?(days_remaining)
return D3_CALLOUT_ID if D3_CALLOUT_RANGE.cover?(days_remaining)
end
def dismissed_feature_callout?(feature_name)
return true if feature_name.blank?
current_user.dismissed_callout?(feature_name: feature_name)
end
def trial_status_common_data_attrs(group) def trial_status_common_data_attrs(group)
{ {
container_id: 'trial-status-sidebar-widget', container_id: 'trial-status-sidebar-widget',
......
---
name: forcibly_show_trial_status_popover
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65283
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/335043
milestone: '14.1'
type: experiment
group: group::conversion
default_enabled: false
...@@ -7,7 +7,6 @@ exports[`TrialStatusPopover component group_contact_sales experiment candidate m ...@@ -7,7 +7,6 @@ exports[`TrialStatusPopover component group_contact_sales experiment candidate m
delay="[object Object]" delay="[object Object]"
placement="rightbottom" placement="rightbottom"
target="target-element-identifier" target="target-element-identifier"
triggers="hover focus"
> >
<gl-sprintf-stub <gl-sprintf-stub
...@@ -18,7 +17,7 @@ exports[`TrialStatusPopover component group_contact_sales experiment candidate m ...@@ -18,7 +17,7 @@ exports[`TrialStatusPopover component group_contact_sales experiment candidate m
class="gl-mt-5" class="gl-mt-5"
> >
<div <div
data-testid="contactSalesBtn" data-testid="contact-sales-btn"
> >
<div <div
class="js-hand-raise-lead-button" class="js-hand-raise-lead-button"
...@@ -37,7 +36,7 @@ exports[`TrialStatusPopover component group_contact_sales experiment candidate m ...@@ -37,7 +36,7 @@ exports[`TrialStatusPopover component group_contact_sales experiment candidate m
buttontextclasses="" buttontextclasses=""
category="secondary" category="secondary"
class="gl-mb-0" class="gl-mb-0"
data-testid="compareBtn" data-testid="compare-btn"
href="billing/path-for/group" href="billing/path-for/group"
icon="" icon=""
size="small" size="small"
...@@ -61,7 +60,6 @@ exports[`TrialStatusPopover component group_contact_sales experiment control mat ...@@ -61,7 +60,6 @@ exports[`TrialStatusPopover component group_contact_sales experiment control mat
delay="[object Object]" delay="[object Object]"
placement="rightbottom" placement="rightbottom"
target="target-element-identifier" target="target-element-identifier"
triggers="hover focus"
> >
<gl-sprintf-stub <gl-sprintf-stub
...@@ -76,6 +74,7 @@ exports[`TrialStatusPopover component group_contact_sales experiment control mat ...@@ -76,6 +74,7 @@ exports[`TrialStatusPopover component group_contact_sales experiment control mat
buttontextclasses="" buttontextclasses=""
category="primary" category="primary"
class="gl-mb-0" class="gl-mb-0"
data-testid="upgrade-btn"
href="transactions/new" href="transactions/new"
icon="" icon=""
size="small" size="small"
...@@ -93,7 +92,7 @@ exports[`TrialStatusPopover component group_contact_sales experiment control mat ...@@ -93,7 +92,7 @@ exports[`TrialStatusPopover component group_contact_sales experiment control mat
buttontextclasses="" buttontextclasses=""
category="secondary" category="secondary"
class="gl-mb-0" class="gl-mb-0"
data-testid="compareBtn" data-testid="compare-btn"
href="billing/path-for/group" href="billing/path-for/group"
icon="" icon=""
size="small" size="small"
......
...@@ -7,6 +7,7 @@ exports[`TrialStatusWidget component without the optional containerId prop match ...@@ -7,6 +7,7 @@ exports[`TrialStatusWidget component without the optional containerId prop match
> >
<div <div
class="gl-display-flex gl-flex-direction-column gl-align-items-stretch gl-w-full" class="gl-display-flex gl-flex-direction-column gl-align-items-stretch gl-w-full"
data-testid="widget-menu"
> >
<span <span
class="gl-display-flex gl-align-items-center" class="gl-display-flex gl-align-items-center"
......
...@@ -2,17 +2,12 @@ import { GlPopover } from '@gitlab/ui'; ...@@ -2,17 +2,12 @@ import { GlPopover } from '@gitlab/ui';
import { GlBreakpointInstance } from '@gitlab/ui/dist/utils'; import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
import { mount, shallowMount } from '@vue/test-utils'; import { mount, shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue'; import Vue, { nextTick } from 'vue';
import { import { POPOVER } from 'ee/contextual_sidebar/components/constants';
POPOVER,
TRACKING_PROPERTY_WHEN_FORCED,
TRACKING_PROPERTY_WHEN_VOLUNTARY,
} from 'ee/contextual_sidebar/components/constants';
import TrialStatusPopover from 'ee/contextual_sidebar/components/trial_status_popover.vue'; import TrialStatusPopover from 'ee/contextual_sidebar/components/trial_status_popover.vue';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { stubExperiments } from 'helpers/experimentation_helper'; import { stubExperiments } from 'helpers/experimentation_helper';
import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue'; import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
import axios from '~/lib/utils/axios_utils';
Vue.config.ignoredElements = ['gl-emoji']; Vue.config.ignoredElements = ['gl-emoji'];
...@@ -24,14 +19,9 @@ describe('TrialStatusPopover component', () => { ...@@ -24,14 +19,9 @@ describe('TrialStatusPopover component', () => {
const defaultDaysRemaining = 20; const defaultDaysRemaining = 20;
const findGlPopover = () => wrapper.findComponent(GlPopover); const findGlPopover = () => wrapper.findComponent(GlPopover);
const findByRef = (ref) => wrapper.find({ ref });
const expectTracking = ({ action, ...options } = {}) => { const expectTracking = ({ action, ...options } = {}) => {
return expect(trackingSpy).toHaveBeenCalledWith(undefined, action, { return expect(trackingSpy).toHaveBeenCalledWith(undefined, action, { ...options });
property: TRACKING_PROPERTY_WHEN_VOLUNTARY,
value: defaultDaysRemaining,
...options,
});
}; };
const createComponent = ({ providers = {}, mountFn = shallowMount, stubs = {} } = {}) => { const createComponent = ({ providers = {}, mountFn = shallowMount, stubs = {} } = {}) => {
...@@ -46,8 +36,6 @@ describe('TrialStatusPopover component', () => { ...@@ -46,8 +36,6 @@ describe('TrialStatusPopover component', () => {
purchaseHref: 'transactions/new', purchaseHref: 'transactions/new',
targetId: 'target-element-identifier', targetId: 'target-element-identifier',
trialEndDate: new Date('2021-02-28'), trialEndDate: new Date('2021-02-28'),
userCalloutsPath: undefined,
userCalloutsFeatureId: undefined,
user: { user: {
namespaceId: 'namespaceId', namespaceId: 'namespaceId',
userName: 'userName', userName: 'userName',
...@@ -65,7 +53,7 @@ describe('TrialStatusPopover component', () => { ...@@ -65,7 +53,7 @@ describe('TrialStatusPopover component', () => {
beforeEach(() => { beforeEach(() => {
wrapper = createComponent(); wrapper = createComponent();
trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn); trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
}); });
afterEach(() => { afterEach(() => {
...@@ -82,7 +70,7 @@ describe('TrialStatusPopover component', () => { ...@@ -82,7 +70,7 @@ describe('TrialStatusPopover component', () => {
}); });
it('tracks when the compare button is clicked', () => { it('tracks when the compare button is clicked', () => {
wrapper.findByTestId('compareBtn').vm.$emit('click'); wrapper.findByTestId('compare-btn').vm.$emit('click');
expectTracking(trackingEvents.compareBtnClick); expectTracking(trackingEvents.compareBtnClick);
}); });
...@@ -101,17 +89,14 @@ describe('TrialStatusPopover component', () => { ...@@ -101,17 +89,14 @@ describe('TrialStatusPopover component', () => {
beforeEach(() => { beforeEach(() => {
stubExperiments({ group_contact_sales: 'control' }); stubExperiments({ group_contact_sales: 'control' });
wrapper = createComponent({ stubs: { GitlabExperiment } }); wrapper = createComponent({ stubs: { GitlabExperiment } });
trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
}); });
it('matches the snapshot', () => { it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot(); expect(wrapper.element).toMatchSnapshot();
}); });
it('tracks when the upgrade button is clicked', () => { it('renders the upgrade button', () => {
findByRef('upgradeBtn').vm.$emit('click'); expect(wrapper.findByTestId('upgrade-btn').exists()).toBe(true);
expectTracking(trackingEvents.upgradeBtnClick);
}); });
}); });
...@@ -119,7 +104,7 @@ describe('TrialStatusPopover component', () => { ...@@ -119,7 +104,7 @@ describe('TrialStatusPopover component', () => {
beforeEach(() => { beforeEach(() => {
stubExperiments({ group_contact_sales: 'candidate' }); stubExperiments({ group_contact_sales: 'candidate' });
wrapper = createComponent({ stubs: { GitlabExperiment } }); wrapper = createComponent({ stubs: { GitlabExperiment } });
trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn); trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
}); });
it('matches the snapshot', () => { it('matches the snapshot', () => {
...@@ -127,126 +112,15 @@ describe('TrialStatusPopover component', () => { ...@@ -127,126 +112,15 @@ describe('TrialStatusPopover component', () => {
}); });
it('tracks when the contact sales button is clicked', () => { it('tracks when the contact sales button is clicked', () => {
wrapper.findByTestId('contactSalesBtn').trigger('click'); wrapper.findByTestId('contact-sales-btn').trigger('click');
expectTracking(trackingEvents.contactSalesBtnClick); expectTracking({ ...trackingEvents.contactSalesBtnClick, context: expect.any(Object) });
});
});
});
describe('startInitiallyShown', () => {
const userCalloutProviders = {
userCalloutsPath: 'user_callouts/path',
userCalloutsFeatureId: 'feature_id',
};
beforeEach(() => {
jest.spyOn(axios, 'post').mockResolvedValue('success');
});
describe('when set to true', () => {
beforeEach(() => {
wrapper = createComponent({ providers: { startInitiallyShown: true } });
});
it('causes the popover to be shown by default', () => {
expect(findGlPopover().attributes('show')).toBeTruthy();
});
it('removes the popover triggers', () => {
expect(findGlPopover().attributes('triggers')).toBe('');
});
describe('and the user callout values are provided', () => {
beforeEach(() => {
wrapper = createComponent({
providers: {
startInitiallyShown: true,
...userCalloutProviders,
},
});
});
it('sends a request to update the specified UserCallout record', () => {
expect(axios.post).toHaveBeenCalledWith(userCalloutProviders.userCalloutsPath, {
feature_name: userCalloutProviders.userCalloutsFeatureId,
});
});
});
describe('but the user callout values are not provided', () => {
it('does not send a request to update a UserCallout record', () => {
expect(axios.post).not.toHaveBeenCalled();
});
});
});
describe('when set to false', () => {
beforeEach(() => {
wrapper = createComponent({ providers: { ...userCalloutProviders } });
});
it('does not cause the popover to be shown by default', () => {
expect(findGlPopover().attributes('show')).toBeFalsy();
});
it('uses the standard triggers for the popover', () => {
expect(findGlPopover().attributes('triggers')).toBe('hover focus');
});
it('never sends a request to update a UserCallout record', () => {
expect(axios.post).not.toHaveBeenCalled();
});
});
});
describe('close button', () => {
describe('when the popover starts off forcibly shown', () => {
beforeEach(() => {
wrapper = createComponent({ providers: { startInitiallyShown: true }, mountFn: mount });
});
it('is enabled', () => {
expect(findGlPopover().props('showCloseButton')).toBe(true);
});
describe('when clicked', () => {
const preventDefault = jest.fn();
beforeEach(async () => {
findGlPopover().vm.$emit('close-button-clicked', {
preventDefault,
});
await nextTick();
});
it("calls `preventDefault` so user doesn't trigger the anchor tag", () => {
expect(preventDefault).toHaveBeenCalled();
});
it('closes the popover component', () => {
expect(findGlPopover().props('show')).toBeFalsy();
});
it('tracks an event', () => {
expectTracking(trackingEvents.closeBtnClick);
});
it('continues to be shown in the popover', () => {
expect(findGlPopover().props('showCloseButton')).toBe(true);
});
});
});
describe('when the popover does not start off forcibly shown', () => {
it('is not rendered', () => {
expect(findGlPopover().props('showCloseButton')).toBe(false);
}); });
}); });
}); });
describe('methods', () => { describe('methods', () => {
describe('onResize', () => { describe('updateDisabledState', () => {
it.each` it.each`
bp | isDisabled bp | isDisabled
${'xs'} | ${'true'} ${'xs'} | ${'true'}
...@@ -259,7 +133,7 @@ describe('TrialStatusPopover component', () => { ...@@ -259,7 +133,7 @@ describe('TrialStatusPopover component', () => {
async ({ bp, isDisabled }) => { async ({ bp, isDisabled }) => {
jest.spyOn(GlBreakpointInstance, 'getBreakpointSize').mockReturnValue(bp); jest.spyOn(GlBreakpointInstance, 'getBreakpointSize').mockReturnValue(bp);
wrapper.vm.onResize(); window.dispatchEvent(new Event('resize'));
await nextTick(); await nextTick();
expect(findGlPopover().attributes('disabled')).toBe(isDisabled); expect(findGlPopover().attributes('disabled')).toBe(isDisabled);
...@@ -271,30 +145,8 @@ describe('TrialStatusPopover component', () => { ...@@ -271,30 +145,8 @@ describe('TrialStatusPopover component', () => {
it('dispatches tracking event', () => { it('dispatches tracking event', () => {
findGlPopover().vm.$emit('shown'); findGlPopover().vm.$emit('shown');
expectTracking(trackingEvents.popoverShown); expectTracking({ ...trackingEvents.popoverShown, context: expect.any(Object) });
}); });
}); });
}); });
describe('trackingPropertyAndValue', () => {
it.each`
daysRemaining | startInitiallyShown | property
${14} | ${false} | ${TRACKING_PROPERTY_WHEN_VOLUNTARY}
${14} | ${true} | ${TRACKING_PROPERTY_WHEN_FORCED}
`(
'sets the expected values for `property` & `value`',
({ daysRemaining, startInitiallyShown, property }) => {
wrapper = createComponent({ providers: { daysRemaining, startInitiallyShown } });
// We'll use the "onShown" method to exercise trackingPropertyAndValue
findGlPopover().vm.$emit('shown');
expectTracking({
...trackingEvents.popoverShown,
property,
value: daysRemaining,
});
},
);
});
}); });
...@@ -51,16 +51,13 @@ describe('TrialStatusWidget component', () => { ...@@ -51,16 +51,13 @@ describe('TrialStatusWidget component', () => {
expect(findGlLink().attributes('id')).toBe(undefined); expect(findGlLink().attributes('id')).toBe(undefined);
}); });
it('tracks when the widget is clicked', () => { it('tracks when the widget menu is clicked', () => {
const { action, ...options } = trackingEvents.widgetClick; const { action, ...options } = trackingEvents.widgetClick;
const trackingSpy = mockTracking(undefined, undefined, jest.spyOn); const trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
findGlLink().vm.$emit('click'); wrapper.find('[data-testid="widget-menu"]').trigger('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, action, { expect(trackingSpy).toHaveBeenCalledWith(undefined, action, { ...options });
...options,
value: defaultDaysRemaining,
});
unmockTracking(); unmockTracking();
}); });
......
...@@ -28,7 +28,6 @@ RSpec.describe TrialStatusWidgetHelper, :saas do ...@@ -28,7 +28,6 @@ RSpec.describe TrialStatusWidgetHelper, :saas do
trial_ends_on: trial_end_date trial_ends_on: trial_end_date
) )
stub_experiments(group_contact_sales: :control) stub_experiments(group_contact_sales: :control)
stub_experiments(forcibly_show_trial_status_popover: :candidate)
allow_next_instance_of(GitlabSubscriptions::FetchSubscriptionPlansService, plan: :free) do |instance| allow_next_instance_of(GitlabSubscriptions::FetchSubscriptionPlansService, plan: :free) do |instance|
allow(instance).to receive(:execute).and_return([ allow(instance).to receive(:execute).and_return([
{ 'code' => 'ultimate', 'id' => 'ultimate-plan-id' } { 'code' => 'ultimate', 'id' => 'ultimate-plan-id' }
...@@ -37,97 +36,23 @@ RSpec.describe TrialStatusWidgetHelper, :saas do ...@@ -37,97 +36,23 @@ RSpec.describe TrialStatusWidgetHelper, :saas do
end end
describe '#trial_status_popover_data_attrs' do describe '#trial_status_popover_data_attrs' do
using RSpec::Parameterized::TableSyntax
d14_callout_id = described_class::D14_CALLOUT_ID
d3_callout_id = described_class::D3_CALLOUT_ID
let(:user_callouts_feature_id) { nil }
let(:dismissed_callout) { true }
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
before do before do
allow(helper).to receive(:current_user).and_return(user) allow(helper).to receive(:current_user).and_return(user)
allow(user).to receive(:dismissed_callout?).with(feature_name: user_callouts_feature_id).and_return(dismissed_callout)
end end
subject(:data_attrs) { helper.trial_status_popover_data_attrs(group) } subject(:data_attrs) { helper.trial_status_popover_data_attrs(group) }
shared_examples 'has correct data attributes' do it 'returns the needed data attributes for mounting the popover Vue component' do
it 'returns the needed data attributes for mounting the popover Vue component' do expect(data_attrs).to match(
expect(data_attrs).to match( shared_expected_attrs.merge(
shared_expected_attrs.merge( group_name: group.name,
group_name: group.name, purchase_href: new_subscriptions_path(namespace_id: group.id, plan_id: 'ultimate-plan-id'),
purchase_href: new_subscriptions_path(namespace_id: group.id, plan_id: 'ultimate-plan-id'), target_id: shared_expected_attrs[:container_id],
target_id: shared_expected_attrs[:container_id], trial_end_date: trial_end_date
start_initially_shown: start_initially_shown,
trial_end_date: trial_end_date,
user_callouts_path: callouts_path,
user_callouts_feature_id: user_callouts_feature_id
)
) )
end )
end
where(:trial_days_remaining, :user_callouts_feature_id, :dismissed_callout, :start_initially_shown) do
# days| callout ID | dismissed? | shown?
30 | nil | false | false
20 | nil | false | false
15 | nil | false | false
14 | d14_callout_id | false | true
14 | d14_callout_id | true | false
10 | d14_callout_id | false | true
10 | d14_callout_id | true | false
7 | d14_callout_id | false | true
7 | d14_callout_id | true | false
# days| callout ID | dismissed? | shown?
6 | nil | false | false
4 | nil | false | false
3 | d3_callout_id | false | true
3 | d3_callout_id | true | false
1 | d3_callout_id | false | true
1 | d3_callout_id | true | false
0 | d3_callout_id | false | true
0 | d3_callout_id | true | false
-1 | nil | false | false
end
with_them { include_examples 'has correct data attributes' }
context 'when not part of the experiment' do
before do
stub_experiments(forcibly_show_trial_status_popover: :control)
end
where(:trial_days_remaining, :user_callouts_feature_id, :dismissed_callout, :start_initially_shown) do
# days| callout ID | dismissed? | shown?
30 | nil | false | false
20 | nil | false | false
15 | nil | false | false
14 | d14_callout_id | false | false
14 | d14_callout_id | true | false
10 | d14_callout_id | false | false
10 | d14_callout_id | true | false
7 | d14_callout_id | false | false
7 | d14_callout_id | true | false
# days| callout ID | dismissed? | shown?
6 | nil | false | false
4 | nil | false | false
3 | d3_callout_id | false | false
3 | d3_callout_id | true | false
1 | d3_callout_id | false | false
1 | d3_callout_id | true | false
0 | d3_callout_id | false | false
0 | d3_callout_id | true | false
-1 | nil | false | false
end
with_them { include_examples 'has correct data attributes' }
end
it 'records the experiment subject' do
expect { data_attrs }.to change { ExperimentSubject.count }
end end
context 'when group_contact_sales is enabled' do context 'when group_contact_sales is enabled' do
...@@ -147,10 +72,7 @@ RSpec.describe TrialStatusWidgetHelper, :saas do ...@@ -147,10 +72,7 @@ RSpec.describe TrialStatusWidgetHelper, :saas do
group_name: group.name, group_name: group.name,
purchase_href: new_subscriptions_path(namespace_id: group.id, plan_id: 'ultimate-plan-id'), purchase_href: new_subscriptions_path(namespace_id: group.id, plan_id: 'ultimate-plan-id'),
target_id: shared_expected_attrs[:container_id], target_id: shared_expected_attrs[:container_id],
start_initially_shown: false, trial_end_date: trial_end_date
trial_end_date: trial_end_date,
user_callouts_path: callouts_path,
user_callouts_feature_id: user_callouts_feature_id
) )
) )
end end
......
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