UNPKG

@sentry/wizard

Version:

Sentry wizard helping you to configure your project

265 lines (253 loc) 11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const Constants_1 = require("../../lib/Constants"); const utils_1 = require("../utils"); const vitest_1 = require("vitest"); //@ts-expect-error - clifty is ESM only const clifty_1 = require("clifty"); const SERVER_TEMPLATE = `import { createRequestHandler } from '@remix-run/express'; import { installGlobals } from '@remix-run/node'; import compression from 'compression'; import express from 'express'; import morgan from 'morgan'; installGlobals(); const viteDevServer = process.env.NODE_ENV === 'production' ? undefined : await import('vite').then(vite => vite.createServer({ server: { middlewareMode: true }, }), ); const app = express(); app.use(compression()); app.disable('x-powered-by'); if (viteDevServer) { app.use(viteDevServer.middlewares); } else { app.use('/assets', express.static('build/client/assets', { immutable: true, maxAge: '1y' })); } app.use(express.static('build/client', { maxAge: '1h' })); app.use(morgan('tiny')); app.all( '*', createRequestHandler({ build: viteDevServer ? () => viteDevServer.ssrLoadModule('virtual:remix/server-build') : await import('./build/server/index.js'), }), ); app.listen(0, () => console.log('Express server listening')); `; async function runWizardOnRemixProject(projectDir, integration, fileModificationFn) { const wizardInteraction = (0, clifty_1.withEnv)({ cwd: projectDir, }).defineInteraction(); if (fileModificationFn) { fileModificationFn(projectDir, integration); wizardInteraction .whenAsked('Do you want to continue anyway?') .respondWith(clifty_1.KEYS.ENTER); } return wizardInteraction .whenAsked('Please select your package manager.') .respondWith(clifty_1.KEYS.DOWN, clifty_1.KEYS.ENTER) .whenAsked('to track the performance of your application?', { timeout: 240000, // package installation can take a while in CI }) .respondWith(clifty_1.KEYS.ENTER) .whenAsked('to get a video-like reproduction of errors during a user session?') .respondWith(clifty_1.KEYS.ENTER) .whenAsked('to send your application logs to Sentry?') .respondWith(clifty_1.KEYS.ENTER) .whenAsked('Do you want to create an example page') .respondWith(clifty_1.KEYS.ENTER) .whenAsked('Optionally add a project-scoped MCP server configuration for the Sentry MCP?') .respondWith(clifty_1.KEYS.DOWN, clifty_1.KEYS.ENTER) .expectOutput('Sentry has been successfully configured for your Remix project') .run((0, utils_1.getWizardCommand)(integration)); } (0, vitest_1.describe)('Remix', () => { (0, vitest_1.describe)('with empty project', () => { const integration = Constants_1.Integration.remix; let wizardExitCode; const { projectDir, cleanup } = (0, utils_1.createIsolatedTestEnv)('remix-test-app'); (0, vitest_1.beforeAll)(async () => { wizardExitCode = await runWizardOnRemixProject(projectDir, integration); }); (0, vitest_1.afterAll)(() => { cleanup(); }); (0, vitest_1.test)('exits with exit code 0', () => { (0, vitest_1.expect)(wizardExitCode).toBe(0); }); (0, vitest_1.test)('package.json is updated correctly', () => { (0, utils_1.checkPackageJson)(projectDir, '@sentry/remix'); }); (0, vitest_1.test)('.env-sentry-build-plugin is created and contains the auth token', () => { (0, utils_1.checkEnvBuildPlugin)(projectDir); }); (0, vitest_1.test)('example page exists', () => { (0, utils_1.checkFileExists)(`${projectDir}/app/routes/sentry-example-page.tsx`); }); (0, vitest_1.test)('instrumentation.server file exists', () => { (0, utils_1.checkFileExists)(`${projectDir}/instrumentation.server.mjs`); }); (0, vitest_1.test)('entry.client file contains Sentry initialization', () => { (0, utils_1.checkFileContents)(`${projectDir}/app/entry.client.tsx`, [ 'import { init, replayIntegration, browserTracingIntegration } from "@sentry/remix";', `init({ dsn: "${utils_1.TEST_ARGS.PROJECT_DSN}", tracesSampleRate: 1, enableLogs: true, integrations: [browserTracingIntegration({ useEffect, useLocation, useMatches }), replayIntegration({ maskAllText: true, blockAllMedia: true })], replaysSessionSampleRate: 0.1, replaysOnErrorSampleRate: 1, sendDefaultPii: true })`, ]); }); (0, vitest_1.test)('entry.server file contains Sentry code', () => { (0, utils_1.checkFileContents)(`${projectDir}/app/entry.server.tsx`, [ 'import * as Sentry from "@sentry/remix";', `export const handleError = Sentry.wrapHandleErrorWithSentry((error, { request }) => { // Custom handleError implementation });`, ]); }); (0, vitest_1.test)('instrumentation.server file contains Sentry initialization', () => { (0, utils_1.checkFileContents)(`${projectDir}/instrumentation.server.mjs`, [ 'import * as Sentry from "@sentry/remix";', `Sentry.init({ dsn: "${utils_1.TEST_ARGS.PROJECT_DSN}", tracesSampleRate: 1, enableLogs: true })`, ]); }); (0, vitest_1.test)('root file contains Sentry ErrorBoundary and withSentry wrapper', () => { (0, utils_1.checkFileContents)(`${projectDir}/app/root.tsx`, [ 'import { captureRemixErrorBoundaryError, withSentry } from "@sentry/remix";', `export const ErrorBoundary = () => { const error = useRouteError(); captureRemixErrorBoundaryError(error); return <div>Something went wrong</div>; };`, `export default withSentry(App);`, ]); }); (0, vitest_1.test)('builds successfully', async () => { await (0, utils_1.checkIfBuilds)(projectDir); }); (0, vitest_1.test)('runs on dev mode correctly', async () => { await (0, utils_1.checkIfRunsOnDevMode)(projectDir, 'to expose'); }); (0, vitest_1.test)('runs on prod mode correctly', async () => { await (0, utils_1.checkIfRunsOnProdMode)(projectDir, '[remix-serve]'); }); }); (0, vitest_1.describe)('with existing custom Express server', () => { const integration = Constants_1.Integration.remix; let wizardExitCode; const { projectDir, cleanup } = (0, utils_1.createIsolatedTestEnv)('remix-test-app'); (0, vitest_1.beforeAll)(async () => { wizardExitCode = await runWizardOnRemixProject(projectDir, integration, (projectDir) => { (0, utils_1.createFile)(`${projectDir}/server.mjs`, SERVER_TEMPLATE); (0, utils_1.modifyFile)(`${projectDir}/package.json`, { '"start": "remix-serve ./build/server/index.js"': '"start": "node ./server.mjs"', '"dev": "remix vite:dev"': '"dev": "node ./server.mjs"', }); }); }); (0, vitest_1.afterAll)(() => { cleanup(); }); (0, vitest_1.test)('exits with exit code 0', () => { (0, vitest_1.expect)(wizardExitCode).toBe(0); }); (0, vitest_1.test)('package.json is updated correctly', () => { (0, utils_1.checkPackageJson)(projectDir, '@sentry/remix'); }); (0, vitest_1.test)('.env-sentry-build-plugin is created and contains the auth token', () => { (0, utils_1.checkEnvBuildPlugin)(projectDir); }); (0, vitest_1.test)('example page exists', () => { (0, utils_1.checkFileExists)(`${projectDir}/app/routes/sentry-example-page.tsx`); }); (0, vitest_1.test)('instrumentation.server file exists', () => { (0, utils_1.checkFileExists)(`${projectDir}/instrumentation.server.mjs`); }); (0, vitest_1.test)('entry.client file contains Sentry initialization', () => { (0, utils_1.checkFileContents)(`${projectDir}/app/entry.client.tsx`, [ 'import { init, replayIntegration, browserTracingIntegration } from "@sentry/remix";', `init({ dsn: "${utils_1.TEST_ARGS.PROJECT_DSN}", tracesSampleRate: 1, enableLogs: true, integrations: [browserTracingIntegration({ useEffect, useLocation, useMatches }), replayIntegration({ maskAllText: true, blockAllMedia: true })], replaysSessionSampleRate: 0.1, replaysOnErrorSampleRate: 1, sendDefaultPii: true })`, ]); }); (0, vitest_1.test)('entry.server file contains Sentry code', () => { (0, utils_1.checkFileContents)(`${projectDir}/app/entry.server.tsx`, [ 'import * as Sentry from "@sentry/remix";', `export const handleError = Sentry.wrapHandleErrorWithSentry((error, { request }) => { // Custom handleError implementation });`, ]); }); (0, vitest_1.test)('instrumentation.server file contains Sentry initialization', () => { (0, utils_1.checkFileContents)(`${projectDir}/instrumentation.server.mjs`, [ 'import * as Sentry from "@sentry/remix";', `Sentry.init({ dsn: "${utils_1.TEST_ARGS.PROJECT_DSN}", tracesSampleRate: 1, enableLogs: true })`, ]); }); (0, vitest_1.test)('root file contains Sentry ErrorBoundary and withSentry wrapper', () => { (0, utils_1.checkFileContents)(`${projectDir}/app/root.tsx`, [ 'import { captureRemixErrorBoundaryError, withSentry } from "@sentry/remix";', `export const ErrorBoundary = () => { const error = useRouteError(); captureRemixErrorBoundaryError(error); return <div>Something went wrong</div>; };`, `export default withSentry(App);`, ]); }); (0, vitest_1.test)('builds successfully', async () => { await (0, utils_1.checkIfBuilds)(projectDir); }); (0, vitest_1.test)('runs on dev mode correctly', async () => { await (0, utils_1.checkIfRunsOnDevMode)(projectDir, 'Express server listening'); }); (0, vitest_1.test)('runs on prod mode correctly', async () => { await (0, utils_1.checkIfRunsOnProdMode)(projectDir, 'Express server listening'); }); (0, vitest_1.test)('server.mjs contains instrumentation file import', () => { (0, utils_1.checkFileContents)(`${projectDir}/server.mjs`, [ "import './instrumentation.server.mjs';", ]); }); }); }); //# sourceMappingURL=remix.test.js.map