Skip to content

test(e2e): Add a Mistral E2E app covering both instrumentation paths - #24378

Merged
RulaKhaled merged 1 commit into
developfrom
test/mistral-e2e-app
Sep 15, 2026
Merged

RulaKhaled merged 1 commit into
developfrom
test/mistral-e2e-app

Conversation

@RulaKhaled

@RulaKhaled RulaKhaled commented Sep 14, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #24243. Adds an E2E test app for the Mistral integration.

The suite runs twice against the same Express app, selected by TEST_ENV. development serves unbundled ESM through the runtime --import hook; production serves an esbuild bundle transformed by sentryEsbuildPlugin. Every assertion runs against both paths, which matters most for a provider that ships ESM-only.

What it covers:

  • gen_ai spans for streaming and non-streaming calls, with request, response and usage attributes.
  • The tee() and pipeThrough drain paths, each asserting one span and only one.
  • A failed call reaching Sentry as an error, with the span marked errored and on the same trace.
  • A manual span under the request span, and the gen_ai span directly under the manual one.
  • dataloader spans in the same trace as gen_ai spans.

@RulaKhaled
RulaKhaled added this pull request to stack #24379 September 14, 2026 18:53
@github-actions

github-actions Bot commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

size-limit report 📦

⚠️ Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

Path Size % Change Change
@sentry/browser 28.96 kB - -
@sentry/browser - with treeshaking flags 27.26 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 27.15 kB - -
@sentry/browser (incl. Tracing) 50.51 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 50.52 kB - -
@sentry/browser (incl. Tracing, Profiling) 53.5 kB - -
@sentry/browser (incl. Tracing, Replay) 90.07 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 79.16 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 94.77 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 107.73 kB - -
@sentry/browser (incl. Feedback) 46.46 kB - -
@sentry/browser (incl. sendFeedback) 34.01 kB - -
@sentry/browser (incl. FeedbackAsync) 39.12 kB - -
@sentry/browser (incl. Metrics) 29.98 kB - -
@sentry/browser (incl. Logs) 30.24 kB - -
@sentry/browser (incl. Metrics & Logs) 30.91 kB - -
@sentry/react 30.72 kB - -
@sentry/react (incl. Tracing) 52.81 kB - -
@sentry/vue 36.2 kB - -
@sentry/vue (incl. Tracing) 52.76 kB - -
@sentry/svelte 28.98 kB - -
CDN Bundle 30.7 kB - -
CDN Bundle (incl. Tracing) 51.01 kB - -
CDN Bundle (incl. Logs, Metrics) 32.98 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 52.99 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 73.67 kB - -
CDN Bundle (incl. Tracing, Replay) 88.56 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 90.53 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 94.64 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 96.63 kB - -
CDN Bundle - uncompressed 90.83 kB - -
CDN Bundle (incl. Tracing) - uncompressed 152.33 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 97.41 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 158.29 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 226.82 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 271.9 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 277.85 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 285.6 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 291.54 kB - -
@sentry/nextjs (client) 55.13 kB - -
@sentry/sveltekit (client) 50.93 kB - -
@sentry/core/server 37.13 kB - -
@sentry/core/browser 13.66 kB - -
@sentry/node 132.21 kB +1.21% +1.57 kB 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 82.03 kB +0.18% +145 B 🔺
@sentry/node - without tracing 89.83 kB +0.19% +163 B 🔺
@sentry/node - without channel injection 111.08 kB +1.41% +1.53 kB 🔺
@sentry/aws-serverless 98.08 kB +0.19% +177 B 🔺
@sentry/cloudflare (withSentry) - minified 203.54 kB +0.09% +179 B 🔺
@sentry/cloudflare (withSentry) 506.83 kB +0.08% +389 B 🔺

View base workflow run

@mydea mydea left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is great!

@RulaKhaled
RulaKhaled marked this pull request as ready for review September 15, 2026 09:01

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

const chatSpan = spans.find(isChatSpan);

expect(chatSpan).toBeDefined();
expectCommonChatAttributes(chatSpan!);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pipe path skips uniqueness check

Low Severity

The pipeThrough case picks the first gen_ai.chat span with find and never checks that only one was emitted. Duplicate spans on this drain path would still satisfy the later attribute and nesting checks, so the suite would not catch a double-instrumentation regression.

Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot

Reviewed by Cursor Bugbot for commit 2fc5bc8. Configure here.

debug: !!process.env.DEBUG,
tunnel: 'http://localhost:3031/',
tracesSampleRate: 1,
traceLifecycle: 'stream',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l:

Suggested change
traceLifecycle: 'stream',

tracesSampleRate: 1,
traceLifecycle: 'stream',
enableRuntimeChannelInjection: isDev,
integrations: [Sentry.spanStreamingIntegration()],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: I think this can be removed too? This should be used only in browsers AFAIK

Suggested change
integrations: [Sentry.spanStreamingIntegration()],

Base automatically changed from nh/mistral-integration to develop September 15, 2026 11:10
@JPeer264
JPeer264 requested review from a team as code owners September 15, 2026 11:10
@JPeer264
JPeer264 requested review from andreiborza, chargome, isaacs and s1gr1d and removed request for a team September 15, 2026 11:10
Follows `node-eve` and `node-mastra`: the Mistral SDK talks to a real endpoint
through `E2E_OPENROUTER_API_KEY` rather than a mock, and the app is marked
`sentryTest.optional` so it lands on the job where that secret is set.

The suite runs twice the way `node-mastra` splits dev and prod, so both
instrumentation paths are covered by the same assertions:

  production  - `dist/app.cjs`, whose Mistral, dataloader and express copies were
                transformed at build time by `sentryEsbuildPlugin`
  development - unbundled ESM behind the runtime `--import` hook

What it covers:

- gen_ai spans for streaming and non-streaming calls, and the shapes of
  `gen_ai.response.text` and `gen_ai.output.messages`
- a rejected model id reaches Sentry as an error, the gen_ai span is marked
  errored and records nothing from a response, and the error shares its trace
- a manual span nests under the request span, and the gen_ai span directly under
  the manual one, for both streaming and not
- streams drained through `tee()` and `pipeThrough()`, which take their reader
  from internal slots and so produced no span before the accompanying fix
- dataloader spans in the same trace as gen_ai spans, which also covers a
  CommonJS and an ESM-only module through the same transform in one process

Assertions avoid anything a live model decides. Token counts are checked as
positive numbers and response text for shape, while origin, provider, operation
name, the `chat {model}` naming rule, the stream flags and every parent/child
relationship are exact.

`Sentry.init` registers the runtime hook unless `enableRuntimeChannelInjection`
is false, which the bundled mode sets, so the production run also asserts the
injected channel names are present in the built file. Without that a passing
production run would not distinguish build-time instrumentation from a silent
runtime fallback.

OpenRouter serves an OpenAI-compatible `/v1/chat/completions`, which is what
`chat.complete` and `chat.stream` post to, and the SDK's response schemas accept
it: `usage` carries a `catchall` and `finish_reason` is an open enum.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@JPeer264
JPeer264 force-pushed the test/mistral-e2e-app branch from 2fc5bc8 to 7919617 Compare September 15, 2026 11:10

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7919617. Configure here.

import { APP, attr, expectCommonChatAttributes, isChatSpan } from './utils';

test('emits a gen_ai.chat span for a non-streaming call', async ({ baseURL, request }) => {
const spansPromise = collectStreamedSpansUntilSegment(APP, 'GET /chat');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shared routes use non-unique waiters

Medium Severity

Several tests wait only on GET /chat or GET /chat-stream, with no per-request id. collectStreamedSpans can treat a late envelope from an earlier hit of the same route as the trace under test, especially on the development retries. The /chat-error tests already uniquify with the model id; these routes do not.

Additional Locations (2)
Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot

Reviewed by Cursor Bugbot for commit 7919617. Configure here.

@RulaKhaled
RulaKhaled merged commit 77fc816 into develop Sep 15, 2026
43 checks passed
@RulaKhaled
RulaKhaled deleted the test/mistral-e2e-app branch September 15, 2026 11:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants