-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add support to google consent mode for
v1
- Loading branch information
1 parent
7a59906
commit c4e226b
Showing
10 changed files
with
262 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
.../src/analytics/integrations/shared/ConsentManagementProtocol/ConsentManagementProtocol.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* CMP - Consent Management Protocol */ | ||
|
||
export class ConsentManagementProtocol { | ||
constructor() { | ||
this.dataLayers = []; | ||
this.enabled = true; | ||
this.mappingConsentCategories = this.defaultMappings(); | ||
} | ||
|
||
addIntegration(consent, dataLayer) { | ||
if (this.enabled) { | ||
this.dataLayers.push(dataLayer); | ||
this.gtag(dataLayer, consent); | ||
} | ||
} | ||
|
||
disable() { | ||
this.enabled = false; | ||
} | ||
|
||
defaultMappings() { | ||
return { | ||
ad_storage: [], | ||
ad_user_data: [], | ||
ad_personalization: [], | ||
analytics_storage: [], | ||
}; | ||
} | ||
|
||
setCustomCustomCategoriesMapping(customMapping) { | ||
this.mappingConsentCategories = customMapping; | ||
} | ||
|
||
getConsentValues(consents) { | ||
// Dealing with null or undefined consent values | ||
const consentList = consents || {}; | ||
|
||
return Object.keys(this.mappingConsentCategories).reduce( | ||
(result, consentKey) => ({ | ||
...result, | ||
[consentKey]: this.mappingConsentCategories[consentKey]?.every( | ||
consent => consentList[consent], | ||
) | ||
? 'granted' | ||
: 'deny', | ||
}), | ||
{}, | ||
); | ||
} | ||
|
||
setConsents(consents, dataLayer) { | ||
if (this.enabled) { | ||
const dataLayers = dataLayer ? [dataLayer] : this.dataLayers; | ||
dataLayers.forEach(layer => this.gtag(layer, consents, 'update')); | ||
} | ||
} | ||
|
||
gtag(dataLayer, consent, command = 'default') { | ||
if (this.enabled && typeof window !== 'undefined') { | ||
// @ts-ignore | ||
window[dataLayer] = window[dataLayer] || []; | ||
|
||
/** | ||
* | ||
*/ | ||
function internalGtag() { | ||
// @ts-ignore | ||
// eslint-disable-next-line | ||
window[dataLayer].push(arguments); | ||
} | ||
|
||
// @ts-ignore | ||
internalGtag('consent', command, this.getConsentValues(consent)); | ||
} | ||
} | ||
} | ||
|
||
const instance = new ConsentManagementProtocol(); | ||
|
||
export default instance; |
95 changes: 95 additions & 0 deletions
95
...integrations/shared/ConsentManagementProtocol/__tests__/ConsentManagementProtocol.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { consentManagementProtocol } from '../index.js'; | ||
|
||
describe('ConsentManagementProtocol', () => { | ||
let instance; | ||
let spyGtag; | ||
const mockConsent = {}; | ||
|
||
beforeEach(() => { | ||
instance = consentManagementProtocol; | ||
spyGtag = jest.spyOn(instance, 'gtag'); | ||
spyGtag.mockClear(); | ||
window['dataLayer'] = []; | ||
}); | ||
|
||
it('should add integrations and initialize data layers', () => { | ||
instance.addIntegration(mockConsent, 'dataLayer'); | ||
instance.addIntegration(mockConsent, 'ga4DataLayer'); | ||
|
||
expect(instance['dataLayers']).toEqual(['dataLayer', 'ga4DataLayer']); | ||
|
||
expect(window['dataLayer']).toMatchSnapshot(); | ||
}); | ||
|
||
it('should set custom consent categories mapping and initialize a data layer; only 1 consent should be granted', () => { | ||
const customMappings = { | ||
ad_storage: ['consent1'], | ||
ad_user_data: ['consent1', 'consent2'], | ||
ad_personalization: [], | ||
analytics_storage: ['consent3'], | ||
}; | ||
|
||
instance.setCustomCustomCategoriesMapping(customMappings); | ||
|
||
instance.addIntegration(mockConsent, 'dataLayer'); | ||
|
||
expect(instance['mappingConsentCategories']).toEqual(customMappings); | ||
|
||
expect(window['dataLayer']).toMatchSnapshot(); | ||
}); | ||
|
||
it('should correctly process consent values', () => { | ||
instance.setCustomCustomCategoriesMapping({ | ||
ad_storage: ['consent1'], | ||
ad_user_data: ['consent2'], | ||
ad_personalization: [], | ||
analytics_storage: ['consent3'], | ||
}); | ||
|
||
const mockConsentWithValues = { | ||
consent1: true, | ||
consent2: true, | ||
consent3: false, | ||
}; | ||
|
||
const consentValues = instance['getConsentValues'](mockConsentWithValues); | ||
|
||
expect(consentValues).toEqual({ | ||
ad_storage: 'granted', | ||
ad_user_data: 'granted', | ||
ad_personalization: 'granted', | ||
analytics_storage: 'deny', | ||
}); | ||
}); | ||
|
||
it('should set consents for specific or all data layers', () => { | ||
const spyGtag = jest.spyOn(instance, 'gtag'); | ||
|
||
instance['dataLayers'] = ['dataLayer1', 'dataLayer2']; | ||
|
||
instance.setConsents(mockConsent, 'dataLayer'); | ||
expect(spyGtag).toHaveBeenCalledWith('dataLayer', mockConsent, 'update'); | ||
|
||
expect(spyGtag).not.toHaveBeenCalledWith( | ||
'dataLayer1', | ||
mockConsent, | ||
'update', | ||
); | ||
|
||
instance.setConsents(mockConsent); | ||
|
||
expect(spyGtag).toHaveBeenCalledWith('dataLayer1', mockConsent, 'update'); | ||
}); | ||
|
||
it('should not be fill the datalayer when consent mode is disabled', () => { | ||
instance['dataLayers'] = ['dataLayer1', 'dataLayer2']; | ||
instance.setConsents(mockConsent, 'dataLayer'); | ||
expect(spyGtag).toHaveBeenCalled(); | ||
|
||
spyGtag.mockClear(); | ||
instance.disable(); | ||
|
||
instance.setConsents(mockConsent, 'dataLayer'); | ||
expect(spyGtag).not.toHaveBeenCalled(); | ||
}); | ||
}); |
31 changes: 31 additions & 0 deletions
31
.../ConsentManagementProtocol/__tests__/__snapshots__/ConsentManagementProtocol.test.js.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`ConsentManagementProtocol should add integrations and initialize data layers 1`] = ` | ||
Array [ | ||
Arguments [ | ||
"consent", | ||
"default", | ||
Object { | ||
"ad_personalization": "granted", | ||
"ad_storage": "granted", | ||
"ad_user_data": "granted", | ||
"analytics_storage": "granted", | ||
}, | ||
], | ||
] | ||
`; | ||
|
||
exports[`ConsentManagementProtocol should set custom consent categories mapping and initialize a data layer; only 1 consent should be granted 1`] = ` | ||
Array [ | ||
Arguments [ | ||
"consent", | ||
"default", | ||
Object { | ||
"ad_personalization": "granted", | ||
"ad_storage": "deny", | ||
"ad_user_data": "deny", | ||
"analytics_storage": "deny", | ||
}, | ||
], | ||
] | ||
`; |
4 changes: 4 additions & 0 deletions
4
packages/react/src/analytics/integrations/shared/ConsentManagementProtocol/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export { | ||
ConsentManagementProtocol, | ||
default as consentManagementProtocol, | ||
} from './ConsentManagementProtocol'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export { | ||
ConsentManagementProtocol, | ||
consentManagementProtocol, | ||
} from './ConsentManagementProtocol'; | ||
|
||
export { AnalyticsConstants } from './constants'; |