Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,10 @@ Use `abortIfCancelled()` wrapper for all Clack prompts to handle Ctrl+C graceful

- `test-applications/`: Complete framework apps for testing
- `tests/`: Test files that run wizard against test apps
- `utils/`: Test helpers including `WizardTestEnv` class
- `utils/`: Test helpers including assertion functions for reusable checks (e.g. `checkIfBuilds`)
- Requires `.env` file with Sentry credentials
- Use `yarn test:e2e [framework]` to run specific framework tests
- Use `clifty` to define wizard run and interactions

## Special Considerations

Expand Down
79 changes: 64 additions & 15 deletions e2e-tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,8 @@ modifiers that can be used in (`*.test.ts`).

#### Helpers

- `startWizardInstance` - Starts a new instance of `WizardTestEnv`.

- `initGit` - Initializes a temporary git repository in the test project.
- `cleanupGit` - Cleans up the temporary git repository in the test project.
- `revertLocalChanges` - Reverts local changes (git tracked or untracked) in the
test project.
- `createIsolatedTestEnv` - creates a new isolated test env by copying the test app to a temporary directory.
Also initializes git in the tmp dir

- `createFile` - Creates a file (optionally with content) in the test project.
- `modifyFile` - Modifies a file in the test project.
Expand All @@ -61,12 +57,6 @@ modifiers that can be used in (`*.test.ts`).
- `checkSentryProperties` - Checks if the Flutter `sentry.properties` file
contains the auth token

#### `WizardTestEnv`

`WizardTestEnv` is a class that can be used to run the Sentry Wizard in a test
environment. It provides methods to run the wizard with specific arguments and
stdio.

## Running Tests Locally

First, you need to create a `.env` file set the environment variables from the
Expand All @@ -82,6 +72,65 @@ To run a specific test application

## Writing Tests

Each test file should contain a single test suite that tests the Sentry Wizard
for a specific framework. The test suite should contain a `beforeAll` and
`afterAll` function that starts and stops the test application respectively.
Each test file should test the Sentry Wizard for a specific framework and project.

The test suite may contain multiple wizard runs but for consistency, each scenario must be
isolated via `createIsolatedTestEnv`. You can most easily do this by using a `describe` block
per wizard run.

For every `describe` block, isolate the test, run the wizard in `beforeAll`, `test` what you
want to test and clean up the tmp dir in `afterAll`:

```ts
describe('no sentry files present', () => {
const {projectDir, cleanup} = createIsolatedTestEnv();

beforeAll(() => {
await runWizard(projectDir);
});

afterAll(() => {
cleanup()
})
})

describe('with sentry files present', () => {
const {projectDir, cleanup} = createIsolatedTestEnv();

beforeAll(() => {
addSentryFiles(projectDir);
await runWizard(projectDir);
});

afterAll(() => {
cleanup()
})
})
```

### Running the wizard

To define how a wizard run should look like (i.e. which responses the "user" makes) on
wizard prompots, use `clifty`. Clifty's `run` method starts a new process to run the wizard
with the predefined interaction and returns the processe's exit code.
You can use this to check for a successful wizard run.

```ts
import { KEYS, withEnv } from 'clifty';

const wizardExitCode = await withEnv({
cwd: projectDir,
})
.defineInteraction()
.whenAsked('Do you want to enable Tracing')
.respondWith(KEYS.ENTER)
.expectOutput('Added Sentry code to sentry.client.ts')
.run(getWizardCommand(Integrations.nextjs));

// ...

test('wizard ran successfully', () => {
expect(wizardExitCode).toBe(0);
})
```

2 changes: 1 addition & 1 deletion e2e-tests/tests/angular-17.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ function checkAngularProject(
},
) {
test('package.json is updated correctly', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/angular');

const packageJsonFile = path.resolve(projectDir, 'package.json');
checkFileContents(packageJsonFile, [
Expand Down
2 changes: 1 addition & 1 deletion e2e-tests/tests/angular-19.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ function checkAngularProject(
},
) {
test('package.json is updated correctly', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/angular');

const packageJsonFile = path.resolve(projectDir, 'package.json');
checkFileContents(packageJsonFile, [
Expand Down
3 changes: 1 addition & 2 deletions e2e-tests/tests/cloudflare-worker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ describe('cloudflare-worker', () => {
const { projectDir, cleanup } = createIsolatedTestEnv('cloudflare-test-app');

beforeAll(async () => {

// Capture the date before running the wizard (wizard runs in subprocess)
expectedCompatibilityDate = new Date().toISOString().slice(0, 10);

Expand Down Expand Up @@ -61,7 +60,7 @@ describe('cloudflare-worker', () => {
});

it('adds the SDK dependency to package.json', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/cloudflare');
});

it('builds correctly', async () => {
Expand Down
2 changes: 1 addition & 1 deletion e2e-tests/tests/nextjs-14.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ describe('NextJS-14', () => {
});

test('package.json is updated correctly', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/nextjs');
});

test('.env-sentry-build-plugin is created and contains the auth token', () => {
Expand Down
14 changes: 8 additions & 6 deletions e2e-tests/tests/nextjs-15.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
checkIfRunsOnProdMode,
checkPackageJson,
getWizardCommand,
initGit,
} from '../utils';
import { describe, beforeAll, afterAll, test, expect } from 'vitest';

Expand Down Expand Up @@ -72,7 +71,7 @@ describe('NextJS-15', () => {
});

test('package.json is updated correctly', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/nextjs');
});

test('.env-sentry-build-plugin is created and contains the auth token', () => {
Expand Down Expand Up @@ -146,13 +145,12 @@ export const onRequestError = Sentry.captureRequestError;`,

describe('NextJS-15 Spotlight', () => {
const integration = Integration.nextjs;
let wizardExitCode: number;

const { projectDir, cleanup } = createIsolatedTestEnv('nextjs-15-test-app');

beforeAll(async () => {
initGit(projectDir);

await withEnv({
wizardExitCode = await withEnv({
cwd: projectDir,
})
.defineInteraction()
Expand Down Expand Up @@ -189,8 +187,12 @@ describe('NextJS-15 Spotlight', () => {
cleanup();
});

test('exits with exit code 0', () => {
expect(wizardExitCode).toBe(0);
});

test('package.json is updated correctly', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/nextjs');
});

test('.env-sentry-build-plugin should NOT exist in spotlight mode', () => {
Expand Down
7 changes: 1 addition & 6 deletions e2e-tests/tests/nextjs-16.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import {
checkPackageJson,
createIsolatedTestEnv,
getWizardCommand,
initGit,
revertLocalChanges,
} from '../utils';
import { describe, beforeAll, afterAll, test, expect } from 'vitest';

Expand All @@ -23,9 +21,6 @@ describe('NextJS-16 with Prettier, Biome, and ESLint', () => {
const { projectDir, cleanup } = createIsolatedTestEnv('nextjs-16-test-app');

beforeAll(async () => {
initGit(projectDir);
revertLocalChanges(projectDir);

wizardExitCode = await withEnv({
cwd: projectDir,
})
Expand Down Expand Up @@ -75,7 +70,7 @@ describe('NextJS-16 with Prettier, Biome, and ESLint', () => {
});

test('package.json is updated correctly', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/nextjs');
});

test('config files created', () => {
Expand Down
2 changes: 1 addition & 1 deletion e2e-tests/tests/nuxt-3.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('Nuxt-3', () => {
});

test('package.json is updated correctly', () => {
checkPackageJson(projectDir, Integration.nuxt);
checkPackageJson(projectDir, '@sentry/nuxt');
});

test('.env-sentry-build-plugin is created and contains the auth token', () => {
Expand Down
2 changes: 1 addition & 1 deletion e2e-tests/tests/nuxt-4.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('Nuxt-4', () => {
});

test('package.json is updated correctly', () => {
checkPackageJson(projectDir, Integration.nuxt);
checkPackageJson(projectDir, '@sentry/nuxt');
});

test('.env-sentry-build-plugin is created and contains the auth token', () => {
Expand Down
7 changes: 4 additions & 3 deletions e2e-tests/tests/pnpm-workspace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ describe('pnpm workspace', () => {
const integration = Integration.sveltekit;
let wizardExitCode: number;

const { projectDir: workspaceDir, cleanup } = createIsolatedTestEnv('pnpm-workspace-test-app');
const { projectDir: workspaceDir, cleanup } = createIsolatedTestEnv(
'pnpm-workspace-test-app',
);
const projectDir = path.resolve(workspaceDir, 'packages/sveltekit');

beforeAll(async () => {

wizardExitCode = await withEnv({
cwd: projectDir,
})
Expand Down Expand Up @@ -70,7 +71,7 @@ describe('pnpm workspace', () => {
});

it('adds the SDK dependency to package.json', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/sveltekit');
});

it('adds the .env.sentry-build-plugin', () => {
Expand Down
6 changes: 3 additions & 3 deletions e2e-tests/tests/react-router.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ describe('React Router', () => {
});

test('package.json is updated correctly', () => {
checkPackageJson(projectDir, Integration.reactRouter);
checkPackageJson(projectDir, '@sentry/react-router');
});

test('.env.sentry-build-plugin is created and contains the auth token', () => {
Expand Down Expand Up @@ -267,7 +267,7 @@ startTransition(() => {

// Only test the essential checks for this edge case
test('package.json is updated correctly', () => {
checkPackageJson(projectDir, Integration.reactRouter);
checkPackageJson(projectDir, '@sentry/react-router');
});

test('essential files exist or wizard completes gracefully', () => {
Expand Down Expand Up @@ -336,7 +336,7 @@ startTransition(() => {
});

test('basic configuration still works', () => {
checkPackageJson(projectDir, Integration.reactRouter);
checkPackageJson(projectDir, '@sentry/react-router');
checkFileExists(`${projectDir}/instrument.server.mjs`);
});
});
Expand Down
4 changes: 2 additions & 2 deletions e2e-tests/tests/remix.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ describe('Remix', () => {
});

test('package.json is updated correctly', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/remix');
});

test('.env-sentry-build-plugin is created and contains the auth token', () => {
Expand Down Expand Up @@ -241,7 +241,7 @@ describe('Remix', () => {
});

test('package.json is updated correctly', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/remix');
});

test('.env-sentry-build-plugin is created and contains the auth token', () => {
Expand Down
14 changes: 8 additions & 6 deletions e2e-tests/tests/sveltekit-hooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ describe.sequential('Sveltekit', () => {
describe('without existing hooks', () => {
const integration = Integration.sveltekit;

const { projectDir, cleanup } = createIsolatedTestEnv('sveltekit-hooks-test-app');
const { projectDir, cleanup } = createIsolatedTestEnv(
'sveltekit-hooks-test-app',
);

beforeAll(async () => {

await runWizardOnSvelteKitProject(projectDir, integration);
});

Expand All @@ -57,7 +58,7 @@ describe.sequential('Sveltekit', () => {
});

test('has the correct package.json', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/sveltekit');
});

test('has the correct .env.sentry-build-plugin', () => {
Expand Down Expand Up @@ -159,10 +160,11 @@ describe.sequential('Sveltekit', () => {
describe('with existing hooks', () => {
const integration = Integration.sveltekit;

const { projectDir, cleanup } = createIsolatedTestEnv('sveltekit-hooks-test-app');
const { projectDir, cleanup } = createIsolatedTestEnv(
'sveltekit-hooks-test-app',
);

beforeAll(async () => {

await runWizardOnSvelteKitProject(
projectDir,
integration,
Expand All @@ -185,7 +187,7 @@ describe.sequential('Sveltekit', () => {
});

test('has the correct package.json', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/sveltekit');
});

test('has the correct .env.sentry-build-plugin', () => {
Expand Down
7 changes: 4 additions & 3 deletions e2e-tests/tests/sveltekit-tracing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ describe('Sveltekit with instrumentation and tracing', () => {
const integration = Integration.sveltekit;
let wizardExitCode: number;

const { projectDir, cleanup } = createIsolatedTestEnv('sveltekit-tracing-test-app');
const { projectDir, cleanup } = createIsolatedTestEnv(
'sveltekit-tracing-test-app',
);

beforeAll(async () => {

wizardExitCode = await withEnv({
cwd: projectDir,
})
Expand Down Expand Up @@ -69,7 +70,7 @@ describe('Sveltekit with instrumentation and tracing', () => {
});

it('adds the SDK dependency to package.json', () => {
checkPackageJson(projectDir, integration);
checkPackageJson(projectDir, '@sentry/sveltekit');
});

it('adds the .env.sentry-build-plugin', () => {
Expand Down
Loading
Loading