From 36802a4daf6fbddd95398a583768bff6210fbc58 Mon Sep 17 00:00:00 2001 From: xiaoweii Date: Thu, 11 Apr 2024 12:15:49 +0800 Subject: [PATCH 1/2] feat: add preset traffic source attributes --- README.md | 23 +++++++--- src/index.ts | 2 +- src/types/Analytics.ts | 24 ++++++++++ test/ClickstreamAnalytics.test.ts | 73 +++++++++++++++++++++++++++---- 4 files changed, 108 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 6b8d631..5440551 100644 --- a/README.md +++ b/README.md @@ -79,13 +79,23 @@ When opening for the first time after integrating the SDK, you need to manually #### Add global attribute 1. Add global attributes when initializing the SDK + The following example code shows how to add traffic source fields as global attributes when initializing the SDK. + ```typescript + import { ClickstreamAnalytics, Attr } from '@aws/clickstream-web'; + ClickstreamAnalytics.init({ appId: "your appId", endpoint: "https://example.com/collect", globalAttributes:{ - _traffic_source_medium: "Search engine", - _traffic_source_name: "Summer promotion", + [Attr.TRAFFIC_SOURCE_SOURCE]: 'amazon', + [Attr.TRAFFIC_SOURCE_MEDIUM]: 'cpc', + [Attr.TRAFFIC_SOURCE_CAMPAIGN]: 'summer_promotion', + [Attr.TRAFFIC_SOURCE_CAMPAIGN_ID]: 'summer_promotion_01', + [Attr.TRAFFIC_SOURCE_TERM]: 'running_shoes', + [Attr.TRAFFIC_SOURCE_CONTENT]: 'banner_ad_1', + [Attr.TRAFFIC_SOURCE_CLID]: 'amazon_ad_123', + [Attr.TRAFFIC_SOURCE_CLID_PLATFORM]: 'amazon_ads', } }); ``` @@ -93,8 +103,10 @@ When opening for the first time after integrating the SDK, you need to manually 2. Add global attributes after initializing the SDK ``` typescript + import { ClickstreamAnalytics, Attr } from '@aws/clickstream-web'; + ClickstreamAnalytics.setGlobalAttributes({ - _traffic_source_medium: "Search engine", + [Attr.TRAFFIC_SOURCE_MEDIUM]: "Search engine", level: 10, }); ``` @@ -108,7 +120,7 @@ You can add the following code to log an event with an item. **Note: Only pipelines from version 1.1+ can handle items with custom attribute.** ```typescript -import { ClickstreamAnalytics, Item } from '@aws/clickstream-web'; +import { ClickstreamAnalytics, Item, Attr } from '@aws/clickstream-web'; const itemBook: Item = { id: '123', @@ -120,7 +132,8 @@ const itemBook: Item = { ClickstreamAnalytics.record({ name: 'view_item', attributes: { - currency: 'USD', + [Attr.CURRENCY]: 'USD', + [Attr.VALUE]: 99, event_category: 'recommended', }, items: [itemBook], diff --git a/src/index.ts b/src/index.ts index a21136f..976eacb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,4 +12,4 @@ */ export { ClickstreamAnalytics } from './ClickstreamAnalytics'; -export { PageType, SendMode, Item } from './types'; +export { PageType, SendMode, Item, Attr } from './types'; diff --git a/src/types/Analytics.ts b/src/types/Analytics.ts index 876753e..58ffbc2 100644 --- a/src/types/Analytics.ts +++ b/src/types/Analytics.ts @@ -46,7 +46,31 @@ export enum PageType { multiPageApp = 'multiPageApp', } +export enum Attr { + TRAFFIC_SOURCE_SOURCE = '_traffic_source_source', + TRAFFIC_SOURCE_MEDIUM = '_traffic_source_medium', + TRAFFIC_SOURCE_CAMPAIGN = '_traffic_source_campaign', + TRAFFIC_SOURCE_CAMPAIGN_ID = '_traffic_source_campaign_id', + TRAFFIC_SOURCE_TERM = '_traffic_source_term', + TRAFFIC_SOURCE_CONTENT = '_traffic_source_content', + TRAFFIC_SOURCE_CLID = '_traffic_source_clid', + TRAFFIC_SOURCE_CLID_PLATFORM = '_traffic_source_clid_platform', + VALUE = '_value', + CURRENCY = '_currency', +} + export interface ClickstreamAttribute { + [Attr.TRAFFIC_SOURCE_SOURCE]?: string; + [Attr.TRAFFIC_SOURCE_MEDIUM]?: string; + [Attr.TRAFFIC_SOURCE_CAMPAIGN]?: string; + [Attr.TRAFFIC_SOURCE_CAMPAIGN_ID]?: string; + [Attr.TRAFFIC_SOURCE_TERM]?: string; + [Attr.TRAFFIC_SOURCE_CONTENT]?: string; + [Attr.TRAFFIC_SOURCE_CLID]?: string; + [Attr.TRAFFIC_SOURCE_CLID_PLATFORM]?: string; + [Attr.VALUE]?: number; + [Attr.CURRENCY]?: string; + [key: string]: string | number | boolean | null; } diff --git a/test/ClickstreamAnalytics.test.ts b/test/ClickstreamAnalytics.test.ts index 22685d5..b81d324 100644 --- a/test/ClickstreamAnalytics.test.ts +++ b/test/ClickstreamAnalytics.test.ts @@ -10,8 +10,8 @@ * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * and limitations under the License. */ -import { setUpBrowserPerformance } from "./browser/BrowserUtil"; -import { ClickstreamAnalytics, Item, SendMode } from '../src'; +import { setUpBrowserPerformance } from './browser/BrowserUtil'; +import { ClickstreamAnalytics, Item, SendMode, Attr } from '../src'; import { NetRequest } from '../src/network/NetRequest'; import { Event } from '../src/provider'; import { StorageUtil } from '../src/util/StorageUtil'; @@ -66,17 +66,72 @@ describe('ClickstreamAnalytics test', () => { ); const firstEvent = eventList[0]; expect(firstEvent.event_type).toBe(Event.PresetEvent.FIRST_OPEN); - expect(firstEvent.user[Event.ReservedAttribute.USER_FIRST_TOUCH_TIMESTAMP]).not.toBeUndefined() + expect( + firstEvent.user[Event.ReservedAttribute.USER_FIRST_TOUCH_TIMESTAMP] + ).not.toBeUndefined(); expect(firstEvent.attributes.brand).toBe('Samsung'); expect(firstEvent.attributes.level).toBe(10); - expect(firstEvent.attributes[Event.ReservedAttribute.SESSION_ID]).not.toBeUndefined(); - expect(firstEvent.attributes[Event.ReservedAttribute.SESSION_NUMBER]).not.toBeUndefined(); - expect(firstEvent.attributes[Event.ReservedAttribute.SESSION_START_TIMESTAMP]).not.toBeUndefined(); - expect(firstEvent.attributes[Event.ReservedAttribute.SESSION_DURATION]).not.toBeUndefined(); + expect( + firstEvent.attributes[Event.ReservedAttribute.SESSION_ID] + ).not.toBeUndefined(); + expect( + firstEvent.attributes[Event.ReservedAttribute.SESSION_NUMBER] + ).not.toBeUndefined(); + expect( + firstEvent.attributes[Event.ReservedAttribute.SESSION_START_TIMESTAMP] + ).not.toBeUndefined(); + expect( + firstEvent.attributes[Event.ReservedAttribute.SESSION_DURATION] + ).not.toBeUndefined(); const testEvent = eventList[eventList.length - 1]; expect(testEvent.attributes.brand).toBeUndefined(); }); + test('test init sdk with traffic source global attributes', async () => { + const result = ClickstreamAnalytics.init({ + appId: 'testApp', + endpoint: 'https://example.com/collect', + sendMode: SendMode.Batch, + globalAttributes: { + [Attr.TRAFFIC_SOURCE_SOURCE]: 'amazon', + [Attr.TRAFFIC_SOURCE_MEDIUM]: 'cpc', + [Attr.TRAFFIC_SOURCE_CAMPAIGN]: 'summer_promotion', + [Attr.TRAFFIC_SOURCE_CAMPAIGN_ID]: 'summer_promotion_01', + [Attr.TRAFFIC_SOURCE_TERM]: 'running_shoes', + [Attr.TRAFFIC_SOURCE_CONTENT]: 'banner_ad_1', + [Attr.TRAFFIC_SOURCE_CLID]: 'amazon_ad_123', + [Attr.TRAFFIC_SOURCE_CLID_PLATFORM]: 'amazon_ads', + }, + }); + expect(result).toBeTruthy(); + await sleep(100); + const eventList = JSON.parse( + StorageUtil.getAllEvents() + Event.Constants.SUFFIX + ); + const firstEvent = eventList[0]; + expect(firstEvent.event_type).toBe(Event.PresetEvent.FIRST_OPEN); + expect(firstEvent.attributes[Attr.TRAFFIC_SOURCE_SOURCE]).toBe('amazon'); + expect(firstEvent.attributes[Attr.TRAFFIC_SOURCE_MEDIUM]).toBe('cpc'); + expect(firstEvent.attributes[Attr.TRAFFIC_SOURCE_CAMPAIGN]).toBe( + 'summer_promotion' + ); + expect(firstEvent.attributes[Attr.TRAFFIC_SOURCE_CAMPAIGN_ID]).toBe( + 'summer_promotion_01' + ); + expect(firstEvent.attributes[Attr.TRAFFIC_SOURCE_TERM]).toBe( + 'running_shoes' + ); + expect(firstEvent.attributes[Attr.TRAFFIC_SOURCE_CONTENT]).toBe( + 'banner_ad_1' + ); + expect(firstEvent.attributes[Attr.TRAFFIC_SOURCE_CLID]).toBe( + 'amazon_ad_123' + ); + expect(firstEvent.attributes[Attr.TRAFFIC_SOURCE_CLID_PLATFORM]).toBe( + 'amazon_ads' + ); + }); + test('test record event with name success', async () => { const sendRequestMock = jest.spyOn(NetRequest, 'sendRequest'); ClickstreamAnalytics.init({ @@ -111,7 +166,7 @@ describe('ClickstreamAnalytics test', () => { name: 'Nature', category: 'book', price: 56.5, - customKey: "customValue", + customKey: 'customValue', }; ClickstreamAnalytics.record({ name: 'testEvent', @@ -120,6 +175,8 @@ describe('ClickstreamAnalytics test', () => { longValue: 4232032890992380000, isNew: true, score: 85.22, + [Attr.VALUE]: 56.5, + [Attr.CURRENCY]: 'USD', }, items: [item], }); From 4255416fe9cfaf448af2de756df6f4aec18a0723 Mon Sep 17 00:00:00 2001 From: xiaoweii Date: Thu, 11 Apr 2024 12:22:51 +0800 Subject: [PATCH 2/2] ci: add token for codecov --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2ce4618..822b813 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,8 @@ jobs: npm i npm run test - name: Upload Test Report - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: + token: ${{ secrets.CODECOV_TOKEN }} name: report files: coverage/coverage-final.json