Skip to content

Commit

Permalink
feat: ✅ skip queue for zaraz.consent methods, increase tests
Browse files Browse the repository at this point in the history
  • Loading branch information
davevanhoorn committed Apr 18, 2024
1 parent ada8793 commit 8de4b54
Show file tree
Hide file tree
Showing 17 changed files with 158 additions and 25 deletions.
14 changes: 12 additions & 2 deletions src/consent/get-all.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,18 @@ afterAll(() => {
});

describe('getAll()', () => {
it('should return all consents from zaraz consent', () => {
const consentsMock = { key1: true, key2: false };
it("should return an empty object when Zaraz hasn't been initialized", () => {
const consents = getAll();
expect(consents).toEqual({});
});

it('should return all consents when Zaraz has been initialised', () => {
const consentsMock = {
key1: true,
key2: false,
key3: undefined,
};

window.zaraz = {
consent: {
getAll: jest.fn().mockReturnValue(consentsMock),
Expand Down
16 changes: 13 additions & 3 deletions src/consent/get-all.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import { getZaraz } from '../helpers/get-zaraz';

export type PurposeStatuses = {
[key: string]: undefined | boolean; // The key is equal to the ID in Zaraz, e.g. "OVAL" or "DVEA".
};

/**
* Returns an object with the consent status of all purposes.
* Returns an object with the status of all purposes.
*
* - When the value is undefined, the consent hasn't been given yet
* - When the value is true, the consent has been given
* - When the value is false, the consent has been denied
*
* When Zaraz hasn't been initalised, it returns an empty object.
*/
export function getAll(): { [key: string]: boolean } {
return getZaraz().consent.getAll();
export function getAll(): PurposeStatuses {
return getZaraz({ skipQueue: true })?.consent?.getAll() || {};
}
38 changes: 38 additions & 0 deletions src/consent/get-api-ready.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { getAPIReady } from './get-api-ready';

declare global {
interface Window {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
zaraz: any;
}
}

let windowObj: Window & typeof globalThis;

beforeAll(() => {
windowObj = window;
});

afterAll(() => {
window = windowObj;
});

describe('getAPIReady()', () => {
it('should return false when the Zaraz consent API is not ready', () => {
const apiReady = getAPIReady();

expect(apiReady).toEqual(false);
});

it('should return true when the Zaraz consent API is ready', () => {
window.zaraz = {
consent: {
APIReady: true,
},
};

const apiReady = getAPIReady();

expect(apiReady).toEqual(true);
});
});
8 changes: 8 additions & 0 deletions src/consent/get-api-ready.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { getZaraz } from '../helpers/get-zaraz';

/**
* Indicates whether the Consent API is currently available on the page.
*/
export function getAPIReady(): boolean {
return getZaraz({ skipQueue: true })?.consent?.APIReady || false;
}
24 changes: 19 additions & 5 deletions src/consent/get-purposes.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getPurposes } from './get-purposes';
import { getPurposes, Purposes } from './get-purposes';

declare global {
interface Window {
Expand All @@ -18,11 +18,25 @@ afterAll(() => {
});

describe('getPurposes()', () => {
it('should return all purposes from zaraz consent', () => {
const purposesMock = {
key1: { name: 'Name 1', description: 'Description 1', order: 1 },
key2: { name: 'Name 2', description: 'Description 2', order: 2 },
it("should return an empty object when the Zaraz consent API isn't initialised", () => {
const purposes = getPurposes();
expect(purposes).toEqual({});
});

it('should return all purposes from the Zaraz consent API when Zaraz is initialised', () => {
const purposesMock: Purposes = {
ORFL: {
name: { en: 'Name 1' },
description: { en: 'Description 1' },
order: 100,
},
OAVL: {
name: { en: 'Name 2' },
description: { en: 'Description 2' },
order: 200,
},
};

window.zaraz = {
consent: {
purposes: purposesMock,
Expand Down
18 changes: 13 additions & 5 deletions src/consent/get-purposes.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { getZaraz } from '../helpers/get-zaraz';

type Purpose = {
name: string;
description: string;
export type Purpose = {
order: number;
name: {
[key: string]: string; // the key is the language set in Zaraz (e.g. "en")
};
description: {
[key: string]: string; // the key is the language set in Zaraz (e.g. "en")
};
};

export type Purposes = {
[key: string]: Purpose; // the key is also the ID visible in Zaraz (e.g. "OrGL" or "OAVL")
};

/**
* An object containing all configured purposes, with their ID, name, description, and order.
*/
export function getPurposes(): { [key: string]: Purpose } {
return getZaraz().consent.purposes;
export function getPurposes(): Purposes {
return getZaraz({ skipQueue: true })?.consent?.purposes || {};
}
8 changes: 7 additions & 1 deletion src/consent/get.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,14 @@ afterAll(() => {
});

describe('get()', () => {
it('should return the consent status for a purpose from zaraz consent', () => {
it("should return undefined when Zaraz hasn't been initialised", () => {
const consentStatus = get('key');
expect(consentStatus).toBe(undefined);
});

it('should return the consent status for a purpose when Zaraz has been initialised', () => {
const getMock = jest.fn().mockReturnValue(true);

window.zaraz = {
consent: {
get: getMock,
Expand Down
4 changes: 2 additions & 2 deletions src/consent/get.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getZaraz } from '../helpers/get-zaraz';

/**
* Get the current consent status for a purpose using the purpose ID.
* Get the consent status for a specific purpose using the purpose ID.
*
* ```
* true: The consent was granted.
Expand All @@ -10,5 +10,5 @@ import { getZaraz } from '../helpers/get-zaraz';
* ```
*/
export function get(purposeId: string): boolean | undefined {
return getZaraz().consent.get(purposeId);
return getZaraz({ skipQueue: true })?.consent?.get(purposeId) || undefined;
}
1 change: 1 addition & 0 deletions src/consent/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ describe('consent', () => {
setAll: expect.any(Function),
getAllCheckboxes: expect.any(Function),
getPurposes: expect.any(Function),
getAPIReady: expect.any(Function),
setCheckboxes: expect.any(Function),
setAllCheckboxes: expect.any(Function),
sendQueuedEvents: expect.any(Function),
Expand Down
2 changes: 2 additions & 0 deletions src/consent/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { get } from './get';
import { getAll } from './get-all';
import { getAllCheckboxes } from './get-all-checkboxes';
import { getAPIReady } from './get-api-ready';
import { getPurposes } from './get-purposes';
import { sendQueuedEvents } from './send-queued-events';
import { set } from './set';
Expand All @@ -14,6 +15,7 @@ export const consent = {
getAll,
setAll,
getPurposes,
getAPIReady,
getAllCheckboxes,
setCheckboxes,
setAllCheckboxes,
Expand Down
7 changes: 7 additions & 0 deletions src/consent/send-queued-event.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,15 @@ afterAll(() => {
});

describe('sendQueuedEvents()', () => {
it("should not break when Zaraz hasn't been initialised yet", () => {
const sendQueuedEventsMock = jest.fn();
sendQueuedEvents();
expect(sendQueuedEventsMock).toHaveBeenCalledTimes(0);
});

it('should call sendQueuedEvents method on zaraz consent', () => {
const sendQueuedEventsMock = jest.fn();

window.zaraz = {
consent: {
sendQueuedEvents: sendQueuedEventsMock,
Expand Down
2 changes: 1 addition & 1 deletion src/consent/send-queued-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import { getZaraz } from '../helpers/get-zaraz';
* If some Pageview-based events were not sent due to a lack of consent, they can be sent using this method after consent was granted.
*/
export function sendQueuedEvents(): void {
getZaraz().consent.sendQueuedEvents();
getZaraz({ skipQueue: true })?.consent?.sendQueuedEvents();
}
6 changes: 6 additions & 0 deletions src/consent/set-all.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,14 @@ afterAll(() => {
});

describe('setAll()', () => {
it("should not break when Zaraz hasn't been initialised yet", () => {
const result = setAll(true);
expect(result).toEqual(undefined);
});

it('should call setAll method on zaraz consent with the correct argument', () => {
const setAllMock = jest.fn();

window.zaraz = {
consent: {
setAll: setAllMock,
Expand Down
2 changes: 1 addition & 1 deletion src/consent/set-all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import { getZaraz } from '../helpers/get-zaraz';
* Set the consent status for all purposes at once.
*/
export function setAll(consentStatus: boolean): void {
getZaraz().consent.setAll(consentStatus);
getZaraz({ skipQueue: true })?.consent?.setAll(consentStatus);
}
6 changes: 6 additions & 0 deletions src/consent/set.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,14 @@ afterAll(() => {
});

describe('set()', () => {
it("should not break when Zaraz hasn't been initialised yet", () => {
const result = set({ key1: true, key2: false });
expect(result).toEqual(undefined);
});

it('should call set method on zaraz consent with the correct argument', () => {
const setMock = jest.fn();

window.zaraz = {
consent: {
set: setMock,
Expand Down
13 changes: 10 additions & 3 deletions src/consent/set.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { getZaraz } from '../helpers/get-zaraz';

export type ConsentPreferences = { [key: string]: boolean };

/**
* Set the consent status for some purposes using the purpose ID.
* Set the consent status for a specific purpose using the purpose ID.
*
* ```
* true: The consent was granted.
* false: The consent was not granted.
* ```
*/
export function set(consentPreferences: { [key: string]: boolean }): void {
getZaraz().consent.set(consentPreferences);
export function set(consentPreferences: ConsentPreferences): void {
getZaraz({ skipQueue: true })?.consent?.set(consentPreferences);
}
14 changes: 12 additions & 2 deletions src/helpers/get-zaraz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,27 @@ type QueueItem = {

let queue: QueueItem[] = [];

type getZarazOptions = {
skipQueue?: boolean;
};

/**
* A utility that checks if zaraz exists on the window object. If not it queues
* the events until zaraz is initialized. If zaraz is initialized, it flushes
* the queue.
*/
export function getZaraz() {
export function getZaraz(options?: getZarazOptions) {
const skipQueue = options?.skipQueue || false;

if (typeof window === 'undefined') {
throw new Error(`Cannot use Zaraz Web API, because window is not defined.`);
}

if (!window?.zaraz) {
if (!window?.zaraz && skipQueue) {
return undefined;
}

if (!window?.zaraz && !skipQueue) {
// eslint-disable-next-line no-console
console.log(`Zaraz Web API is not initialized. Queueing events...`);

Expand Down

0 comments on commit 8de4b54

Please sign in to comment.