Commit 273a053e authored by Dallas Reedy's avatar Dallas Reedy

Promote the contact_sales_btn_in_app experiment to product feature

- Remove the experiment feature flag
- Solidify the Snowplow tracking events
- Clean up the code in use
- Add & update specs accordingly

Changelog: added
parent 885ebcee
...@@ -21,10 +21,7 @@ class Groups::BillingsController < Groups::ApplicationController ...@@ -21,10 +21,7 @@ class Groups::BillingsController < Groups::ApplicationController
.new(plan: current_plan, namespace_id: relevant_group.id) .new(plan: current_plan, namespace_id: relevant_group.id)
.execute .execute
if @plans_data unless @plans_data
track_experiment_event(:contact_sales_btn_in_app, 'page_view:billing_plans:group')
record_experiment_user(:contact_sales_btn_in_app)
else
render 'shared/billings/customers_dot_unavailable' render 'shared/billings/customers_dot_unavailable'
end end
end end
......
...@@ -11,10 +11,7 @@ class Profiles::BillingsController < Profiles::ApplicationController ...@@ -11,10 +11,7 @@ class Profiles::BillingsController < Profiles::ApplicationController
.new(plan: current_user.namespace.plan_name_for_upgrading, namespace_id: current_user.namespace_id) .new(plan: current_user.namespace.plan_name_for_upgrading, namespace_id: current_user.namespace_id)
.execute .execute
if @plans_data unless @plans_data
track_experiment_event(:contact_sales_btn_in_app, 'page_view:billing_plans:profile')
record_experiment_user(:contact_sales_btn_in_app)
else
render 'shared/billings/customers_dot_unavailable' render 'shared/billings/customers_dot_unavailable'
end end
end end
......
...@@ -19,19 +19,19 @@ module BillingPlansHelper ...@@ -19,19 +19,19 @@ module BillingPlansHelper
end end
def has_upgrade?(upgrade_offer) def has_upgrade?(upgrade_offer)
upgrade_offer == :upgrade_for_free || upgrade_offer == :upgrade_for_offer [:upgrade_for_free, :upgrade_for_offer].include?(upgrade_offer)
end end
def show_contact_sales_button?(purchase_link_action, upgrade_offer) def show_contact_sales_button?(purchase_link_action, upgrade_offer)
return false unless purchase_link_action == 'upgrade' return false unless purchase_link_action == 'upgrade'
upgrade_offer == :upgrade_for_offer || [:upgrade_for_offer, :no_offer].include?(upgrade_offer)
(experiment_enabled?(:contact_sales_btn_in_app) && upgrade_offer == :no_offer)
end end
def show_upgrade_button?(purchase_link_action, upgrade_offer) def show_upgrade_button?(purchase_link_action, upgrade_offer)
purchase_link_action == 'upgrade' && return false unless purchase_link_action == 'upgrade'
(upgrade_offer == :no_offer || upgrade_offer == :upgrade_for_free)
[:no_offer, :upgrade_for_free].include?(upgrade_offer)
end end
def subscription_plan_data_attributes(namespace, plan) def subscription_plan_data_attributes(namespace, plan)
...@@ -62,18 +62,6 @@ module BillingPlansHelper ...@@ -62,18 +62,6 @@ module BillingPlansHelper
namespace.group? && (namespace.actual_plan_name == Plan::FREE || namespace.trial_active?) namespace.group? && (namespace.actual_plan_name == Plan::FREE || namespace.trial_active?)
end end
def experiment_tracking_data_for_button_click(button_label)
return {} unless Gitlab::Experimentation.active?(:contact_sales_btn_in_app)
{
track: {
event: 'click_button',
label: button_label,
property: experiment_tracking_category_and_group(:contact_sales_btn_in_app)
}
}
end
def plan_feature_list(plan) def plan_feature_list(plan)
return [] unless plan.features return [] unless plan.features
...@@ -116,11 +104,16 @@ module BillingPlansHelper ...@@ -116,11 +104,16 @@ module BillingPlansHelper
_('Seats usage data is updated every day at 12:00pm UTC') _('Seats usage data is updated every day at 12:00pm UTC')
end end
def upgrade_button_text(plan_offer_type)
plan_offer_type === :upgrade_for_free ? s_('BillingPlan|Upgrade for free') : s_('BillingPlan|Upgrade')
end
def upgrade_button_css_classes(namespace, plan, is_current_plan) def upgrade_button_css_classes(namespace, plan, is_current_plan)
css_classes = %w[btn btn-success gl-button] css_classes = []
css_classes << 'disabled' if is_current_plan && !namespace.trial_active? css_classes << 'disabled' if is_current_plan && !namespace.trial_active?
css_classes << 'invisible' if ::Feature.enabled?(:hide_deprecated_billing_plans) && plan.deprecated? css_classes << 'invisible' if ::Feature.enabled?(:hide_deprecated_billing_plans) && plan.deprecated?
css_classes << "billing-cta-purchase#{'-new' if use_new_purchase_flow?(namespace)}"
css_classes.join(' ') css_classes.join(' ')
end end
......
...@@ -63,13 +63,9 @@ ...@@ -63,13 +63,9 @@
= link_to s_("BillingPlans|See all %{plan_name} features") % { plan_name: plan.name }, EE::SUBSCRIPTIONS_COMPARISON_URL = link_to s_("BillingPlans|See all %{plan_name} features") % { plan_name: plan.name }, EE::SUBSCRIPTIONS_COMPARISON_URL
.card-footer .card-footer
- cta_class = '-new' if use_new_purchase_flow?(namespace)
- upgrade_button_classes = upgrade_button_css_classes(namespace, plan, is_current)
- upgrade_button_text = plan_offer_type === :upgrade_for_free ? s_('BillingPlan|Upgrade for free') : s_('BillingPlan|Upgrade')
- show_upgrade_button = show_upgrade_button?(purchase_link.action, plan_offer_type) - show_upgrade_button = show_upgrade_button?(purchase_link.action, plan_offer_type)
- show_contact_sales_button = show_contact_sales_button?(purchase_link.action, plan_offer_type)
.gl-min-h-7.gl-display-flex.gl-flex-wrap.gl-justify-content-end .gl-min-h-7.gl-display-flex.gl-flex-wrap.gl-justify-content-end
- if show_contact_sales_button - if show_contact_sales_button?(purchase_link.action, plan_offer_type)
= link_to s_('BillingPlan|Contact sales'), "#{contact_sales_url}?test=inappcontactsales#{plan.code}", class: ["btn gl-button", show_upgrade_button ? "btn-success-secondary" : "btn-success"], data: { **experiment_tracking_data_for_button_click('contact_sales') } = link_to s_('BillingPlan|Contact sales'), "#{contact_sales_url}?test=inappcontactsales#{plan.code}", class: ["btn gl-button", show_upgrade_button ? "btn-success-secondary" : "btn-success"], data: { 'track-action': 'click_button', 'track-label': 'contact_sales', 'track-property': plan.code }
- if show_upgrade_button - if show_upgrade_button
= link_to upgrade_button_text, plan_purchase_or_upgrade_url(namespace, plan), class: "#{upgrade_button_classes} billing-cta-purchase#{cta_class} gl-ml-3", data: { **experiment_tracking_data_for_button_click('upgrade'), qa_selector: "upgrade_to_#{plan.code}" } = link_to upgrade_button_text(plan_offer_type), plan_purchase_or_upgrade_url(namespace, plan), class: ["btn btn-success gl-button", upgrade_button_css_classes(namespace, plan, is_current), "gl-ml-3"], data: { 'track-action': 'click_button', 'track-label': 'upgrade', 'track-property': plan.code, qa_selector: "upgrade_to_#{plan.code}" }
---
name: contact_sales_btn_in_app_experiment_percentage
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38508
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/238207
milestone: '13.3'
type: experiment
group: group::conversion
default_enabled: true
...@@ -50,18 +50,6 @@ RSpec.describe Groups::BillingsController do ...@@ -50,18 +50,6 @@ RSpec.describe Groups::BillingsController do
expect(assigns(:plans_data)).to eq(data) expect(assigns(:plans_data)).to eq(data)
end end
it 'tracks the page view for the contact_sales_btn_in_app experiment' do
expect(controller).to receive(:track_experiment_event).with(:contact_sales_btn_in_app, 'page_view:billing_plans:group')
get_index
end
it 'records user for the contact_sales_btn_in_app experiment' do
expect(controller).to receive(:record_experiment_user).with(:contact_sales_btn_in_app)
get_index
end
context 'when CustomersDot is unavailable' do context 'when CustomersDot is unavailable' do
before do before do
allow_next_instance_of(GitlabSubscriptions::FetchSubscriptionPlansService) do |instance| allow_next_instance_of(GitlabSubscriptions::FetchSubscriptionPlansService) do |instance|
...@@ -69,17 +57,7 @@ RSpec.describe Groups::BillingsController do ...@@ -69,17 +57,7 @@ RSpec.describe Groups::BillingsController do
end end
end end
it 'does not track the page view for the contact_sales_btn_in_app experiment' do it 'renders a different partial' do
expect(controller).not_to receive(:track_experiment_event)
get_index
expect(response).to render_template('shared/billings/customers_dot_unavailable')
end
it 'does not record the user for the contact_sales_btn_in_app experiment' do
expect(controller).not_to receive(:record_experiment_user)
get_index get_index
expect(response).to render_template('shared/billings/customers_dot_unavailable') expect(response).to render_template('shared/billings/customers_dot_unavailable')
......
...@@ -40,18 +40,6 @@ RSpec.describe Profiles::BillingsController do ...@@ -40,18 +40,6 @@ RSpec.describe Profiles::BillingsController do
expect(assigns(:plans_data)).to eq(data) expect(assigns(:plans_data)).to eq(data)
end end
it 'tracks the page view for the contact_sales_btn_in_app experiment' do
expect(controller).to receive(:track_experiment_event).with(:contact_sales_btn_in_app, 'page_view:billing_plans:profile')
get_index
end
it 'records user for the contact_sales_btn_in_app experiment' do
expect(controller).to receive(:record_experiment_user).with(:contact_sales_btn_in_app)
get_index
end
context 'when CustomersDot is unavailable' do context 'when CustomersDot is unavailable' do
before do before do
allow_next_instance_of(GitlabSubscriptions::FetchSubscriptionPlansService) do |instance| allow_next_instance_of(GitlabSubscriptions::FetchSubscriptionPlansService) do |instance|
...@@ -59,17 +47,7 @@ RSpec.describe Profiles::BillingsController do ...@@ -59,17 +47,7 @@ RSpec.describe Profiles::BillingsController do
end end
end end
it 'does not track the page view for the contact_sales_btn_in_app experiment' do it 'renders a different partial' do
expect(controller).not_to receive(:track_experiment_event)
get_index
expect(response).to render_template('shared/billings/customers_dot_unavailable')
end
it 'does not record the user for the contact_sales_btn_in_app experiment' do
expect(controller).not_to receive(:record_experiment_user)
get_index get_index
expect(response).to render_template('shared/billings/customers_dot_unavailable') expect(response).to render_template('shared/billings/customers_dot_unavailable')
......
...@@ -17,7 +17,6 @@ RSpec.describe 'Billing plan pages', :feature, :js do ...@@ -17,7 +17,6 @@ RSpec.describe 'Billing plan pages', :feature, :js do
before do before do
stub_feature_flags(show_billing_eoa_banner: true) stub_feature_flags(show_billing_eoa_banner: true)
stub_feature_flags(hide_deprecated_billing_plans: false) stub_feature_flags(hide_deprecated_billing_plans: false)
stub_experiment_for_subject(contact_sales_btn_in_app: true)
stub_billing_plans(namespace.id, plan.name, plans_data.to_json) stub_billing_plans(namespace.id, plan.name, plans_data.to_json)
stub_eoa_eligibility_request(namespace.id) stub_eoa_eligibility_request(namespace.id)
stub_application_setting(check_namespace_plan: true) stub_application_setting(check_namespace_plan: true)
......
...@@ -277,22 +277,16 @@ RSpec.describe BillingPlansHelper do ...@@ -277,22 +277,16 @@ RSpec.describe BillingPlansHelper do
describe '#show_contact_sales_button?' do describe '#show_contact_sales_button?' do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
where(:experiment_enabled, :link_action, :upgrade_offer, :result) do where(:link_action, :upgrade_offer, :result) do
true | 'upgrade' | :no_offer | true 'upgrade' | :no_offer | true
true | 'upgrade' | :upgrade_for_offer | true 'upgrade' | :upgrade_for_free | false
true | 'no_upgrade' | :no_offer | false 'upgrade' | :upgrade_for_offer | true
true | 'no_upgrade' | :upgrade_for_offer | false 'no_upgrade' | :no_offer | false
false | 'upgrade' | :no_offer | false 'no_upgrade' | :upgrade_for_free | false
false | 'upgrade' | :upgrade_for_offer | true 'no_upgrade' | :upgrade_for_offer | false
false | 'no_upgrade' | :no_offer | false
false | 'no_upgrade' | :upgrade_for_offer | false
end end
with_them do with_them do
before do
allow(helper).to receive(:experiment_enabled?).with(:contact_sales_btn_in_app).and_return(experiment_enabled)
end
subject { helper.show_contact_sales_button?(link_action, upgrade_offer) } subject { helper.show_contact_sales_button?(link_action, upgrade_offer) }
it { is_expected.to eq(result) } it { is_expected.to eq(result) }
...@@ -318,39 +312,6 @@ RSpec.describe BillingPlansHelper do ...@@ -318,39 +312,6 @@ RSpec.describe BillingPlansHelper do
end end
end end
describe '#experiment_tracking_data_for_button_click' do
let(:button_label) { 'some_label' }
let(:experiment_enabled) { false }
subject { helper.experiment_tracking_data_for_button_click(button_label) }
before do
stub_experiment(contact_sales_btn_in_app: experiment_enabled)
end
context 'when the experiment is not enabled' do
it { is_expected.to eq({}) }
end
context 'when the experiment is enabled' do
let(:experiment_enabled) { true }
before do
allow(helper).to receive(:experiment_tracking_category_and_group).with(:contact_sales_btn_in_app).and_return("Category:control_group")
end
it 'returns a hash to be used as data-attributes in a view' do
is_expected.to eq({
track: {
event: 'click_button',
label: button_label,
property: 'Category:control_group'
}
})
end
end
end
describe '#plan_feature_list' do describe '#plan_feature_list' do
let(:plan) do let(:plan) do
Hashie::Mash.new(features: (1..3).map { |i| { title: "feat 0#{i}", highlight: i.even? } }) Hashie::Mash.new(features: (1..3).map { |i| { title: "feat 0#{i}", highlight: i.even? } })
...@@ -430,36 +391,48 @@ RSpec.describe BillingPlansHelper do ...@@ -430,36 +391,48 @@ RSpec.describe BillingPlansHelper do
end end
end end
describe '#upgrade_button_css_classes' do describe '#upgrade_button_text' do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
let(:plan) { double('Plan', deprecated?: false) } subject { helper.upgrade_button_text(plan_offer_type) }
it 'returns button-related classes only' do where(:plan_offer_type, :result) do
expect(helper.upgrade_button_css_classes(nil, plan, false)).to eq('btn btn-success gl-button') :no_offer | 'Upgrade'
:upgrade_for_free | 'Upgrade for free'
:upgrade_for_offer | 'Upgrade'
end end
where(:is_current_plan, :trial_active, :result) do with_them do
false | false | 'btn btn-success gl-button' it { is_expected.to eq(result) }
false | true | 'btn btn-success gl-button'
true | true | 'btn btn-success gl-button'
true | false | 'btn btn-success gl-button disabled'
false | false | 'btn btn-success gl-button'
end end
end
with_them do describe '#upgrade_button_css_classes' do
let(:namespace) { OpenStruct.new(trial_active: trial_active) } let(:plan) { double('Plan', deprecated?: plan_is_deprecated) }
let(:namespace) { double('Namespace', trial_active?: trial_active) }
subject { helper.upgrade_button_css_classes(namespace, plan, is_current_plan) } subject { helper.upgrade_button_css_classes(namespace, plan, is_current_plan) }
it { is_expected.to include(result) } before do
allow(helper).to receive(:use_new_purchase_flow?).and_return(use_new_purchase_flow)
end end
context 'when plan is deprecated' do where(
let(:deprecated_plan) { double('Plan', deprecated?: true) } is_current_plan: [true, false],
trial_active: [true, false],
plan_is_deprecated: [true, false],
use_new_purchase_flow: [true, false]
)
it 'returns invisible class' do with_them do
expect(helper.upgrade_button_css_classes(nil, deprecated_plan, false)).to include('invisible') it 'returns the expected list of CSS classes' do
expected_classes = [].tap do |ary|
ary << 'disabled' if is_current_plan && !trial_active
ary << 'invisible' if plan_is_deprecated
ary << "billing-cta-purchase#{'-new' if use_new_purchase_flow}"
end.join(' ')
is_expected.to eq(expected_classes)
end end
end end
end end
......
...@@ -38,10 +38,6 @@ module Gitlab ...@@ -38,10 +38,6 @@ module Gitlab
tracking_category: 'Growth::Expansion::Experiment::InviteMembersEmptyGroupVersionA', tracking_category: 'Growth::Expansion::Experiment::InviteMembersEmptyGroupVersionA',
use_backwards_compatible_subject_index: true use_backwards_compatible_subject_index: true
}, },
contact_sales_btn_in_app: {
tracking_category: 'Growth::Conversion::Experiment::ContactSalesInApp',
use_backwards_compatible_subject_index: true
},
remove_known_trial_form_fields_welcoming: { remove_known_trial_form_fields_welcoming: {
tracking_category: 'Growth::Conversion::Experiment::RemoveKnownTrialFormFieldsWelcoming', tracking_category: 'Growth::Conversion::Experiment::RemoveKnownTrialFormFieldsWelcoming',
rollout_strategy: :user rollout_strategy: :user
......
...@@ -6,10 +6,7 @@ require 'spec_helper' ...@@ -6,10 +6,7 @@ require 'spec_helper'
# Originally created as part of https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45733 for https://gitlab.com/gitlab-org/gitlab/-/issues/270858. # Originally created as part of https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45733 for https://gitlab.com/gitlab-org/gitlab/-/issues/270858.
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_empty_group_version_a]
:invite_members_empty_group_version_a,
:contact_sales_btn_in_app
]
backwards_compatible_experiment_keys = described_class.filter { |_, v| v[:use_backwards_compatible_subject_index] }.keys backwards_compatible_experiment_keys = described_class.filter { |_, v| v[:use_backwards_compatible_subject_index] }.keys
......
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