Skip to content

Improve the typing when importing/exporting the CategoryConsentStatusProvider type #904

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

Closed
Changes from all 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
6 changes: 2 additions & 4 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -14,9 +14,7 @@ export {
} from './util';
export { SegmentClient } from './analytics';
export { SegmentDestination } from './plugins/SegmentDestination';
export {
CategoryConsentStatusProvider,
ConsentPlugin,
} from './plugins/ConsentPlugin';
export type { CategoryConsentStatusProvider } from './plugins/ConsentPlugin';
export { ConsentPlugin } from './plugins/ConsentPlugin';
export * from './flushPolicies';
export * from './errors';
2 changes: 0 additions & 2 deletions packages/core/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/* eslint-disable @typescript-eslint/no-unused-vars */

import type { SegmentClient } from './analytics';
import { Timeline } from './timeline';
import {
60 changes: 36 additions & 24 deletions packages/core/src/plugins/ConsentPlugin.ts
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@ export class ConsentPlugin extends Plugin {
}

async execute(event: SegmentEvent): Promise<SegmentEvent> {
if ((event as TrackEventType).event === CONSENT_PREF_UPDATE_EVENT) {
if (this.isConsentUpdateEvent(event)) {
return event;
}

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

private injectConsentFilterIfApplicable = (plugin: Plugin) => {
if (
this.isDestinationPlugin(plugin) &&
plugin.key !== SEGMENT_DESTINATION_KEY
) {
const settings = this.analytics?.settings.get()?.[plugin.key];

if (this.isDestinationPlugin(plugin)) {
plugin.add(
new ConsentFilterPlugin(
this.containsConsentSettings(settings)
? settings.consentSettings.categories
: []
)
new ConsentFilterPlugin((event) => {
const settings = this.analytics?.settings.get() || {};
const preferences = event.context?.consent?.categoryPreferences || {};

if (plugin.key === SEGMENT_DESTINATION_KEY) {
return (
this.isConsentUpdateEvent(event) ||
!(
Object.values(preferences).every((consented) => !consented) &&
Object.entries(settings)
.filter(([k]) => k !== SEGMENT_DESTINATION_KEY)
.every(([_, v]) => this.containsConsentSettings(v))
)
);
}

const integrationSettings = settings?.[plugin.key];

if (this.containsConsentSettings(integrationSettings)) {
const categories = integrationSettings.consentSettings.categories;
return (
!this.isConsentUpdateEvent(event) &&
categories.every((category) => preferences?.[category])
);
}

return true;
})
);
}
};
@@ -105,6 +123,10 @@ export class ConsentPlugin extends Plugin {
?.categories === 'object'
);
};

private isConsentUpdateEvent(event: SegmentEvent): boolean {
return (event as TrackEventType).event === CONSENT_PREF_UPDATE_EVENT;
}
}

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

constructor(private categories: string[]) {
constructor(private shouldAllowEvent: (event: SegmentEvent) => boolean) {
super();
}

execute(event: SegmentEvent): SegmentEvent | undefined {
const preferences = event.context?.consent?.categoryPreferences;

// if consent plugin is active but the setup isn't properly configured - events are blocked by default
if (!preferences || this.categories.length === 0) {
return undefined;
}

// all categories this destination is tagged with must be present, and allowed in consent preferences
return this.categories.every((category) => preferences?.[category])
? event
: undefined;
return this.shouldAllowEvent(event) ? event : undefined;
}
}
Submodule analytics-swift-consent added at 8e2324
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { createTestClient } from '../../../__tests__/__helpers__/setupSegmentClient';
import { ConsentPlugin } from '../../ConsentPlugin';

import {
setupTestDestinations,
createConsentProvider,
createSegmentWatcher,
} from './utils';
import consentNotEnabledAtSegment from './mockSettings/ConsentNotEnabledAtSegment.json';

describe('Consent not enabled at Segment', () => {
const createClient = () =>
createTestClient(
{
settings: consentNotEnabledAtSegment.integrations,
},
{ autoAddSegmentDestination: true }
);

test('no to all', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: false,
C0002: false,
C0003: false,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).toHaveBeenCalled();
expect(testDestinations.dest2.track).toHaveBeenCalled();
expect(testDestinations.dest3.track).toHaveBeenCalled();
expect(testDestinations.dest4.track).toHaveBeenCalled();
expect(testDestinations.dest5.track).toHaveBeenCalled();
});

test('yes to some', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: false,
C0002: true,
C0003: false,
C0004: true,
C0005: true,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).toHaveBeenCalled();
expect(testDestinations.dest2.track).toHaveBeenCalled();
expect(testDestinations.dest3.track).toHaveBeenCalled();
expect(testDestinations.dest4.track).toHaveBeenCalled();
expect(testDestinations.dest5.track).toHaveBeenCalled();
});

test('yes to all', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: true,
C0002: true,
C0003: true,
C0004: true,
C0005: true,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).toHaveBeenCalled();
expect(testDestinations.dest2.track).toHaveBeenCalled();
expect(testDestinations.dest3.track).toHaveBeenCalled();
expect(testDestinations.dest4.track).toHaveBeenCalled();
expect(testDestinations.dest5.track).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { createTestClient } from '../../../__tests__/__helpers__/setupSegmentClient';
import { ConsentPlugin } from '../../ConsentPlugin';

import {
setupTestDestinations,
createConsentProvider,
createSegmentWatcher,
} from './utils';
import destinationsMultipleCategories from './mockSettings/DestinationsMultipleCategories.json';

describe('Destinations multiple categories', () => {
const createClient = () =>
createTestClient(
{
settings: destinationsMultipleCategories.integrations,
},
{ autoAddSegmentDestination: true }
);

test('no to all', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: false,
C0002: false,
C0003: false,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).not.toHaveBeenCalled();
expect(testDestinations.dest1.track).not.toHaveBeenCalled();
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
});

test('yes to 1', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: true,
C0002: false,
C0003: false,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).not.toHaveBeenCalled();
expect(testDestinations.dest2.track).toHaveBeenCalled();
});

test('yes to 2', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: false,
C0002: true,
C0003: false,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).not.toHaveBeenCalled();
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
});

test('yes to all', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: true,
C0002: true,
C0003: true,
C0004: true,
C0005: true,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).toHaveBeenCalled();
expect(testDestinations.dest2.track).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"integrations": {
"DummyDest1": {
"versionSettings": {
"componentTypes": []
}
},
"DummyDest2": {
"versionSettings": {
"componentTypes": []
}
},
"DummyDest3": {
"versionSettings": {
"componentTypes": []
}
},
"DummyDest4": {
"versionSettings": {
"componentTypes": []
}
},
"DummyDest5": {
"versionSettings": {
"componentTypes": []
}
},
"Segment.io": {
"apiKey": "test",
"unbundledIntegrations": [],
"addBundledMetadata": true,
"maybeBundledConfigIds": {},
"versionSettings": {
"version": "4.4.7",
"componentTypes": [
"browser"
]
},
"apiHost": "api.segment.io/v1"
}
},
"plan": {
"track": {
"__default": {
"enabled": true,
"integrations": {}
}
},
"identify": {
"__default": {
"enabled": true
}
},
"group": {
"__default": {
"enabled": true
}
}
},
"edgeFunction": {},
"analyticsNextEnabled": true,
"middlewareSettings": {},
"enabledMiddleware": {},
"metrics": {
"sampleRate": 0.1,
"host": "api.segment.io/v1"
},
"legacyVideoPluginsEnabled": false,
"remotePlugins": []
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"integrations": {
"DummyDest1": {
"versionSettings": {
"componentTypes": []
},
"consentSettings": {
"categories": [
"C0001",
"C0002"
]
}
},
"DummyDest2": {
"versionSettings": {
"componentTypes": []
},
"consentSettings": {
"categories": [
"C0001"
]
}
},
"Segment.io": {
"apiKey": "test",
"unbundledIntegrations": [],
"addBundledMetadata": true,
"maybeBundledConfigIds": {},
"versionSettings": {
"version": "4.4.7",
"componentTypes": [
"browser"
]
},
"apiHost": "api.segment.io/v1"
}
},
"plan": {
"track": {
"__default": {
"enabled": true,
"integrations": {}
}
},
"identify": {
"__default": {
"enabled": true
}
},
"group": {
"__default": {
"enabled": true
}
}
},
"edgeFunction": {},
"analyticsNextEnabled": true,
"middlewareSettings": {},
"enabledMiddleware": {},
"metrics": {
"sampleRate": 0.1,
"host": "api.segment.io/v1"
},
"legacyVideoPluginsEnabled": false,
"remotePlugins": [],
"consentSettings": {
"allCategories": [
"C0001",
"C0002"
]
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
{
"integrations": {
"DummyDest1": {
"versionSettings": {
"componentTypes": []
},
"consentSettings": {
"categories": [
"C0001"
]
}
},
"DummyDest2": {
"versionSettings": {
"componentTypes": []
},
"consentSettings": {
"categories": [
"C0002"
]
}
},
"DummyDest3": {
"versionSettings": {
"componentTypes": []
},
"consentSettings": {
"categories": [
"C0003"
]
}
},
"DummyDest4": {
"versionSettings": {
"componentTypes": []
},
"consentSettings": {
"categories": [
"C0004"
]
}
},
"DummyDest5": {
"versionSettings": {
"componentTypes": []
},
"consentSettings": {
"categories": [
"C0005"
]
}
},
"Segment.io": {
"apiKey": "test",
"unbundledIntegrations": [],
"addBundledMetadata": true,
"maybeBundledConfigIds": {},
"versionSettings": {
"version": "4.4.7",
"componentTypes": [
"browser"
]
},
"apiHost": "api.segment.io/v1"
}
},
"plan": {
"track": {
"__default": {
"enabled": true,
"integrations": {}
}
},
"identify": {
"__default": {
"enabled": true
}
},
"group": {
"__default": {
"enabled": true
}
}
},
"edgeFunction": {},
"analyticsNextEnabled": true,
"middlewareSettings": {},
"enabledMiddleware": {},
"metrics": {
"sampleRate": 0.1,
"host": "api.segment.io/v1"
},
"legacyVideoPluginsEnabled": false,
"remotePlugins": [],
"consentSettings": {
"allCategories": [
"C0001",
"C0002",
"C0003",
"C0004",
"C0005"
]
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
{
"integrations": {
"DummyDest1": {
"versionSettings": {
"componentTypes": []
},
"consentSettings": {
"categories": [
"C0001",
"C0002"
]
}
},
"DummyDest2": {
"versionSettings": {
"componentTypes": []
},
"consentSettings": {
"categories": [
"C0003"
]
}
},
"DummyDest3": {
"versionSettings": {
"componentTypes": []
},
"consentSettings": {
"categories": [
"C0004"
]
}
},
"DummyDest4": {
"versionSettings": {
"componentTypes": []
},
"consentSettings": {
"categories": [
"C0005"
]
}
},
"DummyDest5": {
"versionSettings": {
"componentTypes": []
}
},
"Segment.io": {
"apiKey": "test",
"unbundledIntegrations": [],
"addBundledMetadata": true,
"maybeBundledConfigIds": {},
"versionSettings": {
"version": "4.4.7",
"componentTypes": [
"browser"
]
},
"apiHost": "api.segment.io/v1"
}
},
"plan": {
"track": {
"__default": {
"enabled": true,
"integrations": {}
}
},
"identify": {
"__default": {
"enabled": true
}
},
"group": {
"__default": {
"enabled": true
}
}
},
"edgeFunction": {},
"analyticsNextEnabled": true,
"middlewareSettings": {},
"enabledMiddleware": {},
"metrics": {
"sampleRate": 0.1,
"host": "api.segment.io/v1"
},
"legacyVideoPluginsEnabled": false,
"remotePlugins": [],
"consentSettings": {
"allCategories": [
"C0001",
"C0002",
"C0003",
"C0004",
"C0005"
]
}
}

213 changes: 213 additions & 0 deletions packages/core/src/plugins/__tests__/consent/noUnmapped.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import { createTestClient } from '../../../__tests__/__helpers__/setupSegmentClient';
import { ConsentPlugin } from '../../ConsentPlugin';

import { setupTestDestinations, createConsentProvider } from './utils';
import noUnmappedDestinations from './mockSettings/NoUnmappedDestinations.json';

describe('No unmapped destinations', () => {
const createClient = () =>
createTestClient({
settings: noUnmappedDestinations.integrations,
});

test('no to all', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: false,
C0002: false,
C0003: false,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

await client.track('test');

Object.values(testDestinations).forEach((testDestination) => {
expect(testDestination.track).not.toHaveBeenCalled();
});
});

test('yes to 1', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: true,
C0002: false,
C0003: false,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

await client.track('test');

expect(testDestinations.dest1.track).toHaveBeenCalled();
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
expect(testDestinations.dest3.track).not.toHaveBeenCalled();
expect(testDestinations.dest4.track).not.toHaveBeenCalled();
expect(testDestinations.dest5.track).not.toHaveBeenCalled();
});

test('yes to 2', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: false,
C0002: true,
C0003: false,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

await client.track('test');

expect(testDestinations.dest1.track).not.toHaveBeenCalled();
expect(testDestinations.dest2.track).toHaveBeenCalled();
expect(testDestinations.dest3.track).not.toHaveBeenCalled();
expect(testDestinations.dest4.track).not.toHaveBeenCalled();
expect(testDestinations.dest5.track).not.toHaveBeenCalled();
});

test('yes to 3', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: false,
C0002: false,
C0003: true,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

await client.track('test');

expect(testDestinations.dest1.track).not.toHaveBeenCalled();
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
expect(testDestinations.dest3.track).toHaveBeenCalled();
expect(testDestinations.dest4.track).not.toHaveBeenCalled();
expect(testDestinations.dest5.track).not.toHaveBeenCalled();
});

test('yes to 4', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: false,
C0002: false,
C0003: false,
C0004: true,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

await client.track('test');

expect(testDestinations.dest1.track).not.toHaveBeenCalled();
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
expect(testDestinations.dest3.track).not.toHaveBeenCalled();
expect(testDestinations.dest4.track).toHaveBeenCalled();
expect(testDestinations.dest5.track).not.toHaveBeenCalled();
});

test('yes to 1 and 3', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: true,
C0002: false,
C0003: true,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

await client.track('test');

expect(testDestinations.dest1.track).toHaveBeenCalled();
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
expect(testDestinations.dest3.track).toHaveBeenCalled();
expect(testDestinations.dest4.track).not.toHaveBeenCalled();
expect(testDestinations.dest5.track).not.toHaveBeenCalled();
});

test('yes to all', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: true,
C0002: true,
C0003: true,
C0004: true,
C0005: true,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

await client.track('test');

expect(testDestinations.dest1.track).toHaveBeenCalled();
expect(testDestinations.dest2.track).toHaveBeenCalled();
expect(testDestinations.dest3.track).toHaveBeenCalled();
expect(testDestinations.dest4.track).toHaveBeenCalled();
expect(testDestinations.dest5.track).toHaveBeenCalled();
});
});
243 changes: 243 additions & 0 deletions packages/core/src/plugins/__tests__/consent/unmapped.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
import { createTestClient } from '../../../__tests__/__helpers__/setupSegmentClient';
import { ConsentPlugin } from '../../ConsentPlugin';

import {
setupTestDestinations,
createConsentProvider,
createSegmentWatcher,
} from './utils';
import unmappedDestinations from './mockSettings/UnmappedDestinations.json';

describe('Unmapped destinations', () => {
const createClient = () =>
createTestClient(
{
settings: unmappedDestinations.integrations,
},
{ autoAddSegmentDestination: true }
);

test('no to all', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: false,
C0002: false,
C0003: false,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).not.toHaveBeenCalled();
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
expect(testDestinations.dest3.track).not.toHaveBeenCalled();
expect(testDestinations.dest4.track).not.toHaveBeenCalled();
expect(testDestinations.dest5.track).toHaveBeenCalled();
});

test('yes to 1', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: true,
C0002: false,
C0003: false,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).not.toHaveBeenCalled();
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
expect(testDestinations.dest3.track).not.toHaveBeenCalled();
expect(testDestinations.dest4.track).not.toHaveBeenCalled();
expect(testDestinations.dest5.track).toHaveBeenCalled();
});

test('yes to 2', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: false,
C0002: true,
C0003: false,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).not.toHaveBeenCalled();
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
expect(testDestinations.dest3.track).not.toHaveBeenCalled();
expect(testDestinations.dest4.track).not.toHaveBeenCalled();
expect(testDestinations.dest5.track).toHaveBeenCalled();
});

test('yes to 3', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: false,
C0002: false,
C0003: true,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).not.toHaveBeenCalled();
expect(testDestinations.dest2.track).toHaveBeenCalled();
expect(testDestinations.dest3.track).not.toHaveBeenCalled();
expect(testDestinations.dest4.track).not.toHaveBeenCalled();
expect(testDestinations.dest5.track).toHaveBeenCalled();
});

test('yes to 4', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: false,
C0002: false,
C0003: false,
C0004: true,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).not.toHaveBeenCalled();
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
expect(testDestinations.dest3.track).toHaveBeenCalled();
expect(testDestinations.dest4.track).not.toHaveBeenCalled();
expect(testDestinations.dest5.track).toHaveBeenCalled();
});

test('yes to 1 and 2', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: true,
C0002: true,
C0003: false,
C0004: false,
C0005: false,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).toHaveBeenCalled();
expect(testDestinations.dest2.track).not.toHaveBeenCalled();
expect(testDestinations.dest3.track).not.toHaveBeenCalled();
expect(testDestinations.dest4.track).not.toHaveBeenCalled();
expect(testDestinations.dest5.track).toHaveBeenCalled();
});

test('yes to all', async () => {
const { client } = createClient();
const testDestinations = setupTestDestinations(client);
const mockConsentStatuses = {
C0001: true,
C0002: true,
C0003: true,
C0004: true,
C0005: true,
};

client.add({
plugin: new ConsentPlugin(
createConsentProvider(mockConsentStatuses),
Object.keys(mockConsentStatuses)
),
});

await client.init();

const segmentDestination = createSegmentWatcher(client);

await client.track('test');

expect(segmentDestination).toHaveBeenCalled();
expect(testDestinations.dest1.track).toHaveBeenCalled();
expect(testDestinations.dest2.track).toHaveBeenCalled();
expect(testDestinations.dest3.track).toHaveBeenCalled();
expect(testDestinations.dest4.track).toHaveBeenCalled();
expect(testDestinations.dest5.track).toHaveBeenCalled();
});
});
78 changes: 78 additions & 0 deletions packages/core/src/plugins/__tests__/consent/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {
DestinationPlugin,
PluginType,
SegmentClient,
UtilityPlugin,
} from '@segment/analytics-react-native';
import type { CategoryConsentStatusProvider } from '@segment/analytics-react-native';
import { SegmentDestination } from '../../SegmentDestination';

beforeEach(() => {
jest.spyOn(SegmentDestination.prototype, 'execute');
});

class SegmentWatcherPlugin extends UtilityPlugin {
type = PluginType.after;
execute = jest.fn();
}

class MockDestination extends DestinationPlugin {
track = jest.fn();

constructor(public readonly key: string) {
super();
}
}

export const setupTestDestinations = (client: SegmentClient) => {
const dest1 = new MockDestination('DummyDest1');
const dest2 = new MockDestination('DummyDest2');
const dest3 = new MockDestination('DummyDest3');
const dest4 = new MockDestination('DummyDest4');
const dest5 = new MockDestination('DummyDest5');

client.add({ plugin: dest1 });
client.add({ plugin: dest2 });
client.add({ plugin: dest3 });
client.add({ plugin: dest4 });
client.add({ plugin: dest5 });

return {
dest1,
dest2,
dest3,
dest4,
dest5,
};
};

export const createSegmentWatcher = (client: SegmentClient) => {
const segmentDestination = client
.getPlugins()
.find(
(p) => (p as DestinationPlugin).key === 'Segment.io'
) as SegmentDestination;

const segmentWatcher = new SegmentWatcherPlugin();
segmentDestination.add(segmentWatcher);

return segmentWatcher.execute;
};

export const createConsentProvider = (
statuses: Record<string, boolean>
): CategoryConsentStatusProvider => ({
getConsentStatus: () => Promise.resolve(statuses),
setApplicableCategories: () => {
/** no op */
},
onConsentChange: () => {
/** no op */
},
});

describe('Consent test utils', () => {
it('works', () => {
// this is just to suppress jest error - "must have at least one test"
});
});
2 changes: 1 addition & 1 deletion packages/core/tsconfig.json
Original file line number Diff line number Diff line change
@@ -4,5 +4,5 @@
"outDir": "lib/typescript"
},
"references": [{ "path": "../sovran" }],
"include": ["src/**/*", "package.json", "types.d.ts"]
"include": ["src/**/*", "package.json", "src/**/*.json", "types.d.ts"]
}