Skip to content
Closed
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
6 changes: 3 additions & 3 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ on:
jobs:
build:

runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
Comment thread
hdervisevic marked this conversation as resolved.

steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '16'
- run: npm ci
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,35 @@ For example, if a shopper performed the following events, the visitor ID `abc` w
- Waits a while, but less than a year, during which time you upgrade to version 5.
- Visits the site again, clicks their cart (at which point version 5 replaces the visitor ID `bcd` with `abc`), and completes the purchase.

## Conversational Commerce origin (new)

To attribute analytics for Conversational Commerce correctly, the AutoSearch event now supports a new origin flag: `origin.conversation`.

Example:

```typescript
import GbTracker from 'gb-tracker-client';
import { AutoSearchEvent } from 'gb-tracker-client/models';

const tracker = new GbTracker('customer_id', 'area');
tracker.autoSetVisitor();

const event: AutoSearchEvent = {
search: {
id: 'response_12345',
origin: { conversation: true }
}
};

tracker.sendAutoSearchEvent(event);
```

Notes:
- You do not need to send a separate direct search when using AutoSearch for CC; set `origin.conversation=true` and include the CC response ID in `search.id`.
- Other origin flags (sayt, search, etc.) remain supported; only set the one that applies to the given event.

See also docs/event-types.md for more examples.

## More Usage Details

See the docs for more detailed information about implementing beacons:
Expand Down
5 changes: 3 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gb-tracker-client",
"version": "5.4.0",
"version": "5.5.0",
"description": "GroupBy client-side event tracker",
"main": "index.js",
"keywords": [
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace GbTracker {
autosearch?: boolean;
navigation?: boolean;
collectionSwitcher?: boolean;
conversation?: boolean;
}

export type SanitizeEventFn = (event: AnySendableEvent, schema?: any) => any;
Expand Down
1 change: 1 addition & 0 deletions src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ export interface SendableOrigin {
autosearch?: boolean;
navigation?: boolean;
collectionSwitcher?: boolean;
conversation?: boolean;
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/schemas/autoSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@ export default {
type: 'boolean',
optional: false,
def: false
},
conversation: {
type: 'boolean',
optional: false,
def: false
}
}
},
Expand Down
20 changes: 19 additions & 1 deletion test-integration/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,16 @@ async function startServersAndBrowser() {
closables.push(siteAppServer);


const ciArgs = process.env.CI ? [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu'
] : [];

const browser = await puppeteer.launch({
headless: true,
args: ciArgs,
Comment thread
hdervisevic marked this conversation as resolved.
env: {
TZ: 'UTC',
...process.env,
Expand All @@ -84,6 +92,9 @@ async function startServersAndBrowser() {
// Therefore, we manually set user agent version to something known.
await page.setUserAgent('headlesschrome');

// Make navigation timeout align with our mocha timeout
try { page.setDefaultNavigationTimeout(TIMEOUT_MS); } catch (e) { /* old puppeteer may not support */ }

return page;
}

Expand Down Expand Up @@ -123,6 +134,9 @@ async function visitSiteAndAssert(page, expectedReceivedBeacon) {
expect(receivedBeacon.visit.generated).to.not.be.undefined;
expect(receivedBeacon.visit.generated).to.be.a('object');

expect(receivedBeacon.visit.generated.timezoneOffset).to.not.be.undefined;
expect(receivedBeacon.visit.generated.timezoneOffset).to.be.a('number');
Comment thread
hdervisevic marked this conversation as resolved.

expect(receivedBeacon.visit.generated.localTime).to.not.be.undefined;
expect(receivedBeacon.visit.generated.localTime).to.be.a('string');
// invalid ISO8601 date strings result in an error when parsed with
Expand All @@ -132,6 +146,9 @@ async function visitSiteAndAssert(page, expectedReceivedBeacon) {
expect(d).to.be.a('Date');
expect(d.toString()).not.eql('Invalid Date');

expect(Number.isFinite(receivedBeacon.visit.generated.timezoneOffset)).to.be.true;
expectedReceivedBeacon.visit.generated.timezoneOffset = receivedBeacon.visit.generated.timezoneOffset;

// Delete nondeterministic properties and assert on rest of beacon.
delete receivedBeacon.clientVersion.raw;
delete receivedBeacon.visit.customerData.sessionId;
Expand Down Expand Up @@ -230,6 +247,7 @@ describe('gb-tracker-client, running in a web browser', () => {
recommendations: false,
sayt: false,
search: true,
conversation: false,
},
},
};
Expand Down Expand Up @@ -450,4 +468,4 @@ describe('gb-tracker-client, running in a web browser', () => {
await visitSiteAndAssert(page, expectedReceivedBeacon);
}).timeout(TIMEOUT_MS);

});
});
49 changes: 48 additions & 1 deletion test/events/autoSearch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ describe('autoSearch tests', () => {
autosearch: false,
navigation: false,
collectionSwitcher: false,
conversation: false,
},
});

Expand All @@ -74,6 +75,52 @@ describe('autoSearch tests', () => {
});
});

it('should propagate conversation origin flag', (done) => {
const expectedEvent = {
search: {
id: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
origin: {
conversation: true,
},
},
customer: {
id: 'testcustomer',
area: 'area',
},
};

const gbTrackerCore = new GbTrackerCore(expectedEvent.customer.id, expectedEvent.customer.area);

gbTrackerCore.__getInternals().sendEvent = (event: any) => {

expect(event.search).to.eql({
...expectedEvent.search,
origin: {
dym: false,
sayt: false,
search: false,
recommendations: false,
autosearch: false,
navigation: false,
collectionSwitcher: false,
conversation: true,
},
});

done();
};

gbTrackerCore.setVisitor('visitor', 'session');

gbTrackerCore.setInvalidEventCallback(() => {
done('fail');
});

gbTrackerCore.sendAutoSearchEvent({
search: expectedEvent.search,
});
});

it('should accept autoSearch event that has only search id', (done) => {
const gbTrackerCore = new GbTrackerCore('testcustomer', 'area');

Expand All @@ -97,4 +144,4 @@ describe('autoSearch tests', () => {
},
});
});
});
});