Commit 0175304d authored by Simon Knox's avatar Simon Knox

Merge branch 'sy-forcibly_show_trial_status_popover-cleanup' into 'master'

Clean up forcibly_show_trial_status_popover experiment

See merge request gitlab-org/gitlab!80413
parents bb829cc8 1b93b0c3
......@@ -4,9 +4,7 @@ const CLICK_BUTTON_ACTION = 'click_button';
const RESIZE_EVENT_DEBOUNCE_MS = 150;
export const RESIZE_EVENT = 'resize';
export const EXPERIMENT_KEY = 'forcibly_show_trial_status_popover';
export const TRACKING_PROPERTY_WHEN_FORCED = 'forced';
export const TRACKING_PROPERTY_WHEN_VOLUNTARY = 'voluntary';
export const EXPERIMENT_KEY = 'group_contact_sales';
export const WIDGET = {
i18n: {
......@@ -21,11 +19,7 @@ export const WIDGET = {
},
},
trackingEvents: {
widgetClick: {
action: 'click_link',
label: 'trial_status_widget',
property: TRACKING_PROPERTY_WHEN_VOLUNTARY,
},
widgetClick: { action: 'click_link', label: 'trial_status_widget' },
},
};
......@@ -43,9 +37,7 @@ export const POPOVER = {
},
trackingEvents: {
popoverShown: { action: 'popover_shown', label: 'trial_status_popover' },
closeBtnClick: { action: CLICK_BUTTON_ACTION, label: 'close_popover' },
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' },
},
resizeEventDebounceMS: RESIZE_EVENT_DEBOUNCE_MS,
......
......@@ -5,17 +5,10 @@ import { debounce } from 'lodash';
import { removeTrialSuffix } from 'ee/billings/billings_util';
import { shouldHandRaiseLeadButtonMount } from 'ee/hand_raise_leads/hand_raise_lead';
import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
import axios from '~/lib/utils/axios_utils';
import { formatDate } from '~/lib/utils/datetime_utility';
import { sprintf } from '~/locale';
import Tracking from '~/tracking';
import {
POPOVER,
RESIZE_EVENT,
EXPERIMENT_KEY,
TRACKING_PROPERTY_WHEN_FORCED,
TRACKING_PROPERTY_WHEN_VOLUNTARY,
} from './constants';
import { POPOVER, RESIZE_EVENT, EXPERIMENT_KEY } from './constants';
const {
i18n,
......@@ -41,18 +34,13 @@ export default {
planName: {},
plansHref: {},
purchaseHref: {},
startInitiallyShown: { default: false },
targetId: {},
trialEndDate: {},
userCalloutsPath: {},
userCalloutsFeatureId: {},
user: {},
},
data() {
return {
disabled: false,
forciblyShowing: false,
show: false,
};
},
i18n,
......@@ -69,27 +57,13 @@ export default {
planName: removeTrialSuffix(this.planName),
});
},
trackingPropertyAndValue() {
return {
property: this.forciblyShowing
? TRACKING_PROPERTY_WHEN_FORCED
: TRACKING_PROPERTY_WHEN_VOLUNTARY,
value: this.daysRemaining,
};
},
},
created() {
this.debouncedResize = debounce(() => this.onResize(), resizeEventDebounceMS);
this.debouncedResize = debounce(() => this.updateDisabledState(), resizeEventDebounceMS);
window.addEventListener(RESIZE_EVENT, this.debouncedResize);
if (this.startInitiallyShown) {
this.forciblyShowing = true;
this.show = true;
this.onForciblyShown();
}
},
mounted() {
this.onResize();
this.updateDisabledState();
},
beforeDestroy() {
window.removeEventListener(RESIZE_EVENT, this.debouncedResize);
......@@ -97,34 +71,15 @@ export default {
methods: {
trackPageAction(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() {
this.updateDisabledState();
updateDisabledState() {
this.disabled = disabledBreakpoints.includes(bp.getBreakpointSize());
},
onShown() {
this.trackPageAction('popoverShown');
shouldHandRaiseLeadButtonMount();
},
updateDisabledState() {
this.disabled = disabledBreakpoints.includes(bp.getBreakpointSize());
},
},
};
</script>
......@@ -132,17 +87,13 @@ export default {
<template>
<gl-popover
ref="popover"
placement="rightbottom"
boundary="viewport"
:container="containerId"
:target="targetId"
:disabled="disabled"
placement="rightbottom"
boundary="viewport"
:delay="{ hide: 400 }"
:show="show"
:triggers="forciblyShowing ? '' : 'hover focus'"
:show-close-button="startInitiallyShown"
@shown="onShown"
@close-button-clicked.prevent="onClose"
>
<template #title>
{{ $options.i18n.popoverTitle }}
......@@ -160,21 +111,20 @@ export default {
<gitlab-experiment name="group_contact_sales">
<template #control>
<gl-button
ref="upgradeBtn"
data-testid="upgrade-btn"
category="primary"
variant="confirm"
size="small"
class="gl-mb-0"
block
:href="purchaseHref"
@click="trackPageAction('upgradeBtnClick')"
>
<span class="gl-font-sm">{{ upgradeButtonTitle }}</span>
</gl-button>
</template>
<template #candidate>
<div data-testid="contactSalesBtn" @click="trackPageAction('contactSalesBtnClick')">
<div data-testid="contact-sales-btn" @click="trackPageAction('contactSalesBtnClick')">
<div
class="js-hand-raise-lead-button"
:data-namespace-id="user.namespaceId"
......@@ -196,7 +146,7 @@ export default {
size="small"
class="gl-mb-0"
block
data-testid="compareBtn"
data-testid="compare-btn"
:title="$options.i18n.compareAllButtonTitle"
@click="trackPageAction('compareBtnClick')"
>
......
......@@ -36,15 +36,19 @@ export default {
methods: {
onWidgetClick() {
const { action, ...options } = trackingEvents.widgetClick;
this.track(action, { ...options, value: this.daysRemaining });
this.track(action, { ...options });
},
},
};
</script>
<template>
<gl-link :id="containerId" :title="widgetTitle" :href="plansHref" @click="onWidgetClick">
<div class="gl-display-flex gl-flex-direction-column gl-align-items-stretch gl-w-full">
<gl-link :id="containerId" :title="widgetTitle" :href="plansHref">
<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="nav-icon-container svg-container">
<img :src="navIconImagePath" width="16" class="svg" />
......
......@@ -42,11 +42,8 @@ export const initTrialStatusPopover = () => {
planName,
plansHref,
purchaseHref,
startInitiallyShown,
targetId,
trialEndDate,
userCalloutsPath,
userCalloutsFeatureId,
namespaceId,
userName,
firstName,
......@@ -64,11 +61,8 @@ export const initTrialStatusPopover = () => {
planName,
plansHref,
purchaseHref,
startInitiallyShown: startInitiallyShown !== undefined,
targetId,
trialEndDate: new Date(trialEndDate),
userCalloutsPath,
userCalloutsFeatureId,
user: {
namespaceId,
userName,
......
......@@ -6,11 +6,6 @@
# the codebase) could trigger the need to extract these patterns into a single,
# reusable, sharable helper.
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)
hand_raise_attrs = experiment(:group_contact_sales, namespace: group.root_ancestor, user: current_user, sticky_to: current_user) do |e|
e.control { {} }
......@@ -23,11 +18,8 @@ module TrialStatusWidgetHelper
days_remaining: group.trial_days_remaining, # for experiment tracking
group_name: group.name,
purchase_href: ultimate_subscription_path_for_group(group),
start_initially_shown: force_popover_to_be_shown?(group),
target_id: base_attrs[:container_id],
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)
trial_end_date: group.trial_ends_on
)
end
......@@ -49,32 +41,6 @@ module TrialStatusWidgetHelper
group.trial_active? && can?(current_user, :admin_namespace, group)
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)
{
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
delay="[object Object]"
placement="rightbottom"
target="target-element-identifier"
triggers="hover focus"
>
<gl-sprintf-stub
......@@ -18,7 +17,7 @@ exports[`TrialStatusPopover component group_contact_sales experiment candidate m
class="gl-mt-5"
>
<div
data-testid="contactSalesBtn"
data-testid="contact-sales-btn"
>
<div
class="js-hand-raise-lead-button"
......@@ -37,7 +36,7 @@ exports[`TrialStatusPopover component group_contact_sales experiment candidate m
buttontextclasses=""
category="secondary"
class="gl-mb-0"
data-testid="compareBtn"
data-testid="compare-btn"
href="billing/path-for/group"
icon=""
size="small"
......@@ -61,7 +60,6 @@ exports[`TrialStatusPopover component group_contact_sales experiment control mat
delay="[object Object]"
placement="rightbottom"
target="target-element-identifier"
triggers="hover focus"
>
<gl-sprintf-stub
......@@ -76,6 +74,7 @@ exports[`TrialStatusPopover component group_contact_sales experiment control mat
buttontextclasses=""
category="primary"
class="gl-mb-0"
data-testid="upgrade-btn"
href="transactions/new"
icon=""
size="small"
......@@ -93,7 +92,7 @@ exports[`TrialStatusPopover component group_contact_sales experiment control mat
buttontextclasses=""
category="secondary"
class="gl-mb-0"
data-testid="compareBtn"
data-testid="compare-btn"
href="billing/path-for/group"
icon=""
size="small"
......
......@@ -7,6 +7,7 @@ exports[`TrialStatusWidget component without the optional containerId prop match
>
<div
class="gl-display-flex gl-flex-direction-column gl-align-items-stretch gl-w-full"
data-testid="widget-menu"
>
<span
class="gl-display-flex gl-align-items-center"
......
......@@ -2,17 +2,12 @@ import { GlPopover } from '@gitlab/ui';
import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
import { mount, shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import {
POPOVER,
TRACKING_PROPERTY_WHEN_FORCED,
TRACKING_PROPERTY_WHEN_VOLUNTARY,
} from 'ee/contextual_sidebar/components/constants';
import { POPOVER } from 'ee/contextual_sidebar/components/constants';
import TrialStatusPopover from 'ee/contextual_sidebar/components/trial_status_popover.vue';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { stubExperiments } from 'helpers/experimentation_helper';
import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue';
import axios from '~/lib/utils/axios_utils';
Vue.config.ignoredElements = ['gl-emoji'];
......@@ -24,14 +19,9 @@ describe('TrialStatusPopover component', () => {
const defaultDaysRemaining = 20;
const findGlPopover = () => wrapper.findComponent(GlPopover);
const findByRef = (ref) => wrapper.find({ ref });
const expectTracking = ({ action, ...options } = {}) => {
return expect(trackingSpy).toHaveBeenCalledWith(undefined, action, {
property: TRACKING_PROPERTY_WHEN_VOLUNTARY,
value: defaultDaysRemaining,
...options,
});
return expect(trackingSpy).toHaveBeenCalledWith(undefined, action, { ...options });
};
const createComponent = ({ providers = {}, mountFn = shallowMount, stubs = {} } = {}) => {
......@@ -46,8 +36,6 @@ describe('TrialStatusPopover component', () => {
purchaseHref: 'transactions/new',
targetId: 'target-element-identifier',
trialEndDate: new Date('2021-02-28'),
userCalloutsPath: undefined,
userCalloutsFeatureId: undefined,
user: {
namespaceId: 'namespaceId',
userName: 'userName',
......@@ -65,7 +53,7 @@ describe('TrialStatusPopover component', () => {
beforeEach(() => {
wrapper = createComponent();
trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
});
afterEach(() => {
......@@ -82,7 +70,7 @@ describe('TrialStatusPopover component', () => {
});
it('tracks when the compare button is clicked', () => {
wrapper.findByTestId('compareBtn').vm.$emit('click');
wrapper.findByTestId('compare-btn').vm.$emit('click');
expectTracking(trackingEvents.compareBtnClick);
});
......@@ -101,17 +89,14 @@ describe('TrialStatusPopover component', () => {
beforeEach(() => {
stubExperiments({ group_contact_sales: 'control' });
wrapper = createComponent({ stubs: { GitlabExperiment } });
trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
});
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('tracks when the upgrade button is clicked', () => {
findByRef('upgradeBtn').vm.$emit('click');
expectTracking(trackingEvents.upgradeBtnClick);
it('renders the upgrade button', () => {
expect(wrapper.findByTestId('upgrade-btn').exists()).toBe(true);
});
});
......@@ -119,7 +104,7 @@ describe('TrialStatusPopover component', () => {
beforeEach(() => {
stubExperiments({ group_contact_sales: 'candidate' });
wrapper = createComponent({ stubs: { GitlabExperiment } });
trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
});
it('matches the snapshot', () => {
......@@ -127,126 +112,15 @@ describe('TrialStatusPopover component', () => {
});
it('tracks when the contact sales button is clicked', () => {
wrapper.findByTestId('contactSalesBtn').trigger('click');
expectTracking(trackingEvents.contactSalesBtnClick);
});
});
});
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();
});
wrapper.findByTestId('contact-sales-btn').trigger('click');
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);
expectTracking({ ...trackingEvents.contactSalesBtnClick, context: expect.any(Object) });
});
});
});
describe('methods', () => {
describe('onResize', () => {
describe('updateDisabledState', () => {
it.each`
bp | isDisabled
${'xs'} | ${'true'}
......@@ -259,7 +133,7 @@ describe('TrialStatusPopover component', () => {
async ({ bp, isDisabled }) => {
jest.spyOn(GlBreakpointInstance, 'getBreakpointSize').mockReturnValue(bp);
wrapper.vm.onResize();
window.dispatchEvent(new Event('resize'));
await nextTick();
expect(findGlPopover().attributes('disabled')).toBe(isDisabled);
......@@ -271,30 +145,8 @@ describe('TrialStatusPopover component', () => {
it('dispatches tracking event', () => {
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', () => {
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 trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
findGlLink().vm.$emit('click');
wrapper.find('[data-testid="widget-menu"]').trigger('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, action, {
...options,
value: defaultDaysRemaining,
});
expect(trackingSpy).toHaveBeenCalledWith(undefined, action, { ...options });
unmockTracking();
});
......
......@@ -28,7 +28,6 @@ RSpec.describe TrialStatusWidgetHelper, :saas do
trial_ends_on: trial_end_date
)
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(instance).to receive(:execute).and_return([
{ 'code' => 'ultimate', 'id' => 'ultimate-plan-id' }
......@@ -37,98 +36,24 @@ RSpec.describe TrialStatusWidgetHelper, :saas do
end
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) }
before do
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
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
expect(data_attrs).to match(
shared_expected_attrs.merge(
group_name: group.name,
purchase_href: new_subscriptions_path(namespace_id: group.id, plan_id: 'ultimate-plan-id'),
target_id: shared_expected_attrs[:container_id],
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
trial_end_date: trial_end_date
)
)
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
context 'when group_contact_sales is enabled' do
before do
......@@ -147,10 +72,7 @@ RSpec.describe TrialStatusWidgetHelper, :saas do
group_name: group.name,
purchase_href: new_subscriptions_path(namespace_id: group.id, plan_id: 'ultimate-plan-id'),
target_id: shared_expected_attrs[:container_id],
start_initially_shown: false,
trial_end_date: trial_end_date,
user_callouts_path: callouts_path,
user_callouts_feature_id: user_callouts_feature_id
trial_end_date: trial_end_date
)
)
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