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

EventsSDK: Add debug mode #130

Merged
merged 8 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
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
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ pagesAnalytics.report({

### Debugging

#### Debug Mode

The SDK has a debug mode which can be activated by setting the `debug` property in your AnalyticsConfig to `true`.
This will prevent `report()` from sending a real request to the Yext Events API. Instead it will print the EventPayload and AnalyticsConfig to console.

#### fetch + keepalive

We use `fetch()` + `keepalive` by default in [supported browsers](https://developer.mozilla.org/en-US/docs/Web/API/fetch) to make debugging easier. For browsers like Firefox that do not support `keepalive`, [we use the Beacon API](https://developer.mozilla.org/en-US/docs/Web/API/Beacon_API). Users can set `forceFetch: true` in their config, which will make these browsers use `fetch()` instead of the `Beacon API`. Be warned, since `forceFetch` uses `fetch()` without `keepalive`, **requests in progress for browsers like FireFox will be canceled if the page is unloaded**.

## Module support
Expand Down
13 changes: 13 additions & 0 deletions docs/analytics.analyticsconfig.debug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/analytics](./analytics.md) &gt; [AnalyticsConfig](./analytics.analyticsconfig.md) &gt; [debug](./analytics.analyticsconfig.debug.md)

## AnalyticsConfig.debug property

Used to enable debug mode, which is false by default. When enabled the SDK will not send requests to the Events API, but will log the request with other useful debug information instead.

**Signature:**

```typescript
debug?: boolean;
```
1 change: 1 addition & 0 deletions docs/analytics.analyticsconfig.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface AnalyticsConfig
| --- | --- | --- | --- |
| [authorization](./analytics.analyticsconfig.authorization.md) | | string | The API Key, OAuth, or bearer token for accessing the Analytics Events API. |
| [authorizationType](./analytics.analyticsconfig.authorizationtype.md) | | 'apiKey' \| 'bearer' | Used for specifying if an API Key or Bearer Token is used for the authorization property. |
| [debug?](./analytics.analyticsconfig.debug.md) | | boolean | _(Optional)_ Used to enable debug mode, which is false by default. When enabled the SDK will not send requests to the Events API, but will log the request with other useful debug information instead. |
| [env?](./analytics.analyticsconfig.env.md) | | [Environment](./analytics.environment.md) | _(Optional)_ The Yext environment to send requests to. Defaults to 'PRODUCTION'. |
| [forceFetch?](./analytics.analyticsconfig.forcefetch.md) | | boolean | _(Optional)_ Used to force sending the request with fetch even if the browser does not support fetch with the keepalive flag (like Firefox). If the browser does support it, fetch is used by default. |
| [region?](./analytics.analyticsconfig.region.md) | | [Region](./analytics.region.md) | _(Optional)_ The region to send requests to. Defaults to 'US'. |
Expand Down
1 change: 1 addition & 0 deletions etc/analytics.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function analytics(config: AnalyticsConfig): AnalyticsEventService;
export interface AnalyticsConfig {
authorization: string;
authorizationType: 'apiKey' | 'bearer';
debug?: boolean;
ejaffee01 marked this conversation as resolved.
Show resolved Hide resolved
env?: Environment;
forceFetch?: boolean;
region?: Region;
Expand Down
7 changes: 7 additions & 0 deletions src/AnalyticsConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,11 @@ export interface AnalyticsConfig {
* does not support fetch with the keepalive flag (like Firefox).
* If the browser does support it, fetch is used by default. */
forceFetch?: boolean;

/**
* Used to enable debug mode, which is false by default.
* When enabled the SDK will not send requests to the Events API, but will log the request
* with other useful debug information instead.
*/
debug?: boolean;
}
5 changes: 3 additions & 2 deletions src/AnalyticsEventReporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export class AnalyticsEventReporter implements AnalyticsEventService {
with(payload: EventPayload): AnalyticsEventService {
const currentPayload =
this.payload === undefined ? payload : merge(this.payload, payload);

return new AnalyticsEventReporter(this.config, currentPayload);
}

Expand Down Expand Up @@ -69,7 +70,7 @@ export class AnalyticsEventReporter implements AnalyticsEventService {
// If useBeacon returns true, return boolean response of postWithBeacon as string.
if (shouldUseBeacon) {
return new Promise((resolve, reject) => {
ejaffee01 marked this conversation as resolved.
Show resolved Hide resolved
if (postWithBeacon(requestUrl, finalPayload)) {
if (postWithBeacon(requestUrl, finalPayload, this.config)) {
resolve('');
} else {
reject('Failed Beacon Call');
Expand All @@ -80,7 +81,7 @@ export class AnalyticsEventReporter implements AnalyticsEventService {
/** If useBeacon returns false, use postWithFetch.
If result is successful, return result json.
If request fails, return errors. */
return postWithFetch(requestUrl, finalPayload)
return postWithFetch(requestUrl, finalPayload, this.config)
.then((response) => response)
.catch((e) => e);
}
Expand Down
52 changes: 42 additions & 10 deletions src/post.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AnalyticsConfig } from './AnalyticsConfig';
import { EventPayload } from './EventPayload';

/**
Expand All @@ -8,11 +9,20 @@ import { EventPayload } from './EventPayload';
* @param url URL that the request will be sent to
* @param body the EventPayload object
*/
export function postWithBeacon(url: string, body: EventPayload): boolean {
return navigator.sendBeacon(url, JSON.stringify(body));
export function postWithBeacon(
url: string,
body: EventPayload,
config: AnalyticsConfig
): boolean {
if (config.debug) {
printDebugLog(true, body, config);
return true;
} else {
return navigator.sendBeacon(url, JSON.stringify(body));
}
}

/**
/*
* Used by the AnalyticsEventReport report() method to send an analytics event request via
* fetch. Used when forceFetch is true.
*
Expand All @@ -21,14 +31,20 @@ export function postWithBeacon(url: string, body: EventPayload): boolean {
*/
export function postWithFetch(
url: string,
body: EventPayload
body: EventPayload,
config: AnalyticsConfig
): Promise<Response> {
return fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
keepalive: true
});
if (config.debug) {
printDebugLog(false, body, config);
return Promise.resolve(new Response());
} else {
return fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
keepalive: true
});
}
}

/**
Expand All @@ -49,3 +65,19 @@ export function useBeacon(
navigator.userAgent.toLowerCase().includes('firefox')
);
}

function printDebugLog(
usingBeacon: boolean,
finalPayload: EventPayload,
config: AnalyticsConfig
): void {
const method = usingBeacon ? 'Beacon' : 'fetch()';
console.log(
'[DEBUG] AnalyticsConfig object at time of call to report():',
config
);
console.log(
`[DEBUG] The following EventPayload would be sent to the Yext Events API using ${method}:`,
finalPayload
);
}
36 changes: 24 additions & 12 deletions tests/AnalyticsEventReporter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ describe('Test report function', () => {
referrerUrl: 'https://yext.com',
destinationUrl: 'https://google.com',
count: 5
}
},
config
);
});

Expand Down Expand Up @@ -165,7 +166,8 @@ describe('Test report function', () => {
},
destinationUrl: 'https://google.com',
count: 5
}
},
config
);
}
);
Expand Down Expand Up @@ -222,7 +224,8 @@ describe('Test report function', () => {
referrerUrl: 'https://yext.com',
count: 5,
sessionId: 'ULID1234'
}
},
config
);
});
it('should call post with correct fields, and use the original sessionId', async () => {
Expand Down Expand Up @@ -278,7 +281,8 @@ describe('Test report function', () => {
referrerUrl: 'https://yext.com',
count: 5,
sessionId: 'ULIDORIGINAL'
}
},
config
);
});

Expand Down Expand Up @@ -331,7 +335,8 @@ describe('Test report function', () => {
referrerUrl: 'https://yext.com',
count: 5,
sessionId: undefined
}
},
config
);
});

Expand Down Expand Up @@ -377,7 +382,8 @@ describe('Test report function', () => {
},
referrerUrl: 'https://yext.com',
count: 5
}
},
config
);
});

Expand Down Expand Up @@ -424,7 +430,8 @@ describe('Test report function', () => {
},
referrerUrl: 'https://yext.com',
count: 5
}
},
config
);
});

Expand Down Expand Up @@ -464,7 +471,8 @@ describe('Test report function', () => {
clientSdk: {
ANALYTICS: '1.0.0-beta.4'
}
}
},
config
);
});
it('call report with no argument and no with() result in Failed Beacon Call for beacon', async () => {
Expand Down Expand Up @@ -502,7 +510,8 @@ describe('Test report function', () => {
clientSdk: {
ANALYTICS: '1.0.0-beta.4'
}
}
},
config
);
});

Expand Down Expand Up @@ -546,7 +555,8 @@ describe('Test report function', () => {
},
referrerUrl: 'https://yext.com',
count: 5
}
},
config
);

const reporter2 = reporter1.with({
Expand Down Expand Up @@ -578,7 +588,8 @@ describe('Test report function', () => {
destinationUrl: 'https://google.com',
referrerUrl: 'https://yext.com',
count: 5
}
},
config
);
});

Expand Down Expand Up @@ -746,7 +757,8 @@ describe('Test report function', () => {
visitor: {
'visitor-id': 'visitor-id'
}
}
},
config
);
});
});
13 changes: 9 additions & 4 deletions tests/post.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ describe('Test post util function', () => {
locale: 'en_US'
};

const standardConfig: AnalyticsConfig = {
authorizationType: 'apiKey',
authorization: 'test-api-key'
};

const url = 'https://dev.us.yextevents.com/accounts/me/events';

const optionsA = {
Expand Down Expand Up @@ -65,7 +70,7 @@ describe('Test post util function', () => {

it('should send fetch request', async () => {
// forceFetch: true
await postWithFetch(url, eventPayloadA);
await postWithFetch(url, eventPayloadA, standardConfig);
expect(
fetchMock.calls('https://dev.us.yextevents.com/accounts/me/events').length
).toEqual(1);
Expand All @@ -84,7 +89,7 @@ describe('Test post util function', () => {
value: navigator,
writable: true
});
await postWithFetch(url, eventPayloadA);
await postWithFetch(url, eventPayloadA, standardConfig);
expect(
fetchMock.calls('https://dev.us.yextevents.com/accounts/me/events').length
).toEqual(2);
Expand All @@ -93,7 +98,7 @@ describe('Test post util function', () => {
).toEqual(optionsA);

// forceFetch: true, browser is not Firefox
await postWithFetch(url, eventPayloadA);
await postWithFetch(url, eventPayloadA, standardConfig);
expect(
fetchMock.calls('https://dev.us.yextevents.com/accounts/me/events').length
).toEqual(3);
Expand All @@ -106,7 +111,7 @@ describe('Test post util function', () => {

it('should send beacon request', async () => {
// forceFetch: false and browser defined in navigator is Firefox
const result = await postWithBeacon(url, eventPayloadA);
const result = await postWithBeacon(url, eventPayloadA, standardConfig);
expect(
fetchMock.calls('https://dev.us.yextevents.com/accounts/me/events').length
).toEqual(0);
Expand Down
Loading