Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module.exports = {
'scripts/**',
'coverage/**',
'lib/Helper/test-fixtures/**',
'e2e-tests/test-applications/**',
],
extends: [
'eslint:recommended',
Expand All @@ -31,6 +32,7 @@ module.exports = {
overrides: [
{
files: [
'**/e2e-tests/utils/**/*.ts',
'*.test.js',
'*.test.ts',
'**/__tests__/**/*.ts',
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,20 @@ jobs:
run: yarn install --frozen-lockfile
- name: Run Unit Tests
run: yarn test

job_e2e_test:
name: End-to-End Tests
needs: job_build
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: 22
cache: 'yarn'
- name: Install dependencies with yarn
run: yarn install --frozen-lockfile
- name: Run End-to-End Tests
run: yarn test:e2e
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ yarn sentry-wizard
npx @sentry/wizard
```

At the current moment, the wizard is meant to be used for React Native, Cordova, Electron or Next.js. If you have other platforms you would like the wizard to support, please open a [GitHub issue](https://github.com/getsentry/sentry-wizard/issues)!
At the current moment, the wizard is meant to be used for React Native, Cordova, Electron, Next.js, Remix and Sveltekit. If you have other platforms you would like the wizard to support, please open a [GitHub issue](https://github.com/getsentry/sentry-wizard/issues)!

# Options

Expand Down
86 changes: 59 additions & 27 deletions bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,79 +21,111 @@ import { run } from './src/run';

export * from './lib/Setup';

const PRESELECTED_PROJECT_OPTIONS = {
'preSelectedProject.authToken': {
describe: 'Preselected project auth token',
},
'preSelectedProject.selfHosted': {
describe: 'Preselected project is self-hosted',
},
'preSelectedProject.dsn': {
describe: 'Preselected project DSN',
},
'preSelectedProject.id': {
describe: 'Preselected project id',
},
'preSelectedProject.projectSlug': {
describe: 'Preselected project slug',
},
'preSelectedProject.projectName': {
describe: 'Preselected project name',
},
'preSelectedProject.orgId': {
describe: 'Preselected organization id',
},
'preSelectedProject.orgName': {
describe: 'Preselected organization name',
},
'preSelectedProject.orgSlug': {
describe: 'Preselected organization slug',
},
};

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
const argv = yargs(hideBin(process.argv))
.option('debug', {
const argv = yargs(hideBin(process.argv)).options({
debug: {
default: false,
describe: 'Enable verbose logging\nenv: SENTRY_WIZARD_DEBUG',
type: 'boolean',
})
.option('uninstall', {
},
uninstall: {
default: false,
describe: 'Revert project setup process\nenv: SENTRY_WIZARD_UNINSTALL',
type: 'boolean',
})
.option('skip-connect', {
},
'skip-connect': {
default: false,
describe:
'Skips the connection to the server\nenv: SENTRY_WIZARD_SKIP_CONNECT',
type: 'boolean',
})
.option('quiet', {
},
quiet: {
default: false,
describe:
'Do not fallback to prompting user asking questions\nenv: SENTRY_WIZARD_QUIET',
type: 'boolean',
})
.option('i', {
},
i: {
alias: 'integration',
choices: Object.keys(Integration),
describe: 'Choose the integration to setup\nenv: SENTRY_WIZARD_INTEGRATION',
})
.option('p', {
},
p: {
alias: 'platform',
choices: Object.keys(Platform),
describe: 'Choose platform(s)\nenv: SENTRY_WIZARD_PLATFORM',
type: 'array',
})
.option('u', {
},
u: {
alias: 'url',
describe: 'The url to your Sentry installation\nenv: SENTRY_WIZARD_URL',
})
.option('project', {
},
project: {
type: 'string',
describe: 'The Sentry project slug to use',
defaultDescription: 'Select project during setup',
default: undefined,
})
.option('org', {
},
org: {
type: 'string',
describe: 'The Sentry org slug to use',
defaultDescription: 'Select org during setup',
default: undefined,
})
.option('saas', {
},
saas: {
default: false,
describe: 'Skip the self-hosted or SaaS URL selection process',
defaultDescription: 'Select self-hosted or SaaS during setup',
type: 'boolean',
})
.option('s', {
},
s: {
alias: 'signup',
default: false,
describe: 'Redirect to signup page if not logged in',
type: 'boolean',
})
.option('disable-telemetry', {
},
'disable-telemetry': {
default: false,
describe: "Don't send telemetry data to Sentry",
type: 'boolean',
})
.option('promo-code', {
},
'promo-code': {
alias: 'promo-code',
describe: 'A promo code that will be applied during signup',
type: 'string',
}).argv;
},
...PRESELECTED_PROJECT_OPTIONS,
}).argv;

// @ts-expect-error - for some reason TS doesn't recognize the aliases as valid properties
// meaning it only knows e.g. u but not url. Maybe a bug in this old version of yargs?
Expand Down
14 changes: 14 additions & 0 deletions e2e-tests/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default {
testTimeout: 360000,
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
globals: {
'ts-jest': {
tsconfig: 'tsconfig.json',
},
},
}
5 changes: 5 additions & 0 deletions e2e-tests/test-applications/remix-test-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules

/.cache
/build
.env
18 changes: 18 additions & 0 deletions e2e-tests/test-applications/remix-test-app/app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.client
*/

import { RemixBrowser } from "@remix-run/react";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";

startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>
);
});
140 changes: 140 additions & 0 deletions e2e-tests/test-applications/remix-test-app/app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.server
*/

import { PassThrough } from "node:stream";

import type { AppLoadContext, EntryContext } from "@remix-run/node";
import { createReadableStreamFromReadable } from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import { isbot } from "isbot";
import { renderToPipeableStream } from "react-dom/server";

const ABORT_DELAY = 5_000;

export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
// This is ignored so we can keep it in the template for visibility. Feel
// free to delete this parameter in your app if you're not using it!
// eslint-disable-next-line @typescript-eslint/no-unused-vars
loadContext: AppLoadContext
) {
return isbot(request.headers.get("user-agent") || "")
? handleBotRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
)
: handleBrowserRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
);
}

function handleBotRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
return new Promise((resolve, reject) => {
let shellRendered = false;
const { pipe, abort } = renderToPipeableStream(
<RemixServer
context={remixContext}
url={request.url}
abortDelay={ABORT_DELAY}
/>,
{
onAllReady() {
shellRendered = true;
const body = new PassThrough();
const stream = createReadableStreamFromReadable(body);

responseHeaders.set("Content-Type", "text/html");

resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
})
);

pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
}
);

setTimeout(abort, ABORT_DELAY);
});
}

function handleBrowserRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
return new Promise((resolve, reject) => {
let shellRendered = false;
const { pipe, abort } = renderToPipeableStream(
<RemixServer
context={remixContext}
url={request.url}
abortDelay={ABORT_DELAY}
/>,
{
onShellReady() {
shellRendered = true;
const body = new PassThrough();
const stream = createReadableStreamFromReadable(body);

responseHeaders.set("Content-Type", "text/html");

resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
})
);

pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
}
);

setTimeout(abort, ABORT_DELAY);
});
}
30 changes: 30 additions & 0 deletions e2e-tests/test-applications/remix-test-app/app/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
import "./tailwind.css";

export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}

export default function App() {
return <Outlet />;
}
Loading
Loading