diff --git a/README.md b/README.md index 332f69c..7aee5b1 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ See [schema.json](schema.json) for a JSON Schema of the output. | Pendo | ✅ | ❌ | ❌ | ❌ | | Heap | ✅ | ❌ | ❌ | ❌ | | Snowplow | ✅ | ✅ | ✅ | ✅ | +| Datadog RUM | ✅ | ❌ | ❌ | ❌ | | Custom Function | ✅ | ✅ | ✅ | ✅ | ✳️ Rudderstack's SDKs often use the same format as Segment, so Rudderstack events may be detected as Segment events. @@ -375,6 +376,27 @@ See [schema.json](schema.json) for a JSON Schema of the output. +
+ Datadog RUM + + **JavaScript/TypeScript** + ```js + datadogRum.addAction('', { + '': '' + }); + + // Or via window + window.DD_RUM.addAction('', { + '': '' + }); + + // Or via global DD_RUM + DD_RUM.addAction('', { + '': '' + }); + ``` +
+
Snowplow (Structured Events) diff --git a/schema.json b/schema.json index 5dc5504..11067a4 100644 --- a/schema.json +++ b/schema.json @@ -67,6 +67,7 @@ "pendo", "heap", "snowplow", + "datadog", "custom", "unknown" ], diff --git a/src/analyze/javascript/constants.js b/src/analyze/javascript/constants.js index b04f95a..102673b 100644 --- a/src/analyze/javascript/constants.js +++ b/src/analyze/javascript/constants.js @@ -75,6 +75,12 @@ const ANALYTICS_PROVIDERS = { name: 'googleanalytics', functionName: 'gtag', type: 'function' + }, + DATADOG_RUM: { + name: 'datadog', + objectNames: ['datadogRum', 'DD_RUM'], + methodName: 'addAction', + type: 'member' } }; diff --git a/src/analyze/javascript/detectors/analytics-source.js b/src/analyze/javascript/detectors/analytics-source.js index 26ef558..66bf85d 100644 --- a/src/analyze/javascript/detectors/analytics-source.js +++ b/src/analyze/javascript/detectors/analytics-source.js @@ -131,8 +131,17 @@ function detectMemberBasedProvider(node) { return 'unknown'; } - const objectName = node.callee.object.name; const methodName = node.callee.property.name; + let objectName = node.callee.object.name; + + // Handle nested member expressions like window.DD_RUM.addAction + if (!objectName && node.callee.object.type === NODE_TYPES.MEMBER_EXPRESSION) { + // For window.DD_RUM.addAction, we want to check if it matches DD_RUM.addAction pattern + const nestedObjectName = node.callee.object.property.name; + if (nestedObjectName) { + objectName = nestedObjectName; + } + } if (!objectName || !methodName) { return 'unknown'; diff --git a/src/analyze/typescript/constants.js b/src/analyze/typescript/constants.js index 66a0706..52d7fa9 100644 --- a/src/analyze/typescript/constants.js +++ b/src/analyze/typescript/constants.js @@ -75,6 +75,12 @@ const ANALYTICS_PROVIDERS = { name: 'googleanalytics', functionName: 'gtag', type: 'function' + }, + DATADOG_RUM: { + name: 'datadog', + objectNames: ['datadogRum', 'DD_RUM'], + methodName: 'addAction', + type: 'member' } }; diff --git a/src/analyze/typescript/detectors/analytics-source.js b/src/analyze/typescript/detectors/analytics-source.js index 1624421..064da8e 100644 --- a/src/analyze/typescript/detectors/analytics-source.js +++ b/src/analyze/typescript/detectors/analytics-source.js @@ -87,8 +87,17 @@ function detectMemberBasedProvider(node) { return 'unknown'; } - const objectName = node.expression.expression?.escapedText; const methodName = node.expression.name?.escapedText; + let objectName = node.expression.expression?.escapedText; + + // Handle nested member expressions like window.DD_RUM.addAction + if (!objectName && ts.isPropertyAccessExpression(node.expression.expression)) { + // For window.DD_RUM.addAction, we want to check if it matches DD_RUM.addAction pattern + const nestedObjectName = node.expression.expression.name?.escapedText; + if (nestedObjectName) { + objectName = nestedObjectName; + } + } if (!objectName || !methodName) { return 'unknown'; diff --git a/tests/analyzeJavaScript.test.js b/tests/analyzeJavaScript.test.js index 7da03af..2b266b1 100644 --- a/tests/analyzeJavaScript.test.js +++ b/tests/analyzeJavaScript.test.js @@ -16,7 +16,7 @@ test.describe('analyzeJsFile', () => { // Sort events by line number for consistent ordering events.sort((a, b) => a.line - b.line); - assert.strictEqual(events.length, 12); + assert.strictEqual(events.length, 15); // Test Google Analytics event const gaEvent = events.find(e => e.eventName === 'purchase' && e.source === 'googleanalytics'); @@ -176,7 +176,7 @@ test.describe('analyzeJsFile', () => { assert.ok(snowplowEvent); assert.strictEqual(snowplowEvent.source, 'snowplow'); assert.strictEqual(snowplowEvent.functionName, 'trackSnowplow'); - assert.strictEqual(snowplowEvent.line, 138); + assert.strictEqual(snowplowEvent.line, 157); assert.deepStrictEqual(snowplowEvent.properties, { category: { type: 'string' }, label: { type: 'string' }, @@ -189,7 +189,7 @@ test.describe('analyzeJsFile', () => { assert.ok(customEvent); assert.strictEqual(customEvent.source, 'custom'); assert.strictEqual(customEvent.functionName, 'global'); - assert.strictEqual(customEvent.line, 152); + assert.strictEqual(customEvent.line, 171); assert.deepStrictEqual(customEvent.properties, { userId: { type: 'string' }, order_id: { type: 'string' }, @@ -232,7 +232,7 @@ test.describe('analyzeJsFile', () => { const events = analyzeJsFile(testFilePath, null); // Should find all events except the custom one - assert.strictEqual(events.length, 11); + assert.strictEqual(events.length, 14); assert.strictEqual(events.find(e => e.source === 'custom'), undefined); }); diff --git a/tests/analyzeTypeScript.test.js b/tests/analyzeTypeScript.test.js index 8d6d968..693a4a2 100644 --- a/tests/analyzeTypeScript.test.js +++ b/tests/analyzeTypeScript.test.js @@ -37,14 +37,14 @@ test.describe('analyzeTsFile', () => { // Sort events by line number for consistent ordering events.sort((a, b) => a.line - b.line); - assert.strictEqual(events.length, 20); + assert.strictEqual(events.length, 23); // Test Google Analytics event const gaEvent = events.find(e => e.eventName === 'order_completed' && e.source === 'googleanalytics'); assert.ok(gaEvent); assert.strictEqual(gaEvent.source, 'googleanalytics'); assert.strictEqual(gaEvent.functionName, 'trackOrderCompletedGA'); - assert.strictEqual(gaEvent.line, 105); + assert.strictEqual(gaEvent.line, 119); assert.deepStrictEqual(gaEvent.properties, { order_id: { type: 'string' }, products: { @@ -76,7 +76,7 @@ test.describe('analyzeTsFile', () => { assert.ok(segmentEvent); assert.strictEqual(segmentEvent.source, 'segment'); assert.strictEqual(segmentEvent.functionName, 'checkout'); - assert.strictEqual(segmentEvent.line, 121); + assert.strictEqual(segmentEvent.line, 135); assert.deepStrictEqual(segmentEvent.properties, { stage: { type: 'string' }, method: { type: 'string' }, @@ -88,7 +88,7 @@ test.describe('analyzeTsFile', () => { assert.ok(mixpanelEvent); assert.strictEqual(mixpanelEvent.source, 'mixpanel'); assert.strictEqual(mixpanelEvent.functionName, 'confirmPurchaseMixpanel'); - assert.strictEqual(mixpanelEvent.line, 130); + assert.strictEqual(mixpanelEvent.line, 144); assert.deepStrictEqual(mixpanelEvent.properties, { order_id: { type: 'string' }, items: { @@ -111,7 +111,7 @@ test.describe('analyzeTsFile', () => { assert.ok(amplitudeEvent); assert.strictEqual(amplitudeEvent.source, 'amplitude'); assert.strictEqual(amplitudeEvent.functionName, 'checkout'); - assert.strictEqual(amplitudeEvent.line, 135); + assert.strictEqual(amplitudeEvent.line, 149); assert.deepStrictEqual(amplitudeEvent.properties, { order_id: { type: 'string' }, items: { @@ -143,7 +143,7 @@ test.describe('analyzeTsFile', () => { assert.ok(rudderstackEvent); assert.strictEqual(rudderstackEvent.source, 'rudderstack'); assert.strictEqual(rudderstackEvent.functionName, 'checkout'); - assert.strictEqual(rudderstackEvent.line, 150); + assert.strictEqual(rudderstackEvent.line, 164); assert.deepStrictEqual(rudderstackEvent.properties, { order_id: { type: 'string' }, items: { @@ -174,7 +174,7 @@ test.describe('analyzeTsFile', () => { assert.ok(mparticleEvent); assert.strictEqual(mparticleEvent.source, 'mparticle'); assert.strictEqual(mparticleEvent.functionName, 'checkout2'); - assert.strictEqual(mparticleEvent.line, 176); + assert.strictEqual(mparticleEvent.line, 190); assert.deepStrictEqual(mparticleEvent.properties, { order_id: { type: 'string' }, items: { @@ -205,7 +205,7 @@ test.describe('analyzeTsFile', () => { assert.ok(posthogEvent); assert.strictEqual(posthogEvent.source, 'posthog'); assert.strictEqual(posthogEvent.functionName, 'checkout2'); - assert.strictEqual(posthogEvent.line, 195); + assert.strictEqual(posthogEvent.line, 209); assert.deepStrictEqual(posthogEvent.properties, { order_id: { type: 'string' }, retry: { type: 'number' }, @@ -237,7 +237,7 @@ test.describe('analyzeTsFile', () => { assert.ok(pendoEvent); assert.strictEqual(pendoEvent.source, 'pendo'); assert.strictEqual(pendoEvent.functionName, 'checkout3'); - assert.strictEqual(pendoEvent.line, 216); + assert.strictEqual(pendoEvent.line, 230); assert.deepStrictEqual(pendoEvent.properties, { order_id: { type: 'string' }, products: { @@ -268,7 +268,7 @@ test.describe('analyzeTsFile', () => { assert.ok(heapEvent); assert.strictEqual(heapEvent.source, 'heap'); assert.strictEqual(heapEvent.functionName, 'checkout3'); - assert.strictEqual(heapEvent.line, 230); + assert.strictEqual(heapEvent.line, 244); assert.deepStrictEqual(heapEvent.properties, { user_id: { type: 'string' }, email: { type: 'string' }, @@ -284,7 +284,7 @@ test.describe('analyzeTsFile', () => { assert.ok(snowplowEvent1); assert.strictEqual(snowplowEvent1.source, 'snowplow'); assert.strictEqual(snowplowEvent1.functionName, 'trackSnowplow'); - assert.strictEqual(snowplowEvent1.line, 247); + assert.strictEqual(snowplowEvent1.line, 282); assert.deepStrictEqual(snowplowEvent1.properties, { category: { type: 'string' }, label: { type: 'string' }, @@ -296,14 +296,14 @@ test.describe('analyzeTsFile', () => { assert.ok(snowplowEvent2); assert.strictEqual(snowplowEvent2.source, 'snowplow'); assert.strictEqual(snowplowEvent2.functionName, 'trackSnowplow2'); - assert.strictEqual(snowplowEvent2.line, 251); + assert.strictEqual(snowplowEvent2.line, 286); // Test custom function event const customEvent = events.find(e => e.eventName === 'custom_event_v2'); assert.ok(customEvent); assert.strictEqual(customEvent.source, 'custom'); assert.strictEqual(customEvent.functionName, 'global'); - assert.strictEqual(customEvent.line, 280); + assert.strictEqual(customEvent.line, 315); assert.deepStrictEqual(customEvent.properties, { userId: { type: 'string' }, order_id: { type: 'string' }, @@ -326,7 +326,7 @@ test.describe('analyzeTsFile', () => { assert.ok(constantEvent); assert.strictEqual(constantEvent.source, 'custom'); assert.strictEqual(constantEvent.functionName, 'global'); - assert.strictEqual(constantEvent.line, 291); + assert.strictEqual(constantEvent.line, 326); assert.deepStrictEqual(constantEvent.properties, { userId: { type: 'string' }, orderId: { type: 'string' }, @@ -342,7 +342,7 @@ test.describe('analyzeTsFile', () => { assert.ok(importedConstantEvent); assert.strictEqual(importedConstantEvent.source, 'segment'); assert.strictEqual(importedConstantEvent.functionName, 'global'); - assert.strictEqual(importedConstantEvent.line, 293); + assert.strictEqual(importedConstantEvent.line, 328); assert.deepStrictEqual(importedConstantEvent.properties, { orderId: { type: 'string' }, total: { type: 'number' }, @@ -357,7 +357,7 @@ test.describe('analyzeTsFile', () => { assert.ok(frozenConstantEvent); assert.strictEqual(frozenConstantEvent.source, 'mixpanel'); assert.strictEqual(frozenConstantEvent.functionName, 'global'); - assert.strictEqual(frozenConstantEvent.line, 292); + assert.strictEqual(frozenConstantEvent.line, 327); assert.deepStrictEqual(frozenConstantEvent.properties, { orderId: { type: 'string' }, total: { type: 'number' }, @@ -405,7 +405,7 @@ test.describe('analyzeTsFile', () => { const events = analyzeTsFile(testFilePath, program, null); // Should find all events except the custom ones - assert.strictEqual(events.length, 13); + assert.strictEqual(events.length, 16); assert.strictEqual(events.find(e => e.source === 'custom'), undefined); }); diff --git a/tests/fixtures/javascript/main.js b/tests/fixtures/javascript/main.js index 8f0ba3c..6a4b06a 100644 --- a/tests/fixtures/javascript/main.js +++ b/tests/fixtures/javascript/main.js @@ -126,6 +126,25 @@ export const checkout3 = function() { email: 'user123@example.com', name: 'John Doe' }); + + // datadog tracking examples - all three patterns + datadogRum.addAction('checkout', { + total: 500, + order_id: 'ABC123', + currency: 'USD' + }); + + window.DD_RUM.addAction('user_login', { + user_id: 'user123', + method: 'email', + success: true + }); + + DD_RUM.addAction('page_view', { + page: '/checkout', + section: 'payment', + user_type: 'premium' + }); } class MyClass { diff --git a/tests/fixtures/javascript/tracking-schema-javascript.yaml b/tests/fixtures/javascript/tracking-schema-javascript.yaml index 5f79c77..c050f0f 100644 --- a/tests/fixtures/javascript/tracking-schema-javascript.yaml +++ b/tests/fixtures/javascript/tracking-schema-javascript.yaml @@ -55,13 +55,17 @@ events: line: 44 function: checkout destination: amplitude + - path: main.js + line: 131 + function: checkout3 + destination: datadog properties: order_id: - type: any + type: string products: type: any total: - type: any + type: number address: type: object properties: @@ -69,6 +73,8 @@ events: type: string state: type: string + currency: + type: string Order Completed: implementations: - path: main.js @@ -169,7 +175,7 @@ events: someevent: implementations: - path: main.js - line: 138 + line: 157 function: trackSnowplow destination: snowplow properties: @@ -184,7 +190,7 @@ events: customEvent: implementations: - path: main.js - line: 152 + line: 171 function: global destination: custom properties: @@ -201,7 +207,7 @@ events: custom_event0: implementations: - path: main.js - line: 162 + line: 181 function: global destination: custom properties: @@ -210,7 +216,7 @@ events: custom_event1: implementations: - path: main.js - line: 163 + line: 182 function: global destination: custom properties: @@ -219,7 +225,7 @@ events: custom_event2: implementations: - path: main.js - line: 164 + line: 183 function: global destination: custom properties: @@ -230,7 +236,7 @@ events: custom_event3: implementations: - path: main.js - line: 165 + line: 184 function: global destination: custom properties: @@ -241,7 +247,7 @@ events: custom_event4: implementations: - path: main.js - line: 166 + line: 185 function: global destination: custom properties: @@ -259,7 +265,7 @@ events: custom_module_event: implementations: - path: main.js - line: 178 + line: 197 function: global destination: custom properties: @@ -269,10 +275,23 @@ events: type: string userId: type: string + page_view: + implementations: + - path: main.js + line: 143 + function: checkout3 + destination: datadog + properties: + page: + type: string + section: + type: string + user_type: + type: string ecommerce_purchase_frozen: implementations: - path: main.js - line: 190 + line: 209 function: global destination: mixpanel properties: @@ -284,3 +303,16 @@ events: type: array items: type: string + user_login: + implementations: + - path: main.js + line: 137 + function: checkout3 + destination: datadog + properties: + user_id: + type: string + method: + type: string + success: + type: boolean diff --git a/tests/fixtures/tracking-schema-all.yaml b/tests/fixtures/tracking-schema-all.yaml index 9be81fc..b156ec1 100644 --- a/tests/fixtures/tracking-schema-all.yaml +++ b/tests/fixtures/tracking-schema-all.yaml @@ -168,7 +168,7 @@ events: function: main destination: custom - path: javascript/main.js - line: 162 + line: 181 function: global destination: custom - path: python/main.py @@ -180,7 +180,7 @@ events: function: global destination: custom - path: typescript/main.ts - line: 306 + line: 341 function: global destination: custom properties: @@ -193,7 +193,7 @@ events: function: main destination: custom - path: javascript/main.js - line: 163 + line: 182 function: global destination: custom - path: python/main.py @@ -205,7 +205,7 @@ events: function: global destination: custom - path: typescript/main.ts - line: 307 + line: 342 function: global destination: custom properties: @@ -218,7 +218,7 @@ events: function: main destination: custom - path: javascript/main.js - line: 164 + line: 183 function: global destination: custom - path: python/main.py @@ -230,7 +230,7 @@ events: function: global destination: custom - path: typescript/main.ts - line: 308 + line: 343 function: global destination: custom properties: @@ -245,7 +245,7 @@ events: function: main destination: custom - path: javascript/main.js - line: 165 + line: 184 function: global destination: custom - path: python/main.py @@ -257,7 +257,7 @@ events: function: global destination: custom - path: typescript/main.ts - line: 309 + line: 344 function: global destination: custom properties: @@ -272,7 +272,7 @@ events: function: main destination: custom - path: javascript/main.js - line: 166 + line: 185 function: global destination: custom - path: python/main.py @@ -284,7 +284,7 @@ events: function: global destination: custom - path: typescript/main.ts - line: 310 + line: 345 function: global destination: custom properties: @@ -349,13 +349,17 @@ events: line: 44 function: checkout destination: amplitude + - path: javascript/main.js + line: 131 + function: checkout3 + destination: datadog properties: order_id: - type: any + type: string products: type: any total: - type: any + type: number address: type: object properties: @@ -363,6 +367,8 @@ events: type: string state: type: string + currency: + type: string Order Completed: implementations: - path: javascript/main.js @@ -463,7 +469,7 @@ events: someevent: implementations: - path: javascript/main.js - line: 138 + line: 157 function: trackSnowplow destination: snowplow properties: @@ -478,7 +484,7 @@ events: customEvent: implementations: - path: javascript/main.js - line: 152 + line: 171 function: global destination: custom properties: @@ -495,7 +501,7 @@ events: custom_module_event: implementations: - path: javascript/main.js - line: 178 + line: 197 function: global destination: custom - path: python/main.py @@ -503,7 +509,7 @@ events: function: main destination: custom - path: typescript/main.ts - line: 322 + line: 357 function: global destination: custom properties: @@ -513,14 +519,27 @@ events: type: string userId: type: string + page_view: + implementations: + - path: javascript/main.js + line: 143 + function: checkout3 + destination: datadog + properties: + page: + type: string + section: + type: string + user_type: + type: string ecommerce_purchase_frozen: implementations: - path: javascript/main.js - line: 190 + line: 209 function: global destination: mixpanel - path: typescript/main.ts - line: 292 + line: 327 function: global destination: mixpanel properties: @@ -532,6 +551,31 @@ events: type: array items: type: string + user_login: + implementations: + - path: javascript/main.js + line: 137 + function: checkout3 + destination: datadog + - path: typescript/main.ts + line: 244 + function: checkout3 + destination: heap + properties: + user_id: + type: string + method: + type: string + success: + type: boolean + email: + type: string + name: + type: string + roles: + type: array + items: + type: string User Signed Up: implementations: - path: python/main.py @@ -640,7 +684,7 @@ events: order_completed: implementations: - path: typescript/main.ts - line: 105 + line: 119 function: trackOrderCompletedGA destination: googleanalytics properties: @@ -675,7 +719,7 @@ events: user_checkout: implementations: - path: typescript/main.ts - line: 121 + line: 135 function: checkout destination: segment properties: @@ -688,7 +732,7 @@ events: purchase_confirmed: implementations: - path: typescript/main.ts - line: 130 + line: 144 function: confirmPurchaseMixpanel destination: mixpanel properties: @@ -712,7 +756,7 @@ events: checkout_initiated: implementations: - path: typescript/main.ts - line: 135 + line: 149 function: checkout destination: amplitude properties: @@ -747,7 +791,7 @@ events: order_finalized: implementations: - path: typescript/main.ts - line: 150 + line: 164 function: checkout destination: rudderstack properties: @@ -780,7 +824,7 @@ events: BuyNow: implementations: - path: typescript/main.ts - line: 176 + line: 190 function: checkout2 destination: mparticle properties: @@ -813,7 +857,7 @@ events: user_action: implementations: - path: typescript/main.ts - line: 195 + line: 209 function: checkout2 destination: posthog properties: @@ -848,7 +892,7 @@ events: customer_checkout: implementations: - path: typescript/main.ts - line: 216 + line: 230 function: checkout3 destination: pendo properties: @@ -878,27 +922,10 @@ events: type: string postalCode: type: string - user_login: - implementations: - - path: typescript/main.ts - line: 230 - function: checkout3 - destination: heap - properties: - user_id: - type: string - email: - type: string - name: - type: string - roles: - type: array - items: - type: string item_view: implementations: - path: typescript/main.ts - line: 247 + line: 282 function: trackSnowplow destination: snowplow properties: @@ -913,7 +940,7 @@ events: button_click: implementations: - path: typescript/main.ts - line: 251 + line: 286 function: trackSnowplow2 destination: snowplow properties: @@ -928,7 +955,7 @@ events: custom_event_v2: implementations: - path: typescript/main.ts - line: 280 + line: 315 function: global destination: custom properties: @@ -952,7 +979,7 @@ events: ecommerce_purchase: implementations: - path: typescript/main.ts - line: 291 + line: 326 function: global destination: custom properties: @@ -969,7 +996,7 @@ events: ecommerce_purchase_v2: implementations: - path: typescript/main.ts - line: 293 + line: 328 function: global destination: segment properties: @@ -1118,11 +1145,11 @@ events: FailedPayment: implementations: - path: typescript/main.ts - line: 361 + line: 396 function: global destination: custom - path: typescript/main.ts - line: 417 + line: 452 function: trackFailedPayment destination: custom properties: @@ -1133,11 +1160,11 @@ events: InitiatedPayment: implementations: - path: typescript/main.ts - line: 349 + line: 384 function: global destination: custom - path: typescript/main.ts - line: 422 + line: 457 function: trackInitiatedPayment destination: custom properties: @@ -1148,7 +1175,7 @@ events: ViewedAttorneyAgreement: implementations: - path: typescript/main.ts - line: 375 + line: 410 function: handleView destination: custom properties: {} @@ -1161,6 +1188,49 @@ events: properties: foo: type: string + checkout_completed: + implementations: + - path: typescript/main.ts + line: 247 + function: checkout3 + destination: datadog + properties: + total: + type: number + orderId: + type: string + currency: + type: string + items: + type: number + user_registration: + implementations: + - path: typescript/main.ts + line: 254 + function: checkout3 + destination: datadog + properties: + user_id: + type: string + method: + type: string + success: + type: boolean + referrer: + type: string + error_occurred: + implementations: + - path: typescript/main.ts + line: 261 + function: checkout3 + destination: datadog + properties: + error_type: + type: string + field: + type: string + page: + type: string UnlessEvent: implementations: - path: ruby/node_types.rb diff --git a/tests/fixtures/typescript/main.ts b/tests/fixtures/typescript/main.ts index b3e9e6b..506e599 100644 --- a/tests/fixtures/typescript/main.ts +++ b/tests/fixtures/typescript/main.ts @@ -49,6 +49,20 @@ declare const heap: { track(eventName: string, properties: Record): void; }; +declare const datadogRum: { + addAction(eventName: string, properties: Record): void; +}; + +declare const DD_RUM: { + addAction(eventName: string, properties: Record): void; +}; + +declare const window: { + DD_RUM: { + addAction(eventName: string, properties: Record): void; + }; +}; + declare const tracker: { track(event: unknown): void; }; @@ -228,6 +242,27 @@ export function checkout3(): void { roles: ['admin', 'editor'], }; heap.track('user_login', heapData); + + // Datadog tracking examples - all three patterns + datadogRum.addAction('checkout_completed', { + total: 500, + orderId: 'ABC123', + currency: 'USD', + items: itemsList.length + }); + + window.DD_RUM.addAction('user_registration', { + user_id: 'user123', + method: 'email', + success: true, + referrer: 'organic' + }); + + DD_RUM.addAction('error_occurred', { + error_type: 'validation', + field: 'email', + page: '/checkout' + }); } // ----------------------------------------------------------------------------- diff --git a/tests/fixtures/typescript/tracking-schema-typescript.yaml b/tests/fixtures/typescript/tracking-schema-typescript.yaml index 2857a52..f18f826 100644 --- a/tests/fixtures/typescript/tracking-schema-typescript.yaml +++ b/tests/fixtures/typescript/tracking-schema-typescript.yaml @@ -8,7 +8,7 @@ events: order_completed: implementations: - path: main.ts - line: 105 + line: 119 function: trackOrderCompletedGA destination: googleanalytics properties: @@ -43,7 +43,7 @@ events: user_checkout: implementations: - path: main.ts - line: 121 + line: 135 function: checkout destination: segment properties: @@ -56,7 +56,7 @@ events: purchase_confirmed: implementations: - path: main.ts - line: 130 + line: 144 function: confirmPurchaseMixpanel destination: mixpanel properties: @@ -80,7 +80,7 @@ events: checkout_initiated: implementations: - path: main.ts - line: 135 + line: 149 function: checkout destination: amplitude properties: @@ -115,7 +115,7 @@ events: order_finalized: implementations: - path: main.ts - line: 150 + line: 164 function: checkout destination: rudderstack properties: @@ -148,7 +148,7 @@ events: BuyNow: implementations: - path: main.ts - line: 176 + line: 190 function: checkout2 destination: mparticle properties: @@ -181,7 +181,7 @@ events: user_action: implementations: - path: main.ts - line: 195 + line: 209 function: checkout2 destination: posthog properties: @@ -216,7 +216,7 @@ events: customer_checkout: implementations: - path: main.ts - line: 216 + line: 230 function: checkout3 destination: pendo properties: @@ -249,7 +249,7 @@ events: user_login: implementations: - path: main.ts - line: 230 + line: 244 function: checkout3 destination: heap properties: @@ -266,7 +266,7 @@ events: item_view: implementations: - path: main.ts - line: 247 + line: 282 function: trackSnowplow destination: snowplow properties: @@ -281,7 +281,7 @@ events: button_click: implementations: - path: main.ts - line: 251 + line: 286 function: trackSnowplow2 destination: snowplow properties: @@ -296,7 +296,7 @@ events: custom_event_v2: implementations: - path: main.ts - line: 280 + line: 315 function: global destination: custom properties: @@ -320,7 +320,7 @@ events: ecommerce_purchase: implementations: - path: main.ts - line: 291 + line: 326 function: global destination: custom properties: @@ -337,7 +337,7 @@ events: ecommerce_purchase_frozen: implementations: - path: main.ts - line: 292 + line: 327 function: global destination: mixpanel properties: @@ -352,7 +352,7 @@ events: ecommerce_purchase_v2: implementations: - path: main.ts - line: 293 + line: 328 function: global destination: segment properties: @@ -367,7 +367,7 @@ events: custom_event0: implementations: - path: main.ts - line: 306 + line: 341 function: global destination: custom properties: @@ -376,7 +376,7 @@ events: custom_event1: implementations: - path: main.ts - line: 307 + line: 342 function: global destination: custom properties: @@ -385,7 +385,7 @@ events: custom_event2: implementations: - path: main.ts - line: 308 + line: 343 function: global destination: custom properties: @@ -396,7 +396,7 @@ events: custom_event3: implementations: - path: main.ts - line: 309 + line: 344 function: global destination: custom properties: @@ -407,7 +407,7 @@ events: custom_event4: implementations: - path: main.ts - line: 310 + line: 345 function: global destination: custom properties: @@ -425,7 +425,7 @@ events: custom_module_event: implementations: - path: main.ts - line: 322 + line: 357 function: global destination: custom properties: @@ -438,11 +438,11 @@ events: FailedPayment: implementations: - path: main.ts - line: 361 + line: 396 function: global destination: custom - path: main.ts - line: 417 + line: 452 function: trackFailedPayment destination: custom properties: @@ -453,11 +453,11 @@ events: InitiatedPayment: implementations: - path: main.ts - line: 349 + line: 384 function: global destination: custom - path: main.ts - line: 422 + line: 457 function: trackInitiatedPayment destination: custom properties: @@ -468,7 +468,50 @@ events: ViewedAttorneyAgreement: implementations: - path: main.ts - line: 375 + line: 410 function: handleView destination: custom properties: {} + checkout_completed: + implementations: + - path: main.ts + line: 247 + function: checkout3 + destination: datadog + properties: + total: + type: number + orderId: + type: string + currency: + type: string + items: + type: number + user_registration: + implementations: + - path: main.ts + line: 254 + function: checkout3 + destination: datadog + properties: + user_id: + type: string + method: + type: string + success: + type: boolean + referrer: + type: string + error_occurred: + implementations: + - path: main.ts + line: 261 + function: checkout3 + destination: datadog + properties: + error_type: + type: string + field: + type: string + page: + type: string diff --git a/tests/schema.test.js b/tests/schema.test.js index 678c426..5d988df 100644 --- a/tests/schema.test.js +++ b/tests/schema.test.js @@ -178,7 +178,7 @@ test.describe('Schema Validation Tests', () => { const validDestinations = [ 'googleanalytics', 'segment', 'mixpanel', 'amplitude', 'rudderstack', 'mparticle', 'posthog', 'pendo', - 'heap', 'snowplow', 'custom', 'unknown' + 'heap', 'snowplow', 'datadog', 'custom', 'unknown', ]; // Check that all destinations are valid