Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement/9147 ads connected status #9742

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,22 @@ import {
provideModules,
render,
} from '../../../../tests/js/test-utils';
import { CORE_SITE } from '../../googlesitekit/datastore/site/constants';
import ConfirmDisableConsentModeDialog from './ConfirmDisableConsentModeDialog';

describe( 'ConfirmDisableConsentModeDialog', () => {
let registry;

beforeEach( () => {
registry = createTestRegistry();

provideModules( registry );
} );

it( 'should display appropriate subtitle with Ads not connected', async () => {
provideModules( registry, [
{ slug: 'ads', active: false, connected: false },
] );
registry
.dispatch( CORE_SITE )
.receiveGetAdsMeasurementStatus( { connected: false } );

const { getByText, waitForRegistry } = render(
<ConfirmDisableConsentModeDialog
Expand All @@ -58,9 +61,9 @@ describe( 'ConfirmDisableConsentModeDialog', () => {
} );

it( 'should display appropriate subtitle with Ads connected', async () => {
provideModules( registry, [
{ slug: 'ads', active: true, connected: true },
] );
registry
.dispatch( CORE_SITE )
.receiveGetAdsMeasurementStatus( { connected: true } );

const { getByText, waitForRegistry } = render(
<ConfirmDisableConsentModeDialog
Expand Down
25 changes: 15 additions & 10 deletions assets/js/components/consent-mode/ConsentModeSetupCTAWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,6 @@ function ConsentModeSetupCTAWidget( { Widget, WidgetNull } ) {
select( CORE_SITE ).isConsentModeEnabled()
);

const isAdsConnected = useSelect( ( select ) =>
select( CORE_SITE ).isAdsConnected()
);

const settingsURL = useSelect( ( select ) =>
select( CORE_SITE ).getAdminURL( 'googlesitekit-settings' )
);
Expand Down Expand Up @@ -119,12 +115,21 @@ function ConsentModeSetupCTAWidget( { Widget, WidgetNull } ) {
const [ hasBeenInView, setHasBeenInView ] = useState( false );
const inView = !! intersectionEntry?.intersectionRatio;

const shouldShowWidget =
! viewOnlyDashboard &&
( isSaving ||
( isDismissed === false &&
isConsentModeEnabled === false &&
isAdsConnected ) );
const shouldShowWidget = useSelect( ( select ) => {
if ( viewOnlyDashboard ) {
return false;
}

if ( isSaving ) {
return true;
}

if ( isDismissed !== false || isConsentModeEnabled !== false ) {
return false;
}

return select( CORE_SITE ).isAdsConnected();
} );

useEffect( () => {
if ( inView && ! hasBeenInView && shouldShowWidget ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ export default {
.dispatch( CORE_SITE )
.receiveGetConsentModeSettings( { enabled: false } );

registry
.dispatch( CORE_SITE )
.receiveGetAdsMeasurementStatus( { connected: true } );

fetchMock.postOnce(
new RegExp(
'google-site-kit/v1/core/site/data/consent-mode'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ WithAdsConnected.args = {
adsLinked: false,
googleTagContainerDestinationIDs: null,
} );

registry
.dispatch( CORE_SITE )
.receiveGetAdsMeasurementStatus( { connected: true } );
},
};
WithAdsConnected.scenario = {
Expand Down
71 changes: 29 additions & 42 deletions assets/js/googlesitekit/datastore/site/consent-mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@ import {
} from 'googlesitekit-data';
import { createFetchStore } from '../../data/create-fetch-store';
import { createReducer } from '../../data/create-reducer';
import { CORE_MODULES } from '../../modules/datastore/constants';
import { CORE_SITE } from './constants';
import { CORE_USER } from '../user/constants';
import { MODULES_ANALYTICS_4 } from '../../../modules/analytics-4/datastore/constants';
import { actions as errorStoreActions } from '../../data/create-error-store';
const { clearError, receiveError } = errorStoreActions;

Expand Down Expand Up @@ -129,12 +127,25 @@ const fetchActivateConsentAPI = createFetchStore( {
},
} );

const fetchGetAdsMeasurementStatusStore = createFetchStore( {
baseName: 'getAdsMeasurementStatus',
controlCallback: () => {
return API.get( 'core', 'site', 'ads-measurement-status', null, {
useCache: false,
} );
},
reducerCallback: createReducer( ( state, response ) => {
state.consentMode.adsConnected = response.connected;
} ),
} );

const baseInitialState = {
consentMode: {
settings: undefined,
apiInfo: undefined,
apiInstallResponse: undefined,
isApiFetching: undefined,
adsConnected: undefined,
},
};

Expand Down Expand Up @@ -337,49 +348,14 @@ const baseSelectors = {
*
* @since 1.124.0
* @since 1.125.0 Updated to consider Ads connection status via the Analytics tag config, and to source Conversion ID field from Ads module.
* @since n.e.x.t Updated to a simple selector which returns value from the state.
*
* @param {Object} state Data store's state.
* @return {boolean|undefined} True if Google Ads is in use, false otherwise. Undefined if the selectors have not loaded.
*/
isAdsConnected: createRegistrySelector( ( select ) => () => {
const { isModuleConnected } = select( CORE_MODULES );

// The Ads module being connected implies that an Ads conversion tracking
// ID is set. If so, return true.
if ( isModuleConnected( 'ads' ) ) {
return true;
}

if ( isModuleConnected( 'analytics-4' ) ) {
const { getAdsLinked, getGoogleTagContainerDestinationIDs } =
select( MODULES_ANALYTICS_4 );

const adsLinked = getAdsLinked();
const googleTagContainerDestinationIDs =
getGoogleTagContainerDestinationIDs();

// If necessary settings have not loaded, return undefined.
if (
[ adsLinked, googleTagContainerDestinationIDs ].includes(
undefined
)
) {
return undefined;
}

if (
Array.isArray( googleTagContainerDestinationIDs ) &&
googleTagContainerDestinationIDs.some( ( id ) =>
id.startsWith( 'AW-' )
)
) {
return true;
}

return !! adsLinked;
}

return false;
} ),
isAdsConnected: ( state ) => {
return state.consentMode.adsConnected;
},
};

const baseResolvers = {
Expand All @@ -402,6 +378,16 @@ const baseResolvers = {

yield fetchGetConsentAPIInfoStore.actions.fetchGetConsentAPIInfo();
},

*isAdsConnected() {
const { select } = yield getRegistry();

if ( select( CORE_SITE ).isAdsConnected() !== undefined ) {
return;
}

yield fetchGetAdsMeasurementStatusStore.actions.fetchGetAdsMeasurementStatus();
},
};

const store = combineStores(
Expand All @@ -410,6 +396,7 @@ const store = combineStores(
fetchGetConsentAPIInfoStore,
fetchInstallActivateWPConsentAPI,
fetchActivateConsentAPI,
fetchGetAdsMeasurementStatusStore,
{
initialState: baseInitialState,
actions: baseActions,
Expand Down
147 changes: 40 additions & 107 deletions assets/js/googlesitekit/datastore/site/consent-mode.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@
import API from 'googlesitekit-api';
import {
createTestRegistry,
provideModules,
untilResolved,
waitForDefaultTimeouts,
} from '../../../../../tests/js/utils';
import { CORE_SITE } from './constants';
import { MODULES_ANALYTICS_4 } from '../../../modules/analytics-4/datastore/constants';

describe( 'core/site Consent Mode', () => {
let registry;
Expand Down Expand Up @@ -297,128 +295,63 @@ describe( 'core/site Consent Mode', () => {
} );

describe( 'isAdsConnected', () => {
it( 'returns false if both the Ads and Analytics modules are disconnected', () => {
provideModules( registry, [
{
slug: 'ads',
active: false,
connected: false,
},
{
slug: 'analytics-4',
active: false,
connected: false,
},
] );
const adsMeasurementStatusEndpointRegExp = new RegExp(
'^/google-site-kit/v1/core/site/data/ads-measurement-status'
);

expect( registry.select( CORE_SITE ).isAdsConnected() ).toBe(
false
);
} );
it( 'uses a resolver to make a network request', async () => {
const response = { connected: true };

it( 'returns true if the Ads module is connected', () => {
provideModules( registry, [
{
slug: 'ads',
active: true,
connected: true,
},
] );
fetchMock.getOnce( adsMeasurementStatusEndpointRegExp, {
body: response,
status: 200,
} );

expect( registry.select( CORE_SITE ).isAdsConnected() ).toBe(
true
);
} );
const initialIsAdsConnected = registry
.select( CORE_SITE )
.isAdsConnected();

it( 'returns undefined if the Ads module is disconnected and the Analytics module settings have not loaded', () => {
provideModules( registry, [
{
slug: 'ads',
active: false,
connected: false,
},
{
slug: 'analytics-4',
active: true,
connected: true,
},
] );
expect( initialIsAdsConnected ).toBeUndefined();

registry
.dispatch( MODULES_ANALYTICS_4 )
.receiveGetSettings( {} );
await untilResolved( registry, CORE_SITE ).isAdsConnected();

expect( registry.select( CORE_SITE ).isAdsConnected() ).toBe(
undefined
);
} );
const isAdsConnected = registry
.select( CORE_SITE )
.isAdsConnected();

it( 'returns true if Analytics and Ads are linked', () => {
provideModules( registry, [
{
slug: 'analytics-4',
active: true,
connected: true,
},
] );

registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetSettings( {
adsLinked: true,
// Set the following to default, as otherwise if it is set to
// undefined, the `core/site` `isAdsConnected` selector will
// return undefined.
googleTagContainerDestinationIDs: null,
} );
expect( isAdsConnected ).toEqual( response.connected );

expect( registry.select( CORE_SITE ).isAdsConnected() ).toBe(
true
expect( fetchMock ).toHaveFetched(
adsMeasurementStatusEndpointRegExp
);
} );

it( 'returns true if Ads is connected via Google Tag', () => {
provideModules( registry, [
{
slug: 'analytics-4',
active: true,
connected: true,
},
] );

registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetSettings( {
googleTagContainerDestinationIDs: [ 'AW-12345' ],
// Set the following to default, as otherwise if it is set to
// undefined, the `core/site` `isAdsConnected` selector will
// return undefined.
adsLinked: false,
it( 'returns undefined if the request fails', async () => {
fetchMock.getOnce( adsMeasurementStatusEndpointRegExp, {
body: { error: 'something went wrong' },
status: 500,
} );

expect( registry.select( CORE_SITE ).isAdsConnected() ).toBe(
true
);
} );
const initialIsAdsConnected = registry
.select( CORE_SITE )
.isAdsConnected();

it( 'returns false if the Ads module is disconnected, Analytics and Ads are not linked, and the Google Tag does not have an Ads conversion tracking ID as a destination', () => {
provideModules( registry, [
{
slug: 'ads',
active: false,
connected: false,
},
{
slug: 'analytics-4',
active: true,
connected: true,
},
] );
expect( initialIsAdsConnected ).toBeUndefined();

registry.dispatch( MODULES_ANALYTICS_4 ).receiveGetSettings( {
adsLinked: false,
googleTagContainerDestinationIDs: null,
} );
await untilResolved( registry, CORE_SITE ).isAdsConnected();

const isAdsConnected = registry
.select( CORE_SITE )
.isAdsConnected();

expect( registry.select( CORE_SITE ).isAdsConnected() ).toBe(
false
// Verify the API info is still undefined after the selector is resolved.
expect( isAdsConnected ).toBeUndefined();

expect( fetchMock ).toHaveFetched(
adsMeasurementStatusEndpointRegExp
);

expect( console ).toHaveErrored();
} );
} );
} );
Expand Down
Loading
Loading