diff --git a/packages/sveltekit/src/vite/sourceMaps.ts b/packages/sveltekit/src/vite/sourceMaps.ts index 5559f5be4592..eb3b449144f8 100644 --- a/packages/sveltekit/src/vite/sourceMaps.ts +++ b/packages/sveltekit/src/vite/sourceMaps.ts @@ -1,5 +1,5 @@ /* eslint-disable max-lines */ -import { consoleSandbox, escapeStringForRegex, uuid4 } from '@sentry/core'; +import { escapeStringForRegex, uuid4 } from '@sentry/core'; import { getSentryRelease } from '@sentry/node'; import type { SentryVitePluginOptions } from '@sentry/vite-plugin'; import { sentryVitePlugin } from '@sentry/vite-plugin'; @@ -27,6 +27,8 @@ type Sorcery = { // and we only want to generate a uuid once in case we have to fall back to it. const releaseName = detectSentryRelease(); +type FilesToDeleteAfterUpload = string | string[] | undefined; + /** * Creates a new Vite plugin that uses the unplugin-based Sentry Vite plugin to create * releases and upload source maps to Sentry. @@ -60,8 +62,12 @@ export async function makeCustomSentryVitePlugins(options?: CustomSentryVitePlug }, }; - const { promise: filesToDeleteAfterUpload, resolve: resolveFilesToDeleteAfterUpload } = - createFilesToDeleteAfterUploadPromise(); + let _resolveFilesToDeleteAfterUpload: + | undefined + | ((value: FilesToDeleteAfterUpload | Promise) => void); + const filesToDeleteAfterUploadPromise = new Promise(resolve => { + _resolveFilesToDeleteAfterUpload = resolve; + }); const mergedOptions = { ...defaultPluginOptions, @@ -72,7 +78,7 @@ export async function makeCustomSentryVitePlugins(options?: CustomSentryVitePlug }, sourcemaps: { ...options?.sourcemaps, - filesToDeleteAfterUpload, + filesToDeleteAfterUpload: filesToDeleteAfterUploadPromise, }, }; @@ -100,7 +106,7 @@ export async function makeCustomSentryVitePlugins(options?: CustomSentryVitePlug ); // resolving filesToDeleteAfterUpload here, because we return the original deletion plugin which awaits the promise - resolveFilesToDeleteAfterUpload(undefined); + _resolveFilesToDeleteAfterUpload?.(undefined); return sentryPlugins; } @@ -113,7 +119,7 @@ export async function makeCustomSentryVitePlugins(options?: CustomSentryVitePlug ); // resolving filesToDeleteAfterUpload here, because we return the original deletion plugin which awaits the promise - resolveFilesToDeleteAfterUpload(undefined); + _resolveFilesToDeleteAfterUpload?.(undefined); return sentryPlugins; } @@ -126,7 +132,7 @@ export async function makeCustomSentryVitePlugins(options?: CustomSentryVitePlug ); // resolving filesToDeleteAfterUpload here, because we return the original deletion plugin which awaits the promise - resolveFilesToDeleteAfterUpload(undefined); + _resolveFilesToDeleteAfterUpload?.(undefined); return sentryPlugins; } @@ -153,64 +159,40 @@ export async function makeCustomSentryVitePlugins(options?: CustomSentryVitePlug name: 'sentry-sveltekit-update-source-map-setting-plugin', apply: 'build', // only apply this plugin at build time config: async (config: UserConfig) => { - const settingKey = 'build.sourcemap'; - - const { updatedSourceMapSetting, previousSourceMapSetting } = getUpdatedSourceMapSetting(config); - - const userProvidedFilesToDeleteAfterUpload = await options?.sourcemaps?.filesToDeleteAfterUpload; - - if (previousSourceMapSetting === 'unset') { - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.log(`[Sentry] Enabled source map generation in the build options with \`${settingKey}: "hidden"\`.`); - }); - - if (userProvidedFilesToDeleteAfterUpload) { - resolveFilesToDeleteAfterUpload(userProvidedFilesToDeleteAfterUpload); - } else { - // Including all hidden (`.*`) directories by default so that folders like .vercel, - // .netlify, etc are also cleaned up. Additionally, we include the adapter output - // dir which could be a non-hidden directory, like `build` for the Node adapter. - const defaultFileDeletionGlob = ['./.*/**/*.map', `./${adapterOutputDir}/**/*.map`]; - - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.warn( - `[Sentry] Automatically setting \`sourceMapsUploadOptions.sourcemaps.filesToDeleteAfterUpload: [${defaultFileDeletionGlob - .map(file => `"${file}"`) - .join(', ')}]\` to delete generated source maps after they were uploaded to Sentry.`, - ); - }); + return { + ...config, + build: { + ...config.build, + sourcemap: _getUpdatedSourceMapSettings(config, options), + }, + }; + }, + }; - // In case we enabled source maps and users didn't specify a glob patter to delete, we set a default pattern: - resolveFilesToDeleteAfterUpload(defaultFileDeletionGlob); - } + const filesToDeleteAfterUploadConfigPlugin: Plugin = { + name: 'sentry-sveltekit-files-to-delete-after-upload-setting-plugin', + apply: 'build', // only apply this plugin at build time + config: (config: UserConfig) => { + const originalFilesToDeleteAfterUpload = options?.sourcemaps?.filesToDeleteAfterUpload; - return { - ...config, - build: { ...config.build, sourcemap: updatedSourceMapSetting }, - }; - } + if (typeof originalFilesToDeleteAfterUpload === 'undefined' && typeof config.build?.sourcemap === 'undefined') { + // Including all hidden (`.*`) directories by default so that folders like .vercel, + // .netlify, etc are also cleaned up. Additionally, we include the adapter output + // dir which could be a non-hidden directory, like `build` for the Node adapter. + const defaultFileDeletionGlob = ['./.*/**/*.map', `./${adapterOutputDir}/**/*.map`]; - if (previousSourceMapSetting === 'disabled') { - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.warn( - `[Sentry] Parts of source map generation are currently disabled in your Vite configuration (\`${settingKey}: false\`). This setting is either a default setting or was explicitly set in your configuration. Sentry won't override this setting. Without source maps, code snippets on the Sentry Issues page will remain minified. To show unminified code, enable source maps in \`${settingKey}\` (e.g. by setting them to \`hidden\`).`, + debug && + // eslint-disable-next-line no-console + console.info( + `[Sentry] Automatically setting \`sourceMapsUploadOptions.sourcemaps.filesToDeleteAfterUpload: [${defaultFileDeletionGlob + .map(file => `"${file}"`) + .join(', ')}]\` to delete generated source maps after they were uploaded to Sentry.`, ); - }); - } else if (previousSourceMapSetting === 'enabled') { - if (mergedOptions?.debug) { - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.log( - `[Sentry] We discovered you enabled source map generation in your Vite configuration (\`${settingKey}\`). Sentry will keep this source map setting. This will un-minify the code snippet on the Sentry Issue page.`, - ); - }); - } - } - resolveFilesToDeleteAfterUpload(userProvidedFilesToDeleteAfterUpload); + _resolveFilesToDeleteAfterUpload?.(defaultFileDeletionGlob); + } else { + _resolveFilesToDeleteAfterUpload?.(originalFilesToDeleteAfterUpload); + } return config; }, @@ -390,18 +372,14 @@ export async function makeCustomSentryVitePlugins(options?: CustomSentryVitePlug return [ ...unchangedSentryVitePlugins, sourceMapSettingsPlugin, + filesToDeleteAfterUploadConfigPlugin, customReleaseManagementPlugin, customDebugIdUploadPlugin, customFileDeletionPlugin, ]; } -/** - * Whether the user enabled (true, 'hidden', 'inline') or disabled (false) source maps - */ -type UserSourceMapSetting = 'enabled' | 'disabled' | 'unset' | undefined; - -/** There are 3 ways to set up source map generation (https://github.com/getsentry/sentry-javascript/issues/13993) +/** There are 3 ways to set up source map generation (https://github.com/getsentry/sentry-j avascript/issues/13993) * * 1. User explicitly disabled source maps * - keep this setting (emit a warning that errors won't be unminified in Sentry) @@ -416,30 +394,50 @@ type UserSourceMapSetting = 'enabled' | 'disabled' | 'unset' | undefined; * * --> only exported for testing */ -export function getUpdatedSourceMapSetting(viteConfig: { - build?: { - sourcemap?: boolean | 'inline' | 'hidden'; - }; -}): { updatedSourceMapSetting: boolean | 'inline' | 'hidden'; previousSourceMapSetting: UserSourceMapSetting } { +export function _getUpdatedSourceMapSettings( + viteConfig: UserConfig, + sentryPluginOptions?: CustomSentryVitePluginOptions, +): boolean | 'inline' | 'hidden' { viteConfig.build = viteConfig.build || {}; - const originalSourcemapSetting = viteConfig.build.sourcemap; + const viteSourceMap = viteConfig?.build?.sourcemap; + let updatedSourceMapSetting = viteSourceMap; - if (originalSourcemapSetting === false) { - return { - previousSourceMapSetting: 'disabled', - updatedSourceMapSetting: originalSourcemapSetting, - }; - } + const settingKey = 'build.sourcemap'; + const debug = sentryPluginOptions?.debug; + + if (viteSourceMap === false) { + updatedSourceMapSetting = viteSourceMap; + + if (debug) { + // Longer debug message with more details + // eslint-disable-next-line no-console + console.warn( + `[Sentry] Source map generation is currently disabled in your Vite configuration (\`${settingKey}: false \`). This setting is either a default setting or was explicitly set in your configuration. Sentry won't override this setting. Without source maps, code snippets on the Sentry Issues page will remain minified. To show unminified code, enable source maps in \`${settingKey}\` (e.g. by setting them to \`hidden\`).`, + ); + } else { + // eslint-disable-next-line no-console + console.warn('[Sentry] Source map generation is disabled in your Vite configuration.'); + } + } else if (viteSourceMap && ['hidden', 'inline', true].includes(viteSourceMap)) { + updatedSourceMapSetting = viteSourceMap; + + debug && + // eslint-disable-next-line no-console + console.log( + `[Sentry] We discovered \`${settingKey}\` is set to \`${viteSourceMap.toString()}\`. Sentry will keep this source map setting. This will un-minify the code snippet on the Sentry Issue page.`, + ); + } else { + updatedSourceMapSetting = 'hidden'; - if (originalSourcemapSetting && ['hidden', 'inline', true].includes(originalSourcemapSetting)) { - return { previousSourceMapSetting: 'enabled', updatedSourceMapSetting: originalSourcemapSetting }; + debug && + // eslint-disable-next-line no-console + console.log( + `[Sentry] Enabled source map generation in the build options with \`${settingKey}: 'hidden'\`. The source maps will be deleted after they were uploaded to Sentry.`, + ); } - return { - previousSourceMapSetting: 'unset', - updatedSourceMapSetting: 'hidden', - }; + return updatedSourceMapSetting; } function getFiles(dir: string): string[] { @@ -475,22 +473,3 @@ function detectSentryRelease(): string { return release; } - -/** - * Creates a deferred promise that can be resolved/rejected by calling the - * `resolve` or `reject` function. - * Inspired by: https://stackoverflow.com/a/69027809 - */ -function createFilesToDeleteAfterUploadPromise(): { - promise: Promise; - resolve: (value: string | string[] | undefined) => void; - reject: (reason?: unknown) => void; -} { - let resolve!: (value: string | string[] | undefined) => void; - let reject!: (reason?: unknown) => void; - const promise = new Promise((res, rej) => { - resolve = res; - reject = rej; - }); - return { resolve, reject, promise }; -} diff --git a/packages/sveltekit/test/vite/sentrySvelteKitPlugins.test.ts b/packages/sveltekit/test/vite/sentrySvelteKitPlugins.test.ts index 36c79afffb06..d21bcf0d8d04 100644 --- a/packages/sveltekit/test/vite/sentrySvelteKitPlugins.test.ts +++ b/packages/sveltekit/test/vite/sentrySvelteKitPlugins.test.ts @@ -42,7 +42,7 @@ describe('sentrySvelteKit()', () => { expect(plugins).toBeInstanceOf(Array); // 1 auto instrument plugin + 5 source maps plugins - expect(plugins).toHaveLength(8); + expect(plugins).toHaveLength(9); }); it('returns the custom sentry source maps upload plugin, unmodified sourcemaps plugins and the auto-instrument plugin by default', async () => { @@ -56,6 +56,7 @@ describe('sentrySvelteKit()', () => { 'sentry-vite-release-injection-plugin', 'sentry-vite-debug-id-injection-plugin', 'sentry-sveltekit-update-source-map-setting-plugin', + 'sentry-sveltekit-files-to-delete-after-upload-setting-plugin', // custom release plugin: 'sentry-sveltekit-release-management-plugin', // custom source maps plugin: @@ -86,7 +87,7 @@ describe('sentrySvelteKit()', () => { it("doesn't return the auto instrument plugin if autoInstrument is `false`", async () => { const plugins = await getSentrySvelteKitPlugins({ autoInstrument: false }); const pluginNames = plugins.map(plugin => plugin.name); - expect(plugins).toHaveLength(7); + expect(plugins).toHaveLength(8); expect(pluginNames).not.toContain('sentry-upload-source-maps'); }); @@ -184,7 +185,7 @@ describe('sentrySvelteKit()', () => { // just to ignore the source maps plugin: autoUploadSourceMaps: false, }); - const plugin = plugins[0]; + const plugin = plugins[0]!; expect(plugin.name).toEqual('sentry-auto-instrumentation'); expect(makePluginSpy).toHaveBeenCalledWith({ diff --git a/packages/sveltekit/test/vite/sourceMaps.test.ts b/packages/sveltekit/test/vite/sourceMaps.test.ts index b85d4e4db2cb..97d223dc309b 100644 --- a/packages/sveltekit/test/vite/sourceMaps.test.ts +++ b/packages/sveltekit/test/vite/sourceMaps.test.ts @@ -1,7 +1,9 @@ +import { sentryVitePlugin } from '@sentry/vite-plugin'; import type { Plugin } from 'vite'; import * as vite from 'vite'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { getUpdatedSourceMapSetting, makeCustomSentryVitePlugins } from '../../src/vite/sourceMaps'; +import type { ViteUserConfig } from 'vitest/config'; +import { _getUpdatedSourceMapSettings, makeCustomSentryVitePlugins } from '../../src/vite/sourceMaps'; const mockedViteDebugIdUploadPlugin = { name: 'sentry-vite-debug-id-upload-plugin', @@ -18,25 +20,21 @@ const mockedFileDeletionPlugin = { writeBundle: vi.fn(), }; -vi.mock('vite', async () => { - const original = (await vi.importActual('vite')) as any; +vi.mock('@sentry/vite-plugin', async () => { + const original = (await vi.importActual('@sentry/vite-plugin')) as any; return { ...original, - loadConfigFromFile: vi.fn(), + sentryVitePlugin: vi.fn(), }; }); -vi.mock('@sentry/vite-plugin', async () => { - const original = (await vi.importActual('@sentry/vite-plugin')) as any; +vi.mock('vite', async () => { + const original = (await vi.importActual('vite')) as any; return { ...original, - sentryVitePlugin: () => [ - mockedViteReleaseManagementPlugin, - mockedViteDebugIdUploadPlugin, - mockedFileDeletionPlugin, - ], + loadConfigFromFile: vi.fn(), }; }); @@ -65,6 +63,15 @@ async function getSentryViteSubPlugin(name: string): Promise } describe('makeCustomSentryVitePlugins()', () => { + beforeEach(() => { + // @ts-expect-error - this function exists! + sentryVitePlugin.mockReturnValue([ + mockedViteReleaseManagementPlugin, + mockedViteDebugIdUploadPlugin, + mockedFileDeletionPlugin, + ]); + }); + it('returns the custom sentry source maps plugin', async () => { const plugin = await getSentryViteSubPlugin('sentry-sveltekit-debug-id-upload-plugin'); @@ -87,6 +94,7 @@ describe('makeCustomSentryVitePlugins()', () => { // @ts-expect-error - this global variable is set/accessed in src/vite/sourceMaps.ts globalThis._sentry_sourceMapSetting = undefined; }); + it('returns the custom sentry source maps plugin', async () => { const plugin = await getSentryViteSubPlugin('sentry-sveltekit-update-source-map-setting-plugin'); @@ -117,6 +125,8 @@ describe('makeCustomSentryVitePlugins()', () => { }); it('keeps source map generation settings when previously disabled', async () => { + const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementationOnce(() => {}); + const originalConfig = { build: { sourcemap: false, assetsDir: 'assets' }, }; @@ -138,6 +148,10 @@ describe('makeCustomSentryVitePlugins()', () => { sourcemap: false, }, }); + + expect(consoleWarnSpy).toHaveBeenCalledWith( + '[Sentry] Source map generation is disabled in your Vite configuration.', + ); }); it('enables source map generation with "hidden" when unset', async () => { @@ -201,8 +215,8 @@ describe('makeCustomSentryVitePlugins()', () => { throw new Error('test error'); }); - const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementationOnce(() => {}); - const consoleLogSpy = vi.spyOn(console, 'log').mockImplementationOnce(() => {}); + const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); const plugin = await getSentryViteSubPlugin('sentry-sveltekit-debug-id-upload-plugin'); @@ -315,26 +329,225 @@ describe('makeCustomSentryVitePlugins()', () => { }); }); -describe('changeViteSourceMapSettings()', () => { - const cases = [ - { sourcemap: false, expectedSourcemap: false, expectedPrevious: 'disabled' }, - { sourcemap: 'hidden' as const, expectedSourcemap: 'hidden', expectedPrevious: 'enabled' }, - { sourcemap: 'inline' as const, expectedSourcemap: 'inline', expectedPrevious: 'enabled' }, - { sourcemap: true, expectedSourcemap: true, expectedPrevious: 'enabled' }, - { sourcemap: undefined, expectedSourcemap: 'hidden', expectedPrevious: 'unset' }, - ]; - - it.each(cases)( - 'handles vite source map setting `build.sourcemap: $sourcemap`', - async ({ sourcemap, expectedSourcemap, expectedPrevious }) => { - const viteConfig = { build: { sourcemap } }; - - const result = getUpdatedSourceMapSetting(viteConfig); - - expect(result).toEqual({ - updatedSourceMapSetting: expectedSourcemap, - previousSourceMapSetting: expectedPrevious, +describe('_getUpdatedSourceMapSettings', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.spyOn(console, 'warn').mockImplementation(() => {}); + vi.spyOn(console, 'log').mockImplementation(() => {}); + }); + + describe('when sourcemap is false', () => { + it('should keep sourcemap as false and show short warning when debug is disabled', () => { + const result = _getUpdatedSourceMapSettings({ build: { sourcemap: false } }); + + expect(result).toBe(false); + // eslint-disable-next-line no-console + expect(console.warn).toHaveBeenCalledWith( + '[Sentry] Source map generation is disabled in your Vite configuration.', + ); + }); + + it('should keep sourcemap as false and show long warning when debug is enabled', () => { + const result = _getUpdatedSourceMapSettings({ build: { sourcemap: false } }, { debug: true }); + + expect(result).toBe(false); + // eslint-disable-next-line no-console + expect(console.warn).toHaveBeenCalledWith( + expect.stringContaining('[Sentry] Source map generation is currently disabled in your Vite configuration'), + ); + // eslint-disable-next-line no-console + expect(console.warn).toHaveBeenCalledWith( + expect.stringContaining( + 'This setting is either a default setting or was explicitly set in your configuration.', + ), + ); + }); + }); + + describe('when sourcemap is explicitly set to valid values', () => { + it.each([ + ['hidden', 'hidden'], + ['inline', 'inline'], + [true, true], + ] as ('inline' | 'hidden' | boolean)[][])('should keep sourcemap as %s when set to %s', (input, expected) => { + const result = _getUpdatedSourceMapSettings({ build: { sourcemap: input } }, { debug: true }); + + expect(result).toBe(expected); + // eslint-disable-next-line no-console + expect(console.log).toHaveBeenCalledWith( + expect.stringContaining(`[Sentry] We discovered \`build.sourcemap\` is set to \`${input.toString()}\``), + ); + }); + }); + + describe('when sourcemap is undefined or invalid', () => { + it.each([[undefined], ['invalid'], ['something'], [null]])( + 'should set sourcemap to hidden when value is %s', + input => { + const result = _getUpdatedSourceMapSettings({ build: { sourcemap: input as any } }, { debug: true }); + + expect(result).toBe('hidden'); + // eslint-disable-next-line no-console + expect(console.log).toHaveBeenCalledWith( + expect.stringContaining( + "[Sentry] Enabled source map generation in the build options with `build.sourcemap: 'hidden'`", + ), + ); + }, + ); + + it('should set sourcemap to hidden when build config is empty', () => { + const result = _getUpdatedSourceMapSettings({}, { debug: true }); + + expect(result).toBe('hidden'); + // eslint-disable-next-line no-console + expect(console.log).toHaveBeenCalledWith( + expect.stringContaining( + "[Sentry] Enabled source map generation in the build options with `build.sourcemap: 'hidden'`", + ), + ); + }); + }); +}); + +describe('deleteFilesAfterUpload', () => { + it('works with defauts', async () => { + const viteConfig: ViteUserConfig = {}; + + vi.mock('@sentry/vite-plugin', async () => { + const original = (await vi.importActual('@sentry/vite-plugin')) as any; + + return { + ...original, + sentryVitePlugin: vi.fn(original.sentryVitePlugin), + }; + }); + + const plugins = await makeCustomSentryVitePlugins({ + authToken: 'token', + org: 'org', + project: 'project', + adapter: 'other', + }); + + // @ts-expect-error this function exists! + const mergedOptions = sentryVitePlugin.mock.calls[0][0]; + + expect(mergedOptions).toEqual({ + _metaOptions: { + telemetry: { + metaFramework: 'sveltekit', + }, + }, + authToken: 'token', + org: 'org', + project: 'project', + adapter: 'other', + release: { + name: expect.any(String), + }, + sourcemaps: { + filesToDeleteAfterUpload: expect.any(Promise), + }, + }); + + const sourceMapSettingPlugin = plugins.find( + plugin => plugin.name === 'sentry-sveltekit-update-source-map-setting-plugin', + )!; + + // @ts-expect-error this function exists! + const sourceMapSettingConfig = await sourceMapSettingPlugin.config(viteConfig); + expect(sourceMapSettingConfig).toEqual({ build: { sourcemap: 'hidden' } }); + + const filesToDeleteAfterUploadSettingPlugin = plugins.find( + plugin => plugin.name === 'sentry-sveltekit-files-to-delete-after-upload-setting-plugin', + )!; + + // call this to ensure the filesToDeleteAfterUpload setting is resolved + // @ts-expect-error this function exists! + await filesToDeleteAfterUploadSettingPlugin.config(viteConfig); + + await expect(mergedOptions.sourcemaps.filesToDeleteAfterUpload).resolves.toEqual([ + './.*/**/*.map', + './.svelte-kit/output/**/*.map', + ]); + }); + + it.each([ + [['blub/'], undefined, 'hidden', ['blub/']], + [['blub/'], false, false, ['blub/']], + [undefined, 'hidden' as const, 'hidden', undefined], + [undefined, false, false, undefined], + [undefined, true, true, undefined], + [['/blub/'], true, true, ['/blub/']], + ])( + 'works with filesToDeleteAfterUpload: %j & sourcemap: %s', + async (filesToDeleteAfterUpload, sourcemap, sourcemapExpected, filesToDeleteAfterUploadExpected) => { + const viteConfig: ViteUserConfig = { + build: { + sourcemap, + }, + }; + + vi.mock('@sentry/vite-plugin', async () => { + const original = (await vi.importActual('@sentry/vite-plugin')) as any; + + return { + ...original, + sentryVitePlugin: vi.fn(original.sentryVitePlugin), + }; + }); + + const plugins = await makeCustomSentryVitePlugins({ + authToken: 'token', + org: 'org', + project: 'project', + adapter: 'other', + sourcemaps: { + filesToDeleteAfterUpload, + }, + }); + + // @ts-expect-error this function exists! + const mergedOptions = sentryVitePlugin.mock.calls[0][0]; + + expect(mergedOptions).toEqual({ + _metaOptions: { + telemetry: { + metaFramework: 'sveltekit', + }, + }, + authToken: 'token', + org: 'org', + project: 'project', + adapter: 'other', + release: { + name: expect.any(String), + }, + sourcemaps: { + filesToDeleteAfterUpload: expect.any(Promise), + }, }); + + const sourceMapSettingPlugin = plugins.find( + plugin => plugin.name === 'sentry-sveltekit-update-source-map-setting-plugin', + )!; + + // @ts-expect-error this function exists! + const sourceMapSettingConfig = await sourceMapSettingPlugin.config(viteConfig); + expect(sourceMapSettingConfig).toEqual({ build: { sourcemap: sourcemapExpected } }); + + const filesToDeleteAfterUploadSettingPlugin = plugins.find( + plugin => plugin.name === 'sentry-sveltekit-files-to-delete-after-upload-setting-plugin', + )!; + + // call this to ensure the filesToDeleteAfterUpload setting is resolved + // @ts-expect-error this function exists! + await filesToDeleteAfterUploadSettingPlugin.config(viteConfig); + + await expect(mergedOptions.sourcemaps.filesToDeleteAfterUpload).resolves.toEqual( + filesToDeleteAfterUploadExpected, + ); }, ); });