diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/init.js b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/init.js new file mode 100644 index 000000000000..067dbec23fd4 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/init.js @@ -0,0 +1,19 @@ +import * as Sentry from '@sentry/browser'; +// Import this separately so that generatePlugin can handle it for CDN scenarios +import { feedbackIntegration } from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + integrations: [ + feedbackIntegration({ tags: { from: 'integration init' }, styleNonce: 'foo1234', scriptNonce: 'foo1234' }), + ], +}); + +document.addEventListener('securitypolicyviolation', () => { + const container = document.querySelector('#csp-violation'); + if (container) { + container.innerText = 'CSP Violation'; + } +}); diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/template.html b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/template.html new file mode 100644 index 000000000000..919f372ef468 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/template.html @@ -0,0 +1,13 @@ + + +
+ + + + + + + diff --git a/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/test.ts b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/test.ts new file mode 100644 index 000000000000..95a8a2eacee8 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/feedback/captureFeedbackCsp/test.ts @@ -0,0 +1,84 @@ +import { expect } from '@playwright/test'; + +import { TEST_HOST, sentryTest } from '../../../utils/fixtures'; +import { envelopeRequestParser, getEnvelopeType, shouldSkipFeedbackTest } from '../../../utils/helpers'; + +sentryTest('should capture feedback', async ({ getLocalTestUrl, page }) => { + if (shouldSkipFeedbackTest()) { + sentryTest.skip(); + } + + const feedbackRequestPromise = page.waitForResponse(res => { + const req = res.request(); + + const postData = req.postData(); + if (!postData) { + return false; + } + + try { + return getEnvelopeType(req) === 'feedback'; + } catch (err) { + return false; + } + }); + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + await page.getByText('Report a Bug').click(); + expect(await page.locator(':visible:text-is("Report a Bug")').count()).toEqual(1); + await page.locator('[name="name"]').fill('Jane Doe'); + await page.locator('[name="email"]').fill('janedoe@example.org'); + await page.locator('[name="message"]').fill('my example feedback'); + await page.locator('[data-sentry-feedback] .btn--primary').click(); + + const feedbackEvent = envelopeRequestParser((await feedbackRequestPromise).request()); + expect(feedbackEvent).toEqual({ + type: 'feedback', + breadcrumbs: expect.any(Array), + contexts: { + feedback: { + contact_email: 'janedoe@example.org', + message: 'my example feedback', + name: 'Jane Doe', + source: 'widget', + url: `${TEST_HOST}/index.html`, + }, + trace: { + trace_id: expect.stringMatching(/\w{32}/), + span_id: expect.stringMatching(/\w{16}/), + }, + }, + level: 'info', + tags: { + from: 'integration init', + }, + timestamp: expect.any(Number), + event_id: expect.stringMatching(/\w{32}/), + environment: 'production', + sdk: { + integrations: expect.arrayContaining(['Feedback']), + version: expect.any(String), + name: 'sentry.javascript.browser', + packages: expect.anything(), + }, + request: { + url: `${TEST_HOST}/index.html`, + headers: { + 'User-Agent': expect.stringContaining(''), + }, + }, + platform: 'javascript', + }); + const cspContainer = await page.locator('#csp-violation'); + expect(cspContainer).not.toContainText('CSP Violation'); +}); diff --git a/packages/browser/src/utils/lazyLoadIntegration.ts b/packages/browser/src/utils/lazyLoadIntegration.ts index b023bc18aa95..168d1fd1013b 100644 --- a/packages/browser/src/utils/lazyLoadIntegration.ts +++ b/packages/browser/src/utils/lazyLoadIntegration.ts @@ -31,7 +31,10 @@ const WindowWithMaybeIntegration = WINDOW as { * Lazy load an integration from the CDN. * Rejects if the integration cannot be loaded. */ -export async function lazyLoadIntegration(name: keyof typeof LazyLoadableIntegrations): Promise