From c42af08e96c4e26378042f5e4203d17952bb61d3 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 16 Oct 2026 13:19:55 +0200 Subject: [PATCH] test(nestjs): Fix flaky schedule instrumentation error tests The @Cron and @Interval handlers throw the same error on every tick, so the Dedupe integration drops all but the first one unless another error is sent in between. Once the other erroring cron jobs are killed, that first error can predate the test's listener and it times out. Allow `waitForError` to look back like `waitForStreamedSpan` and use it here. Co-Authored-By: Claude Opus 5.5 --- .../tests/schedule-instrumentation.test.ts | 39 ++++++++++++------- .../test-utils/src/event-proxy-server.ts | 9 ++++- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/schedule-instrumentation.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/schedule-instrumentation.test.ts index aa8a90c66cd5..0717b5074b59 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/schedule-instrumentation.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/schedule-instrumentation.test.ts @@ -2,13 +2,19 @@ import { expect, test } from '@playwright/test'; import { waitForError, waitForStreamedSpan } from '@sentry-internal/test-utils'; test('Sends exceptions to Sentry on error in @Cron decorated method', async ({ baseURL }) => { - const errorEventPromise = waitForError('nestjs-basic', event => { - return ( - !event.type && - event.exception?.values?.[0]?.value === 'Test error from schedule cron' && - event.exception?.values?.[0]?.mechanism?.type === 'auto.function.nestjs.cron' - ); - }); + // The job throws the same error on every tick, so the Dedupe integration drops all but the first + // one unless another error is sent in between. That first error may predate this test. + const errorEventPromise = waitForError( + 'nestjs-basic', + event => { + return ( + !event.type && + event.exception?.values?.[0]?.value === 'Test error from schedule cron' && + event.exception?.values?.[0]?.mechanism?.type === 'auto.function.nestjs.cron' + ); + }, + 0, + ); const errorEvent = await errorEventPromise; @@ -23,13 +29,18 @@ test('Sends exceptions to Sentry on error in @Cron decorated method', async ({ b }); test('Sends exceptions to Sentry on error in @Interval decorated method', async ({ baseURL }) => { - const errorEventPromise = waitForError('nestjs-basic', event => { - return ( - !event.type && - event.exception?.values?.[0]?.value === 'Test error from schedule interval' && - event.exception?.values?.[0]?.mechanism?.type === 'auto.function.nestjs.interval' - ); - }); + // See the @Cron test above for why this looks back to app startup. + const errorEventPromise = waitForError( + 'nestjs-basic', + event => { + return ( + !event.type && + event.exception?.values?.[0]?.value === 'Test error from schedule interval' && + event.exception?.values?.[0]?.mechanism?.type === 'auto.function.nestjs.interval' + ); + }, + 0, + ); const errorEvent = await errorEventPromise; diff --git a/dev-packages/test-utils/src/event-proxy-server.ts b/dev-packages/test-utils/src/event-proxy-server.ts index 627b3995ba05..d5130dc2fe53 100644 --- a/dev-packages/test-utils/src/event-proxy-server.ts +++ b/dev-packages/test-utils/src/event-proxy-server.ts @@ -334,12 +334,17 @@ export function waitForEnvelopeItem( }); } -/** Wait for an error to be sent. */ +/** + * Wait for an error to be sent. + * + * Pass `timestamp` to look further back than the moment of the call, e.g. `0` for an error the app + * emits on its own, before any test can start listening. + */ export function waitForError( proxyServerName: string, callback: (errorEvent: Event) => Promise | boolean, + timestamp: number = getNanosecondTimestamp(), ): Promise { - const timestamp = getNanosecondTimestamp(); return new Promise((resolve, reject) => { waitForEnvelopeItem( proxyServerName,