Skip to content

Commit

Permalink
Only enable integration if _all_ consent categories are consented to. (
Browse files Browse the repository at this point in the history
  • Loading branch information
silesky authored Jul 14, 2023
1 parent 48ce3ec commit 6789f9b
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 31 deletions.
5 changes: 5 additions & 0 deletions .changeset/popular-elephants-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@segment/analytics-consent-tools': patch
---

Change meaning of consent to 'user has consented ALL categories'
Original file line number Diff line number Diff line change
Expand Up @@ -368,11 +368,36 @@ describe(createWrapper, () => {
)
})

it('should allow integration if an integration has multiple categories, and user has multiple categories, but only consents to one', async () => {
it('should allow integration if it has one category and user has consented to that category', async () => {
const mockCdnSettings = settingsBuilder
.addActionDestinationSettings({
creationName: 'mockIntegration',
...createConsentSettings(['Bar', 'Something else']),
...createConsentSettings(['Foo']),
})
.build()

wrapTestAnalytics({
shouldLoad: () => ({ Foo: true }),
})
await analytics.load({
...DEFAULT_LOAD_SETTINGS,
cdnSettings: mockCdnSettings,
})
expect(analyticsLoadSpy).toBeCalled()
const { updatedCDNSettings } = getAnalyticsLoadLastCall()
// remote plugins should be filtered based on consent settings
expect(updatedCDNSettings.remotePlugins).toContainEqual(
mockCdnSettings.remotePlugins?.find(
(p) => p.creationName === 'mockIntegration'
)
)
})

it('should allow integration if it has multiple categories and user consents to all of them.', async () => {
const mockCdnSettings = settingsBuilder
.addActionDestinationSettings({
creationName: 'mockIntegration',
...createConsentSettings(['Foo', 'Bar']),
})
.build()

Expand All @@ -386,18 +411,18 @@ describe(createWrapper, () => {
expect(analyticsLoadSpy).toBeCalled()
const { updatedCDNSettings } = getAnalyticsLoadLastCall()
// remote plugins should be filtered based on consent settings
expect(updatedCDNSettings.remotePlugins).toEqual(
mockCdnSettings.remotePlugins?.filter(
expect(updatedCDNSettings.remotePlugins).toContainEqual(
mockCdnSettings.remotePlugins?.find(
(p) => p.creationName === 'mockIntegration'
)
)
})

it('should allow integration if it has multiple consent categories but user has only consented to one category', async () => {
it('should disable integration if it has multiple categories but user has only consented to one', async () => {
const mockCdnSettings = settingsBuilder
.addActionDestinationSettings({
creationName: 'mockIntegration',
...createConsentSettings(['Foo', 'Something else']),
...createConsentSettings(['Foo', 'Bar']),
})
.build()

Expand All @@ -410,8 +435,8 @@ describe(createWrapper, () => {
})

const { updatedCDNSettings } = getAnalyticsLoadLastCall()
expect(updatedCDNSettings.remotePlugins).toEqual(
mockCdnSettings.remotePlugins?.filter(
expect(updatedCDNSettings.remotePlugins).not.toContainEqual(
mockCdnSettings.remotePlugins?.find(
(p) => p.creationName === 'mockIntegration'
)
)
Expand Down
3 changes: 2 additions & 1 deletion packages/consent/consent-tools/src/domain/create-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ const omitDisabledRemotePlugins = (
return true
}

const hasUserConsent = categories.some((c) => consentedCategories[c])
// Enable if all of its consent categories are consented to
const hasUserConsent = categories.every((c) => consentedCategories[c])
return hasUserConsent
})
26 changes: 4 additions & 22 deletions packages/consent/consent-tools/src/types/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,32 +50,14 @@ export interface CreateWrapperSettings {
integrationCategoryMappings?: IntegrationCategoryMappings

/**
* Predicate function to override default logic around whether or not to load an integration.
* @default
* ```ts
* // consent if user consents to at least one category defined in the integration
* (integrationCategories, categories, _info) => {
* if (!integrationCategories.length) return true
* return integrationCategories.some((c) => categories[c])
* }
* ```
*
* @example -
* ```ts
* (integrationCategories, categories, _info) => {
* // consent if user consents to _all_ categories defined in the integration
* if (!integrationCategories.length) return true
* return integrationCategories.every((c) => categories[c])
* }
* ```
*
* Predicate function to override default logic around whether or not to load an integration. By default, consent requires a user to have all categories enabled for a given integration.
* @example
* ```ts
* // count consent as usual, but always disable a particular plugin
* (integrationCategories, categories, { creationName }) => {
* // Always disable a particular plugin
* const shouldEnableIntegration = (integrationCategories, categories, { creationName }) => {
* if (creationName === 'FullStory') return false
* if (!integrationCategories.length) return true
* return integrationCategories.some((c) => categories[c])
* return integrationCategories.every((c) => categories[c])
* }
* ```
*/
Expand Down

0 comments on commit 6789f9b

Please sign in to comment.