Skip to content

Commit 58ebd32

Browse files
authored
Infer additional consent flags & gate PS join IG (#161)
1 parent 624f9ac commit 58ebd32

10 files changed

+384
-126
lines changed

lib/addons/paapi.test.js

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import OptableSDK from "../sdk";
2+
import { TEST_HOST, TEST_SITE } from "../test/mocks.ts";
3+
import "./paapi.ts";
4+
5+
describe("OptableSDK - joinAdInterestGroups", () => {
6+
let SDK;
7+
const origNavigator = window.navigator;
8+
9+
beforeEach(() => {
10+
SDK = new OptableSDK({ host: TEST_HOST, site: TEST_SITE });
11+
window.navigator = { ...origNavigator };
12+
});
13+
14+
afterEach(() => {
15+
window.navigator = origNavigator;
16+
});
17+
18+
test("injects joinAdInterestGroups func", () => {
19+
expect(SDK.joinAdInterestGroups).toBeDefined();
20+
});
21+
22+
test("joinAdInterestGroups fails when join-ad-interest-group not supported", async () => {
23+
expect.assertions(2);
24+
const expected = "join-ad-interest-group not supported";
25+
await expect(SDK.joinAdInterestGroups()).rejects.toBe(expected);
26+
27+
window.navigator.joinAdInterestGroup = function () {};
28+
await expect(SDK.joinAdInterestGroups()).rejects.not.toBe(expected);
29+
});
30+
31+
test("joinAdInterestGroups fails when consent not granted", async () => {
32+
expect.assertions(4);
33+
const expected = "consent not granted for joining interest groups";
34+
35+
window.navigator.joinAdInterestGroup = function () {};
36+
SDK.dcn.consent.deviceAccess = false;
37+
await expect(SDK.joinAdInterestGroups()).rejects.toBe(expected);
38+
39+
SDK.dcn.consent.deviceAccess = true;
40+
SDK.dcn.consent.createProfilesForAdvertising = false;
41+
await expect(SDK.joinAdInterestGroups()).rejects.toBe(expected);
42+
43+
SDK.dcn.consent.deviceAccess = true;
44+
SDK.dcn.consent.createProfilesForAdvertising = true;
45+
SDK.dcn.consent.measureAdvertisingPerformance = false;
46+
await expect(SDK.joinAdInterestGroups()).rejects.toBe(expected);
47+
48+
SDK.dcn.consent.deviceAccess = true;
49+
SDK.dcn.consent.createProfilesForAdvertising = true;
50+
SDK.dcn.consent.measureAdvertisingPerformance = true;
51+
await expect(SDK.joinAdInterestGroups()).rejects.not.toBe(expected);
52+
});
53+
});

lib/addons/paapi.ts

+11
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,17 @@ OptableSDK.prototype.joinAdInterestGroups = async function () {
157157
throw "join-ad-interest-group not supported";
158158
}
159159

160+
// For now gate for everything happenning inside the join-ig frame.
161+
// Eventually each behavior will be individually gated in the frame itself.
162+
const accessGranted =
163+
this.dcn.consent.deviceAccess &&
164+
this.dcn.consent.createProfilesForAdvertising &&
165+
this.dcn.consent.measureAdvertisingPerformance;
166+
167+
if (!accessGranted) {
168+
throw "consent not granted for joining interest groups";
169+
}
170+
160171
const siteConfig = await this.site();
161172
if (!siteConfig.interestGroupPixel) {
162173
throw "origin not enabled for protected audience apis";

lib/config.test.js

+10-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { getConfig } from "./config";
2-
import globalConsent from "./core/regs/consent";
1+
import { DCN_DEFAULTS, getConfig } from "./config";
2+
3+
const defaultConsent = DCN_DEFAULTS.consent;
34

45
describe("getConfig", () => {
56
it("returns the default config when no overrides are provided", () => {
@@ -8,7 +9,7 @@ describe("getConfig", () => {
89
site: "site",
910
cookies: true,
1011
initPassport: true,
11-
consent: { deviceAccess: true, reg: null },
12+
consent: defaultConsent,
1213
});
1314
});
1415

@@ -19,14 +20,14 @@ describe("getConfig", () => {
1920
site: "site",
2021
cookies: false,
2122
initPassport: false,
22-
consent: { static: { deviceAccess: true, reg: "us" } },
23+
consent: { static: defaultConsent },
2324
})
2425
).toEqual({
2526
host: "host",
2627
site: "site",
2728
cookies: false,
2829
initPassport: false,
29-
consent: { deviceAccess: true, reg: "us" },
30+
consent: defaultConsent,
3031
});
3132
});
3233

@@ -42,7 +43,10 @@ describe("getConfig", () => {
4243
site: "site",
4344
consent: { cmpapi: {} },
4445
});
45-
expect(config.consent).toEqual({ deviceAccess: true, reg: "us" });
46+
expect(config.consent).toEqual({
47+
...defaultConsent,
48+
reg: "us",
49+
});
4650

4751
spy.mockRestore();
4852
});

lib/config.ts

+10-9
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
1-
import { getConsent, Consent, inferRegulation } from "./core/regs/consent";
2-
3-
type CMPApiConfig = {
4-
// An optional vendor ID from GVL (global vendor list) when interpretting TCF/GPP EU consent,
5-
// when not passed, defaults to publisher consent.
6-
tcfeuVendorID?: number;
7-
};
1+
import { getConsent, inferRegulation } from "./core/regs/consent";
2+
import type { CMPApiConfig, Consent } from "./core/regs/consent";
83

94
type InitConsent = {
105
// A "cmpapi" configuration indicating that consent should be gathered from CMP apis.
@@ -28,7 +23,13 @@ type ResolvedConfig = Required<Omit<InitConfig, "consent">> & {
2823
const DCN_DEFAULTS = {
2924
cookies: true,
3025
initPassport: true,
31-
consent: { deviceAccess: true, reg: null },
26+
consent: {
27+
reg: null,
28+
deviceAccess: true,
29+
createProfilesForAdvertising: true,
30+
useProfilesForAdvertising: true,
31+
measureAdvertisingPerformance: true,
32+
},
3233
};
3334

3435
function getConfig(init: InitConfig): ResolvedConfig {
@@ -50,4 +51,4 @@ function getConfig(init: InitConfig): ResolvedConfig {
5051
}
5152

5253
export type { InitConsent, CMPApiConfig, InitConfig, ResolvedConfig };
53-
export { getConfig };
54+
export { getConfig, DCN_DEFAULTS };

0 commit comments

Comments
 (0)