| import { expect } from '@playwright/test' |
| import { |
| expectPlausibleInAction, |
| hideAndShowCurrentTab, |
| focus, |
| blur, |
| blurAndFocusPage, |
| tracker_script_version |
| } from './support/test-utils' |
| import { test } from '@playwright/test' |
| import { LOCAL_SERVER_ADDR } from './support/server' |
|
|
| test.describe('engagement events', () => { |
| test('sends an engagement event with time measurement when navigating to the next page', async ({ |
| page |
| }) => { |
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement.html'), |
| expectedRequests: [{ n: 'pageview' }] |
| }) |
|
|
| await page.waitForTimeout(1000) |
|
|
| const [request] = await expectPlausibleInAction(page, { |
| action: () => page.click('#navigate-away'), |
| expectedRequests: [ |
| { |
| n: 'engagement', |
| u: `${LOCAL_SERVER_ADDR}/engagement.html`, |
| v: tracker_script_version |
| } |
| ] |
| }) |
|
|
| expect(request.e).toBeGreaterThan(1000) |
| expect(request.e).toBeLessThan(1500) |
| }) |
|
|
| test('sends an event and a pageview on hash-based SPA navigation', async ({ |
| page |
| }) => { |
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement-hash.html'), |
| expectedRequests: [{ n: 'pageview' }] |
| }) |
|
|
| await page.waitForTimeout(1000) |
|
|
| const [request] = await expectPlausibleInAction(page, { |
| action: () => page.click('#hash-nav'), |
| expectedRequests: [ |
| { n: 'engagement', u: `${LOCAL_SERVER_ADDR}/engagement-hash.html` }, |
| { |
| n: 'pageview', |
| u: `${LOCAL_SERVER_ADDR}/engagement-hash.html#some-hash` |
| } |
| ] |
| }) |
|
|
| expect(request.e).toBeGreaterThan(1000) |
| expect(request.e).toBeLessThan(1500) |
| }) |
|
|
| test('sends an event and a pageview on history-based SPA navigation', async ({ |
| page |
| }) => { |
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement.html'), |
| expectedRequests: [{ n: 'pageview' }] |
| }) |
|
|
| await page.waitForTimeout(1000) |
|
|
| const [request] = await expectPlausibleInAction(page, { |
| action: () => page.click('#history-nav'), |
| expectedRequests: [ |
| { n: 'engagement', u: `${LOCAL_SERVER_ADDR}/engagement.html` }, |
| { n: 'pageview', u: `${LOCAL_SERVER_ADDR}/another-page` } |
| ] |
| }) |
|
|
| expect(request.e).toBeGreaterThan(1000) |
| expect(request.e).toBeLessThan(1500) |
| }) |
|
|
| test('sends engagements when pageviews are triggered manually on a SPA', async ({ |
| page |
| }) => { |
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement-hash-manual.html'), |
| expectedRequests: [{ n: 'pageview' }] |
| }) |
|
|
| await page.waitForTimeout(1000) |
|
|
| const [request] = await expectPlausibleInAction(page, { |
| action: () => page.click('#about-us-hash-link'), |
| expectedRequests: [ |
| { n: 'engagement', u: `${LOCAL_SERVER_ADDR}/#home` }, |
| { n: 'pageview', u: `${LOCAL_SERVER_ADDR}/#about-us` } |
| ] |
| }) |
|
|
| expect(request.e).toBeGreaterThan(1000) |
| expect(request.e).toBeLessThan(1500) |
| }) |
|
|
| test('sends an event with the manually overridden URL', async ({ page }) => { |
| await page.goto('/engagement-manual.html') |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.click('#pageview-trigger-custom-url'), |
| expectedRequests: [ |
| { n: 'pageview', u: 'https://example.com/custom/location' } |
| ] |
| }) |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.click('#navigate-away'), |
| expectedRequests: [ |
| { n: 'engagement', u: 'https://example.com/custom/location' } |
| ] |
| }) |
| }) |
|
|
| test('does not send an event when pageview was not sent in manual mode', async ({ |
| page |
| }) => { |
| await page.goto('/engagement-manual.html') |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.click('#navigate-away'), |
| refutedRequests: [{ n: 'engagement' }] |
| }) |
| }) |
|
|
| test('script.exclusions.hash.js sends an event only from URLs where a pageview was sent', async ({ |
| page |
| }) => { |
| const pageBaseURL = `${LOCAL_SERVER_ADDR}/engagement-hash-exclusions.html` |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement-hash-exclusions.html'), |
| expectedRequests: [{ n: 'pageview' }] |
| }) |
|
|
| |
| |
| await expectPlausibleInAction(page, { |
| action: () => page.click('#ignored-hash-link'), |
| expectedRequests: [{ n: 'engagement', u: pageBaseURL, h: 1 }] |
| }) |
|
|
| |
| |
| await expectPlausibleInAction(page, { |
| action: () => page.click('#hash-link-1'), |
| expectedRequests: [{ n: 'pageview', u: `${pageBaseURL}#hash1`, h: 1 }], |
| refutedRequests: [{ n: 'engagement' }] |
| }) |
|
|
| |
| |
| await expectPlausibleInAction(page, { |
| action: () => page.click('#hash-link-2'), |
| expectedRequests: [ |
| { n: 'engagement', u: `${pageBaseURL}#hash1`, h: 1 }, |
| { n: 'pageview', u: `${pageBaseURL}#hash2`, h: 1 } |
| ] |
| }) |
| }) |
|
|
| test('sends an event with the same props as pageview (manual extension)', async ({ |
| page |
| }) => { |
| await page.goto('/engagement-manual.html') |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.click('#pageview-trigger-custom-props'), |
| expectedRequests: [{ n: 'pageview', p: { author: 'John' } }] |
| }) |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.click('#navigate-away'), |
| expectedRequests: [{ n: 'engagement', p: { author: 'John' } }] |
| }) |
| }) |
|
|
| test('sends an event with the same props as pageview (pageview-props extension)', async ({ |
| page |
| }) => { |
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement-pageview-props.html'), |
| expectedRequests: [{ n: 'pageview', p: { author: 'John', index: '0' } }] |
| }) |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.click('#navigate-away'), |
| expectedRequests: [{ n: 'engagement', p: { author: 'John', index: '0' } }] |
| }) |
| }) |
|
|
| test('pageview props with custom events and values changing mid-view (pageview-props extension)', async ({ |
| page |
| }) => { |
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement-pageview-props.html'), |
| expectedRequests: [{ n: 'pageview', p: { author: 'John', index: '0' } }] |
| }) |
|
|
| await page.click('#increment-event-index') |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.click('#custom-event-button'), |
| expectedRequests: [ |
| { n: 'Custom event', p: { author: 'Karl', index: '1' } } |
| ] |
| }) |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.click('#navigate-away'), |
| expectedRequests: [{ n: 'engagement', p: { author: 'John', index: '0' } }] |
| }) |
| }) |
|
|
| test('sends an event with the same props as pageview (hash navigation / pageview-props extension)', async ({ |
| page |
| }) => { |
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement-hash-pageview-props.html'), |
| expectedRequests: [{ n: 'pageview', p: {} }] |
| }) |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.click('#john-post'), |
| expectedRequests: [ |
| { n: 'engagement', p: {} }, |
| { n: 'pageview', p: { author: 'john' } } |
| ] |
| }) |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.click('#jane-post'), |
| expectedRequests: [ |
| { n: 'engagement', p: { author: 'john' } }, |
| { n: 'pageview', p: { author: 'jane' } } |
| ] |
| }) |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.click('#home'), |
| expectedRequests: [ |
| { n: 'engagement', p: { author: 'jane' } }, |
| { n: 'pageview', p: {} } |
| ] |
| }) |
| }) |
|
|
| test('sends an event when plausible API is slow and user navigates away before response is received', async ({ |
| page, |
| browserName |
| }) => { |
| test.skip(browserName === 'chromium', 'flaky') |
|
|
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement.html'), |
| expectedRequests: [ |
| { n: 'pageview', u: `${LOCAL_SERVER_ADDR}/engagement.html` } |
| ] |
| }) |
|
|
| await expectPlausibleInAction(page, { |
| action: async () => { |
| await page.click('#to-pageleave-pageview-props') |
| await page.waitForTimeout(500) |
| await page.click('#back-button-trigger') |
| }, |
| expectedRequests: [ |
| { n: 'engagement', u: `${LOCAL_SERVER_ADDR}/engagement.html` }, |
| { |
| n: 'pageview', |
| u: `${LOCAL_SERVER_ADDR}/engagement-pageview-props.html`, |
| p: { author: 'John', index: '0' } |
| }, |
| { |
| n: 'engagement', |
| u: `${LOCAL_SERVER_ADDR}/engagement-pageview-props.html`, |
| p: { author: 'John', index: '0' } |
| }, |
| { n: 'pageview', u: `${LOCAL_SERVER_ADDR}/engagement.html` } |
| ], |
| responseDelay: 1000 |
| }) |
| }) |
|
|
| test('sends engagement events when tab toggles between foreground and background', async ({ |
| page |
| }) => { |
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement.html'), |
| expectedRequests: [{ n: 'pageview' }] |
| }) |
|
|
| const [request1] = await expectPlausibleInAction(page, { |
| action: () => hideAndShowCurrentTab(page, { delay: 2000 }), |
| expectedRequests: [ |
| { n: 'engagement', u: `${LOCAL_SERVER_ADDR}/engagement.html` } |
| ] |
| }) |
| expect(request1.e).toBeLessThan(500) |
|
|
| await page.waitForTimeout(3000) |
|
|
| const [request2] = await expectPlausibleInAction(page, { |
| action: () => hideAndShowCurrentTab(page, { delay: 2000 }), |
| expectedRequests: [ |
| { n: 'engagement', u: `${LOCAL_SERVER_ADDR}/engagement.html` } |
| ] |
| }) |
|
|
| expect(request2.e).toBeGreaterThan(3000) |
| expect(request2.e).toBeLessThan(3500) |
| }) |
|
|
| test('does not send engagement events when tab is only open for a short time until over 3000ms has passed', async ({ |
| page |
| }) => { |
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement.html'), |
| expectedRequests: [{ n: 'pageview' }] |
| }) |
|
|
| const [request1] = await expectPlausibleInAction(page, { |
| action: () => hideAndShowCurrentTab(page), |
| expectedRequests: [ |
| { n: 'engagement', u: `${LOCAL_SERVER_ADDR}/engagement.html` } |
| ] |
| }) |
| expect(request1.e).toBeLessThan(500) |
|
|
| await page.waitForTimeout(500) |
|
|
| await expectPlausibleInAction(page, { |
| action: () => hideAndShowCurrentTab(page), |
| refutedRequests: [{ n: 'engagement' }], |
| mockRequestTimeout: 100 |
| }) |
|
|
| await page.waitForTimeout(2500) |
|
|
| const [request2] = await expectPlausibleInAction(page, { |
| action: () => hideAndShowCurrentTab(page, { delay: 3000 }), |
| expectedRequests: [ |
| { n: 'engagement', u: `${LOCAL_SERVER_ADDR}/engagement.html` } |
| ] |
| }) |
|
|
| |
| expect(request2.e).toBeGreaterThan(3000) |
| expect(request2.e).toBeLessThan(3500) |
| }) |
|
|
| test('tracks engagement time properly in a SPA', async ({ page }) => { |
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement-hash.html'), |
| expectedRequests: [{ n: 'pageview' }] |
| }) |
|
|
| await page.waitForTimeout(1000) |
|
|
| const [request] = await expectPlausibleInAction(page, { |
| action: () => page.click('#hash-nav'), |
| expectedRequests: [ |
| { n: 'engagement', u: `${LOCAL_SERVER_ADDR}/engagement-hash.html` }, |
| { |
| n: 'pageview', |
| u: `${LOCAL_SERVER_ADDR}/engagement-hash.html#some-hash` |
| } |
| ] |
| }) |
|
|
| expect(request.e).toBeGreaterThan(1000) |
| expect(request.e).toBeLessThan(1500) |
|
|
| const [request2] = await expectPlausibleInAction(page, { |
| action: () => page.click('#hash-nav-2'), |
| expectedRequests: [ |
| { |
| n: 'engagement', |
| u: `${LOCAL_SERVER_ADDR}/engagement-hash.html#some-hash` |
| }, |
| { |
| n: 'pageview', |
| u: `${LOCAL_SERVER_ADDR}/engagement-hash.html#another-hash` |
| } |
| ] |
| }) |
|
|
| expect(request2.e).toBeLessThan(200) |
|
|
| await page.waitForTimeout(3000) |
|
|
| const [request3] = await expectPlausibleInAction(page, { |
| action: () => hideAndShowCurrentTab(page), |
| expectedRequests: [ |
| { |
| n: 'engagement', |
| u: `${LOCAL_SERVER_ADDR}/engagement-hash.html#another-hash` |
| } |
| ] |
| }) |
|
|
| expect(request3.e).toBeGreaterThan(3000) |
| expect(request3.e).toBeLessThan(3500) |
|
|
| await page.waitForTimeout(3000) |
| const [request4] = await expectPlausibleInAction(page, { |
| action: () => page.click('#hash-nav'), |
| expectedRequests: [ |
| { |
| n: 'engagement', |
| u: `${LOCAL_SERVER_ADDR}/engagement-hash.html#another-hash` |
| }, |
| { |
| n: 'pageview', |
| u: `${LOCAL_SERVER_ADDR}/engagement-hash.html#some-hash` |
| } |
| ] |
| }) |
|
|
| expect(request4.e).toBeGreaterThan(3000) |
| expect(request4.e).toBeLessThan(3500) |
| }) |
|
|
| test('tracks engagement time whilst tab gains and loses focus', async ({ |
| page |
| }) => { |
| await expectPlausibleInAction(page, { |
| action: () => page.goto('/engagement.html'), |
| expectedRequests: [{ n: 'pageview' }] |
| }) |
|
|
| const [request1] = await expectPlausibleInAction(page, { |
| action: () => blur(page), |
| expectedRequests: [ |
| { n: 'engagement', u: `${LOCAL_SERVER_ADDR}/engagement.html` } |
| ] |
| }) |
| expect(request1.e).toBeLessThan(500) |
|
|
| await focus(page) |
| await page.waitForTimeout(1000) |
|
|
| await expectPlausibleInAction(page, { |
| action: () => blurAndFocusPage(page, { delay: 3000 }), |
| refutedRequests: [{ n: 'engagement' }], |
| mockRequestTimeout: 100 |
| }) |
|
|
| await page.waitForTimeout(2500) |
|
|
| const [request2] = await expectPlausibleInAction(page, { |
| action: () => blur(page), |
| expectedRequests: [ |
| { n: 'engagement', u: `${LOCAL_SERVER_ADDR}/engagement.html` } |
| ] |
| }) |
|
|
| expect(request2.e).toBeGreaterThan(3500) |
| expect(request2.e).toBeLessThan(4000) |
| }) |
| }) |
|
|