diff --git a/nodejs/src/cdp/services/messaging/email-tracking.service.test.ts b/nodejs/src/cdp/services/messaging/email-tracking.service.test.ts index c76983c6f5964..d95f16aacb956 100644 --- a/nodejs/src/cdp/services/messaging/email-tracking.service.test.ts +++ b/nodejs/src/cdp/services/messaging/email-tracking.service.test.ts @@ -1,6 +1,6 @@ import { createMockJobQueue } from '~/tests/helpers/mocks/job-queue.mock' import { mockProducerObserver } from '~/tests/helpers/mocks/producer.mock' -import { mockFetch } from '~/tests/helpers/mocks/request.mock' +import { mockFetch, mockInternalFetch } from '~/tests/helpers/mocks/request.mock' import { Server } from 'http' import supertest from 'supertest' @@ -10,6 +10,7 @@ import { FixtureHogFlowBuilder } from '~/cdp/_tests/builders/hogflow.builder' import { insertHogFunction } from '~/cdp/_tests/fixtures' import { insertHogFlow } from '~/cdp/_tests/fixtures-hogflows' import { CdpApi } from '~/cdp/cdp-api' +import { TeamWorkflowsConfigService } from '~/cdp/services/managers/team-workflows-config.service' import { CyclotronJobInvocationHogFunction, HogFunctionType } from '~/cdp/types' import { setupExpressApp } from '~/common/api/router' import { defaultConfig } from '~/common/config/config' @@ -17,6 +18,7 @@ import { KAFKA_APP_METRICS_2, KAFKA_LOG_ENTRIES } from '~/common/config/kafka-to import { closeHub, createHub } from '~/common/utils/db/hub' import { PostgresUse } from '~/common/utils/db/postgres' import * as envUtils from '~/common/utils/env-utils' +import { parseJSON } from '~/common/utils/json-parse' import { createCdpConsumerDeps } from '~/tests/helpers/cdp' import { waitForExpect } from '~/tests/helpers/expectations' import { createTestTeamFixture } from '~/tests/helpers/sql' @@ -44,6 +46,7 @@ describe('EmailTrackingService', () => { team = (await createTestTeamFixture(hub.postgres)).team mockFetch.mockClear() + mockInternalFetch.mockClear() mockProducerObserver.resetKafkaProducer() }) @@ -364,6 +367,38 @@ describe('EmailTrackingService', () => { } ) + it('should capture the click on the recipient with the run id of the send', async () => { + const captureSpy = jest + .spyOn(TeamWorkflowsConfigService.prototype, 'shouldCaptureEngagementEvents') + .mockResolvedValue(true) + try { + const link = new URL( + signer.redirectUrl( + { functionId: hogFunction.id, id: invocationId, teamId: team.id, distinctId: 'recipient' }, + 'https://example.com/' + ) + ) + + const res = await supertest(app).get(`${link.pathname}${link.search}`) + expect(res.status).toBe(302) + + await waitForExpect(() => { + const captured = mockInternalFetch.mock.calls.map(([, options]) => + parseJSON(options!.body as string) + ) + expect(captured).toEqual([ + expect.objectContaining({ + event: '$workflows_email_link_clicked', + distinct_id: 'recipient', + properties: expect.objectContaining({ $workflow_run_id: invocationId }), + }), + ]) + }) + } finally { + captureSpy.mockRestore() + } + }) + it('should return 404 for an unsigned link after the unsigned link sunset', async () => { setClock(UNSIGNED_REDIRECT_SUNSET) const res = await supertest(app).get('/public/m/redirect?target=https://other.example/') diff --git a/nodejs/src/cdp/services/messaging/email-tracking.service.ts b/nodejs/src/cdp/services/messaging/email-tracking.service.ts index 645866c708851..e46500c5f7aa9 100644 --- a/nodejs/src/cdp/services/messaging/email-tracking.service.ts +++ b/nodejs/src/cdp/services/messaging/email-tracking.service.ts @@ -395,6 +395,7 @@ export class EmailTrackingService { properties: { $workflow_id: appSourceId, $workflow_action_id: actionId, + $workflow_run_id: invocationId, ...(workflowVersion !== undefined ? { $workflow_version: workflowVersion } : {}), ...properties, }, diff --git a/nodejs/src/cdp/services/messaging/email.service.test.ts b/nodejs/src/cdp/services/messaging/email.service.test.ts index 7c3cd05338a00..37800dd23c537 100644 --- a/nodejs/src/cdp/services/messaging/email.service.test.ts +++ b/nodejs/src/cdp/services/messaging/email.service.test.ts @@ -1838,6 +1838,7 @@ describe('EmailService', () => { properties: { $workflow_id: invocation.functionId, $workflow_action_id: invocation.state.actionId, + $workflow_run_id: invocation.id, $email_to: 'test@example.com', $email_tracking_enabled: true, }, diff --git a/nodejs/src/cdp/services/messaging/email.service.ts b/nodejs/src/cdp/services/messaging/email.service.ts index ff83d8746de41..e902c7b076eb3 100644 --- a/nodejs/src/cdp/services/messaging/email.service.ts +++ b/nodejs/src/cdp/services/messaging/email.service.ts @@ -737,6 +737,7 @@ export class EmailService { properties: { $workflow_id: invocation.functionId, $workflow_action_id: invocation.state.actionId, + $workflow_run_id: invocation.id, $email_to: params.to.email, // A sensitive template's subject can carry a login code, so its events leave it out. ...(invocation.hogFunction?.metadata?.sensitive === true ? {} : { $email_subject: params.subject }),