Commit dc10f37e authored by Miguel Rincon's avatar Miguel Rincon

Merge branch '348252-improve-saas-trial-form-by-updating-required-fields-add-state' into 'master'

Convert new trial creation form to Vue

See merge request gitlab-org/gitlab!77537
parents cff7bd5a bcbe2b3d
...@@ -60,10 +60,7 @@ export const trackSaasTrialSubmit = () => { ...@@ -60,10 +60,7 @@ export const trackSaasTrialSubmit = () => {
return; return;
} }
const form = document.getElementById('new_trial'); pushEvent('saasTrialSubmit');
form.addEventListener('submit', () => {
pushEvent('saasTrialSubmit');
});
}; };
export const trackSaasTrialSkip = () => { export const trackSaasTrialSkip = () => {
......
...@@ -15,7 +15,32 @@ import Tracking from '~/tracking'; ...@@ -15,7 +15,32 @@ import Tracking from '~/tracking';
import countriesQuery from 'ee/subscriptions/graphql/queries/countries.query.graphql'; import countriesQuery from 'ee/subscriptions/graphql/queries/countries.query.graphql';
import statesQuery from 'ee/subscriptions/graphql/queries/states.query.graphql'; import statesQuery from 'ee/subscriptions/graphql/queries/states.query.graphql';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow'; import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
import { i18n, companySizes, COUNTRIES_WITH_STATES_ALLOWED } from '../constants'; import {
LEADS_COMPANY_NAME_LABEL,
LEADS_COMPANY_SIZE_LABEL,
LEADS_COUNTRY_LABEL,
LEADS_COUNTRY_PROMPT,
LEADS_FIRST_NAME_LABEL,
LEADS_LAST_NAME_LABEL,
LEADS_PHONE_NUMBER_LABEL,
companySizes,
} from 'ee/vue_shared/leads/constants';
import {
COUNTRIES_WITH_STATES_ALLOWED,
PQL_COMPANY_SIZE_PROMPT,
PQL_PHONE_DESCRIPTION,
PQL_STATE_LABEL,
PQL_STATE_PROMPT,
PQL_COMMENT_LABEL,
PQL_BUTTON_TEXT,
PQL_MODAL_TITLE,
PQL_MODAL_PRIMARY,
PQL_MODAL_CANCEL,
PQL_MODAL_HEADER_TEXT,
PQL_MODAL_FOOTER_TEXT,
PQL_HAND_RAISE_ACTION_ERROR,
PQL_HAND_RAISE_ACTION_SUCCESS,
} from '../constants';
export default { export default {
name: 'HandRaiseLeadButton', name: 'HandRaiseLeadButton',
...@@ -180,7 +205,28 @@ export default { ...@@ -180,7 +205,28 @@ export default {
}); });
}, },
}, },
i18n, i18n: {
firstNameLabel: LEADS_FIRST_NAME_LABEL,
lastNameLabel: LEADS_LAST_NAME_LABEL,
companyNameLabel: LEADS_COMPANY_NAME_LABEL,
companySizeLabel: LEADS_COMPANY_SIZE_LABEL,
phoneNumberLabel: LEADS_PHONE_NUMBER_LABEL,
countryLabel: LEADS_COUNTRY_LABEL,
countrySelectPrompt: LEADS_COUNTRY_PROMPT,
companySizeSelectPrompt: PQL_COMPANY_SIZE_PROMPT,
phoneNumberDescription: PQL_PHONE_DESCRIPTION,
stateLabel: PQL_STATE_LABEL,
stateSelectPrompt: PQL_STATE_PROMPT,
commentLabel: PQL_COMMENT_LABEL,
buttonText: PQL_BUTTON_TEXT,
modalTitle: PQL_MODAL_TITLE,
modalPrimary: PQL_MODAL_PRIMARY,
modalCancel: PQL_MODAL_CANCEL,
modalHeaderText: PQL_MODAL_HEADER_TEXT,
modalFooterText: PQL_MODAL_FOOTER_TEXT,
handRaiseActionError: PQL_HAND_RAISE_ACTION_ERROR,
handRaiseActionSuccess: PQL_HAND_RAISE_ACTION_SUCCESS,
},
}; };
</script> </script>
......
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
export const i18n = Object.freeze({ export const PQL_COMPANY_SIZE_PROMPT = __('- Select -');
firstNameLabel: __('First Name'), export const PQL_PHONE_DESCRIPTION = __('Provide a number our sales team can use to call you.');
lastNameLabel: __('Last Name'), export const PQL_STATE_LABEL = __('State/Province/City');
companyNameLabel: __('Company Name'), export const PQL_STATE_PROMPT = s__('PQL|Please select a city or state');
companySizeLabel: __('Number of employees'), export const PQL_COMMENT_LABEL = s__('PQL|Message for the Sales team (optional)');
companySizeSelectPrompt: __('- Select -'), export const PQL_BUTTON_TEXT = s__('PQL|Contact sales');
phoneNumberLabel: __('Telephone number'), export const PQL_MODAL_TITLE = s__('PQL|Contact our Sales team');
phoneNumberDescription: __('Provide a number our sales team can use to call you.'), export const PQL_MODAL_PRIMARY = s__('PQL|Submit information');
countryLabel: __('Country'), export const PQL_MODAL_CANCEL = s__('PQL|Cancel');
countrySelectPrompt: __('Please select a country'), export const PQL_MODAL_HEADER_TEXT = s__(
stateLabel: __('State/Province/City'), 'PQL|Hello %{userName}. Before putting you in touch with our sales team, we would like you to verify and complete the information below.',
stateSelectPrompt: s__('PQL|Please select a city or state'), );
commentLabel: s__('PQL|Message for the Sales team (optional)'), export const PQL_MODAL_FOOTER_TEXT = s__(
buttonText: s__('PQL|Contact sales'), 'PQL|By providing my contact information, I agree GitLab may contact me via email about its product, services and events. You may opt-out at any time by unsubscribing in emails or visiting our communication preference center.',
modalTitle: s__('PQL|Contact our Sales team'), );
modalPrimary: s__('PQL|Submit information'), export const PQL_HAND_RAISE_ACTION_ERROR = s__(
modalCancel: s__('PQL|Cancel'), 'PQL|An error occurred while sending hand raise lead.',
modalHeaderText: s__( );
'PQL|Hello %{userName}. Before putting you in touch with our sales team, we would like you to verify and complete the information below.', export const PQL_HAND_RAISE_ACTION_SUCCESS = s__(
), 'PQL|Thank you for reaching out! Our sales team will get back to you soon.',
modalFooterText: s__( );
'PQL|By providing my contact information, I agree GitLab may contact me via email about its product, services and events. You may opt-out at any time by unsubscribing in emails or visiting our communication preference center.',
),
handRaiseActionError: s__('PQL|An error occurred while sending hand raise lead.'),
handRaiseActionSuccess: s__(
'PQL|Thank you for reaching out! Our sales team will get back to you soon.',
),
});
export const companySizes = Object.freeze([
{
name: '1 - 99',
id: '1-99',
},
{
name: '100 - 499',
id: '100-499',
},
{
name: '500 - 1,999',
id: '500-1,999',
},
{
name: '2,000 - 9,999',
id: '2,000-9,999',
},
{
name: '10,000 +',
id: '10,000+',
},
]);
export const COUNTRIES_WITH_STATES_ALLOWED = ['US', 'CA']; export const COUNTRIES_WITH_STATES_ALLOWED = ['US', 'CA'];
import 'ee/trials/country_select';
import 'ee/trials/track_trial_user_errors'; import 'ee/trials/track_trial_user_errors';
import { initTrialCreateLeadForm } from 'ee/trials/init_create_lead_form';
initTrialCreateLeadForm();
import 'ee/trials/country_select'; import { trackSaasTrialSkip } from '~/google_tag_manager';
import { trackSaasTrialSubmit, trackSaasTrialSkip } from '~/google_tag_manager'; import { initTrialCreateLeadForm } from 'ee/trials/init_create_lead_form';
trackSaasTrialSubmit(); initTrialCreateLeadForm();
trackSaasTrialSkip(); trackSaasTrialSkip();
<script>
import { GlForm, GlButton, GlFormGroup, GlFormInput, GlFormSelect } from '@gitlab/ui';
import csrf from '~/lib/utils/csrf';
import countriesQuery from 'ee/subscriptions/graphql/queries/countries.query.graphql';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
import { trackSaasTrialSubmit } from '~/google_tag_manager';
import {
LEADS_COMPANY_NAME_LABEL,
LEADS_COMPANY_SIZE_LABEL,
LEADS_COUNTRY_LABEL,
LEADS_COUNTRY_PROMPT,
LEADS_FIRST_NAME_LABEL,
LEADS_LAST_NAME_LABEL,
LEADS_PHONE_NUMBER_LABEL,
companySizes,
} from 'ee/vue_shared/leads/constants';
import {
TRIAL_COMPANY_SIZE_PROMPT,
TRIAL_FORM_SUBMIT_TEXT,
TRIAL_PHONE_DESCRIPTION,
} from '../constants';
export default {
name: 'TrialCreateLeadForm',
csrf,
components: {
GlForm,
GlButton,
GlFormGroup,
GlFormInput,
GlFormSelect,
},
directives: {
autofocusonshow,
},
inject: ['user', 'submitPath'],
data() {
return {
...this.user,
countries: [],
};
},
apollo: {
countries: {
query: countriesQuery,
},
},
computed: {
companySizeOptionsWithDefault() {
return [
{
name: this.$options.i18n.companySizeSelectPrompt,
id: null,
},
...companySizes,
];
},
countryOptionsWithDefault() {
return [
{
name: this.$options.i18n.countrySelectPrompt,
id: null,
},
...this.countries,
];
},
},
methods: {
onSubmit() {
trackSaasTrialSubmit();
},
},
i18n: {
firstNameLabel: LEADS_FIRST_NAME_LABEL,
lastNameLabel: LEADS_LAST_NAME_LABEL,
companyNameLabel: LEADS_COMPANY_NAME_LABEL,
companySizeLabel: LEADS_COMPANY_SIZE_LABEL,
phoneNumberLabel: LEADS_PHONE_NUMBER_LABEL,
countryLabel: LEADS_COUNTRY_LABEL,
countrySelectPrompt: LEADS_COUNTRY_PROMPT,
formSubmitText: TRIAL_FORM_SUBMIT_TEXT,
companySizeSelectPrompt: TRIAL_COMPANY_SIZE_PROMPT,
phoneNumberDescription: TRIAL_PHONE_DESCRIPTION,
},
};
</script>
<template>
<gl-form :action="submitPath" method="post" @submit="onSubmit">
<input :value="$options.csrf.token" type="hidden" name="authenticity_token" />
<div class="gl-display-flex gl-flex-direction-column gl-sm-flex-direction-row gl-mt-5">
<gl-form-group
:label="$options.i18n.firstNameLabel"
label-size="sm"
label-for="first_name"
class="gl-mr-5 gl-w-half gl-xs-w-full"
>
<gl-form-input
id="first_name"
:value="firstName"
name="first_name"
data-qa-selector="first_name"
data-testid="first_name"
required
/>
</gl-form-group>
<gl-form-group
:label="$options.i18n.lastNameLabel"
label-size="sm"
label-for="last_name"
class="gl-w-half gl-xs-w-full"
>
<gl-form-input
id="last_name"
:value="lastName"
name="last_name"
data-qa-selector="last_name"
data-testid="last_name"
required
/>
</gl-form-group>
</div>
<gl-form-group :label="$options.i18n.companyNameLabel" label-size="sm" label-for="company_name">
<gl-form-input
id="company_name"
:value="companyName"
name="company_name"
data-qa-selector="company_name"
data-testid="company_name"
required
/>
</gl-form-group>
<gl-form-group :label="$options.i18n.companySizeLabel" label-size="sm" label-for="company_size">
<gl-form-select
id="company_size"
:value="companySize"
name="company_size"
:options="companySizeOptionsWithDefault"
value-field="id"
text-field="name"
data-qa-selector="number_of_employees"
data-testid="company_size"
required
/>
</gl-form-group>
<gl-form-group
v-if="!$apollo.loading.countries"
:label="$options.i18n.countryLabel"
label-size="sm"
label-for="country"
>
<gl-form-select
id="country"
:value="country"
name="country"
:options="countryOptionsWithDefault"
value-field="id"
text-field="name"
data-qa-selector="country"
data-testid="country"
required
/>
</gl-form-group>
<gl-form-group
:label="$options.i18n.phoneNumberLabel"
label-size="sm"
:description="$options.i18n.phoneNumberDescription"
label-for="phone_number"
>
<gl-form-input
id="phone_number"
:value="phoneNumber"
name="phone_number"
type="tel"
data-qa-selector="telephone_number"
data-testid="phone_number"
pattern="^(\+)*[0-9-\s]+$"
required
/>
</gl-form-group>
<gl-button type="submit" variant="confirm" class="gl-w-20" data-qa-selector="continue">
{{ $options.i18n.formSubmitText }}
</gl-button>
</gl-form>
</template>
import { s__, __ } from '~/locale';
export const TRIAL_FORM_SUBMIT_TEXT = s__('Trial|Continue');
export const TRIAL_COMPANY_SIZE_PROMPT = __('Please select');
export const TRIAL_PHONE_DESCRIPTION = s__('Trial|Allowed characters: +, 0-9, -, and spaces.');
import Vue from 'vue';
import TrialCreateLeadForm from 'ee/trials/components/trial_create_lead_form.vue';
import apolloProvider from 'ee/subscriptions/buy_addons_shared/graphql';
export const initTrialCreateLeadForm = () => {
const el = document.querySelector('#js-trial-create-lead-form');
const {
submitPath,
firstName,
lastName,
companyName,
companySize,
country,
phoneNumber,
} = el.dataset;
return new Vue({
el,
apolloProvider,
provide: {
user: {
firstName,
lastName,
companyName,
companySize: companySize || null,
country: country || null,
phoneNumber,
},
submitPath,
},
render(createElement) {
return createElement(TrialCreateLeadForm);
},
});
};
import { __ } from '~/locale';
export const LEADS_FIRST_NAME_LABEL = __('First Name');
export const LEADS_LAST_NAME_LABEL = __('Last Name');
export const LEADS_COMPANY_NAME_LABEL = __('Company Name');
export const LEADS_COMPANY_SIZE_LABEL = __('Number of employees');
export const LEADS_PHONE_NUMBER_LABEL = __('Telephone number');
export const LEADS_COUNTRY_LABEL = __('Country');
export const LEADS_COUNTRY_PROMPT = __('Please select a country');
export const companySizes = Object.freeze([
{
name: '1 - 99',
id: '1-99',
},
{
name: '100 - 499',
id: '100-499',
},
{
name: '500 - 1,999',
id: '500-1,999',
},
{
name: '2,000 - 9,999',
id: '2,000-9,999',
},
{
name: '10,000 +',
id: '10,000+',
},
]);
...@@ -13,6 +13,15 @@ module EE ...@@ -13,6 +13,15 @@ module EE
], selected) ], selected)
end end
def create_lead_form_data
{
submit_path: create_lead_trials_path(glm_params),
first_name: current_user.first_name,
last_name: current_user.last_name,
company_name: current_user.organization
}.merge(params.slice(:first_name, :last_name, :company_name, :company_size, :phone_number, :country).to_unsafe_h.symbolize_keys)
end
def should_ask_company_question? def should_ask_company_question?
glm_params[:glm_source] != 'about.gitlab.com' glm_params[:glm_source] != 'about.gitlab.com'
end end
......
- page_title _('Start your Free Ultimate Trial') - page_title _('Start your Free Ultimate Trial')
- glm_params = { glm_source: params[:glm_source], glm_content: params[:glm_content] }
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= render "layouts/google_tag_manager_head" = render "layouts/google_tag_manager_head"
= render "layouts/one_trust" = render "layouts/one_trust"
...@@ -15,27 +14,7 @@ ...@@ -15,27 +14,7 @@
= render 'errors' = render 'errors'
= form_tag create_lead_trials_path(glm_params), method: :post, id: "new_trial" do |_f| #js-trial-create-lead-form{ data: create_lead_form_data }
.form-row
.col-12.col-sm-6.form-group
= label_tag :first_name, s_('Trial|First name'), for: :first_name, class: 'col-form-label'
= text_field_tag :first_name, params[:first_name] || current_user.first_name, class: 'form-control gl-form-input', required: true, data: { qa_selector: 'first_name' }
.col-12.col-sm-6.form-group
= label_tag :last_name, s_('Trial|Last name'), for: :last_name, class: 'col-form-label'
= text_field_tag :last_name, params[:last_name] || current_user.last_name, class: 'form-control gl-form-input', required: true, data: { qa_selector: 'last_name' }
.form-group
= label_tag :company_name, s_('Trial|Company name'), for: :company_name, class: 'col-form-label'
= text_field_tag :company_name, params[:company_name] || current_user.organization, class: 'form-control gl-form-input', required: true, data: { qa_selector: 'company_name' }
.form-group.gl-select2-html5-required-fix
= label_tag :company_size, s_('Trial|Number of employees'), for: :company_size, class: 'col-form-label'
= select_tag :company_size, company_size_options_for_select(params[:company_size]), class: 'select2', required: true, data: { qa_selector: 'number_of_employees' }
.form-group.gl-select2-html5-required-fix
= render 'select_country'
.form-group
= label_tag :phone_number, s_('Trial|Telephone number'), for: :phone_number, class: 'col-form-label'
= telephone_field_tag :phone_number, params[:phone_number], pattern: '^(\+)*[0-9-\s]+$', class: 'form-control gl-form-input', required: true, data: { qa_selector: 'telephone_number' }
%p.gl-text-gray-500= _('Allowed characters: +, 0-9, -, and spaces.')
= submit_tag s_('Trial|Continue'), class: 'btn gl-button btn-confirm gl-w-20', data: { qa_selector: 'continue' }
= render 'skip_trial' = render 'skip_trial'
......
...@@ -64,29 +64,6 @@ RSpec.describe 'GitLab.com Google Analytics DataLayer', :js do ...@@ -64,29 +64,6 @@ RSpec.describe 'GitLab.com Google Analytics DataLayer', :js do
end end
end end
context 'on new trial page' do
it 'tracks form submissions in the dataLayer' do
sign_in user
visit new_trial_path
evaluate_script('document.getElementById("new_trial").addEventListener("submit", e => e.preventDefault())')
fill_in 'first_name', with: user_attrs[:first_name]
fill_in 'last_name', with: user_attrs[:last_name]
fill_in 'company_name', with: user_attrs[:company_name]
evaluate_script("document.getElementById('company_size').value = '1-99'")
fill_in 'phone_number', with: user_attrs[:phone_number]
evaluate_script("document.getElementById('country_select').value = 'US'")
click_button 'Continue'
data_layer = execute_script('return window.dataLayer')
last_event_in_data_layer = data_layer[-1]
expect(last_event_in_data_layer["event"]).to eq("saasTrialSubmit")
end
end
context 'on trial group select page' do context 'on trial group select page' do
it 'tracks create group events' do it 'tracks create group events' do
sign_in user sign_in user
......
...@@ -3,80 +3,103 @@ ...@@ -3,80 +3,103 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe 'Trial Capture Lead', :js do RSpec.describe 'Trial Capture Lead', :js do
include Select2Helper let_it_be(:user) { create(:user) }
let(:user) { create(:user) }
before do before do
allow(Gitlab).to receive(:com?).and_return(true).at_least(:once) allow(Gitlab).to receive(:com?).and_return(true).at_least(:once)
sign_in(user) sign_in(user)
end visit new_trial_path
context 'when user' do wait_for_requests
before do end
visit new_trial_path
wait_for_requests context 'with valid company information' do
let(:form_data) do
{
phone_number: '+1 23 456-78-90',
company_size: '1 - 99',
company_name: 'GitLab',
country: { id: 'US', name: 'United States of America' }
}
end end
context 'enters valid company information' do before do
before do trial_user_params = {
expect_any_instance_of(GitlabSubscriptions::CreateLeadService).to receive(:execute) do "company_name" => form_data[:company_name],
{ success: true } "company_size" => form_data[:company_size].delete(' '),
end "first_name" => user.first_name,
"last_name" => user.last_name,
"phone_number" => form_data[:phone_number],
"country" => form_data.dig(:country, :id),
"work_email" => user.email,
"uid" => user.id,
"setup_for_company" => user.setup_for_company,
"skip_email_confirmation" => true,
"gitlab_com_trial" => true,
"provider" => "gitlab",
"newsletter_segment" => user.email_opted_in
}
lead_params = {
trial_user: ActionController::Parameters.new(trial_user_params).permit!
}
expect_any_instance_of(GitlabSubscriptions::CreateLeadService).to receive(:execute).with(lead_params) do
{ success: true }
end end
end
it 'proceeds to the next step' do it 'proceeds to the next step' do
fill_in 'company_name', with: 'GitLab' fill_in 'company_name', with: form_data[:company_name]
select2 '1-99', from: '#company_size' select form_data[:company_size], from: 'company_size'
fill_in 'phone_number', with: '+1 23 456-78-90' fill_in 'phone_number', with: form_data[:phone_number]
select2 'US', from: '#country_select' select form_data.dig(:country, :name), from: 'country'
click_button 'Continue' click_button 'Continue'
expect(page).not_to have_css('flash-container') expect(page).not_to have_css('flash-container')
expect(current_path).to eq(select_trials_path) expect(current_path).to eq(select_trials_path)
end
end end
end
context 'enters company information' do context 'with phone number validations' do
before do before do
fill_in 'company_name', with: 'GitLab' fill_in 'company_name', with: 'GitLab'
select2 '1-99', from: '#company_size' select '1 - 99', from: 'company_size'
select2 'US', from: '#country_select' select 'United States of America', from: 'country'
end end
context 'without phone number' do
it 'shows validation error' do
click_button 'Continue'
message = page.find('#phone_number').native.attribute('validationMessage') context 'without phone number' do
it 'shows validation error' do
click_button 'Continue'
expect(message).to eq('Please fill out this field.') expect(phone_validation_message).to eq('Please fill out this field.')
expect(current_path).to eq(new_trial_path) expect(current_path).to eq(new_trial_path)
end
end end
end
context 'with invalid phone number format' do context 'with invalid phone number format' do
it 'shows validation error' do it 'shows validation error' do
invalid_phone_numbers = [ invalid_phone_numbers = [
'+1 (121) 22-12-23', '+1 (121) 22-12-23',
'+12190AX ', '+12190AX ',
'Tel:129120', 'Tel:129120',
'11290+12' '11290+12'
] ]
invalid_phone_numbers.each do |phone_number|
fill_in 'phone_number', with: phone_number
click_button 'Continue' invalid_phone_numbers.each do |phone_number|
fill_in 'phone_number', with: phone_number
message = page.find('#phone_number').native.attribute('validationMessage') click_button 'Continue'
expect(message).to eq('Please match the requested format.') expect(phone_validation_message).to eq('Please match the requested format.')
expect(current_path).to eq(new_trial_path) expect(current_path).to eq(new_trial_path)
end
end end
end end
end end
def phone_validation_message
page.find('[data-testid="phone_number"]').native.attribute('validationMessage')
end
end end
end end
...@@ -6,7 +6,13 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; ...@@ -6,7 +6,13 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
import { mockTracking } from 'helpers/tracking_helper'; import { mockTracking } from 'helpers/tracking_helper';
import HandRaiseLeadButton from 'ee/hand_raise_leads/hand_raise_lead/components/hand_raise_lead_button.vue'; import HandRaiseLeadButton from 'ee/hand_raise_leads/hand_raise_lead/components/hand_raise_lead_button.vue';
import { i18n } from 'ee/hand_raise_leads/hand_raise_lead/constants'; import {
PQL_BUTTON_TEXT,
PQL_MODAL_PRIMARY,
PQL_MODAL_CANCEL,
PQL_MODAL_HEADER_TEXT,
PQL_MODAL_FOOTER_TEXT,
} from 'ee/hand_raise_leads/hand_raise_lead/constants';
import * as SubscriptionsApi from 'ee/api/subscriptions_api'; import * as SubscriptionsApi from 'ee/api/subscriptions_api';
import { formData, states, countries } from './mock_data'; import { formData, states, countries } from './mock_data';
...@@ -67,7 +73,7 @@ describe('HandRaiseLeadButton', () => { ...@@ -67,7 +73,7 @@ describe('HandRaiseLeadButton', () => {
}); });
it('has the "Contact sales" text on the button', () => { it('has the "Contact sales" text on the button', () => {
expect(findButton().text()).toBe(i18n.buttonText); expect(findButton().text()).toBe(PQL_BUTTON_TEXT);
}); });
it('has the default injected values', async () => { it('has the default injected values', async () => {
...@@ -103,17 +109,17 @@ describe('HandRaiseLeadButton', () => { ...@@ -103,17 +109,17 @@ describe('HandRaiseLeadButton', () => {
}); });
it('has the correct text in the modal content', () => { it('has the correct text in the modal content', () => {
expect(findModal().text()).toContain(sprintf(i18n.modalHeaderText, { userName: 'joe' })); expect(findModal().text()).toContain(sprintf(PQL_MODAL_HEADER_TEXT, { userName: 'joe' }));
expect(findModal().text()).toContain(i18n.modalFooterText); expect(findModal().text()).toContain(PQL_MODAL_FOOTER_TEXT);
}); });
it('has the correct modal props', () => { it('has the correct modal props', () => {
expect(findModal().props('actionPrimary')).toStrictEqual({ expect(findModal().props('actionPrimary')).toStrictEqual({
text: i18n.modalPrimary, text: PQL_MODAL_PRIMARY,
attributes: [{ variant: 'success' }, { disabled: true }], attributes: [{ variant: 'success' }, { disabled: true }],
}); });
expect(findModal().props('actionCancel')).toStrictEqual({ expect(findModal().props('actionCancel')).toStrictEqual({
text: i18n.modalCancel, text: PQL_MODAL_CANCEL,
}); });
}); });
...@@ -139,7 +145,7 @@ describe('HandRaiseLeadButton', () => { ...@@ -139,7 +145,7 @@ describe('HandRaiseLeadButton', () => {
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
expect(findModal().props('actionPrimary')).toStrictEqual({ expect(findModal().props('actionPrimary')).toStrictEqual({
text: i18n.modalPrimary, text: PQL_MODAL_PRIMARY,
attributes: [{ variant: 'success' }, { disabled: false }], attributes: [{ variant: 'success' }, { disabled: false }],
}); });
}); });
......
export const submitPath = '_submit_path_';
export const formData = {
firstName: 'Joe',
lastName: 'Doe',
companyName: 'ACME',
companySize: '1-99',
phoneNumber: '192919',
country: 'US',
};
import { GlButton, GlForm } from '@gitlab/ui';
import { createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import TrialCreateLeadForm from 'ee/trials/components/trial_create_lead_form.vue';
import { TRIAL_FORM_SUBMIT_TEXT } from 'ee/trials/constants';
import { trackSaasTrialSubmit } from '~/google_tag_manager';
import { formData, submitPath } from './mock_data';
jest.mock('~/google_tag_manager', () => ({
trackSaasTrialSubmit: jest.fn(),
}));
const localVue = createLocalVue();
localVue.use(VueApollo);
describe('TrialCreateLeadForm', () => {
let wrapper;
const createComponent = ({ mountFunction = shallowMountExtended } = {}) => {
const mockResolvers = {
Query: {
countries() {
return [{ id: 'US', name: 'United States' }];
},
},
};
return mountFunction(TrialCreateLeadForm, {
localVue,
apolloProvider: createMockApollo([], mockResolvers),
provide: {
submitPath,
user: formData,
},
});
};
const findForm = () => wrapper.findComponent(GlForm);
const findButton = () => wrapper.findComponent(GlButton);
const findFormInput = (testId) => wrapper.findByTestId(testId);
afterEach(() => {
wrapper.destroy();
});
describe('rendering', () => {
beforeEach(() => {
wrapper = createComponent();
});
it('has the "Continue" text on the submit button', () => {
expect(findButton().text()).toBe(TRIAL_FORM_SUBMIT_TEXT);
});
it.each`
testid | value
${'first_name'} | ${'Joe'}
${'last_name'} | ${'Doe'}
${'company_name'} | ${'ACME'}
${'phone_number'} | ${'192919'}
${'company_size'} | ${'1-99'}
${'country'} | ${'US'}
`('has the default injected value for $testid', ({ testid, value }) => {
expect(findFormInput(testid).attributes('value')).toBe(value);
});
it('has the correct form input in the form content', () => {
const visibleFields = [
'first_name',
'last_name',
'company_name',
'company_size',
'phone_number',
'country',
];
visibleFields.forEach((f) => expect(wrapper.findByTestId(f).exists()).toBe(true));
});
});
describe('submitting', () => {
beforeEach(() => {
wrapper = createComponent({ mountFunction: mountExtended });
});
it('tracks the saas Trial', () => {
findForm().trigger('submit');
expect(trackSaasTrialSubmit).toHaveBeenCalled();
});
});
});
...@@ -5,6 +5,56 @@ require 'spec_helper' ...@@ -5,6 +5,56 @@ require 'spec_helper'
RSpec.describe EE::TrialHelper do RSpec.describe EE::TrialHelper do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
describe '#create_lead_form_data' do
let(:user) do
double('User', first_name: '_first_name_', last_name: '_last_name_', organization: '_company_name_')
end
let(:extra_params) do
{
first_name: '_params_first_name_',
last_name: '_params_last_name_',
company_name: '_params_company_name_',
company_size: '_company_size_',
phone_number: '1234',
country: '_country_'
}
end
let(:params) do
ActionController::Parameters.new(extra_params.merge(glm_source: '_glm_source_', glm_content: '_glm_content_'))
end
before do
allow(helper).to receive(:params).and_return(params)
allow(helper).to receive(:current_user).and_return(user)
end
it 'provides expected form data' do
keys = extra_params.keys + [:submit_path]
expect(helper.create_lead_form_data.keys.map(&:to_sym)).to match_array(keys)
end
it 'allows overriding data with params' do
expect(helper.create_lead_form_data).to match(a_hash_including(extra_params))
end
context 'when params are empty' do
let(:extra_params) { {} }
it 'uses the values from current user' do
current_user_attributes = {
first_name: user.first_name,
last_name: user.last_name,
company_name: user.organization
}
expect(helper.create_lead_form_data).to match(a_hash_including(current_user_attributes))
end
end
end
describe '#should_ask_company_question?' do describe '#should_ask_company_question?' do
before do before do
allow(helper).to receive(:glm_params).and_return(glm_source ? { glm_source: glm_source } : {}) allow(helper).to receive(:glm_params).and_return(glm_source ? { glm_source: glm_source } : {})
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'trials/new.html.haml' do
include ApplicationHelper
let_it_be(:variant) { :control }
let_it_be(:user) { build(:user) }
before do
allow(view).to receive(:current_user) { user }
render
end
subject { rendered }
it 'has fields for first, last company name and size', :aggregate_failures do
is_expected.to have_field('first_name')
is_expected.to have_field('last_name')
is_expected.to have_field('company_name')
sizes = ['Please select', '1 - 99', '100 - 499', '500 - 1,999', '2,000 - 9,999', '10,000 +']
is_expected.to have_select('company_size', options: sizes, selected: [])
end
end
...@@ -37550,6 +37550,9 @@ msgstr "" ...@@ -37550,6 +37550,9 @@ msgstr ""
msgid "Trials|Your trial ends on %{boldStart}%{trialEndDate}%{boldEnd}. We hope you’re enjoying the features of GitLab %{planName}. To keep those features after your trial ends, you’ll need to buy a subscription. (You can also choose GitLab Premium if it meets your needs.)" msgid "Trials|Your trial ends on %{boldStart}%{trialEndDate}%{boldEnd}. We hope you’re enjoying the features of GitLab %{planName}. To keep those features after your trial ends, you’ll need to buy a subscription. (You can also choose GitLab Premium if it meets your needs.)"
msgstr "" msgstr ""
msgid "Trial|Allowed characters: +, 0-9, -, and spaces."
msgstr ""
msgid "Trial|Company name" msgid "Trial|Company name"
msgstr "" msgstr ""
...@@ -37565,15 +37568,9 @@ msgstr "" ...@@ -37565,15 +37568,9 @@ msgstr ""
msgid "Trial|Dismiss" msgid "Trial|Dismiss"
msgstr "" msgstr ""
msgid "Trial|First name"
msgstr ""
msgid "Trial|GitLab Ultimate trial (optional)" msgid "Trial|GitLab Ultimate trial (optional)"
msgstr "" msgstr ""
msgid "Trial|Last name"
msgstr ""
msgid "Trial|Number of employees" msgid "Trial|Number of employees"
msgstr "" msgstr ""
......
...@@ -135,9 +135,6 @@ describe('~/google_tag_manager/index', () => { ...@@ -135,9 +135,6 @@ describe('~/google_tag_manager/index', () => {
describe.each([ describe.each([
createOmniAuthTestCase(trackFreeTrialAccountSubmissions, 'freeThirtyDayTrial'), createOmniAuthTestCase(trackFreeTrialAccountSubmissions, 'freeThirtyDayTrial'),
createOmniAuthTestCase(trackNewRegistrations, 'standardSignUp'), createOmniAuthTestCase(trackNewRegistrations, 'standardSignUp'),
createTestCase(trackSaasTrialSubmit, {
forms: [{ id: 'new_trial', expectation: { event: 'saasTrialSubmit' } }],
}),
createTestCase(trackSaasTrialSkip, { createTestCase(trackSaasTrialSkip, {
links: [{ cls: 'js-skip-trial', expectation: { event: 'saasTrialSkip' } }], links: [{ cls: 'js-skip-trial', expectation: { event: 'saasTrialSkip' } }],
}), }),
...@@ -202,6 +199,18 @@ describe('~/google_tag_manager/index', () => { ...@@ -202,6 +199,18 @@ describe('~/google_tag_manager/index', () => {
}); });
}); });
describe('No listener events', () => {
it('when trackSaasTrialSubmit is invoked', () => {
expect(spy).not.toHaveBeenCalled();
trackSaasTrialSubmit();
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith({ event: 'saasTrialSubmit' });
expect(logError).not.toHaveBeenCalled();
});
});
describe.each([ describe.each([
{ dataLayer: null }, { dataLayer: null },
{ gon: { features: null } }, { gon: { features: null } },
......
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