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
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# build output
dist/

# generated types
.astro/

# dependencies
node_modules/

# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# environment variables
.env
.env.production

# macOS-specific files
.DS_Store

# jetbrains setting folder
.idea/

test-results
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@sentry:registry=http://127.0.0.1:4873
@sentry-internal:registry=http://127.0.0.1:4873
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import cloudflare from '@astrojs/cloudflare';
import sentry from '@sentry/astro';
// @ts-check
import { defineConfig } from 'astro/config';

// https://astro.build/config
export default defineConfig({
integrations: [
sentry({
debug: true,
sourceMapsUploadOptions: {
enabled: false,
},
}),
],
output: 'server',
adapter: cloudflare(),
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "astro-5-cf-workers",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "wrangler dev --port 3030",
"test:build": "pnpm install && pnpm build",
"test:assert": "TEST_ENV=production playwright test"
},
"dependencies": {
"@astrojs/cloudflare": "^12.6.12",
"@playwright/test": "~1.56.0",
"@sentry-internal/test-utils": "link:../../../test-utils",
"@sentry/astro": "latest || *",
"@sentry/cloudflare": "latest || *",
"astro": "^5.17.1"
},
"devDependencies": {
"wrangler": "^4.63.0"
},
"pnpm": {
"overrides": {
"esbuild": "0.24.0"
}
},
"volta": {
"extends": "../../package.json"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { getPlaywrightConfig } from '@sentry-internal/test-utils';

const testEnv = process.env.TEST_ENV;

if (!testEnv) {
throw new Error('No test env defined');
}

const config = getPlaywrightConfig({
startCommand: 'pnpm preview',
port: 3030,
});

export default config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as Sentry from '@sentry/astro';

Sentry.init({
dsn: import.meta.env.PUBLIC_E2E_TEST_DSN,
environment: 'qa',
tracesSampleRate: 1.0,
tunnel: 'http://localhost:3031/', // proxy server
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as Sentry from '@sentry/astro';

Sentry.init({
dsn: import.meta.env.PUBLIC_E2E_TEST_DSN,
environment: 'qa',
tracesSampleRate: 1.0,
tunnel: 'http://localhost:3031/', // proxy server
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { defineAction, ActionError } from 'astro:actions';
import { z } from 'astro:schema';

export const server = {
testAction: defineAction({
input: z.object({
name: z.string(),
shouldError: z.boolean().optional(),
}),
handler: async input => {
if (input.shouldError) {
throw new ActionError({
code: 'BAD_REQUEST',
message: 'Test Action Error',
});
}

return {
status: 'success',
name: input.name,
};
},
}),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>Astro Basics</title>
</head>
<body>
<slot />
</body>
</html>

<style>
html,
body {
margin: 0;
width: 100%;
height: 100%;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
import Layout from '../../layouts/Layout.astro';

export const prerender = false;
---

<Layout title="Action Test">
<h1>Action Test Page</h1>
<form id="test-form">
<input type="text" name="name" value="test" />
<button type="submit">Submit Action</button>
</form>
<div id="result"></div>

<script>
import { actions } from 'astro:actions';

const form = document.getElementById('test-form') as HTMLFormElement;
const result = document.getElementById('result') as HTMLDivElement;

form.addEventListener('submit', async e => {
e.preventDefault();
try {
const response = await actions.testAction({ name: 'test', shouldError: false });
result.textContent = JSON.stringify(response);
} catch (err) {
result.textContent = `Error: ${err}`;
}
});
</script>
</Layout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { APIRoute } from 'astro';

export const prerender = false;

export const GET: APIRoute = () => {
throw new Error('This is a test error from an API route');
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { APIRoute } from 'astro';

export const prerender = false;

export const GET: APIRoute = ({ request, url }) => {
if (url.searchParams.has('error')) {
throw new Error('Endpoint Error');
}
return new Response(
JSON.stringify({
search: url.search,
sp: url.searchParams,
}),
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
import Layout from '../../layouts/Layout.astro';

export const prerender = false;
---

<Layout title="Endpoint Error">
<button onclick="fetch('endpoint-error/api?error=1')">Get Data</button>
</Layout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
import Layout from '../layouts/Layout.astro';
---

<Layout title="Welcome to Astro.">
<main>
<h1>Astro CF Workers E2E Test App</h1>
<ul role="list" style="display: flex; flex-direction: column;">
<a href="/ssr-error">SSR Error</a>
<a href="/endpoint-error">Endpoint Error</a>
<a href="/action-test">Action Test</a>
<a href="/api/test-error">API Error</a>
</ul>
</main>
</Layout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
import Layout from '../../layouts/Layout.astro';

const a = {} as any;
console.log(a.foo.x);
export const prerender = false;
---

<Layout title="SSR Error">
<h1>Page with SSR error</h1>
</Layout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { startEventProxyServer } from '@sentry-internal/test-utils';

startEventProxyServer({
port: 3031,
proxyServerName: 'astro-5-cf-workers',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { expect, test } from '@playwright/test';
import { waitForTransaction } from '@sentry-internal/test-utils';

test.describe('Astro actions', () => {
test('captures transaction for action call', async ({ page }) => {
const transactionEventPromise = waitForTransaction('astro-5-cf-workers', transactionEvent => {
return transactionEvent.transaction === 'GET /action-test';
});

await page.goto('/action-test');

const transactionEvent = await transactionEventPromise;

expect(transactionEvent).toMatchObject({
transaction: 'GET /action-test',
});

const traceId = transactionEvent.contexts?.trace?.trace_id;
expect(traceId).toMatch(/[a-f0-9]{32}/);
});

test('action submission creates a transaction', async ({ page }) => {
await page.goto('/action-test');

const transactionEventPromise = waitForTransaction('astro-5-cf-workers', transactionEvent => {
return (
transactionEvent.transaction?.includes('action-test') && transactionEvent.transaction !== 'GET /action-test'
);
});

await page.getByText('Submit Action').click();

// Wait for the result to appear on the page
await page.waitForSelector('#result:not(:empty)');

const resultText = await page.locator('#result').textContent();
expect(resultText).toContain('success');

const transactionEvent = await transactionEventPromise;
expect(transactionEvent).toBeDefined();
expect(transactionEvent.contexts?.trace?.trace_id).toMatch(/[a-f0-9]{32}/);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { expect, test } from '@playwright/test';
import { waitForError } from '@sentry-internal/test-utils';

test.describe('Cloudflare Runtime', () => {
test('Should report cloudflare as the runtime in SSR error events', async ({ page }) => {
const errorEventPromise = waitForError('astro-5-cf-workers', errorEvent => {
return errorEvent?.exception?.values?.[0]?.value === "Cannot read properties of undefined (reading 'x')";
});

await page.goto('/ssr-error').catch(() => {
// Expected to fail with net::ERR_HTTP_RESPONSE_CODE_FAILURE
});

const errorEvent = await errorEventPromise;

expect(errorEvent.contexts?.runtime).toEqual({
name: 'cloudflare',
});

// The SDK info should include cloudflare in the packages
expect(errorEvent.sdk?.packages).toEqual(
expect.arrayContaining([
expect.objectContaining({
name: 'npm:@sentry/cloudflare',
}),
]),
);
});

test('Should report cloudflare as the runtime in API route error events', async ({ request }) => {
const errorEventPromise = waitForError('astro-5-cf-workers', errorEvent => {
return !!errorEvent?.exception?.values?.some(value =>
value.value?.includes('This is a test error from an API route'),
);
});

request.get('/api/test-error').catch(() => {
// Expected to fail
});

const errorEvent = await errorEventPromise;

expect(errorEvent.contexts?.runtime).toEqual({
name: 'cloudflare',
});

expect(errorEvent.sdk?.packages).toEqual(
expect.arrayContaining([
expect.objectContaining({
name: 'npm:@sentry/cloudflare',
}),
]),
);
});
});
Loading
Loading