Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(e2e): Add behaviour test for Transactions in standard React E2E tests application #5912

Merged
4 changes: 4 additions & 0 deletions packages/e2e-tests/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ const recipeResults: RecipeResult[] = recipePaths.map(recipePath => {
cwd: path.dirname(recipePath),
timeout: (test.timeoutSeconds ?? DEFAULT_TEST_TIMEOUT_SECONDS) * 1000,
encoding: 'utf8',
env: {
...process.env,
E2E_TEST_AUTH_TOKEN: authToken,
},
shell: true, // needed so we can pass the test command in as whole without splitting it up into args
env: {
...process.env,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ yarn-error.log*
/playwright/.cache/

!*.d.ts
/test-results/
/playwright-report/
/playwright/.cache/
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,94 @@ test('Sends an exception to Sentry', async ({ page }) => {
}
}
});

test('Sends a pageload transaction to Sentry', async ({ page }) => {
await page.goto('/');

const recordedTransactionsHandle = await page.waitForFunction(() => {
if (window.recordedTransactions && window.recordedTransactions?.length >= 1) {
return window.recordedTransactions;
} else {
return undefined;
}
});
const recordedTransactionEventIds = (await recordedTransactionsHandle.jsonValue()) as string[];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Why is the type assertion needed? Shouldn’t we handled the other case here?


const timeout = setTimeout(() => {
throw new Error('Timeout reached while polling events.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: let’s make this a util that (timeout + fetch):

  • handles a timeout for polling
  • allows for a hardcoded retry amount
  • throws an error when 500s are returned

We can also do this in a follow up PR, since we are consolidating with the errors tests.

}, EVENT_POLLING_TIMEOUT);

let hadPageLoadTransaction = false;

await Promise.all(
recordedTransactionEventIds.map(async (transactionEventId, i) => {
while (true) {
try {
const response = await axios.get(
`https://sentry.io/api/0/projects/${SENTRY_TEST_ORG_SLUG}/${SENTRY_TEST_PROJECT}/events/${transactionEventId}/`,
{ headers: { Authorization: `Bearer ${authToken}` } },
);
expect(response?.status).toBe(200);
if (response.data.contexts.trace.op === 'pageload') {
hadPageLoadTransaction = true;
}
break;
} catch (e) {
await new Promise(resolve => setTimeout(resolve, EVENT_POLLING_RETRY_INTERVAL));
}
}
}),
);

clearTimeout(timeout);

expect(hadPageLoadTransaction).toBe(true);
});

test.only('Sends a navigation transaction to Sentry', async ({ page }) => {
await page.goto('/');

// Give pageload transaction time to finish
page.waitForTimeout(4000);

const linkElement = page.locator('id=navigation');
await linkElement.click();

const recordedTransactionsHandle = await page.waitForFunction(() => {
if (window.recordedTransactions && window.recordedTransactions?.length >= 2) {
return window.recordedTransactions;
} else {
return undefined;
}
});
const recordedTransactionEventIds = (await recordedTransactionsHandle.jsonValue()) as string[];

const timeout = setTimeout(() => {
throw new Error('Timeout reached while polling events.');
}, EVENT_POLLING_TIMEOUT);

let hadPageNavigationTransaction = false;

await Promise.all(
recordedTransactionEventIds.map(async (transactionEventId, i) => {
while (true) {
try {
const response = await axios.get(
`https://sentry.io/api/0/projects/${SENTRY_TEST_ORG_SLUG}/${SENTRY_TEST_PROJECT}/events/${transactionEventId}/`,
{ headers: { Authorization: `Bearer ${authToken}` } },
);
expect(response?.status).toBe(200);
if (response.data.contexts.trace.op === 'pageload') {
hadPageNavigationTransaction = true;
}
break;
} catch (e) {
await new Promise(resolve => setTimeout(resolve, EVENT_POLLING_RETRY_INTERVAL));
}
}
}),
);

clearTimeout(timeout);
expect(hadPageNavigationTransaction).toBe(true);
});
32 changes: 32 additions & 0 deletions packages/e2e-tests/validate-auth-token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable no-console */
import * as fs from 'fs';
import * as path from 'path';

if (!process.env.E2E_TEST_AUTH_TOKEN) {
const authTokenPath = path.resolve(__dirname, 'auth-token.json');
AbhiPrasad marked this conversation as resolved.
Show resolved Hide resolved
const authTokenHint = "Put your auth token with scope 'project:read' here!";

if (!fs.existsSync(authTokenPath)) {
fs.writeFileSync(authTokenPath, JSON.stringify({ authToken: authTokenHint }, null, 2));
console.log(
'No auth token configured for E2E tests! Please set the E2E_TEST_AUTH_TOKEN environment variable or put your auth token in "auth-token.json"!',
);

process.exit(1);
}

let authTokenJson;
try {
authTokenJson = require(authTokenPath);
} catch (e) {
console.log('Failed to read auth-token.json!');
process.exit(1);
}

const { authToken } = authTokenJson;

if (!authToken || authToken === authTokenHint) {
console.log('No auth token configured in auth-token.json!');
process.exit(1);
}
}