diff --git a/assets/js/components/key-metrics-setup/KeyMetricsSetupApp.js b/assets/js/components/key-metrics-setup/KeyMetricsSetupApp.js index c67a8ae2f32..a3d91b6b375 100644 --- a/assets/js/components/key-metrics-setup/KeyMetricsSetupApp.js +++ b/assets/js/components/key-metrics-setup/KeyMetricsSetupApp.js @@ -112,6 +112,17 @@ export default function KeyMetricsSetupApp() { select( MODULES_SEARCH_CONSOLE ).isGatheringData(); } ); + // Await the resolution of Analytics 4 settings before triggering + // the background sync of audiences and custom dimensions. This + // ensures propertyID is available for the sync and isSyncing + // check, preventing the button from being stuck in a disabled state. + const hasResolvedAnalytics4Settings = useSelect( ( select ) => { + select( MODULES_ANALYTICS_4 ).getSettings(); + return select( MODULES_ANALYTICS_4 ).hasFinishedResolution( + 'getSettings' + ); + } ); + const isSyncing = useSelect( ( select ) => { const isFetchingSyncAvailableCustomDimensions = select( @@ -189,9 +200,15 @@ export default function KeyMetricsSetupApp() { useDispatch( MODULES_ANALYTICS_4 ); useEffect( () => { - syncAvailableAudiences(); - fetchSyncAvailableCustomDimensions(); - }, [ syncAvailableAudiences, fetchSyncAvailableCustomDimensions ] ); + if ( hasResolvedAnalytics4Settings ) { + syncAvailableAudiences(); + fetchSyncAvailableCustomDimensions(); + } + }, [ + hasResolvedAnalytics4Settings, + syncAvailableAudiences, + fetchSyncAvailableCustomDimensions, + ] ); const onSaveClick = useCallback( () => { if ( isBusy || isSyncing ) { diff --git a/assets/js/components/key-metrics-setup/KeyMetricsSetupApp.test.js b/assets/js/components/key-metrics-setup/KeyMetricsSetupApp.test.js index 1fdbe22ee2e..b3afc891b39 100644 --- a/assets/js/components/key-metrics-setup/KeyMetricsSetupApp.test.js +++ b/assets/js/components/key-metrics-setup/KeyMetricsSetupApp.test.js @@ -123,6 +123,8 @@ describe( 'KeyMetricsSetupApp', () => { registry .dispatch( CORE_MODULES ) .receiveGetModules( withConnected( MODULE_SLUG_ANALYTICS_4 ) ); + + registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetSettings( {} ); } ); afterEach( () => { @@ -347,6 +349,67 @@ describe( 'KeyMetricsSetupApp', () => { expect( fetchMock ).toHaveFetched( syncCustomDimensionsEndpoint ); } ); + it( 'should not sync audiences and custom dimensions until Analytics 4 settings have resolved', async () => { + const analytics4SettingsEndpoint = new RegExp( + '^/google-site-kit/v1/modules/analytics-4/data/settings' + ); + + // Create a fresh registry without pre-populated Analytics 4 + // settings so getSettings resolution remains pending. + const freshRegistry = createTestRegistry(); + provideUserAuthentication( freshRegistry ); + provideSiteInfo( freshRegistry ); + freshRegistry.dispatch( CORE_USER ).receiveGetUserInputSettings( {} ); + freshRegistry.dispatch( CORE_USER ).receiveGetDismissedItems( [] ); + freshRegistry.dispatch( CORE_USER ).receiveGetDismissedPrompts( {} ); + freshRegistry.dispatch( CORE_USER ).receiveGetCapabilities( {} ); + freshRegistry + .dispatch( CORE_USER ) + .receiveGetUserAudienceSettings( { + configuredAudiences: null, + isAudienceSegmentationWidgetHidden: false, + didSetAudiences: false, + } ); + freshRegistry.dispatch( CORE_USER ).receiveGetInitialSetupSettings( { + isAnalyticsSetupComplete: false, + } ); + freshRegistry + .dispatch( CORE_MODULES ) + .receiveGetModules( withConnected( MODULE_SLUG_ANALYTICS_4 ) ); + + // Freeze the Analytics 4 settings endpoint so the resolver + // never completes and hasFinishedResolution stays false. + freezeFetch( analytics4SettingsEndpoint ); + + fetchMock.post( syncAudiencesEndpoint, { body: [], status: 200 } ); + fetchMock.post( syncCustomDimensionsEndpoint, { + body: [], + status: 200, + } ); + fetchMock.getOnce( searchAnalyticsRegexp, { + body: searchConsoleFixtures.report, + } ); + fetchMock.getOnce( analytics4ReportRegexp, { + body: analyticsFixtures.report, + } ); + muteFetch( searchConsoleDataAvailableRegexp ); + muteFetch( analytics4DataAvailableRegexp ); + + const { waitForRegistry } = render( , { + registry: freshRegistry, + viewContext: VIEW_CONTEXT_KEY_METRICS_SETUP, + } ); + + await waitForRegistry(); + + // Since Analytics 4 settings have not resolved, the sync + // actions should not have been dispatched yet. + expect( fetchMock ).not.toHaveFetched( syncAudiencesEndpoint ); + expect( fetchMock ).not.toHaveFetched( + syncCustomDimensionsEndpoint + ); + } ); + it( 'should not attempt to sync again while syncing is already in progress', async () => { registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetAudienceSettings( { availableAudiences: null,