Skip to content
Open
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
28 changes: 28 additions & 0 deletions packages/cloudflare/test/executionContext.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { ExecutionContext } from '@cloudflare/workers-types';
import { describe, expectTypeOf, it } from 'vitest';
import type { ExecutionContextCompat } from '../src/executionContext';

// The shape of `ExecutionContext` in `@cloudflare/workers-types` v4, which has no `exports` and an optional `tracing`.
interface ExecutionContextV4 {
waitUntil(promise: Promise<unknown>): void;
passThroughOnException(): void;
readonly props: unknown;
}

describe('ExecutionContextCompat', () => {
it('accepts a v5 ExecutionContext', () => {
expectTypeOf<ExecutionContext>().toExtend<ExecutionContextCompat>();
});

it('accepts a v4 ExecutionContext without the members v5 made required', () => {
expectTypeOf<ExecutionContextV4>().toExtend<ExecutionContextCompat>();
});

it('rejects a context without waitUntil', () => {
expectTypeOf<Omit<ExecutionContextV4, 'waitUntil'>>().not.toExtend<ExecutionContextCompat>();
});

it('exposes waitUntil from both majors', () => {
expectTypeOf<ExecutionContextCompat['waitUntil']>().toEqualTypeOf<ExecutionContext['waitUntil']>();
});
});
73 changes: 73 additions & 0 deletions packages/cloudflare/test/withSentry.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type { ExecutionContext } from '@cloudflare/workers-types';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { withSentry } from '../src/withSentry';
import { resetSdk } from './testUtils';

const MOCK_ENV = {
SENTRY_DSN: 'https://public@dsn.ingest.sentry.io/1337',
};

function createMockExecutionContext(): ExecutionContext {
return {
waitUntil: vi.fn(),
passThroughOnException: vi.fn(),
props: {},
} as unknown as ExecutionContext;
}

class WorkerEntrypoint {
public constructor(
public ctx: ExecutionContext,
public env: unknown,
) {}
}

describe('withSentry', () => {
afterEach(() => {
vi.restoreAllMocks();
resetSdk();
});

it('returns the same handler object with its methods wrapped', () => {
const fetch = vi.fn();
const handler = { fetch };

const wrapped = withSentry(() => ({}), handler);

expect(wrapped).toBe(handler);
expect(wrapped.fetch).not.toBe(fetch);
});

it('instruments a WorkerEntrypoint class instead of treating it as a handler object', () => {
class MyEntrypoint extends WorkerEntrypoint {
public ping(): string {
return 'pong';
}
}

const optionsCallback = vi.fn().mockReturnValue({ dsn: MOCK_ENV.SENTRY_DSN });
const context = createMockExecutionContext();

const Wrapped = withSentry(optionsCallback, MyEntrypoint as never) as unknown as typeof MyEntrypoint;
const instance = new Wrapped(context, MOCK_ENV);

expect(Wrapped).not.toBe(MyEntrypoint);
expect(optionsCallback).toHaveBeenCalledWith(MOCK_ENV);
expect(instance).toBeInstanceOf(MyEntrypoint);
expect(instance.ctx).not.toBe(context);
expect(instance.ping()).toBe('pong');
});

it('returns a handler it cannot instrument unchanged instead of throwing', () => {
const fetch = vi.fn();
const handler = Object.freeze({ fetch });

let wrapped: typeof handler | undefined;
expect(() => {
wrapped = withSentry(() => ({}), handler);
}).not.toThrow();

expect(wrapped).toBe(handler);
expect(wrapped?.fetch).toBe(fetch);
});
});
Loading