|
| 1 | +import { expect } from '@playwright/test'; |
| 2 | +import { sentryTest } from '../../../../../utils/fixtures'; |
| 3 | +import { |
| 4 | + type EventAndTraceHeader, |
| 5 | + eventAndTraceHeaderRequestParser, |
| 6 | + getMultipleSentryEnvelopeRequests, |
| 7 | + shouldSkipFeatureFlagsTest, |
| 8 | + shouldSkipTracingTest, |
| 9 | +} from '../../../../../utils/helpers'; |
| 10 | +import { MAX_FLAGS_PER_SPAN } from '../../constants'; |
| 11 | + |
| 12 | +sentryTest("Feature flags are added to active span's attributes on span end.", async ({ getLocalTestUrl, page }) => { |
| 13 | + if (shouldSkipFeatureFlagsTest() || shouldSkipTracingTest()) { |
| 14 | + sentryTest.skip(); |
| 15 | + } |
| 16 | + |
| 17 | + await page.route('https://dsn.ingest.sentry.io/**/*', route => { |
| 18 | + return route.fulfill({ |
| 19 | + status: 200, |
| 20 | + contentType: 'application/json', |
| 21 | + body: JSON.stringify({}), |
| 22 | + }); |
| 23 | + }); |
| 24 | + |
| 25 | + const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true }); |
| 26 | + await page.goto(url); |
| 27 | + |
| 28 | + const envelopeRequestPromise = getMultipleSentryEnvelopeRequests<EventAndTraceHeader>( |
| 29 | + page, |
| 30 | + 1, |
| 31 | + {}, |
| 32 | + eventAndTraceHeaderRequestParser, |
| 33 | + ); |
| 34 | + |
| 35 | + // withNestedSpans is a util used to start 3 nested spans: root-span (not recorded in transaction_event.spans), span, and nested-span. |
| 36 | + await page.evaluate(maxFlags => { |
| 37 | + (window as any).withNestedSpans(() => { |
| 38 | + const flagsIntegration = (window as any).Sentry.getClient().getIntegrationByName('FeatureFlags'); |
| 39 | + for (let i = 1; i <= maxFlags; i++) { |
| 40 | + flagsIntegration.addFeatureFlag(`feat${i}`, false); |
| 41 | + } |
| 42 | + flagsIntegration.addFeatureFlag(`feat${maxFlags + 1}`, true); // dropped flag |
| 43 | + flagsIntegration.addFeatureFlag('feat3', true); // update |
| 44 | + }); |
| 45 | + return true; |
| 46 | + }, MAX_FLAGS_PER_SPAN); |
| 47 | + |
| 48 | + const event = (await envelopeRequestPromise)[0][0]; |
| 49 | + const innerSpan = event.spans?.[0]; |
| 50 | + const outerSpan = event.spans?.[1]; |
| 51 | + const outerSpanFlags = Object.entries(outerSpan?.data ?? {}).filter(([key, _val]) => |
| 52 | + key.startsWith('flag.evaluation'), |
| 53 | + ); |
| 54 | + const innerSpanFlags = Object.entries(innerSpan?.data ?? {}).filter(([key, _val]) => |
| 55 | + key.startsWith('flag.evaluation'), |
| 56 | + ); |
| 57 | + |
| 58 | + expect(innerSpanFlags).toEqual([]); |
| 59 | + |
| 60 | + const expectedOuterSpanFlags = []; |
| 61 | + for (let i = 1; i <= MAX_FLAGS_PER_SPAN; i++) { |
| 62 | + expectedOuterSpanFlags.push([`flag.evaluation.feat${i}`, i === 3]); |
| 63 | + } |
| 64 | + // Order agnostic (attribute dict is unordered). |
| 65 | + expect(outerSpanFlags.sort()).toEqual(expectedOuterSpanFlags.sort()); |
| 66 | +}); |
0 commit comments