Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans, getSpanOp, waitForStreamedSpan } from '@sentry-internal/test-utils';
import {
collectStreamedSpans,
collectStreamedSpansUntilSegment,
getSpanOp,
waitForStreamedSpan,
} from '@sentry-internal/test-utils';

// The agent request segment is the Durable Object's `http.server` span. It has a parent because
// the worker propagates its trace over the RPC binding; the worker's own segment for the same URL
Expand Down Expand Up @@ -124,14 +129,12 @@ test('does not emit db.query spans for the agents runtime `cf_`-prefixed interna
page,
baseURL,
}) => {
const spansPromise = collectStreamedSpans('cloudflare-agent', spans =>
spans.some(
span =>
getSpanOp(span) === 'http.server' &&
span.is_segment &&
span.attributes['url.path']?.value === '/agents/my-agent/user-123' &&
span.parent_span_id !== undefined,
),
const spansPromise = collectStreamedSpansUntilSegment(
'cloudflare-agent',
span =>
getSpanOp(span) === 'http.server' &&
span.attributes['url.path']?.value === '/agents/my-agent/user-123' &&
span.parent_span_id !== undefined,
);

await page.goto(baseURL!);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans, getSpanOp, waitForStreamedSpan } from '@sentry-internal/test-utils';
import {
collectStreamedSpans,
collectStreamedSpansUntilSegment,
getSpanOp,
waitForStreamedSpan,
} from '@sentry-internal/test-utils';
import { callRpc } from './agent-socket';

// The worker entry (`src/index.ts`) contains no Sentry calls at all — every
Expand Down Expand Up @@ -90,11 +95,9 @@ for (const { title, binding, agentClass } of [
}

test('applies plain Durable Object instrumentation to a non-Agent class', async ({ baseURL }) => {
const spansPromise = collectStreamedSpans('cloudflare-autoinstrument', spans =>
spans.some(
span =>
getSpanOp(span) === 'http.server' && span.is_segment && span.attributes['url.path']?.value === '/plain-do',
),
const spansPromise = collectStreamedSpansUntilSegment(
'cloudflare-autoinstrument',
span => getSpanOp(span) === 'http.server' && span.attributes['url.path']?.value === '/plain-do',
);

const res = await fetch(`${baseURL}/plain-do`);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans, getSpanOp, waitForStreamedSpan } from '@sentry-internal/test-utils';
import { collectStreamedSpansUntilSegment, getSpanOp, waitForStreamedSpan } from '@sentry-internal/test-utils';

test('Sends a segment span for a successful route', async ({ baseURL, request }) => {
const spanPromise = waitForStreamedSpan('elysia-bun', span => {
Expand Down Expand Up @@ -70,9 +70,7 @@ test('Sends a segment span for an errored route', async ({ baseURL, request }) =
});

test('Includes manually started spans with parent-child relationship', async ({ baseURL, request }) => {
const spansPromise = collectStreamedSpans('elysia-bun', spans =>
spans.some(span => span.name === 'GET /test-transaction' && span.is_segment),
);
const spansPromise = collectStreamedSpansUntilSegment('elysia-bun', 'GET /test-transaction');

await request.get(`${baseURL}/test-transaction`);

Expand Down Expand Up @@ -102,9 +100,7 @@ test('Includes manually started spans with parent-child relationship', async ({
});

test('Creates lifecycle spans for Elysia hooks', async ({ baseURL, request }) => {
const spansPromise = collectStreamedSpans('elysia-bun', spans =>
spans.some(span => span.name === 'GET /test-success' && span.is_segment),
);
const spansPromise = collectStreamedSpansUntilSegment('elysia-bun', 'GET /test-success');

await request.get(`${baseURL}/test-success`);

Expand All @@ -128,9 +124,7 @@ test('Creates lifecycle spans for Elysia hooks', async ({ baseURL, request }) =>
});

test('Names handler spans after the route instead of "<unknown>"', async ({ baseURL, request }) => {
const spansPromise = collectStreamedSpans('elysia-bun', spans =>
spans.some(span => span.name === 'GET /with-middleware/test' && span.is_segment),
);
const spansPromise = collectStreamedSpansUntilSegment('elysia-bun', 'GET /with-middleware/test');

// Use a route with middleware so there are child handler spans
await request.get(`${baseURL}/with-middleware/test`);
Expand All @@ -153,9 +147,7 @@ test('Names handler spans after the route instead of "<unknown>"', async ({ base
});

test('Creates lifecycle spans for route-specific middleware', async ({ baseURL, request }) => {
const spansPromise = collectStreamedSpans('elysia-bun', spans =>
spans.some(span => span.name === 'GET /with-middleware/test' && span.is_segment),
);
const spansPromise = collectStreamedSpansUntilSegment('elysia-bun', 'GET /with-middleware/test');

await request.get(`${baseURL}/with-middleware/test`);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans, waitForError, waitForStreamedSpan } from '@sentry-internal/test-utils';
import { collectStreamedSpansUntilSegment, waitForError, waitForStreamedSpan } from '@sentry-internal/test-utils';

// The generation-function spans are children of the segment span, which ends last, so accumulate
// spans until the segment for this request arrives.
function collectSpansForTarget(httpTarget: string) {
return collectStreamedSpans('nextjs-14', spans =>
spans.some(span => span.is_segment && span.attributes['http.target']?.value === httpTarget),
);
return collectStreamedSpansUntilSegment('nextjs-14', span => span.attributes['http.target']?.value === httpTarget);
}

test('Should emit a span for a generateMetadata() function invocation', async ({ page }) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans } from '@sentry-internal/test-utils';
import { collectStreamedSpansUntilSegment } from '@sentry-internal/test-utils';

test('Should send a fetch span', async ({ page }) => {
// The fetch spans are children of the segment span, which ends last.
const spansPromise = collectStreamedSpans('nextjs-14', spans =>
spans.some(span => span.name === 'GET /request-instrumentation' && span.is_segment),
);
const spansPromise = collectStreamedSpansUntilSegment('nextjs-14', 'GET /request-instrumentation');

await page.goto(`/request-instrumentation`);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans } from '@sentry-internal/test-utils';
import { collectStreamedSpansUntilSegment } from '@sentry-internal/test-utils';

test('Prefetch client spans should have a http.request.prefetch attribute', async ({ page }) => {
test.skip(
Expand All @@ -8,9 +8,7 @@ test('Prefetch client spans should have a http.request.prefetch attribute', asyn
);

// The prefetch span is a child of the pageload segment span, which ends last.
const spansPromise = collectStreamedSpans('nextjs-15', spans =>
spans.some(span => span.name === '/prefetching' && span.is_segment),
);
const spansPromise = collectStreamedSpansUntilSegment('nextjs-15', '/prefetching');

await page.goto(`/prefetching`);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans } from '@sentry-internal/test-utils';
import { collectStreamedSpansUntilSegment } from '@sentry-internal/test-utils';

test('Sends a span for a request to app router with URL', async ({ page }) => {
const spansPromise = collectStreamedSpans('nextjs-15', spans =>
spans.some(
span =>
span.name === 'GET /parameterized/[one]/beep/[two]' &&
span.is_segment &&
String(span.attributes['http.target']?.value).startsWith('/parameterized/1337/beep/42'),
),
const spansPromise = collectStreamedSpansUntilSegment(
'nextjs-15',
span =>
span.name === 'GET /parameterized/[one]/beep/[two]' &&
String(span.attributes['http.target']?.value).startsWith('/parameterized/1337/beep/42'),
);

await page.goto('/parameterized/1337/beep/42');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans } from '@sentry-internal/test-utils';

// Streamed spans are flushed across multiple envelopes as they end, so the server-component child spans
// can arrive in a different (earlier) envelope than the `is_segment` root span. Accumulate spans across
// envelopes until the root span (which ends last) is seen.
function collectSpanNamesUntilSegment(segmentName: string): Promise<string[]> {
return collectStreamedSpans('nextjs-16-bun', spans =>
spans.some(span => span.name === segmentName && span.is_segment),
).then(spans => spans.map(span => span.name));
}
import { collectSpanNamesUntilSegment, collectStreamedSpansUntilSegment } from '@sentry-internal/test-utils';

test('Sends a span for a request to app router with URL', async ({ page }) => {
const spansPromise = collectStreamedSpans('nextjs-16-bun', spans =>
spans.some(
span =>
span.name === 'GET /parameterized/[one]/beep/[two]' &&
span.is_segment &&
String(span.attributes['http.target']?.value).startsWith('/parameterized/1337/beep/42'),
),
const spansPromise = collectStreamedSpansUntilSegment(
'nextjs-16-bun',
span =>
span.name === 'GET /parameterized/[one]/beep/[two]' &&
String(span.attributes['http.target']?.value).startsWith('/parameterized/1337/beep/42'),
);

await page.goto('/parameterized/1337/beep/42');
Expand Down Expand Up @@ -54,7 +43,7 @@ test('Sends a span for a request to app router with URL', async ({ page }) => {
test('Will create spans for every server component and metadata generation functions when visiting a page', async ({
page,
}) => {
const spanNamesPromise = collectSpanNamesUntilSegment('GET /nested-layout');
const spanNamesPromise = collectSpanNamesUntilSegment('nextjs-16-bun', 'GET /nested-layout');

await page.goto('/nested-layout');

Expand All @@ -73,7 +62,7 @@ test('Will create spans for every server component and metadata generation funct
test('Will create spans for every server component and metadata generation functions when visiting a dynamic page', async ({
page,
}) => {
const spanNamesPromise = collectSpanNamesUntilSegment('GET /nested-layout/[dynamic]');
const spanNamesPromise = collectSpanNamesUntilSegment('nextjs-16-bun', 'GET /nested-layout/[dynamic]');

await page.goto('/nested-layout/123');

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans } from '@sentry-internal/test-utils';
import { collectStreamedSpansUntilSegment } from '@sentry-internal/test-utils';
import { isDevMode } from './isDevMode';

test('Prefetch client spans should have a http.request.prefetch attribute', async ({ page }) => {
test.skip(isDevMode, "Prefetch requests don't have the prefetch header in dev mode");

// The prefetch span is a child of the pageload segment span, which ends last.
const spansPromise = collectStreamedSpans('nextjs-16-cf-workers', spans =>
spans.some(span => span.name === '/prefetching' && span.is_segment),
);
const spansPromise = collectStreamedSpansUntilSegment('nextjs-16-cf-workers', '/prefetching');

await page.goto(`/prefetching`);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans } from '@sentry-internal/test-utils';

// Streamed spans are flushed across multiple envelopes as they end, so the server-component child spans
// can arrive in a different (earlier) envelope than the `is_segment` root span. Accumulate spans across
// envelopes until the root span (which ends last) is seen.
function collectSpanNamesUntilSegment(segmentName: string): Promise<string[]> {
return collectStreamedSpans('nextjs-16-cf-workers', spans =>
spans.some(span => span.name === segmentName && span.is_segment),
).then(spans => spans.map(span => span.name));
}
import { collectSpanNamesUntilSegment, collectStreamedSpansUntilSegment } from '@sentry-internal/test-utils';

// TODO: Server component tests need SDK adjustments for Cloudflare Workers
test.skip('Sends a span for a request to app router with URL', async ({ page }) => {
const spansPromise = collectStreamedSpans('nextjs-16-cf-workers', spans =>
spans.some(
span =>
span.name === 'GET /parameterized/[one]/beep/[two]' &&
span.is_segment &&
String(span.attributes['http.target']?.value).startsWith('/parameterized/1337/beep/42'),
),
const spansPromise = collectStreamedSpansUntilSegment(
'nextjs-16-cf-workers',
span =>
span.name === 'GET /parameterized/[one]/beep/[two]' &&
String(span.attributes['http.target']?.value).startsWith('/parameterized/1337/beep/42'),
);

await page.goto('/parameterized/1337/beep/42');
Expand Down Expand Up @@ -56,7 +45,7 @@ test.skip('Sends a span for a request to app router with URL', async ({ page })
test.skip('Will create spans for every server component and metadata generation functions when visiting a page', async ({
page,
}) => {
const spanNamesPromise = collectSpanNamesUntilSegment('GET /nested-layout');
const spanNamesPromise = collectSpanNamesUntilSegment('nextjs-16-cf-workers', 'GET /nested-layout');

await page.goto('/nested-layout');

Expand All @@ -76,7 +65,7 @@ test.skip('Will create spans for every server component and metadata generation
test.skip('Will create spans for every server component and metadata generation functions when visiting a dynamic page', async ({
page,
}) => {
const spanNamesPromise = collectSpanNamesUntilSegment('GET /nested-layout/[dynamic]');
const spanNamesPromise = collectSpanNamesUntilSegment('nextjs-16-cf-workers', 'GET /nested-layout/[dynamic]');

await page.goto('/nested-layout/123');

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans, waitForStreamedSpan, getSpanOp } from '@sentry-internal/test-utils';
import { collectSpanNamesUntilSegment, getSpanOp, waitForStreamedSpan } from '@sentry-internal/test-utils';
import { isDevMode } from './isDevMode';

// Streamed spans are flushed across multiple envelopes as they end, so the server-component child spans
// can arrive in a different (earlier) envelope than the `is_segment` root span. Accumulate spans across
// envelopes until the root span (which ends last) is seen.
function collectSpanNamesUntilSegment(segmentName: string): Promise<string[]> {
return collectStreamedSpans('nextjs-16-streaming', spans =>
spans.some(span => span.name === segmentName && span.is_segment),
).then(spans => spans.map(span => span.name));
}

test('Sends a streamed span for a request to app router with URL', async ({ page }) => {
test.skip(isDevMode, 'Turbopack intermittently returns 404 for nested dynamic routes in dev mode');

Expand All @@ -31,7 +22,7 @@ test('Will create streamed spans for every server component and metadata generat
}) => {
test.skip(isDevMode, 'Turbopack intermittently returns 404 for nested dynamic routes in dev mode');

const spanNamesPromise = collectSpanNamesUntilSegment('GET /nested-layout');
const spanNamesPromise = collectSpanNamesUntilSegment('nextjs-16-streaming', 'GET /nested-layout');

await page.goto('/nested-layout');

Expand All @@ -52,7 +43,7 @@ test('Will create streamed spans for every server component and metadata generat
}) => {
test.skip(isDevMode, 'Turbopack intermittently returns 404 for nested dynamic routes in dev mode');

const spanNamesPromise = collectSpanNamesUntilSegment('GET /nested-layout/[dynamic]');
const spanNamesPromise = collectSpanNamesUntilSegment('nextjs-16-streaming', 'GET /nested-layout/[dynamic]');

await page.goto('/nested-layout/123');

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans } from '@sentry-internal/test-utils';
import { collectStreamedSpansUntilSegment } from '@sentry-internal/test-utils';

test('Instruments DB calls made during server-side rendering of a page', async ({ page }) => {
// The db spans are children of the segment span, which ends last.
const spansPromise = collectStreamedSpans('nextjs-16', spans =>
spans.some(span => span.name === 'GET /db-page' && span.is_segment),
);
const spansPromise = collectStreamedSpansUntilSegment('nextjs-16', 'GET /db-page');

await page.goto('/db-page');
await expect(page.locator('#answer')).toHaveText('answer: 42');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans, getSpanOp, waitForStreamedSpan } from '@sentry-internal/test-utils';
import {
collectStreamedSpans,
collectStreamedSpansUntilSegment,
getSpanOp,
waitForStreamedSpan,
} from '@sentry-internal/test-utils';
import { isDevMode } from './isDevMode';

test('Should create a span for middleware', async ({ request }) => {
const spansPromise = collectStreamedSpans('nextjs-16', spans =>
spans.some(span => span.name === 'middleware GET' && span.is_segment),
);
const spansPromise = collectStreamedSpansUntilSegment('nextjs-16', 'middleware GET');

const routeSpanPromise = waitForStreamedSpan('nextjs-16', span => {
return span.name === 'GET /api/endpoint-behind-middleware' && span.is_segment;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { expect, test } from '@playwright/test';
import { collectStreamedSpans } from '@sentry-internal/test-utils';
import { collectStreamedSpansUntilSegment } from '@sentry-internal/test-utils';
import { isDevMode } from './isDevMode';

test('Prefetch client spans should have a http.request.prefetch attribute', async ({ page }) => {
test.skip(isDevMode, "Prefetch requests don't have the prefetch header in dev mode");

// The prefetch span is a child of the pageload segment span, which ends last.
const spansPromise = collectStreamedSpans('nextjs-16', spans =>
spans.some(span => span.name === '/prefetching' && span.is_segment),
);
const spansPromise = collectStreamedSpansUntilSegment('nextjs-16', '/prefetching');

await page.goto(`/prefetching`);

Expand Down
Loading
Loading