From 9ca54043b6c246e4be66808b344849dd5780f191 Mon Sep 17 00:00:00 2001 From: Tobias Lins Date: Thu, 25 Jan 2024 11:55:25 +0100 Subject: [PATCH] Fix tests --- apps/nextjs/app/blog/[slug]/page.tsx | 4 + apps/nextjs/app/layout.tsx | 2 +- apps/nextjs/components/withAnalytics.tsx | 25 ------ .../nextjs/e2e/development/beforeSend.spec.ts | 7 +- apps/nextjs/e2e/development/pageview.spec.ts | 12 ++- apps/nextjs/e2e/production/pageview.spec.ts | 80 +++++++++++++++++++ apps/nextjs/e2e/utils.ts | 7 +- apps/nextjs/pages/before-send/first.tsx | 14 +--- apps/nextjs/pages/before-send/second.tsx | 2 - apps/nextjs/pages/navigation/first.tsx | 1 - apps/nextjs/pages/navigation/second.tsx | 2 - packages/web/src/generic.ts | 13 ++- packages/web/src/types.ts | 2 + 13 files changed, 118 insertions(+), 53 deletions(-) delete mode 100644 apps/nextjs/components/withAnalytics.tsx diff --git a/apps/nextjs/app/blog/[slug]/page.tsx b/apps/nextjs/app/blog/[slug]/page.tsx index a4e438d..96e007a 100644 --- a/apps/nextjs/app/blog/[slug]/page.tsx +++ b/apps/nextjs/app/blog/[slug]/page.tsx @@ -1,7 +1,11 @@ +import Link from 'next/link'; + export default function BlogPage({ params }: { params: { slug: string } }) { return (

{params.slug}

+ + Back to blog
); } diff --git a/apps/nextjs/app/layout.tsx b/apps/nextjs/app/layout.tsx index 2aaf10b..66bc35c 100644 --- a/apps/nextjs/app/layout.tsx +++ b/apps/nextjs/app/layout.tsx @@ -13,7 +13,7 @@ export default function RootLayout({ return ( - + {children} diff --git a/apps/nextjs/components/withAnalytics.tsx b/apps/nextjs/components/withAnalytics.tsx deleted file mode 100644 index f74a8a4..0000000 --- a/apps/nextjs/components/withAnalytics.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Analytics, AnalyticsProps } from '@vercel/analytics/next'; -import React from 'react'; - -export function withAnalytics

>( - Component: React.ComponentType, - props?: P -) { - function WithAnalytics(props?: P) { - return ( - <> - - - - ); - } - - return () => WithAnalytics(props); -} diff --git a/apps/nextjs/e2e/development/beforeSend.spec.ts b/apps/nextjs/e2e/development/beforeSend.spec.ts index 712d611..2d7fb8c 100644 --- a/apps/nextjs/e2e/development/beforeSend.spec.ts +++ b/apps/nextjs/e2e/development/beforeSend.spec.ts @@ -6,6 +6,11 @@ test.describe('beforeSend', () => { page, }) => { const messages: string[] = []; + await useMockForProductionScript({ + page, + onPageView: () => {}, + debug: true, + }); page.on('console', (msg) => { const message = msg.text(); @@ -28,6 +33,6 @@ test.describe('beforeSend', () => { await page.waitForLoadState('networkidle'); - expect(messages).toHaveLength(5); + expect(messages).toHaveLength(6); }); }); diff --git a/apps/nextjs/e2e/development/pageview.spec.ts b/apps/nextjs/e2e/development/pageview.spec.ts index 97e987b..419ba13 100644 --- a/apps/nextjs/e2e/development/pageview.spec.ts +++ b/apps/nextjs/e2e/development/pageview.spec.ts @@ -1,16 +1,20 @@ import { test, expect } from '@playwright/test'; +import { useMockForProductionScript } from '../utils'; test.describe('pageview', () => { test('should track page views when navigating between pages', async ({ page, }) => { const messages: string[] = []; + await useMockForProductionScript({ + page, + onPageView: () => {}, + debug: true, + }); page.on('console', (msg) => { const message = msg.text(); - console.log(message); - if ( message.includes('[Vercel Web Analytics]') || message.includes('[Vercel Analytics]') @@ -20,7 +24,7 @@ test.describe('pageview', () => { }); await page.goto('/navigation/first'); - await page.waitForTimeout(200); + await page.waitForTimeout(800); await page.click('text=Next'); @@ -29,6 +33,6 @@ test.describe('pageview', () => { await page.waitForTimeout(200); - expect(messages).toHaveLength(3); + expect(messages).toHaveLength(6); }); }); diff --git a/apps/nextjs/e2e/production/pageview.spec.ts b/apps/nextjs/e2e/production/pageview.spec.ts index 25b0cd4..fae658d 100644 --- a/apps/nextjs/e2e/production/pageview.spec.ts +++ b/apps/nextjs/e2e/production/pageview.spec.ts @@ -34,6 +34,7 @@ test.describe('pageview', () => { sv: expect.any(String), sdkn: '@vercel/analytics/next', sdkv: expect.any(String), + dp: '/navigation/first', }, }, { @@ -44,6 +45,85 @@ test.describe('pageview', () => { sv: expect.any(String), sdkn: '@vercel/analytics/next', sdkv: expect.any(String), + dp: '/navigation/second', + }, + }, + ]); + }); + + test('should properly send dynamic route', async ({ page }) => { + const payloads: { page: string; payload: Object }[] = []; + + await useMockForProductionScript({ + page, + onPageView: (page, payload) => { + payloads.push({ page, payload }); + }, + }); + + await page.goto('/blog'); + await page.waitForLoadState('networkidle'); + + await page.click('text=My first blog post'); + + await expect(page).toHaveURL('/blog/my-first-blogpost'); + await expect(page.locator('h2')).toContainText('my-first-blogpost'); + + await page.waitForLoadState('networkidle'); + + await page.click('text=Back to blog'); + + await page.waitForLoadState('networkidle'); + await expect(page).toHaveURL('/blog'); + + await page.click('text=Feature just got released'); + + await expect(page.locator('h2')).toContainText('new-feature-release'); + + expect(payloads).toEqual([ + { + page: 'http://localhost:3000/blog', + payload: { + dp: '/blog', + o: 'http://localhost:3000/blog', + r: '', + sdkn: '@vercel/analytics/next', + sdkv: expect.any(String), + sv: expect.any(String), + ts: expect.any(Number), + }, + }, + { + page: 'http://localhost:3000/blog/my-first-blogpost', + payload: { + dp: '/blog/[slug]', + o: 'http://localhost:3000/blog/my-first-blogpost', + sdkn: '@vercel/analytics/next', + sdkv: expect.any(String), + sv: expect.any(String), + ts: expect.any(Number), + }, + }, + { + page: 'http://localhost:3000/blog', + payload: { + dp: '/blog', + o: 'http://localhost:3000/blog', + sdkn: '@vercel/analytics/next', + sdkv: expect.any(String), + sv: expect.any(String), + ts: expect.any(Number), + }, + }, + { + page: 'http://localhost:3000/blog/new-feature-release', + payload: { + dp: '/blog/[slug]', + o: 'http://localhost:3000/blog/new-feature-release', + sdkn: '@vercel/analytics/next', + sdkv: expect.any(String), + sv: expect.any(String), + ts: expect.any(Number), }, }, ]); diff --git a/apps/nextjs/e2e/utils.ts b/apps/nextjs/e2e/utils.ts index e3b6702..9aeeaf5 100644 --- a/apps/nextjs/e2e/utils.ts +++ b/apps/nextjs/e2e/utils.ts @@ -3,11 +3,16 @@ import { Page } from '@playwright/test'; export async function useMockForProductionScript(props: { page: Page; onPageView: (page: string, payload: Object) => void; + debug?: boolean; }) { await props.page.route('**/_vercel/insights/script.js', async (route, _) => { return route.fulfill({ status: 301, - headers: { location: 'https://cdn.vercel-insights.com/v1/script.js' }, + headers: { + location: props.debug + ? 'https://cdn.vercel-insights.com/v1/script.debug.js' + : 'https://cdn.vercel-insights.com/v1/script.js', + }, }); }); diff --git a/apps/nextjs/pages/before-send/first.tsx b/apps/nextjs/pages/before-send/first.tsx index 8786969..816ea17 100644 --- a/apps/nextjs/pages/before-send/first.tsx +++ b/apps/nextjs/pages/before-send/first.tsx @@ -1,5 +1,4 @@ import Link from 'next/link'; -import { withAnalytics } from '../../components/withAnalytics'; function Page() { return ( @@ -10,15 +9,4 @@ function Page() { ); } -export default withAnalytics(Page, { - beforeSend: (event) => { - const url = new URL(event.url); - if (url.searchParams.has('secret')) { - url.searchParams.set('secret', 'REDACTED'); - } - return { - ...event, - url: url.toString(), - }; - }, -}); +export default Page; diff --git a/apps/nextjs/pages/before-send/second.tsx b/apps/nextjs/pages/before-send/second.tsx index fae6c88..f88025a 100644 --- a/apps/nextjs/pages/before-send/second.tsx +++ b/apps/nextjs/pages/before-send/second.tsx @@ -1,5 +1,3 @@ -import { withAnalytics } from '../../components/withAnalytics'; - function Page() { return (

diff --git a/apps/nextjs/pages/navigation/first.tsx b/apps/nextjs/pages/navigation/first.tsx index 9ffec37..dfcdf0f 100644 --- a/apps/nextjs/pages/navigation/first.tsx +++ b/apps/nextjs/pages/navigation/first.tsx @@ -1,5 +1,4 @@ import Link from 'next/link'; -import { withAnalytics } from '../../components/withAnalytics'; function Page() { return ( diff --git a/apps/nextjs/pages/navigation/second.tsx b/apps/nextjs/pages/navigation/second.tsx index fae6c88..f88025a 100644 --- a/apps/nextjs/pages/navigation/second.tsx +++ b/apps/nextjs/pages/navigation/second.tsx @@ -1,5 +1,3 @@ -import { withAnalytics } from '../../components/withAnalytics'; - function Page() { return (
diff --git a/packages/web/src/generic.ts b/packages/web/src/generic.ts index 3bf94d1..9ce6a45 100644 --- a/packages/web/src/generic.ts +++ b/packages/web/src/generic.ts @@ -22,6 +22,7 @@ export const PROD_SCRIPT_URL = '/_vercel/insights/script.js'; * - `development` - Always use the development script. (Logs events to the console) * @param [props.debug] - Whether to enable debug logging in development. Defaults to `true`. * @param [props.beforeSend] - A middleware function to modify events before they are sent. Should return the event object or `null` to cancel the event. + * @param [props.dsn] - The DSN of the project to send events to. Only required when self-hosting. */ function inject( props: AnalyticsProps & { @@ -50,10 +51,16 @@ function inject( script.defer = true; script.dataset.sdkn = packageName + (props.framework ? `/${props.framework}` : ''); - script.setAttribute('data-sdkv', version); + script.dataset.sdkv = version; if (props.disableAutoTrack) { - script.setAttribute('data-disable-auto-track', '1'); + script.dataset.disableAutoTrack = '1'; + } + if (props.endpoint) { + script.dataset.endpoint = props.endpoint; + } + if (props.dsn) { + script.dataset.dsn = props.dsn; } script.onerror = (): void => { @@ -68,7 +75,7 @@ function inject( }; if (isDevelopment() && props.debug === false) { - script.setAttribute('data-debug', 'false'); + script.dataset.debug = 'false'; } document.head.appendChild(script); diff --git a/packages/web/src/types.ts b/packages/web/src/types.ts index 440cba2..aab7ee0 100644 --- a/packages/web/src/types.ts +++ b/packages/web/src/types.ts @@ -23,6 +23,8 @@ export interface AnalyticsProps { scriptSrc?: string; endpoint?: string; + + dsn?: string; } declare global { interface Window {