Skip to content

Commit ff1d332

Browse files
zikaarioscb
authored andcommitted
feat: consent plugin updates and test cases (#894)
1 parent e3ff066 commit ff1d332

13 files changed

+1172
-27
lines changed

packages/core/src/plugin.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
/* eslint-disable @typescript-eslint/no-unused-vars */
2-
31
import type { SegmentClient } from './analytics';
42
import { Timeline } from './timeline';
53
import {

packages/core/src/plugins/ConsentPlugin.ts

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export class ConsentPlugin extends Plugin {
5757
}
5858

5959
async execute(event: SegmentEvent): Promise<SegmentEvent> {
60-
if ((event as TrackEventType).event === CONSENT_PREF_UPDATE_EVENT) {
60+
if (this.isConsentUpdateEvent(event)) {
6161
return event;
6262
}
6363

@@ -77,18 +77,36 @@ export class ConsentPlugin extends Plugin {
7777
}
7878

7979
private injectConsentFilterIfApplicable = (plugin: Plugin) => {
80-
if (
81-
this.isDestinationPlugin(plugin) &&
82-
plugin.key !== SEGMENT_DESTINATION_KEY
83-
) {
84-
const settings = this.analytics?.settings.get()?.[plugin.key];
85-
80+
if (this.isDestinationPlugin(plugin)) {
8681
plugin.add(
87-
new ConsentFilterPlugin(
88-
this.containsConsentSettings(settings)
89-
? settings.consentSettings.categories
90-
: []
91-
)
82+
new ConsentFilterPlugin((event) => {
83+
const settings = this.analytics?.settings.get() || {};
84+
const preferences = event.context?.consent?.categoryPreferences || {};
85+
86+
if (plugin.key === SEGMENT_DESTINATION_KEY) {
87+
return (
88+
this.isConsentUpdateEvent(event) ||
89+
!(
90+
Object.values(preferences).every((consented) => !consented) &&
91+
Object.entries(settings)
92+
.filter(([k]) => k !== SEGMENT_DESTINATION_KEY)
93+
.every(([_, v]) => this.containsConsentSettings(v))
94+
)
95+
);
96+
}
97+
98+
const integrationSettings = settings?.[plugin.key];
99+
100+
if (this.containsConsentSettings(integrationSettings)) {
101+
const categories = integrationSettings.consentSettings.categories;
102+
return (
103+
!this.isConsentUpdateEvent(event) &&
104+
categories.every((category) => preferences?.[category])
105+
);
106+
}
107+
108+
return true;
109+
})
92110
);
93111
}
94112
};
@@ -105,6 +123,10 @@ export class ConsentPlugin extends Plugin {
105123
?.categories === 'object'
106124
);
107125
};
126+
127+
private isConsentUpdateEvent(event: SegmentEvent): boolean {
128+
return (event as TrackEventType).event === CONSENT_PREF_UPDATE_EVENT;
129+
}
108130
}
109131

110132
/**
@@ -114,21 +136,11 @@ export class ConsentPlugin extends Plugin {
114136
class ConsentFilterPlugin extends Plugin {
115137
type = PluginType.before;
116138

117-
constructor(private categories: string[]) {
139+
constructor(private shouldAllowEvent: (event: SegmentEvent) => boolean) {
118140
super();
119141
}
120142

121143
execute(event: SegmentEvent): SegmentEvent | undefined {
122-
const preferences = event.context?.consent?.categoryPreferences;
123-
124-
// if consent plugin is active but the setup isn't properly configured - events are blocked by default
125-
if (!preferences || this.categories.length === 0) {
126-
return undefined;
127-
}
128-
129-
// all categories this destination is tagged with must be present, and allowed in consent preferences
130-
return this.categories.every((category) => preferences?.[category])
131-
? event
132-
: undefined;
144+
return this.shouldAllowEvent(event) ? event : undefined;
133145
}
134146
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 8e23248b87cc8b9d51139abe4a76baad896b99c7
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import { createTestClient } from '../../../__tests__/__helpers__/setupSegmentClient';
2+
import { ConsentPlugin } from '../../ConsentPlugin';
3+
4+
import {
5+
setupTestDestinations,
6+
createConsentProvider,
7+
createSegmentWatcher,
8+
} from './utils';
9+
import consentNotEnabledAtSegment from './mockSettings/ConsentNotEnabledAtSegment.json';
10+
11+
describe('Consent not enabled at Segment', () => {
12+
const createClient = () =>
13+
createTestClient(
14+
{
15+
settings: consentNotEnabledAtSegment.integrations,
16+
},
17+
{ autoAddSegmentDestination: true }
18+
);
19+
20+
test('no to all', async () => {
21+
const { client } = createClient();
22+
const testDestinations = setupTestDestinations(client);
23+
const mockConsentStatuses = {
24+
C0001: false,
25+
C0002: false,
26+
C0003: false,
27+
C0004: false,
28+
C0005: false,
29+
};
30+
31+
client.add({
32+
plugin: new ConsentPlugin(
33+
createConsentProvider(mockConsentStatuses),
34+
Object.keys(mockConsentStatuses)
35+
),
36+
});
37+
38+
await client.init();
39+
40+
const segmentDestination = createSegmentWatcher(client);
41+
42+
await client.track('test');
43+
44+
expect(segmentDestination).toHaveBeenCalled();
45+
expect(testDestinations.dest1.track).toHaveBeenCalled();
46+
expect(testDestinations.dest2.track).toHaveBeenCalled();
47+
expect(testDestinations.dest3.track).toHaveBeenCalled();
48+
expect(testDestinations.dest4.track).toHaveBeenCalled();
49+
expect(testDestinations.dest5.track).toHaveBeenCalled();
50+
});
51+
52+
test('yes to some', async () => {
53+
const { client } = createClient();
54+
const testDestinations = setupTestDestinations(client);
55+
const mockConsentStatuses = {
56+
C0001: false,
57+
C0002: true,
58+
C0003: false,
59+
C0004: true,
60+
C0005: true,
61+
};
62+
63+
client.add({
64+
plugin: new ConsentPlugin(
65+
createConsentProvider(mockConsentStatuses),
66+
Object.keys(mockConsentStatuses)
67+
),
68+
});
69+
70+
await client.init();
71+
72+
const segmentDestination = createSegmentWatcher(client);
73+
74+
await client.track('test');
75+
76+
expect(segmentDestination).toHaveBeenCalled();
77+
expect(testDestinations.dest1.track).toHaveBeenCalled();
78+
expect(testDestinations.dest2.track).toHaveBeenCalled();
79+
expect(testDestinations.dest3.track).toHaveBeenCalled();
80+
expect(testDestinations.dest4.track).toHaveBeenCalled();
81+
expect(testDestinations.dest5.track).toHaveBeenCalled();
82+
});
83+
84+
test('yes to all', async () => {
85+
const { client } = createClient();
86+
const testDestinations = setupTestDestinations(client);
87+
const mockConsentStatuses = {
88+
C0001: true,
89+
C0002: true,
90+
C0003: true,
91+
C0004: true,
92+
C0005: true,
93+
};
94+
95+
client.add({
96+
plugin: new ConsentPlugin(
97+
createConsentProvider(mockConsentStatuses),
98+
Object.keys(mockConsentStatuses)
99+
),
100+
});
101+
102+
await client.init();
103+
104+
const segmentDestination = createSegmentWatcher(client);
105+
106+
await client.track('test');
107+
108+
expect(segmentDestination).toHaveBeenCalled();
109+
expect(testDestinations.dest1.track).toHaveBeenCalled();
110+
expect(testDestinations.dest2.track).toHaveBeenCalled();
111+
expect(testDestinations.dest3.track).toHaveBeenCalled();
112+
expect(testDestinations.dest4.track).toHaveBeenCalled();
113+
expect(testDestinations.dest5.track).toHaveBeenCalled();
114+
});
115+
});
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import { createTestClient } from '../../../__tests__/__helpers__/setupSegmentClient';
2+
import { ConsentPlugin } from '../../ConsentPlugin';
3+
4+
import {
5+
setupTestDestinations,
6+
createConsentProvider,
7+
createSegmentWatcher,
8+
} from './utils';
9+
import destinationsMultipleCategories from './mockSettings/DestinationsMultipleCategories.json';
10+
11+
describe('Destinations multiple categories', () => {
12+
const createClient = () =>
13+
createTestClient(
14+
{
15+
settings: destinationsMultipleCategories.integrations,
16+
},
17+
{ autoAddSegmentDestination: true }
18+
);
19+
20+
test('no to all', async () => {
21+
const { client } = createClient();
22+
const testDestinations = setupTestDestinations(client);
23+
const mockConsentStatuses = {
24+
C0001: false,
25+
C0002: false,
26+
C0003: false,
27+
C0004: false,
28+
C0005: false,
29+
};
30+
31+
client.add({
32+
plugin: new ConsentPlugin(
33+
createConsentProvider(mockConsentStatuses),
34+
Object.keys(mockConsentStatuses)
35+
),
36+
});
37+
38+
await client.init();
39+
40+
const segmentDestination = createSegmentWatcher(client);
41+
42+
await client.track('test');
43+
44+
expect(segmentDestination).not.toHaveBeenCalled();
45+
expect(testDestinations.dest1.track).not.toHaveBeenCalled();
46+
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
47+
});
48+
49+
test('yes to 1', async () => {
50+
const { client } = createClient();
51+
const testDestinations = setupTestDestinations(client);
52+
const mockConsentStatuses = {
53+
C0001: true,
54+
C0002: false,
55+
C0003: false,
56+
C0004: false,
57+
C0005: false,
58+
};
59+
60+
client.add({
61+
plugin: new ConsentPlugin(
62+
createConsentProvider(mockConsentStatuses),
63+
Object.keys(mockConsentStatuses)
64+
),
65+
});
66+
67+
await client.init();
68+
69+
const segmentDestination = createSegmentWatcher(client);
70+
71+
await client.track('test');
72+
73+
expect(segmentDestination).toHaveBeenCalled();
74+
expect(testDestinations.dest1.track).not.toHaveBeenCalled();
75+
expect(testDestinations.dest2.track).toHaveBeenCalled();
76+
});
77+
78+
test('yes to 2', async () => {
79+
const { client } = createClient();
80+
const testDestinations = setupTestDestinations(client);
81+
const mockConsentStatuses = {
82+
C0001: false,
83+
C0002: true,
84+
C0003: false,
85+
C0004: false,
86+
C0005: false,
87+
};
88+
89+
client.add({
90+
plugin: new ConsentPlugin(
91+
createConsentProvider(mockConsentStatuses),
92+
Object.keys(mockConsentStatuses)
93+
),
94+
});
95+
96+
await client.init();
97+
98+
const segmentDestination = createSegmentWatcher(client);
99+
100+
await client.track('test');
101+
102+
expect(segmentDestination).toHaveBeenCalled();
103+
expect(testDestinations.dest1.track).not.toHaveBeenCalled();
104+
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
105+
});
106+
107+
test('yes to all', async () => {
108+
const { client } = createClient();
109+
const testDestinations = setupTestDestinations(client);
110+
const mockConsentStatuses = {
111+
C0001: true,
112+
C0002: true,
113+
C0003: true,
114+
C0004: true,
115+
C0005: true,
116+
};
117+
118+
client.add({
119+
plugin: new ConsentPlugin(
120+
createConsentProvider(mockConsentStatuses),
121+
Object.keys(mockConsentStatuses)
122+
),
123+
});
124+
125+
await client.init();
126+
127+
const segmentDestination = createSegmentWatcher(client);
128+
129+
await client.track('test');
130+
131+
expect(segmentDestination).toHaveBeenCalled();
132+
expect(testDestinations.dest1.track).toHaveBeenCalled();
133+
expect(testDestinations.dest2.track).toHaveBeenCalled();
134+
});
135+
});

0 commit comments

Comments
 (0)