Add newsletter signup to profiler (https://github.com/woocommerce/woocommerce-admin/pull/7601)
* Add email address field to store details step in OBW (https://github.com/woocommerce/woocommerce-admin/pull/7552) * Subscribe store_email to MailChimp (https://github.com/woocommerce/woocommerce-admin/pull/7579) * Add prefill for email field in OBW (https://github.com/woocommerce/woocommerce-admin/pull/7570) * Add error handling for email validation errors from backend (https://github.com/woocommerce/woocommerce-admin/pull/7590) * Remove OnboardingEmailMarketing note class (https://github.com/woocommerce/woocommerce-admin/pull/7595) Co-authored-by: Ilyas Foo <foo.ilyas@gmail.com> Co-authored-by: Moon <moon.kyong@automattic.com>
This commit is contained in:
parent
ccdd32282d
commit
6d23ab7ea1
|
@ -2,6 +2,18 @@
|
|||
|
||||
## Unreleased
|
||||
|
||||
### Add Newsletter Signup #7601
|
||||
|
||||
- Start OBW and set up your browser console to monitor tracks. To do this, run `localStorage.setItem( 'debug', 'wc-admin:*' );`
|
||||
- Observe "Get tips, product updates and inspiration straight to your mailbox" checkbox and "Email address" field in the Store Details step.
|
||||
- Checking the checkbox should make the email field required, you should not be able to continue if it's not filled.
|
||||
- Fill in the email address field with a valid email and click on continue.
|
||||
- Observe in the track `wcadmin_storeprofiler_store_details_continue` with prop `email_signup` that appropriately flags if the user agreed to receive marketing emails.
|
||||
- Continue until Business Features step.
|
||||
- Observe the "I'm setting up a store for a client" checkbox in the step.
|
||||
- Click on continue.
|
||||
- Observe in the track `wcadmin_storeprofiler_store_business_details_continue_variant` with prop `setup_client` that appropriately flags if the user is setting up store for a client.
|
||||
|
||||
### Making business details sticky in OBW #7426
|
||||
|
||||
1. Start out with a fresh store
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: Dev
|
||||
|
||||
Add email address field to OBW #7552
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: Add
|
||||
|
||||
Added MailchimpScheduler that runs daily to subscribe store_email in the profile data #7579
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: Update
|
||||
|
||||
Deleted OnboardingEmailMarketing note class #7595
|
|
@ -11,6 +11,8 @@ import {
|
|||
CardFooter,
|
||||
TabPanel,
|
||||
__experimentalText as Text,
|
||||
FlexItem,
|
||||
CheckboxControl,
|
||||
} from '@wordpress/components';
|
||||
import { withDispatch, withSelect } from '@wordpress/data';
|
||||
import { SelectControl, Form, TextControl } from '@woocommerce/components';
|
||||
|
@ -138,6 +140,7 @@ class BusinessDetails extends Component {
|
|||
product_count: productCount,
|
||||
revenue,
|
||||
selling_venues: sellingVenues,
|
||||
setup_client: isSetupClient,
|
||||
} = this.state.savedValues;
|
||||
|
||||
const updates = {
|
||||
|
@ -147,6 +150,7 @@ class BusinessDetails extends Component {
|
|||
product_count: productCount,
|
||||
revenue,
|
||||
selling_venues: sellingVenues,
|
||||
setup_client: isSetupClient,
|
||||
...additions,
|
||||
};
|
||||
|
||||
|
@ -242,6 +246,7 @@ class BusinessDetails extends Component {
|
|||
product_count: productCount,
|
||||
selling_venues: sellingVenues,
|
||||
revenue,
|
||||
setup_client: isSetupClient,
|
||||
} ) {
|
||||
const { getCurrencyConfig } = this.context;
|
||||
|
||||
|
@ -252,6 +257,7 @@ class BusinessDetails extends Component {
|
|||
revenue,
|
||||
used_platform: otherPlatform,
|
||||
used_platform_name: otherPlatformName,
|
||||
setup_client: isSetupClient,
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -392,7 +398,22 @@ class BusinessDetails extends Component {
|
|||
</>
|
||||
) }
|
||||
</CardBody>
|
||||
<CardFooter isBorderless justify="center">
|
||||
<CardFooter isBorderless>
|
||||
<FlexItem>
|
||||
<div className="woocommerce-profile-wizard__client">
|
||||
<CheckboxControl
|
||||
label={ __(
|
||||
"I'm setting up a store for a client",
|
||||
'woocommerce-admin'
|
||||
) }
|
||||
{ ...getInputProps(
|
||||
'setup_client'
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
</FlexItem>
|
||||
</CardFooter>
|
||||
<CardFooter justify="center">
|
||||
<Button
|
||||
isPrimary
|
||||
onClick={ async () => {
|
||||
|
|
|
@ -18,8 +18,5 @@
|
|||
&__body {
|
||||
padding: $gap $gap 0;
|
||||
}
|
||||
&__footer {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ export const BusinessDetailsStep = ( props ) => {
|
|||
product_count: profileItems.product_count || '',
|
||||
selling_venues: profileItems.selling_venues || '',
|
||||
revenue: profileItems.revenue || '',
|
||||
setup_client: profileItems.setup_client || false,
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
@ -9,12 +9,13 @@ import {
|
|||
CardFooter,
|
||||
CheckboxControl,
|
||||
FlexItem as MaybeFlexItem,
|
||||
Spinner,
|
||||
Popover,
|
||||
} from '@wordpress/components';
|
||||
import { Component } from '@wordpress/element';
|
||||
import { Component, useRef } from '@wordpress/element';
|
||||
import { compose } from '@wordpress/compose';
|
||||
import { withDispatch, withSelect } from '@wordpress/data';
|
||||
import { Form } from '@woocommerce/components';
|
||||
import { Form, TextControl } from '@woocommerce/components';
|
||||
import { getSetting } from '@woocommerce/wc-admin-settings';
|
||||
import {
|
||||
ONBOARDING_STORE_NAME,
|
||||
|
@ -48,10 +49,15 @@ const FlextItemSubstitute = ( { children, align } ) => {
|
|||
};
|
||||
const FlexItem = MaybeFlexItem || FlextItemSubstitute;
|
||||
|
||||
const LoadingPlaceholder = () => (
|
||||
<div className="woocommerce-admin__store-details__spinner">
|
||||
<Spinner />
|
||||
</div>
|
||||
);
|
||||
|
||||
class StoreDetails extends Component {
|
||||
constructor( props ) {
|
||||
super( props );
|
||||
const { profileItems, settings } = props;
|
||||
|
||||
this.state = {
|
||||
showUsageModal: false,
|
||||
|
@ -60,22 +66,6 @@ class StoreDetails extends Component {
|
|||
isSkipSetupPopoverVisible: false,
|
||||
};
|
||||
|
||||
// Check if a store address is set so that we don't default
|
||||
// to WooCommerce's default country of the UK.
|
||||
const countryState =
|
||||
( settings.woocommerce_store_address &&
|
||||
settings.woocommerce_default_country ) ||
|
||||
'';
|
||||
|
||||
this.initialValues = {
|
||||
addressLine1: settings.woocommerce_store_address || '',
|
||||
addressLine2: settings.woocommerce_store_address_2 || '',
|
||||
city: settings.woocommerce_store_city || '',
|
||||
countryState,
|
||||
postCode: settings.woocommerce_store_postcode || '',
|
||||
isClient: profileItems.setup_client || false,
|
||||
};
|
||||
|
||||
this.onContinue = this.onContinue.bind( this );
|
||||
this.onSubmit = this.onSubmit.bind( this );
|
||||
}
|
||||
|
@ -109,12 +99,11 @@ class StoreDetails extends Component {
|
|||
const {
|
||||
createNotice,
|
||||
goToNextStep,
|
||||
isSettingsError,
|
||||
updateProfileItems,
|
||||
isProfileItemsError,
|
||||
updateAndPersistSettingsForGroup,
|
||||
profileItems,
|
||||
settings,
|
||||
errorsRef,
|
||||
} = this.props;
|
||||
|
||||
const currencySettings = this.deriveCurrencySettings(
|
||||
|
@ -126,7 +115,7 @@ class StoreDetails extends Component {
|
|||
recordEvent( 'storeprofiler_store_details_continue', {
|
||||
store_country: getCountryCode( values.countryState ),
|
||||
derived_currency: currencySettings.currency_code,
|
||||
setup_client: values.isClient,
|
||||
email_signup: values.isAgreeMarketing,
|
||||
} );
|
||||
|
||||
await updateAndPersistSettingsForGroup( 'general', {
|
||||
|
@ -147,7 +136,11 @@ class StoreDetails extends Component {
|
|||
},
|
||||
} );
|
||||
|
||||
const profileItemsToUpdate = { setup_client: values.isClient };
|
||||
const profileItemsToUpdate = {
|
||||
is_agree_marketing: values.isAgreeMarketing,
|
||||
store_email: values.storeEmail,
|
||||
};
|
||||
|
||||
const region = getCurrencyRegion( values.countryState );
|
||||
|
||||
/**
|
||||
|
@ -174,9 +167,20 @@ class StoreDetails extends Component {
|
|||
profileItemsToUpdate.industry = trimmedIndustries;
|
||||
}
|
||||
|
||||
await updateProfileItems( profileItemsToUpdate );
|
||||
let errorMessages = [];
|
||||
try {
|
||||
await updateProfileItems( profileItemsToUpdate );
|
||||
} catch ( error ) {
|
||||
// Array of error messages obtained from API response.
|
||||
if ( error?.data?.params ) {
|
||||
errorMessages = Object.values( error.data.params );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isSettingsError && ! isProfileItemsError ) {
|
||||
if (
|
||||
! Boolean( errorsRef.current.settings ) &&
|
||||
! errorMessages.length
|
||||
) {
|
||||
goToNextStep();
|
||||
} else {
|
||||
createNotice(
|
||||
|
@ -186,9 +190,39 @@ class StoreDetails extends Component {
|
|||
'woocommerce-admin'
|
||||
)
|
||||
);
|
||||
|
||||
errorMessages.forEach( ( message ) =>
|
||||
createNotice( 'error', message )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
validateStoreDetails( values ) {
|
||||
const errors = validateStoreAddress( values );
|
||||
|
||||
if (
|
||||
values.isAgreeMarketing &&
|
||||
( ! values.storeEmail || ! values.storeEmail.trim().length )
|
||||
) {
|
||||
errors.storeEmail = __(
|
||||
'Please add an email address',
|
||||
'woocommerce-admin'
|
||||
);
|
||||
}
|
||||
if (
|
||||
values.storeEmail &&
|
||||
values.storeEmail.trim().length &&
|
||||
values.storeEmail.indexOf( '@' ) === -1
|
||||
) {
|
||||
errors.storeEmail = __(
|
||||
'Invalid email address',
|
||||
'woocommerce-admin'
|
||||
);
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
showUsageModal,
|
||||
|
@ -196,7 +230,7 @@ class StoreDetails extends Component {
|
|||
isStoreDetailsPopoverVisible,
|
||||
isSkipSetupPopoverVisible,
|
||||
} = this.state;
|
||||
const { skipProfiler, isBusy } = this.props;
|
||||
const { skipProfiler, isLoading, isBusy, initialValues } = this.props;
|
||||
|
||||
/* eslint-disable @wordpress/i18n-no-collapsible-whitespace */
|
||||
const skipSetupText = __(
|
||||
|
@ -210,6 +244,14 @@ class StoreDetails extends Component {
|
|||
);
|
||||
/* eslint-enable @wordpress/i18n-no-collapsible-whitespace */
|
||||
|
||||
if ( isLoading ) {
|
||||
return (
|
||||
<div className="woocommerce-profile-wizard__store-details">
|
||||
<LoadingPlaceholder />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="woocommerce-profile-wizard__store-details">
|
||||
<div className="woocommerce-profile-wizard__step-header">
|
||||
|
@ -258,9 +300,9 @@ class StoreDetails extends Component {
|
|||
</div>
|
||||
|
||||
<Form
|
||||
initialValues={ this.initialValues }
|
||||
initialValues={ initialValues }
|
||||
onSubmit={ this.onSubmit }
|
||||
validate={ validateStoreAddress }
|
||||
validate={ this.validateStoreDetails }
|
||||
>
|
||||
{ ( {
|
||||
getInputProps,
|
||||
|
@ -292,17 +334,29 @@ class StoreDetails extends Component {
|
|||
getInputProps={ getInputProps }
|
||||
setValue={ setValue }
|
||||
/>
|
||||
|
||||
<TextControl
|
||||
label={ __(
|
||||
'Email address',
|
||||
'woocommerce-admin'
|
||||
) }
|
||||
required
|
||||
autoComplete="email"
|
||||
{ ...getInputProps( 'storeEmail' ) }
|
||||
/>
|
||||
</CardBody>
|
||||
|
||||
<CardFooter>
|
||||
<FlexItem>
|
||||
<div className="woocommerce-profile-wizard__client">
|
||||
<div>
|
||||
<CheckboxControl
|
||||
label={ __(
|
||||
"I'm setting up a store for a client",
|
||||
'Get tips, product updates and inspiration straight to your mailbox',
|
||||
'woocommerce-admin'
|
||||
) }
|
||||
{ ...getInputProps( 'isClient' ) }
|
||||
{ ...getInputProps(
|
||||
'isAgreeMarketing'
|
||||
) }
|
||||
/>
|
||||
</div>
|
||||
</FlexItem>
|
||||
|
@ -376,30 +430,59 @@ export default compose(
|
|||
isUpdateSettingsRequesting,
|
||||
} = select( SETTINGS_STORE_NAME );
|
||||
const {
|
||||
getOnboardingError,
|
||||
getProfileItems,
|
||||
isOnboardingRequesting,
|
||||
getEmailPrefill,
|
||||
hasFinishedResolution: hasFinishedResolutionOnboarding,
|
||||
} = select( ONBOARDING_STORE_NAME );
|
||||
const { isResolving } = select( OPTIONS_STORE_NAME );
|
||||
|
||||
const profileItems = getProfileItems();
|
||||
const isProfileItemsError = Boolean(
|
||||
getOnboardingError( 'updateProfileItems' )
|
||||
);
|
||||
|
||||
const { general: settings = {} } = getSettings( 'general' );
|
||||
const isSettingsError = Boolean( getSettingsError( 'general' ) );
|
||||
const isBusy =
|
||||
isOnboardingRequesting( 'updateProfileItems' ) ||
|
||||
isUpdateSettingsRequesting( 'general' ) ||
|
||||
isResolving( 'getOption', [ 'woocommerce_allow_tracking' ] );
|
||||
const isLoading =
|
||||
! hasFinishedResolutionOnboarding( 'getProfileItems' ) ||
|
||||
! hasFinishedResolutionOnboarding( 'getEmailPrefill' );
|
||||
const errorsRef = useRef( {
|
||||
settings: null,
|
||||
} );
|
||||
errorsRef.current = {
|
||||
settings: getSettingsError( 'general' ),
|
||||
};
|
||||
// Check if a store address is set so that we don't default
|
||||
// to WooCommerce's default country of the UK.
|
||||
const countryState =
|
||||
( settings.woocommerce_store_address &&
|
||||
settings.woocommerce_default_country ) ||
|
||||
'';
|
||||
|
||||
const initialValues = {
|
||||
addressLine1: settings.woocommerce_store_address || '',
|
||||
addressLine2: settings.woocommerce_store_address_2 || '',
|
||||
city: settings.woocommerce_store_city || '',
|
||||
countryState,
|
||||
postCode: settings.woocommerce_store_postcode || '',
|
||||
isAgreeMarketing:
|
||||
typeof profileItems.is_agree_marketing === 'boolean'
|
||||
? profileItems.is_agree_marketing
|
||||
: true,
|
||||
storeEmail:
|
||||
typeof profileItems.store_email === 'string'
|
||||
? profileItems.store_email
|
||||
: getEmailPrefill(),
|
||||
};
|
||||
|
||||
return {
|
||||
isProfileItemsError,
|
||||
isSettingsError,
|
||||
initialValues,
|
||||
isLoading,
|
||||
profileItems,
|
||||
isBusy,
|
||||
settings,
|
||||
errorsRef,
|
||||
};
|
||||
} ),
|
||||
withDispatch( ( dispatch ) => {
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
.woocommerce-profile-wizard__store-details {
|
||||
.woocommerce-admin__store-details__spinner {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.components-popover .components-popover__content {
|
||||
min-width: 360px;
|
||||
}
|
||||
|
|
|
@ -193,10 +193,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.woocommerce-profile-wizard__client {
|
||||
margin: $gap-smaller 0;
|
||||
}
|
||||
|
||||
.woocommerce-profile-wizard__checkbox {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
|
|
|
@ -5,7 +5,12 @@ import { BasePage } from '../../pages/BasePage';
|
|||
import { waitForElementByText } from '../../utils/actions';
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { setCheckbox, unsetCheckbox } = require( '@woocommerce/e2e-utils' );
|
||||
const {
|
||||
setCheckbox,
|
||||
unsetCheckbox,
|
||||
verifyCheckboxIsSet,
|
||||
verifyCheckboxIsUnset,
|
||||
} = require( '@woocommerce/e2e-utils' );
|
||||
/* eslint-enable @typescript-eslint/no-var-requires */
|
||||
|
||||
export class BusinessSection extends BasePage {
|
||||
|
@ -66,4 +71,18 @@ export class BusinessSection extends BasePage {
|
|||
'.woocommerce-profile-wizard__benefit .components-form-toggle__input'
|
||||
);
|
||||
}
|
||||
|
||||
async selectSetupForClient() {
|
||||
await setCheckbox( '.components-checkbox-control__input' );
|
||||
}
|
||||
|
||||
async checkClientSetupCheckbox( selected: boolean ) {
|
||||
if ( selected ) {
|
||||
await verifyCheckboxIsSet( '.components-checkbox-control__input' );
|
||||
} else {
|
||||
await verifyCheckboxIsUnset(
|
||||
'.components-checkbox-control__input'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
*/
|
||||
import { DropdownTypeaheadField } from '../../elements/DropdownTypeaheadField';
|
||||
import { BasePage } from '../../pages/BasePage';
|
||||
import { waitForElementByText } from '../../utils/actions';
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const {
|
||||
setCheckbox,
|
||||
clearAndFillInput,
|
||||
verifyCheckboxIsSet,
|
||||
verifyCheckboxIsUnset,
|
||||
|
@ -22,6 +22,7 @@ interface StoreDetails {
|
|||
countryRegion?: string;
|
||||
city?: string;
|
||||
postcode?: string;
|
||||
storeEmail?: string;
|
||||
}
|
||||
|
||||
export class StoreDetailsSection extends BasePage {
|
||||
|
@ -29,6 +30,10 @@ export class StoreDetailsSection extends BasePage {
|
|||
return this.getDropdownTypeahead( '#woocommerce-select-control' );
|
||||
}
|
||||
|
||||
async isDisplayed() {
|
||||
await waitForElementByText( 'h2', 'Welcome to WooCommerce' );
|
||||
}
|
||||
|
||||
async completeStoreDetailsSection( storeDetails: StoreDetails = {} ) {
|
||||
// const onboardingWizard = new OnboardingWizard( page );
|
||||
// Fill store's address - first line
|
||||
|
@ -66,8 +71,14 @@ export class StoreDetailsSection extends BasePage {
|
|||
config.get( 'addresses.admin.store.postcode' )
|
||||
);
|
||||
|
||||
// Verify that checkbox next to "I'm setting up a store for a client" is not selected
|
||||
await this.checkClientSetupCheckbox( false );
|
||||
// Fill store's email address
|
||||
await this.fillEmailAddress(
|
||||
storeDetails.storeEmail ||
|
||||
config.get( 'addresses.admin.store.email' )
|
||||
);
|
||||
|
||||
// Verify that checkbox next to "Get tips, product updates and inspiration straight to your mailbox" is selected
|
||||
await this.checkMarketingCheckbox( true );
|
||||
}
|
||||
|
||||
async fillAddress( address: string ) {
|
||||
|
@ -95,11 +106,11 @@ export class StoreDetailsSection extends BasePage {
|
|||
await clearAndFillInput( '#inspector-text-control-3', postalCode );
|
||||
}
|
||||
|
||||
async selectSetupForClient() {
|
||||
await setCheckbox( '.components-checkbox-control__input' );
|
||||
async fillEmailAddress( email: string ) {
|
||||
await clearAndFillInput( '#inspector-text-control-4', email );
|
||||
}
|
||||
|
||||
async checkClientSetupCheckbox( selected: boolean ) {
|
||||
async checkMarketingCheckbox( selected: boolean ) {
|
||||
if ( selected ) {
|
||||
await verifyCheckboxIsSet( '.components-checkbox-control__input' );
|
||||
} else {
|
||||
|
|
|
@ -37,6 +37,7 @@ const testAdminOnboardingWizard = () => {
|
|||
} );
|
||||
|
||||
it( 'can complete the store details section', async () => {
|
||||
await profileWizard.storeDetails.isDisplayed();
|
||||
await profileWizard.storeDetails.completeStoreDetailsSection();
|
||||
// Wait for "Continue" button to become active
|
||||
await profileWizard.continue();
|
||||
|
@ -81,7 +82,7 @@ const testAdminOnboardingWizard = () => {
|
|||
await profileWizard.business.selectCurrentlySelling(
|
||||
config.get( 'onboardingwizard.sellingelsewhere' )
|
||||
);
|
||||
|
||||
await profileWizard.business.checkClientSetupCheckbox( false );
|
||||
await profileWizard.continue();
|
||||
} );
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ const TYPES = {
|
|||
SET_ERROR: 'SET_ERROR',
|
||||
SET_IS_REQUESTING: 'SET_IS_REQUESTING',
|
||||
SET_PROFILE_ITEMS: 'SET_PROFILE_ITEMS',
|
||||
SET_EMAIL_PREFILL: 'SET_EMAIL_PREFILL',
|
||||
SET_TASKS_STATUS: 'SET_TASKS_STATUS',
|
||||
GET_PAYMENT_METHODS_SUCCESS: 'GET_PAYMENT_METHODS_SUCCESS',
|
||||
GET_FREE_EXTENSIONS_ERROR: 'GET_FREE_EXTENSIONS_ERROR',
|
||||
|
|
|
@ -163,8 +163,16 @@ export function setPaymentMethods( paymentMethods ) {
|
|||
};
|
||||
}
|
||||
|
||||
export function setEmailPrefill( email ) {
|
||||
return {
|
||||
type: TYPES.SET_EMAIL_PREFILL,
|
||||
emailPrefill: email,
|
||||
};
|
||||
}
|
||||
|
||||
export function* updateProfileItems( items ) {
|
||||
yield setIsRequesting( 'updateProfileItems', true );
|
||||
yield setError( 'updateProfileItems', null );
|
||||
|
||||
try {
|
||||
const results = yield apiFetch( {
|
||||
|
@ -183,7 +191,7 @@ export function* updateProfileItems( items ) {
|
|||
} catch ( error ) {
|
||||
yield setError( 'updateProfileItems', error );
|
||||
yield setIsRequesting( 'updateProfileItems', false );
|
||||
throw new Error();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,10 @@ export const defaultState = {
|
|||
skipped: null,
|
||||
theme: null,
|
||||
wccom_connected: null,
|
||||
is_agree_marketing: null,
|
||||
store_email: null,
|
||||
},
|
||||
emailPrefill: '',
|
||||
paymentMethods: [],
|
||||
requesting: {},
|
||||
taskLists: [],
|
||||
|
@ -50,6 +53,7 @@ const onboarding = (
|
|||
freeExtensions,
|
||||
type,
|
||||
profileItems,
|
||||
emailPrefill,
|
||||
paymentMethods,
|
||||
replace,
|
||||
error,
|
||||
|
@ -69,6 +73,11 @@ const onboarding = (
|
|||
? profileItems
|
||||
: { ...state.profileItems, ...profileItems },
|
||||
};
|
||||
case TYPES.SET_EMAIL_PREFILL:
|
||||
return {
|
||||
...state,
|
||||
emailPrefill,
|
||||
};
|
||||
case TYPES.SET_TASKS_STATUS:
|
||||
return {
|
||||
...state,
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
setError,
|
||||
setTasksStatus,
|
||||
setPaymentMethods,
|
||||
setEmailPrefill,
|
||||
} from './actions';
|
||||
|
||||
export function* getProfileItems() {
|
||||
|
@ -31,6 +32,19 @@ export function* getProfileItems() {
|
|||
}
|
||||
}
|
||||
|
||||
export function* getEmailPrefill() {
|
||||
try {
|
||||
const results = yield apiFetch( {
|
||||
path: WC_ADMIN_NAMESPACE + '/onboarding/profile/get_email_prefill',
|
||||
method: 'GET',
|
||||
} );
|
||||
|
||||
yield setEmailPrefill( results.email );
|
||||
} catch ( error ) {
|
||||
yield setError( 'getEmailPrefill', error );
|
||||
}
|
||||
}
|
||||
|
||||
export function* getTasksStatus() {
|
||||
try {
|
||||
const results = yield apiFetch( {
|
||||
|
|
|
@ -47,6 +47,10 @@ export const isOnboardingRequesting = (
|
|||
return state.requesting[ selector ] || false;
|
||||
};
|
||||
|
||||
export const getEmailPrefill = ( state: OnboardingState ): string => {
|
||||
return state.emailPrefill || '';
|
||||
};
|
||||
|
||||
// Types
|
||||
export type OnboardingSelectors = {
|
||||
getProfileItems: () => ReturnType< typeof getProfileItems >;
|
||||
|
@ -64,6 +68,7 @@ export type OnboardingState = {
|
|||
taskLists: TaskList[];
|
||||
tasksStatus: TasksStatusState;
|
||||
paymentMethods: PaymentMethodsState[];
|
||||
emailPrefill: string;
|
||||
// TODO clarify what the error record's type is
|
||||
errors: Record< string, unknown >;
|
||||
requesting: Record< string, boolean >;
|
||||
|
@ -135,6 +140,8 @@ export type ProfileItemsState = {
|
|||
skipped: boolean | null;
|
||||
theme: string | null;
|
||||
wccom_connected: boolean | null;
|
||||
is_agree_marketing: boolean | null;
|
||||
store_email: string | null;
|
||||
};
|
||||
|
||||
export type FieldLocale = {
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Automattic\WooCommerce\Admin\API;
|
|||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\Features\Onboarding;
|
||||
use \Automattic\Jetpack\Connection\Manager as Jetpack_Connection_Manager;
|
||||
|
||||
/**
|
||||
* Onboarding Profile controller.
|
||||
|
@ -60,6 +61,18 @@ class OnboardingProfile extends \WC_REST_Data_Controller {
|
|||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/get_email_prefill',
|
||||
array(
|
||||
array(
|
||||
'methods' => \WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_email_prefill' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,7 +152,9 @@ class OnboardingProfile extends \WC_REST_Data_Controller {
|
|||
$params = $request->get_json_params();
|
||||
$query_args = $this->prepare_objects_query( $params );
|
||||
$onboarding_data = (array) get_option( Onboarding::PROFILE_DATA_OPTION, array() );
|
||||
update_option( Onboarding::PROFILE_DATA_OPTION, array_merge( $onboarding_data, $query_args ) );
|
||||
$profile_data = array_merge( $onboarding_data, $query_args );
|
||||
update_option( Onboarding::PROFILE_DATA_OPTION, $profile_data );
|
||||
do_action( 'woocommerce_onboarding_profile_data_updated', $onboarding_data, $query_args );
|
||||
|
||||
$result = array(
|
||||
'status' => 'success',
|
||||
|
@ -152,6 +167,36 @@ class OnboardingProfile extends \WC_REST_Data_Controller {
|
|||
return rest_ensure_response( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a default email to be pre-filled in OBW. Prioritizes Jetpack if connected,
|
||||
* otherwise will default to WordPress general settings.
|
||||
*
|
||||
* @param WP_REST_Request $request Request data.
|
||||
* @return WP_Error|WP_REST_Response
|
||||
*/
|
||||
public function get_email_prefill( $request ) {
|
||||
$result = array(
|
||||
'email' => '',
|
||||
);
|
||||
|
||||
// Attempt to get email from Jetpack.
|
||||
if ( class_exists( Jetpack_Connection_Manager::class ) ) {
|
||||
$jetpack_connection_manager = new Jetpack_Connection_Manager();
|
||||
if ( $jetpack_connection_manager->is_active() ) {
|
||||
$jetpack_user = $jetpack_connection_manager->get_connected_user_data();
|
||||
|
||||
$result['email'] = $jetpack_user['email'];
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to get email from WordPress general settings.
|
||||
if ( empty( $result['email'] ) ) {
|
||||
$result['email'] = get_option( 'admin_email' );
|
||||
}
|
||||
|
||||
return rest_ensure_response( $result );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare objects query.
|
||||
*
|
||||
|
@ -360,11 +405,43 @@ class OnboardingProfile extends \WC_REST_Data_Controller {
|
|||
'readonly' => true,
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
),
|
||||
'is_agree_marketing' => array(
|
||||
'type' => 'boolean',
|
||||
'description' => __( 'Whether or not this store agreed to receiving marketing contents from WooCommerce.com.', 'woocommerce-admin' ),
|
||||
'context' => array( 'view' ),
|
||||
'readonly' => true,
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
),
|
||||
'store_email' => array(
|
||||
'type' => 'string',
|
||||
'description' => __( 'Store email address.', 'woocommerce-admin' ),
|
||||
'context' => array( 'view' ),
|
||||
'readonly' => true,
|
||||
'validate_callback' => array( __CLASS__, 'rest_validate_marketing_email' ),
|
||||
),
|
||||
);
|
||||
|
||||
return apply_filters( 'woocommerce_rest_onboarding_profile_properties', $properties );
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally validates email if user agreed to marketing or if email is not empty.
|
||||
*
|
||||
* @param mixed $value Email value.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @param string $param Parameter name.
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
public static function rest_validate_marketing_email( $value, $request, $param ) {
|
||||
$is_agree_marketing = $request->get_param( 'is_agree_marketing' );
|
||||
if (
|
||||
( $is_agree_marketing || ! empty( $value ) ) &&
|
||||
! is_email( $value ) ) {
|
||||
return new \WP_Error( 'rest_invalid_email', __( 'Invalid email address', 'woocommerce-admin' ) );
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the schema, conforming to JSON Schema.
|
||||
*
|
||||
|
|
|
@ -49,6 +49,7 @@ use \Automattic\WooCommerce\Admin\Notes\AddFirstProduct;
|
|||
use \Automattic\WooCommerce\Admin\Notes\DrawAttention;
|
||||
use \Automattic\WooCommerce\Admin\Notes\GettingStartedInEcommerceWebinar;
|
||||
use \Automattic\WooCommerce\Admin\Notes\NavigationNudge;
|
||||
use Automattic\WooCommerce\Admin\Schedulers\MailchimpScheduler;
|
||||
|
||||
/**
|
||||
* Events Class.
|
||||
|
@ -103,6 +104,10 @@ class Events {
|
|||
if ( $this->is_merchant_email_notifications_enabled() ) {
|
||||
MerchantEmailNotifications::run();
|
||||
}
|
||||
|
||||
if ( Features::is_enabled( 'onboarding' ) ) {
|
||||
( new MailchimpScheduler() )->run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,7 +117,6 @@ class Events {
|
|||
NewSalesRecord::possibly_add_note();
|
||||
MobileApp::possibly_add_note();
|
||||
TrackingOptIn::possibly_add_note();
|
||||
OnboardingEmailMarketing::possibly_add_note();
|
||||
OnboardingPayments::possibly_add_note();
|
||||
PersonalizeStore::possibly_add_note();
|
||||
WooCommercePayments::possibly_add_note();
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Automattic\WooCommerce\Admin\Features;
|
|||
use \Automattic\WooCommerce\Admin\Loader;
|
||||
use Automattic\WooCommerce\Admin\PageController;
|
||||
use Automattic\WooCommerce\Admin\WCAdminHelper;
|
||||
use Automattic\WooCommerce\Admin\Schedulers\MailchimpScheduler;
|
||||
|
||||
/**
|
||||
* Contains backend logic for the onboarding profile and checklist feature.
|
||||
|
@ -97,6 +98,8 @@ class Onboarding {
|
|||
// Always hook into Jetpack connection even if outside of admin.
|
||||
add_action( 'jetpack_site_registered', array( $this, 'set_woocommerce_setup_jetpack_opted_in' ) );
|
||||
|
||||
add_action( 'woocommerce_onboarding_profile_data_updated', array( $this, 'on_profile_data_updated' ), 10, 2 );
|
||||
|
||||
if ( ! is_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
@ -977,4 +980,20 @@ class Onboarding {
|
|||
}
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete MailchimpScheduler::SUBSCRIBED_OPTION_NAME option if profile data is being updated with a new email.
|
||||
*
|
||||
* @param array $existing_data Existing option data.
|
||||
* @param array $updating_data Updating option data.
|
||||
*/
|
||||
public function on_profile_data_updated( $existing_data, $updating_data ) {
|
||||
if (
|
||||
isset( $existing_data['store_email'] ) &&
|
||||
isset( $updating_data['store_email'] ) &&
|
||||
$existing_data['store_email'] !== $updating_data['store_email']
|
||||
) {
|
||||
delete_option( MailchimpScheduler::SUBSCRIBED_OPTION_NAME );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* WooCommerce Admin Onboarding Email Marketing Note Provider.
|
||||
*
|
||||
* Adds a note to sign up to email marketing after completing the profiler.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\Notes;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Onboarding_Email_Marketing
|
||||
*/
|
||||
class OnboardingEmailMarketing {
|
||||
/**
|
||||
* Note traits.
|
||||
*/
|
||||
use NoteTraits;
|
||||
|
||||
/**
|
||||
* Name of the note for use in the database.
|
||||
*/
|
||||
const NOTE_NAME = 'wc-admin-onboarding-email-marketing';
|
||||
|
||||
/**
|
||||
* Get the note.
|
||||
*
|
||||
* @return Note
|
||||
*/
|
||||
public static function get_note() {
|
||||
$content = __( 'We\'re here for you - get tips, product updates and inspiration straight to your email box', 'woocommerce-admin' );
|
||||
|
||||
$note = new Note();
|
||||
$note->set_title( __( 'Sign up for tips, product updates, and inspiration', 'woocommerce-admin' ) );
|
||||
$note->set_content( $content );
|
||||
$note->set_content_data( (object) array() );
|
||||
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
|
||||
$note->set_name( self::NOTE_NAME );
|
||||
$note->set_source( 'woocommerce-admin' );
|
||||
$note->add_action( 'yes-please', __( 'Yes please!', 'woocommerce-admin' ), 'https://woocommerce.us8.list-manage.com/subscribe/post?u=2c1434dc56f9506bf3c3ecd21&id=13860df971&SIGNUPPAGE=plugin' );
|
||||
return $note;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\Schedulers;
|
||||
|
||||
/**
|
||||
* Class MailchimpScheduler
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\Schedulers
|
||||
*/
|
||||
class MailchimpScheduler {
|
||||
|
||||
const SUBSCRIBE_ENDPOINT = 'https://woocommerce.com/wp-json/wccom/v1/subscribe';
|
||||
const SUBSCRIBE_ENDPOINT_DEV = 'http://woocommerce.test/wp-json/wccom/v1/subscribe';
|
||||
|
||||
const SUBSCRIBED_OPTION_NAME = 'woocommerce_onboarding_subscribed_to_mailchimp';
|
||||
|
||||
const LOGGER_CONTEXT = 'mailchimp_scheduler';
|
||||
|
||||
/**
|
||||
* The logger instance.
|
||||
*
|
||||
* @var \WC_Logger_Interface|null
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* MailchimpScheduler constructor.
|
||||
*
|
||||
* @param \WC_Logger_Interface|null $logger Logger instance.
|
||||
*/
|
||||
public function __construct( \WC_Logger_Interface $logger = null ) {
|
||||
if ( null === $logger ) {
|
||||
$logger = wc_get_logger();
|
||||
}
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to subscribe store_email to MailChimp.
|
||||
*/
|
||||
public function run() {
|
||||
// Abort if we've already subscribed to MailChimp.
|
||||
if ( 'yes' === get_option( self::SUBSCRIBED_OPTION_NAME ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$profile_data = get_option( 'woocommerce_onboarding_profile' );
|
||||
|
||||
if ( ! isset( $profile_data['is_agree_marketing'] ) || false === $profile_data['is_agree_marketing'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Abort if store_email doesn't exist.
|
||||
if ( ! isset( $profile_data['store_email'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = $this->make_request( $profile_data['store_email'] );
|
||||
|
||||
if ( is_wp_error( $response ) || ! isset( $response['body'] ) ) {
|
||||
$this->logger->error(
|
||||
'Error getting a response from Mailchimp API.',
|
||||
array( 'source' => self::LOGGER_CONTEXT )
|
||||
);
|
||||
return false;
|
||||
} else {
|
||||
$body = json_decode( $response['body'] );
|
||||
if ( isset( $body->success ) && true === $body->success ) {
|
||||
update_option( self::SUBSCRIBED_OPTION_NAME, 'yes' );
|
||||
return true;
|
||||
} else {
|
||||
$this->logger->error(
|
||||
// phpcs:ignore
|
||||
'Incorrect response from Mailchimp API with: ' . print_r( $body, true ),
|
||||
array( 'source' => self::LOGGER_CONTEXT )
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP request to the API.
|
||||
*
|
||||
* @param string $store_email Email address to subscribe.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function make_request( $store_email ) {
|
||||
if ( 'development' === constant( 'WP_ENVIRONMENT_TYPE' ) ) {
|
||||
$subscribe_endpoint = self::SUBSCRIBE_ENDPOINT_DEV;
|
||||
} else {
|
||||
$subscribe_endpoint = self::SUBSCRIBE_ENDPOINT;
|
||||
}
|
||||
|
||||
return wp_remote_post(
|
||||
$subscribe_endpoint,
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'body' => array(
|
||||
'email' => $store_email,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
|
||||
use \Automattic\WooCommerce\Admin\API\OnboardingProfile;
|
||||
use Automattic\WooCommerce\Admin\Features\Onboarding;
|
||||
use Automattic\WooCommerce\Admin\Schedulers\MailchimpScheduler;
|
||||
|
||||
/**
|
||||
* WC Tests API Onboarding Profile
|
||||
|
@ -104,7 +106,7 @@ class WC_Tests_API_Onboarding_Profiles extends WC_REST_Unit_Test_Case {
|
|||
$data = $response->get_data();
|
||||
$properties = $data['schema']['properties'];
|
||||
|
||||
$this->assertCount( 13, $properties );
|
||||
$this->assertCount( 15, $properties );
|
||||
$this->assertArrayHasKey( 'completed', $properties );
|
||||
$this->assertArrayHasKey( 'skipped', $properties );
|
||||
$this->assertArrayHasKey( 'industry', $properties );
|
||||
|
@ -118,6 +120,8 @@ class WC_Tests_API_Onboarding_Profiles extends WC_REST_Unit_Test_Case {
|
|||
$this->assertArrayHasKey( 'theme', $properties );
|
||||
$this->assertArrayHasKey( 'wccom_connected', $properties );
|
||||
$this->assertArrayHasKey( 'setup_client', $properties );
|
||||
$this->assertArrayHasKey( 'is_agree_marketing', $properties );
|
||||
$this->assertArrayHasKey( 'store_email', $properties );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,4 +183,24 @@ class WC_Tests_API_Onboarding_Profiles extends WC_REST_Unit_Test_Case {
|
|||
$this->assertTrue( is_array( $response->get_data() ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a profile data update API request
|
||||
* When the payload has a different store_email value that the existing store_email
|
||||
* Then self::SUBSCRIBED_OPTION_NAME option should be deleted.
|
||||
*/
|
||||
public function test_it_deletes_the_option_when_a_different_email_gets_updated() {
|
||||
wp_set_current_user( $this->user );
|
||||
|
||||
update_option( Onboarding::PROFILE_DATA_OPTION, array( 'store_email' => 'first@test.com' ) );
|
||||
update_option( MailchimpScheduler::SUBSCRIBED_OPTION_NAME, 'yes' );
|
||||
|
||||
$request = new WP_REST_Request( 'POST', '/wc-admin/onboarding/profile' );
|
||||
$request->set_headers( array( 'content-type' => 'application/json' ) );
|
||||
$request->set_body( wp_json_encode( array( 'store_email' => 'second@test.com' ) ) );
|
||||
|
||||
$this->server->dispatch( $request );
|
||||
|
||||
$this->assertFalse( get_option( MailchimpScheduler::SUBSCRIBED_OPTION_NAME, false ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,8 @@
|
|||
"countryandstate": "United States (US) -- California",
|
||||
"city": "San Francisco",
|
||||
"state": "CA",
|
||||
"postcode": "94107"
|
||||
"postcode": "94107",
|
||||
"email": "john.doe@example.com"
|
||||
}
|
||||
},
|
||||
"customer": {
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
/**
|
||||
* MailchimpScheduler tests
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\Schedulers
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Admin\Features\Onboarding;
|
||||
use Automattic\WooCommerce\Admin\Schedulers\MailchimpScheduler;
|
||||
|
||||
/**
|
||||
* Class WC_Tests_Mailchimp_Scheduler
|
||||
*/
|
||||
class WC_Tests_Mailchimp_Scheduler extends WC_Unit_Test_Case {
|
||||
/**
|
||||
* @var MailchimpScheduler MailchimpScheduler instance to test
|
||||
*/
|
||||
private $instance;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject WC_Logger_Interface mock
|
||||
*/
|
||||
private $logger_mock;
|
||||
|
||||
/**
|
||||
* Overridden setUp() method.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->logger_mock = $this->getMockBuilder( \WC_Logger_Interface::class )->getMock();
|
||||
|
||||
$this->instance = $this->getMockBuilder( MailchimpScheduler::class )
|
||||
->setConstructorArgs( array( $this->logger_mock ) )
|
||||
->setMethods( array( 'make_request' ) )
|
||||
->getMock();
|
||||
|
||||
delete_option( MailchimpScheduler::SUBSCRIBED_OPTION_NAME );
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* When woocommerce_onboarding_subscribed_to_mailchimp value us 'yes'.
|
||||
* Then it should abort.
|
||||
*/
|
||||
public function test_it_aborts_if_already_subscribed() {
|
||||
// When.
|
||||
update_option( MailchimpScheduler::SUBSCRIBED_OPTION_NAME, 'yes' );
|
||||
|
||||
// Then.
|
||||
$this->assertFalse( $this->instance->run() );
|
||||
}
|
||||
|
||||
/**
|
||||
* When is_agree_marketing is missing or value is false.
|
||||
* Then it should abort.
|
||||
*/
|
||||
public function test_it_aborts_if_is_agree_marketing_is_false_or_missing() {
|
||||
// When.
|
||||
$profile_data = array( 'store_email' => 'test@test.com' );
|
||||
update_option( Onboarding::PROFILE_DATA_OPTION, $profile_data );
|
||||
$this->assertFalse( $this->instance->run() );
|
||||
|
||||
$profile_data = array(
|
||||
'is_agree_marketing' => false,
|
||||
'store_email' => 'test@test.com',
|
||||
);
|
||||
update_option( Onboarding::PROFILE_DATA_OPTION, $profile_data );
|
||||
|
||||
// Then.
|
||||
$this->assertFalse( $this->instance->run() );
|
||||
}
|
||||
|
||||
/**
|
||||
* When store_email is missing.
|
||||
* Then it should abort.
|
||||
*/
|
||||
public function test_it_aborts_if_store_email_is_missing() {
|
||||
// When.
|
||||
$profile_data = array( 'is_agree_marketing' => true );
|
||||
update_option( Onboarding::PROFILE_DATA_OPTION, $profile_data );
|
||||
|
||||
// Then.
|
||||
$this->assertFalse( $this->instance->run() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Given is_agree_marketing and store_email values are set.
|
||||
* When the request to the API returns WP_Error.
|
||||
* Then it should log an error message.
|
||||
*/
|
||||
public function test_it_logs_error_when_wp_error_is_returned() {
|
||||
// Given.
|
||||
$profile_data = array(
|
||||
'is_agree_marketing' => true,
|
||||
'store_email' => 'test@test.com',
|
||||
);
|
||||
update_option( Onboarding::PROFILE_DATA_OPTION, $profile_data );
|
||||
|
||||
// When.
|
||||
$wp_error = new WP_Error();
|
||||
$this->instance->method( 'make_request' )->willReturn( $wp_error );
|
||||
|
||||
// Then.
|
||||
$this->logger_mock->expects( $this->exactly( 2 ) )
|
||||
->method( 'error' )
|
||||
->with( 'Error getting a response from Mailchimp API.', array( 'source' => MailchimpScheduler::LOGGER_CONTEXT ) );
|
||||
|
||||
$this->instance->run();
|
||||
|
||||
// Check for the missing 'body'.
|
||||
$this->instance->method( 'make_request' )->willReturn( array() );
|
||||
$this->instance->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given is_agree_marketing and store_email values are set.
|
||||
* When the request to the API returns body without 'success'.
|
||||
* Then it should log an error message.
|
||||
*/
|
||||
public function test_it_logs_error_when_response_data_is_incorrect() {
|
||||
// Given.
|
||||
$profile_data = array(
|
||||
'is_agree_marketing' => true,
|
||||
'store_email' => 'test@test.com',
|
||||
);
|
||||
update_option( Onboarding::PROFILE_DATA_OPTION, $profile_data );
|
||||
|
||||
// When.
|
||||
$body = wp_json_encode( array() );
|
||||
$this->instance->method( 'make_request' )->willReturn( array( 'body' => $body ) );
|
||||
|
||||
// Then.
|
||||
$this->logger_mock->expects( $this->once() )
|
||||
->method( 'error' )
|
||||
->with(
|
||||
// phpcs:ignore
|
||||
'Incorrect response from Mailchimp API with: ' . print_r( array(), true ),
|
||||
array( 'source' => MailchimpScheduler::LOGGER_CONTEXT )
|
||||
);
|
||||
|
||||
$this->instance->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given is_agree_marketing and store_email values are set
|
||||
* When the request to the API returns success: true
|
||||
* Then woocommerce_onboarding_subscribed_to_mailchimp should be updated to 'yes'
|
||||
*/
|
||||
public function test_it_updates_option_value_when_everything_went_well() {
|
||||
// Given.
|
||||
$profile_data = array(
|
||||
'is_agree_marketing' => true,
|
||||
'store_email' => 'test@test.com',
|
||||
);
|
||||
update_option( Onboarding::PROFILE_DATA_OPTION, $profile_data );
|
||||
|
||||
// When.
|
||||
$body = wp_json_encode( array( 'success' => true ) );
|
||||
$this->instance->method( 'make_request' )->willReturn( array( 'body' => $body ) );
|
||||
|
||||
$this->instance->run();
|
||||
|
||||
// Then.
|
||||
$this->assertEquals( 'yes', get_option( 'woocommerce_onboarding_subscribed_to_mailchimp' ) );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue