Skip to content

Commit

Permalink
Add: temporary workaround to add experiment metadata for task_view (#…
Browse files Browse the repository at this point in the history
…33052)

rigged a workaround to let products task report its experimental assignment
  • Loading branch information
rjchow committed May 18, 2022
1 parent 31922c1 commit f637dd2
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 54 deletions.
@@ -0,0 +1,4 @@
Significance: minor
Type: Add

Removed experimental product hook and instead poll the slot's fill for variant metadata. To be removed when experiment concludes! #33052
Expand Up @@ -7,10 +7,11 @@ import { Slot, Fill } from '@wordpress/components';

/**
* Internal dependencies
*
* @param {string} taskId Task id.
* @param {string} variant The variant of the task.
*/
import { getProductLayoutExperiment } from './use-product-layout-experiment';

export const trackView = async ( taskId ) => {
export const trackView = async ( taskId, variant ) => {
const activePlugins = wp.data
.select( 'wc/admin/plugins' )
.getActivePlugins();
Expand All @@ -25,7 +26,7 @@ export const trackView = async ( taskId ) => {

recordEvent( 'task_view', {
task_name: taskId,
variant: await getProductLayoutExperiment(),
variant,
wcs_installed: installedPlugins.includes( 'woocommerce-services' ),
wcs_active: activePlugins.includes( 'woocommerce-services' ),
jetpack_installed: installedPlugins.includes( 'jetpack' ),
Expand All @@ -34,23 +35,48 @@ export const trackView = async ( taskId ) => {
} );
};

let experimentalVariant;
/**
* A Fill for adding Onboarding tasks.
*
* @slotFill WooOnboardingTask
* @scope woocommerce-tasks
* @param {Object} props React props.
* @param {string} props.id Task id.
* @param {Object} props React props.
* @param {string} props.variant The variant of the task.
* @param {Object} props.children React component children
* @param {string} props.id Task id.
*/
const WooOnboardingTask = ( { id, ...props } ) => {
const WooOnboardingTask = ( { id, variant, ...props } ) => {
useEffect( () => {
if ( id === 'products' ) {
experimentalVariant = variant;
}
}, [ id, variant ] );

return <Fill name={ 'woocommerce_onboarding_task_' + id } { ...props } />;
};

// We need this here just in case the experiment assignment takes awhile to load, so that we don't fire trackView with a blank experimentalVariant
// Remove all of the code in this file related to experiments and variants when the product task experiment concludes and never speak of the existence of this code to anyone
const pollForExperimentalVariant = ( id, count ) => {
if ( count > 20 ) {
trackView( id, 'experiment_timed_out' ); // if we can't fetch experiment after 4 seconds, give up
} else if ( experimentalVariant ) {
trackView( id, experimentalVariant );
} else {
setTimeout( () => pollForExperimentalVariant( id, count + 1 ), 200 );
}
};

WooOnboardingTask.Slot = ( { id, fillProps } ) => {
// The Slot is a React component and this hook works as expected.
// eslint-disable-next-line react-hooks/rules-of-hooks
useEffect( () => {
trackView( id );
if ( id === 'products' ) {
pollForExperimentalVariant( id, 0 );
} else {
trackView( id );
}
}, [ id ] );

return (
Expand Down
@@ -1,2 +1 @@
export * from './WooOnboardingTask';
export * from './use-product-layout-experiment';
6 changes: 1 addition & 5 deletions packages/js/onboarding/src/index.js
Expand Up @@ -11,8 +11,4 @@ export { default as WCPayLogo } from './images/wcpay-logo';
export { WooPaymentGatewaySetup } from './components/WooPaymentGatewaySetup';
export { WooPaymentGatewayConfigure } from './components/WooPaymentGatewayConfigure';
export { WooOnboardingTaskListItem } from './components/WooOnboardingTaskListItem';
export {
WooOnboardingTask,
useProductTaskExperiment,
isProductTaskExperimentTreatment,
} from './components/WooOnboardingTask';
export { WooOnboardingTask } from './components/WooOnboardingTask';
Expand Up @@ -92,8 +92,7 @@ registerPlugin( 'wc-admin-onboarding-task-products', {
// @ts-expect-error 'scope' does exist. @types/wordpress__plugins is outdated.
scope: 'woocommerce-tasks',
render: () => (
// @ts-expect-error WooOnboardingTask is a pure JS component.
<WooOnboardingTask id="products">
<WooOnboardingTask id="products" variant="import">
<Products />
</WooOnboardingTask>
),
Expand Down
Expand Up @@ -2,10 +2,7 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import {
WooOnboardingTask,
useProductTaskExperiment,
} from '@woocommerce/onboarding';
import { WooOnboardingTask } from '@woocommerce/onboarding';
import { Text } from '@woocommerce/experimental';
import { registerPlugin } from '@wordpress/plugins';
import { useMemo, useState } from '@wordpress/element';
Expand All @@ -30,6 +27,7 @@ import LoadSampleProductModal from '../components/load-sample-product-modal';
import useLoadSampleProducts from '../components/use-load-sample-products';
import useRecordCompletionTime from '../use-record-completion-time';
import { getCountryCode } from '~/dashboard/utils';
import { useProductTaskExperiment } from './use-product-layout-experiment';

const getOnboardingProductType = (): string[] => {
const onboardingData = getAdminSetting( 'onboarding' );
Expand All @@ -56,10 +54,10 @@ const ViewControlButton: React.FC< {

export const Products = () => {
const [ isExpanded, setIsExpanded ] = useState< boolean >( false );
const [
isLoadingExperiment,
const {
isLoading: isLoadingExperiment,
experimentLayout,
] = useProductTaskExperiment();
} = useProductTaskExperiment();

const { isStoreInUS } = useSelect( ( select ) => {
const { getSettings } = select( SETTINGS_STORE_NAME );
Expand Down Expand Up @@ -99,7 +97,7 @@ export const Products = () => {
recordCompletionTime();
},
} ) ),
[ recordCompletionTime ]
[ recordCompletionTime, productTypes ]
);

const {
Expand Down Expand Up @@ -135,7 +133,7 @@ export const Products = () => {
}, [
surfacedProductTypeKeys,
isExpanded,
productTypes,
productTypesWithTimeRecord,
experimentLayout,
loadSampleProduct,
] );
Expand Down Expand Up @@ -187,13 +185,18 @@ export const Products = () => {
);
};

const ExperimentalProductsFill = () => {
const { isLoading, experimentLayout } = useProductTaskExperiment();

return isLoading ? null : (
<WooOnboardingTask id="products" variant={ experimentLayout }>
<Products />
</WooOnboardingTask>
);
};

registerPlugin( 'wc-admin-onboarding-task-products', {
// @ts-expect-error 'scope' does exist. @types/wordpress__plugins is outdated.
scope: 'woocommerce-tasks',
render: () => (
// @ts-expect-error WooOnboardingTask is a pure JS component.
<WooOnboardingTask id="products">
<Products />
</WooOnboardingTask>
),
render: () => <ExperimentalProductsFill />,
} );
Expand Up @@ -3,7 +3,6 @@
*/
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { useProductTaskExperiment } from '@woocommerce/onboarding';
import { recordEvent } from '@woocommerce/tracks';
import { useSelect } from '@wordpress/data';

Expand All @@ -13,6 +12,7 @@ import { useSelect } from '@wordpress/data';
import { Products } from '../';
import { defaultSurfacedProductTypes, productTypes } from '../constants';
import { getAdminSetting } from '~/utils/admin-settings';
import { useProductTaskExperiment } from '../use-product-layout-experiment';

jest.mock( '@wordpress/data', () => ( {
...jest.requireActual( '@wordpress/data' ),
Expand All @@ -23,8 +23,11 @@ jest.mock( '~/utils/admin-settings', () => ( {
getAdminSetting: jest.fn(),
} ) );

jest.mock( '@woocommerce/onboarding', () => ( {
useProductTaskExperiment: jest.fn().mockReturnValue( [ false, 'stacked' ] ),
jest.mock( '../use-product-layout-experiment', () => ( {
useProductTaskExperiment: jest.fn().mockReturnValue( {
isLoading: false,
experimentLayout: 'stacked',
} ),
} ) );

jest.mock( '../use-create-product-by-type', () => ( {
Expand Down Expand Up @@ -263,21 +266,25 @@ describe( 'Products', () => {
} );

it( 'should show spinner when layout experiment is loading', async () => {
( useProductTaskExperiment as jest.Mock ).mockImplementation( () => [
true,
'card',
] );
( useProductTaskExperiment as jest.Mock ).mockImplementation( () => {
return {
isLoading: true,
experimentLayout: 'card',
};
} );
const { container } = render( <Products /> );
expect(
container.getElementsByClassName( 'components-spinner' )
).toHaveLength( 1 );
} );

it( 'should render card layout when experiment is assigned', async () => {
( useProductTaskExperiment as jest.Mock ).mockImplementation( () => [
false,
'card',
] );
( useProductTaskExperiment as jest.Mock ).mockImplementation( () => {
return {
isLoading: false,
experimentLayout: 'card',
};
} );
const { container } = render( <Products /> );
expect(
container.getElementsByClassName(
Expand All @@ -287,10 +294,12 @@ describe( 'Products', () => {
} );

it( 'should render stacked layout when experiment is assigned', async () => {
( useProductTaskExperiment as jest.Mock ).mockImplementation( () => [
false,
'stacked',
] );
( useProductTaskExperiment as jest.Mock ).mockImplementation( () => {
return {
isLoading: false,
experimentLayout: 'stacked',
};
} );
const { container } = render( <Products /> );
expect(
container.getElementsByClassName( 'woocommerce-products-stack' )
Expand Down
Expand Up @@ -38,7 +38,7 @@ export const useProductTaskExperiment = () => {
} );
}, [ setExperimentLayout ] );

return [ isLoading, experimentLayout ];
return { isLoading, experimentLayout };
};

export default useProductTaskExperiment;
7 changes: 1 addition & 6 deletions plugins/woocommerce-admin/client/tasks/fills/index.js
@@ -1,13 +1,8 @@
/**
* External dependencies
*/
import { isProductTaskExperimentTreatment } from '@woocommerce/onboarding';

/**
* Internal dependencies
*/
import { isProductTaskExperimentTreatment } from './experimental-products/use-product-layout-experiment';
import { isImportProductExperiment } from './product-task-experiment';

import './PaymentGatewaySuggestions';
import './shipping';
import './Marketing';
Expand Down
Expand Up @@ -5,6 +5,9 @@ import { getAdminSetting } from '~/utils/admin-settings';

const onboardingData = getAdminSetting( 'onboarding' );

/**
* Returns true if the merchant has indicated that they have another online shop while filling out the OBW
*/
export const isImportProductExperiment = () => {
return (
window?.wcAdminFeatures?.[ 'experimental-import-products-task' ] &&
Expand Down
Expand Up @@ -166,7 +166,7 @@ const Products = () => {
registerPlugin( 'wc-admin-onboarding-task-products', {
scope: 'woocommerce-tasks',
render: () => (
<WooOnboardingTask id="products">
<WooOnboardingTask id="products" variant="control">
<Products />
</WooOnboardingTask>
),
Expand Down
@@ -0,0 +1,4 @@
Significance: minor
Type: Add

Removed experimental product hook and instead poll the slot's fill for variant metadata. To be removed when experiment concludes! #33052

0 comments on commit f637dd2

Please sign in to comment.