Skip to content
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

feat(add-consent): Add zaraz consent for cookies #11

Merged
merged 10 commits into from
Apr 10, 2024
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ A type-safe wrapper around the Cloudflare Zaraz Web API.

- Basic types for `zaraz.track()`;
- Basic types for `zaraz.set()`;
- Basic types for `zaraz.consent()`;
- Extensive types for `zaraz.ecommerce()`;
- Cheks for `zaraz` being available in the window.

Expand All @@ -17,22 +18,22 @@ Import zaraz and call the desired method. That's it!
import { zaraz } from 'zaraz-ts';

// Track custom events on your website, that might happen in real time.
await zaraz.track("button clicked", { userId: "ABC-123", value: 200 })
await zaraz.track('button clicked', { userId: 'ABC-123', value: 200 });
```

```ts
import { zaraz } from 'zaraz-ts';

// Make a variable available in all your events without manually setting it
// Make a variable available in all your events without manually setting it
// every time you are using zaraz.track().
zaraz.set('user_id', '123456');
```

```ts
import { zaraz } from 'zaraz-ts';

// Track common events of the e-commerce user journey, such as when a user adds
// a product to cart, starts the checkout funnel or completes an order.
// Track common events of the e-commerce user journey, such as when a user adds
// a product to cart, starts the checkout funnel or completes an order.
await zaraz.ecommerce('Order Completed', {
checkout_id: '616727740',
order_id: '817286897056801',
Expand Down Expand Up @@ -72,7 +73,6 @@ Checkout the official Cloudflare docs for more details: https://developers.cloud
This package is maintained and actively used by [Expatfile.tax][expatfile-site].
The #1 US expat tax e-filing software. 🇺🇸


[build-url]: https://img.shields.io/github/checks-status/expatfile/zaraz-ts/main
[cov-img]: https://codecov.io/gh/expatfile/zaraz-ts/branch/main/graph/badge.svg?token=mbGgsweFuP
[cov-url]: https://codecov.io/gh/expatfile/zaraz-ts
Expand Down
33 changes: 33 additions & 0 deletions src/consent/get-all-checkboxes.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { getAllCheckboxes } from './get-all-checkboxes';

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('getAllCheckboxes()', () => {
it('should return all checkboxes from zaraz consent', () => {
const checkboxesMock = { key1: true, key2: false };
window.zaraz = {
consent: {
getAllCheckboxes: jest.fn().mockReturnValue(checkboxesMock),
},
};

const checkboxes = getAllCheckboxes();

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

/**
* Returns an object with the checkbox status of all purposes.
*/
export function getAllCheckboxes(): { [key: string]: boolean } {
return getZaraz().consent.getAllCheckboxes();
}
33 changes: 33 additions & 0 deletions src/consent/get-all.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { getAll } from './get-all';

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('getAll()', () => {
it('should return all consents from zaraz consent', () => {
const consentsMock = { key1: true, key2: false };
window.zaraz = {
consent: {
getAll: jest.fn().mockReturnValue(consentsMock),
},
};

const consents = getAll();

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

/**
* Returns an object with the consent status of all purposes.
*/
export function getAll(): { [key: string]: boolean } {
return getZaraz().consent.getAll();
}
36 changes: 36 additions & 0 deletions src/consent/get-purposes.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { getPurposes } from './get-purposes';

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('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 },
};
window.zaraz = {
consent: {
purposes: purposesMock,
},
};

const purposes = getPurposes();

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

type Purpose = {
name: string;
description: string;
order: number;
};

/**
* An object containing all configured purposes, with their ID, name, description, and order.
*/
export function getPurposes(): { [key: string]: Purpose } {
return getZaraz().consent.purposes;
}
34 changes: 34 additions & 0 deletions src/consent/get.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { get } from './get';

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('get()', () => {
it('should return the consent status for a purpose from zaraz consent', () => {
const getMock = jest.fn().mockReturnValue(true);
window.zaraz = {
consent: {
get: getMock,
},
};

const consentStatus = get('key');

expect(consentStatus).toBe(true);
expect(getMock).toHaveBeenCalledWith('key');
});
});
14 changes: 14 additions & 0 deletions src/consent/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { getZaraz } from '../helpers/get-zaraz';

/**
* Get the current consent status for a purpose using the purpose ID.
*
* ```
* true: The consent was granted.
* false: The consent was not granted.
* undefined: The purpose does not exist.
* ```
*/
export function get(purposeId: string): boolean | undefined {
return getZaraz().consent.get(purposeId);
}
17 changes: 17 additions & 0 deletions src/consent/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as consentModule from './index';

describe('consent', () => {
it('should have the expected methods', () => {
expect(consentModule.consent).toEqual({
get: expect.any(Function),
set: expect.any(Function),
getAll: expect.any(Function),
setAll: expect.any(Function),
getAllCheckboxes: expect.any(Function),
getPurposes: expect.any(Function),
setCheckboxes: expect.any(Function),
setAllCheckboxes: expect.any(Function),
sendQueuedEvents: expect.any(Function),
});
});
});
21 changes: 21 additions & 0 deletions src/consent/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { get } from './get';
import { getAll } from './get-all';
import { getAllCheckboxes } from './get-all-checkboxes';
import { getPurposes } from './get-purposes';
import { sendQueuedEvents } from './send-queued-events';
import { set } from './set';
import { setAll } from './set-all';
import { setAllCheckboxes } from './set-all-checkboxes';
import { setCheckboxes } from './set-checkboxes';

export const consent = {
get,
set,
getAll,
setAll,
getPurposes,
getAllCheckboxes,
setCheckboxes,
setAllCheckboxes,
sendQueuedEvents,
};
33 changes: 33 additions & 0 deletions src/consent/send-queued-event.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { sendQueuedEvents } from './send-queued-events';

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('sendQueuedEvents()', () => {
it('should call sendQueuedEvents method on zaraz consent', () => {
const sendQueuedEventsMock = jest.fn();
window.zaraz = {
consent: {
sendQueuedEvents: sendQueuedEventsMock,
},
};

sendQueuedEvents();

expect(sendQueuedEventsMock).toHaveBeenCalled();
});
});
8 changes: 8 additions & 0 deletions src/consent/send-queued-events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
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();
}
33 changes: 33 additions & 0 deletions src/consent/set-all-checkboxes.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { setAllCheckboxes } from './set-all-checkboxes';

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('setAllCheckboxes()', () => {
it('should call setAllCheckboxes method on zaraz consent with the correct argument', () => {
const setAllCheckboxesMock = jest.fn();
window.zaraz = {
consent: {
setAllCheckboxes: setAllCheckboxesMock,
},
};

setAllCheckboxes(true);

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

/**
* Set the checkboxStatus status for all purposes in the consent modal at once.
*/
export function setAllCheckboxes(checkboxStatus: boolean): void {
getZaraz().consent.setAllCheckboxes(checkboxStatus);
}
33 changes: 33 additions & 0 deletions src/consent/set-all.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { setAll } from './set-all';

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('setAll()', () => {
it('should call setAll method on zaraz consent with the correct argument', () => {
const setAllMock = jest.fn();
window.zaraz = {
consent: {
setAll: setAllMock,
},
};

setAll(true);

expect(setAllMock).toHaveBeenCalledWith(true);
});
});
8 changes: 8 additions & 0 deletions src/consent/set-all.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
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);
}
Loading
Loading