From 6e757789984faa7fb17b6f97fa9f424c02cd1439 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Mon, 10 Aug 2026 11:10:10 +0200 Subject: [PATCH 1/2] test(cloudflare): Cover `enableDedupe` option Adds unit tests asserting the Dedupe integration is installed by default and omitted when `enableDedupe: false`, plus an integration test proving identical exceptions captured within a single workflow run are all delivered. The existing workflow retry tests did not cover this: Workflows replay `run` from the top on each retry, so every attempt gets a fresh client and fresh dedupe state. Only duplicates within one invocation can be collapsed, so the new fixture captures the same error twice from the same line. Co-Authored-By: Claude Opus 5 --- .../suites/workflows/step-context/index.ts | 12 +++++++- .../suites/workflows/step-context/test.ts | 30 +++++++++++++++++++ packages/cloudflare/test/sdk.test.ts | 22 ++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/dev-packages/cloudflare-integration-tests/suites/workflows/step-context/index.ts b/dev-packages/cloudflare-integration-tests/suites/workflows/step-context/index.ts index 34e23255cd8a..dea639692074 100644 --- a/dev-packages/cloudflare-integration-tests/suites/workflows/step-context/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/workflows/step-context/index.ts @@ -10,6 +10,7 @@ interface Env { interface WorkflowParams { failCount: number; captureManual?: boolean; + captureManualTwice?: boolean; } class StepContextTestWorkflowBase extends WorkflowEntrypoint { async run(event: WorkflowEvent, step: WorkflowStep): Promise { @@ -28,6 +29,14 @@ class StepContextTestWorkflowBase extends WorkflowEntrypoint 0) { remainingFailures--; throw new Error('Intentional failure for retry test'); @@ -59,10 +68,11 @@ export default Sentry.withSentry( if (url.pathname === '/trigger-workflow') { const failCount = parseInt(url.searchParams.get('failCount') || '0', 10); const captureManual = url.searchParams.get('captureManual') === 'true'; + const captureManualTwice = url.searchParams.get('captureManualTwice') === 'true'; try { const instance = await env.STEP_CONTEXT_WORKFLOW.create({ - params: { failCount, captureManual }, + params: { failCount, captureManual, captureManualTwice }, }); return new Response(JSON.stringify({ id: instance.id }), { headers: { 'Content-Type': 'application/json' } }); diff --git a/dev-packages/cloudflare-integration-tests/suites/workflows/step-context/test.ts b/dev-packages/cloudflare-integration-tests/suites/workflows/step-context/test.ts index 05c0c696a021..c71ad223140a 100644 --- a/dev-packages/cloudflare-integration-tests/suites/workflows/step-context/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/workflows/step-context/test.ts @@ -72,6 +72,36 @@ it('No error event when step eventually succeeds within retry limit', async ({ s await runner.completed(); }); +// Workflows opt out of the Dedupe integration via `enableDedupe: false`, so identical errors +// captured within one run are all delivered instead of being collapsed into a single event. +it('Identical exceptions captured within one run are all sent (Dedupe is disabled)', async ({ signal }) => { + const runner = createRunner(__dirname) + .expectN(2, (envelope: Envelope): void => { + const [, items] = envelope; + const [itemHeader, itemBody] = items[0] as [{ type: string }, Record]; + + expect(itemHeader.type).toBe('event'); + + const exception = itemBody.exception as { values?: Array<{ value?: string }> }; + expect(exception?.values?.[0]?.value).toBe('Manual capture'); + }) + .expect(flushMarkerMatcher) + .unordered() + .start(signal); + + const trigger = await runner.makeRequest( + 'get', + '/trigger-workflow?failCount=0&captureManualTwice=true', + ); + expect(trigger?.id).toBeDefined(); + + const status = await waitForWorkflowStatus(runner.makeRequest.bind(runner), trigger!.id); + expect(status?.status?.status).toBe('complete'); + + await runner.makeRequest('get', '/flush-marker'); + await runner.completed(); +}); + it('Manually captured exceptions are always sent on every attempt', async ({ signal }) => { const runner = createRunner(__dirname) .expectN(3, (envelope: Envelope): void => { diff --git a/packages/cloudflare/test/sdk.test.ts b/packages/cloudflare/test/sdk.test.ts index 23f057d4eee3..edac98354fc0 100644 --- a/packages/cloudflare/test/sdk.test.ts +++ b/packages/cloudflare/test/sdk.test.ts @@ -46,6 +46,28 @@ describe('init', () => { ); }); + test('installs Dedupe integration by default', () => { + init({ dsn: 'https://public@dsn.ingest.sentry.io/1337' }); + const client = getClient(); + + expect(client?.getOptions()).toEqual( + expect.objectContaining({ + integrations: expect.arrayContaining([expect.objectContaining({ name: 'Dedupe' })]), + }), + ); + }); + + test('does not install Dedupe integration when enableDedupe is false', () => { + init({ dsn: 'https://public@dsn.ingest.sentry.io/1337', enableDedupe: false }); + const client = getClient(); + + expect(client?.getOptions()).toEqual( + expect.objectContaining({ + integrations: expect.not.arrayContaining([expect.objectContaining({ name: 'Dedupe' })]), + }), + ); + }); + type MarkedIntegration = Integration & { _custom?: boolean }; test("doesn't add spanStreamingIntegration if user added it manually", () => { From 7a8ff473b8f8141d4b32a9bb3f5be0def4095a12 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Mon, 10 Aug 2026 11:22:29 +0200 Subject: [PATCH 2/2] fixup! test(cloudflare): Cover `enableDedupe` option --- .../suites/workflows/step-context/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dev-packages/cloudflare-integration-tests/suites/workflows/step-context/index.ts b/dev-packages/cloudflare-integration-tests/suites/workflows/step-context/index.ts index dea639692074..d82cea5ef733 100644 --- a/dev-packages/cloudflare-integration-tests/suites/workflows/step-context/index.ts +++ b/dev-packages/cloudflare-integration-tests/suites/workflows/step-context/index.ts @@ -32,9 +32,8 @@ class StepContextTestWorkflowBase extends WorkflowEntrypoint 0) {