ScriptV2: Configuration renames, iteration (#5427)

* plausible-main -> plausible-web

* Change elixir workflow

* Update tracker option names in tracker.ex

* config.hash -> config.hashBasedRouting

* Enable revenue by default for plausible-web

* Enable taggedEvents by default

* config.local -> config.captureOnLocalhost

* manual -> autoCapturePageviews

* Update playwright tests

* Support adding/editing file types for download in plausible-web

Original docs: https://plausible.io/docs/file-downloads-tracking#what-if-i-want-to-track-a-different-file-type

* rebase: initialize-page-dynamically update

* chore: Bump tracker_script_version to 12

* Ignore pageviews in file-downloads.spec

* Phrasing in tests

* Remove unneeded conditional
This commit is contained in:
Karl-Aksel Puulmann 2025-05-27 14:28:17 +03:00 committed by GitHub
parent 1de10b7867
commit 98cdeb23dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 199 additions and 106 deletions

View File

@ -83,9 +83,9 @@ jobs:
filters: |
tracker:
- 'tracker/**'
- name: Check if priv/tracker/js/plausible.js exists
- name: Check if priv/tracker/js/plausible-web.js exists
run: |
if [ -f priv/tracker/js/plausible.js ]; then
if [ -f priv/tracker/js/plausible-web.js ]; then
echo "HAS_BUILT_TRACKER=true" >> $GITHUB_ENV
else
echo "HAS_BUILT_TRACKER=false" >> $GITHUB_ENV

View File

@ -6,12 +6,12 @@ defmodule PlausibleWeb.Tracker do
use Plausible.Repo
alias Plausible.Site.TrackerScriptConfiguration
path = Application.app_dir(:plausible, "priv/tracker/js/plausible-main.js")
path = Application.app_dir(:plausible, "priv/tracker/js/plausible-web.js")
# On CI, the file might not be present for static checks so we create an empty one
File.touch!(path)
@plausible_main_script File.read!(path)
@external_resource "priv/tracker/js/plausible-main.js"
@external_resource "priv/tracker/js/plausible-web.js"
def plausible_main_script_tag(tracker_script_configuration) do
config_js_content =
@ -35,14 +35,10 @@ defmodule PlausibleWeb.Tracker do
%{
domain: tracker_script_configuration.site.domain,
endpoint: "#{PlausibleWeb.Endpoint.url()}/api/event",
hash: tracker_script_configuration.hash_based_routing,
hashBasedRouting: tracker_script_configuration.hash_based_routing,
outboundLinks: tracker_script_configuration.outbound_links,
fileDownloads: tracker_script_configuration.file_downloads,
taggedEvents: tracker_script_configuration.tagged_events,
revenue: tracker_script_configuration.revenue_tracking,
# Options not directly exposed via onboarding
local: false,
manual: false
formSubmissions: tracker_script_configuration.form_submissions
}
end

View File

@ -19,7 +19,7 @@ defmodule PlausibleWeb.TrackerPlugTest do
alias PlausibleWeb.Tracker
describe "plausible-main.js" do
describe "plausible-web.js" do
@example_config %{
installation_type: :manual,
track_404_pages: true,
@ -28,7 +28,8 @@ defmodule PlausibleWeb.TrackerPlugTest do
outbound_links: false,
pageview_props: false,
tagged_events: true,
revenue_tracking: false
revenue_tracking: false,
form_submissions: true
}
test "returns the script for an existing site", %{conn: conn} do
@ -45,9 +46,10 @@ defmodule PlausibleWeb.TrackerPlugTest do
assert String.contains?(response, "!function(){var")
assert String.contains?(response, "domain:\"#{site.domain}\"")
assert String.contains?(response, "hash:!0")
assert String.contains?(response, "taggedEvents:!0")
assert String.contains?(response, "hashBasedRouting:!0")
assert String.contains?(response, "formSubmissions:!0")
refute String.contains?(response, "outboundLinks:!0")
refute String.contains?(response, "fileDownloads:!0")
end
# window.plausible is a substring checked for by the wordpress plugin to avoid 'optimization' by other wordpress plugins

View File

@ -5,7 +5,7 @@ defmodule PlausibleWeb.TrackerTest do
alias Plausible.Site.TrackerScriptConfiguration
alias PlausibleWeb.Tracker
describe "plausible-main.js" do
describe "plausible-web.js" do
@example_config %{
installation_type: :manual,
track_404_pages: true,
@ -14,7 +14,8 @@ defmodule PlausibleWeb.TrackerTest do
outbound_links: false,
pageview_props: false,
tagged_events: true,
revenue_tracking: false
revenue_tracking: false,
form_submissions: true
}
test "can calculate config" do
@ -24,13 +25,10 @@ defmodule PlausibleWeb.TrackerTest do
assert PlausibleWeb.Tracker.plausible_main_config(tracker_script_configuration) == %{
domain: site.domain,
endpoint: "#{PlausibleWeb.Endpoint.url()}/api/event",
hash: true,
hashBasedRouting: true,
outboundLinks: false,
fileDownloads: false,
taggedEvents: true,
revenue: false,
local: false,
manual: false
formSubmissions: true
}
end
@ -41,7 +39,7 @@ defmodule PlausibleWeb.TrackerTest do
script_tag = PlausibleWeb.Tracker.plausible_main_script_tag(tracker_script_configuration)
assert script_tag =~
~s(={endpoint:"#{PlausibleWeb.Endpoint.url()}/api/event",domain:"#{site.domain}",taggedEvents:!0,hash:!0})
~s(={endpoint:"#{PlausibleWeb.Endpoint.url()}/api/event",domain:"#{site.domain}",hashBasedRouting:!0,formSubmissions:!0})
end
test "script tag escapes problematic characters as expected" do

View File

@ -1,9 +1,9 @@
{
"manualVariants": [
{
"name": "plausible-main.js",
"name": "plausible-web.js",
"features": [
"plausible-main"
"plausible-web"
],
"globals": {
"COMPILE_CONFIG": true,

View File

@ -1,5 +1,5 @@
{
"tracker_script_version": 11,
"tracker_script_version": 12,
"type": "module",
"scripts": {
"deploy": "node compile.js",

View File

@ -15,6 +15,7 @@ if (COMPILE_CONFIG) {
var endpoint
var dataDomain
var autoCapturePageviews = !COMPILE_MANUAL
// Exported public function
function trigger(eventName, options) {
@ -29,7 +30,7 @@ function trigger(eventName, options) {
maxScrollDepthPx = getCurrentScrollDepthPx()
}
if (!(COMPILE_LOCAL && (!COMPILE_CONFIG || config.local))) {
if (!(COMPILE_LOCAL && (!COMPILE_CONFIG || config.captureOnLocalhost))) {
if (/^localhost$|^127(\.[0-9]+){0,2}\.[0-9]+$|^\[::1?\]$/.test(location.hostname) || location.protocol === 'file:') {
return onIgnoredEvent(eventName, options, 'localhost')
}
@ -52,7 +53,7 @@ function trigger(eventName, options) {
function pathMatches(wildcardPath) {
var actualPath = location.pathname
if (COMPILE_HASH && (!COMPILE_CONFIG || config.hash)) {
if (COMPILE_HASH && (!COMPILE_CONFIG || config.hashBasedRouting)) {
actualPath += location.hash
}
@ -71,7 +72,7 @@ function trigger(eventName, options) {
payload.n = eventName
payload.v = COMPILE_TRACKER_SCRIPT_VERSION
if (COMPILE_MANUAL && (!COMPILE_CONFIG || config.manual)) {
if (COMPILE_MANUAL || !autoCapturePageviews) {
var customURL = options && options.u
payload.u = customURL ? customURL : location.href
@ -90,7 +91,7 @@ function trigger(eventName, options) {
if (options && options.interactive === false) {
payload.i = false
}
if (COMPILE_REVENUE && (!COMPILE_CONFIG || config.revenue)) {
if (COMPILE_REVENUE) {
if (options && options.revenue) {
payload.$ = options.revenue
}
@ -124,7 +125,7 @@ function trigger(eventName, options) {
}
}
if (COMPILE_HASH && (!COMPILE_CONFIG || config.hash)) {
if (COMPILE_HASH && (!COMPILE_CONFIG || config.hashBasedRouting)) {
payload.h = 1
}
@ -218,7 +219,7 @@ function triggerEngagement() {
runningEngagementStart = 0
currentEngagementTime = 0
if (COMPILE_HASH && (!COMPILE_CONFIG || config.hash)) {
if (COMPILE_HASH && (!COMPILE_CONFIG || config.hashBasedRouting)) {
payload.h = 1
}
@ -308,11 +309,12 @@ function init(overrides) {
return
}
// Explicitly set dataDomain before any overrides are applied as `plausible-main` does not support overriding it
// Explicitly set dataDomain before any overrides are applied as `plausible-web` does not support overriding it
dataDomain = COMPILE_CONFIG ? config.domain : scriptEl.getAttribute('data-domain')
if (COMPILE_CONFIG) {
Object.assign(config, overrides)
autoCapturePageviews = config.autoCapturePageviews !== false
}
endpoint = COMPILE_CONFIG ? config.endpoint : (scriptEl.getAttribute('data-api') || defaultEndpoint())
@ -342,11 +344,11 @@ function init(overrides) {
}
})
if (!(COMPILE_MANUAL && (!COMPILE_CONFIG || config.manual))) {
if (!COMPILE_MANUAL || autoCapturePageviews) {
var lastPage;
function page(isSPANavigation) {
if (!(COMPILE_HASH && (!COMPILE_CONFIG || config.hash))) {
if (!(COMPILE_HASH && (!COMPILE_CONFIG || config.hashBasedRouting))) {
if (isSPANavigation && lastPage === location.pathname) return;
}
@ -356,7 +358,7 @@ function init(overrides) {
var onSPANavigation = function () { page(true) }
if (COMPILE_HASH && (!COMPILE_CONFIG || config.hash)) {
if (COMPILE_HASH && (!COMPILE_CONFIG || config.hashBasedRouting)) {
window.addEventListener('hashchange', onSPANavigation)
} else {
var his = window.history
@ -419,7 +421,7 @@ function init(overrides) {
var link = getLinkEl(event.target)
var hrefWithoutQuery = link && link.href && link.href.split('?')[0]
if (COMPILE_TAGGED_EVENTS && (!COMPILE_CONFIG || config.taggedEvents)) {
if (COMPILE_TAGGED_EVENTS) {
if (isElementOrParentTagged(link, 0)) {
// Return to prevent sending multiple events with the same action.
// Clicks on tagged links are handled by another function.
@ -452,7 +454,7 @@ function init(overrides) {
if (shouldFollowLink(event, link)) {
var attrs = { props: eventAttrs.props, callback: followLink }
if (COMPILE_REVENUE && (!COMPILE_CONFIG || config.revenue)) {
if (COMPILE_REVENUE) {
attrs.revenue = eventAttrs.revenue
}
plausible(eventAttrs.name, attrs)
@ -460,7 +462,7 @@ function init(overrides) {
event.preventDefault()
} else {
var attrs = { props: eventAttrs.props }
if (COMPILE_REVENUE && (!COMPILE_CONFIG || config.revenue)) {
if (COMPILE_REVENUE) {
attrs.revenue = eventAttrs.revenue
}
plausible(eventAttrs.name, attrs)
@ -478,9 +480,23 @@ function init(overrides) {
if (COMPILE_FILE_DOWNLOADS && (!COMPILE_CONFIG || config.fileDownloads)) {
var defaultFileTypes = ['pdf', 'xlsx', 'docx', 'txt', 'rtf', 'csv', 'exe', 'key', 'pps', 'ppt', 'pptx', '7z', 'pkg', 'rar', 'gz', 'zip', 'avi', 'mov', 'mp4', 'mpeg', 'wmv', 'midi', 'mp3', 'wav', 'wma', 'dmg']
var fileTypesAttr = scriptEl.getAttribute('file-types')
var addFileTypesAttr = scriptEl.getAttribute('add-file-types')
var fileTypesToTrack = (fileTypesAttr && fileTypesAttr.split(",")) || (addFileTypesAttr && addFileTypesAttr.split(",").concat(defaultFileTypes)) || defaultFileTypes;
var fileTypesToTrack = defaultFileTypes
if (COMPILE_CONFIG) {
if (Array.isArray(config.fileDownloads)) {
fileTypesToTrack = config.fileDownloads
}
} else {
var fileTypesAttr = scriptEl.getAttribute('file-types')
var addFileTypesAttr = scriptEl.getAttribute('add-file-types')
if (fileTypesAttr) {
fileTypesToTrack = fileTypesAttr.split(",")
}
if (addFileTypesAttr) {
fileTypesToTrack = addFileTypesAttr.split(",").concat(defaultFileTypes)
}
}
function isDownloadToTrack(url) {
if (!url) { return false }
@ -491,7 +507,7 @@ function init(overrides) {
})
}
}
if (COMPILE_CONFIG && config.formSubmissions) {
function trackFormSubmission(e) {
if (e.target.hasAttribute('novalidate') || e.target.checkValidity()) {
@ -502,13 +518,13 @@ function init(overrides) {
document.addEventListener('submit', trackFormSubmission, true);
}
if (COMPILE_TAGGED_EVENTS && (!COMPILE_CONFIG || config.taggedEvents)) {
if (COMPILE_TAGGED_EVENTS) {
// Finds event attributes by iterating over the given element's (or its
// parent's) classList. Returns an object with `name` and `props` keys.
function getTaggedEventAttributes(htmlElement) {
var taggedElement = isTagged(htmlElement) ? htmlElement : htmlElement && htmlElement.parentNode
var eventAttrs = { name: null, props: {} }
if (COMPILE_REVENUE && (!COMPILE_CONFIG || config.revenue)) {
if (COMPILE_REVENUE) {
eventAttrs.revenue = {}
}
@ -530,7 +546,7 @@ function init(overrides) {
}
}
if (COMPILE_REVENUE && (!COMPILE_CONFIG || config.revenue)) {
if (COMPILE_REVENUE) {
var revenueMatchList = className.match(/plausible-revenue-(.+)(=|--)(.+)/)
if (revenueMatchList) {
var key = revenueMatchList[1]
@ -561,7 +577,7 @@ function init(overrides) {
setTimeout(submitForm, 5000)
var attrs = { props: eventAttrs.props, callback: submitForm }
if (COMPILE_REVENUE && (!COMPILE_CONFIG || config.revenue)) {
if (COMPILE_REVENUE) {
attrs.revenue = eventAttrs.revenue
}
plausible(eventAttrs.name, attrs)
@ -603,7 +619,7 @@ function init(overrides) {
} else {
var attrs = {}
attrs.props = eventAttrs.props
if (COMPILE_REVENUE && (!COMPILE_CONFIG || config.revenue)) {
if (COMPILE_REVENUE) {
attrs.revenue = eventAttrs.revenue
}
plausible(eventAttrs.name, attrs)

View File

@ -2,7 +2,7 @@ import { mockRequest, mockManyRequests, metaKey, expectPlausibleInAction } from
import { expect, test } from '@playwright/test'
import { LOCAL_SERVER_ADDR } from './support/server'
test.describe('file-downloads extension', () => {
test.describe('legacy file-downloads extension', () => {
test('sends event and does not start download when link opens in new tab', async ({ page }) => {
await page.goto('/file-download.html')
const downloadURL = await page.locator('#link').getAttribute('href')
@ -51,3 +51,71 @@ test.describe('file-downloads extension', () => {
expect((await downloadRequestMockList).length).toBe(1)
})
})
test.describe('file downloads', () => {
test.beforeEach(({ page }) => {
// Mock file download requests
mockRequest(page, 'https://awesome.website.com/file.iso')
})
const DEFAULT_CONFIG = {
domain: 'example.com',
endpoint: `${LOCAL_SERVER_ADDR}/api/event`,
captureOnLocalhost: true,
autoCapturePageviews: false
}
async function openPage(page, config) {
await page.goto(`/file-download-plausible-web.html`)
await page.waitForFunction('window.plausible !== undefined')
await page.evaluate((config) => {
window.plausible.init(config)
}, { ...DEFAULT_CONFIG, ...config })
}
test('does not track iso files by default', async ({ page }) => {
await openPage(page, { fileDownloads: true })
await expectPlausibleInAction(page, {
action: () => page.click('#file-download-iso', { modifiers: [metaKey()] }),
expectedRequests: [],
rejectRequests: [{ n: 'File Download' }],
})
})
test('tracks iso but not pdf files when config.fileDownloads includes "iso"', async ({ page }) => {
await openPage(page, { fileDownloads: ['iso'] })
await expectPlausibleInAction(page, {
action: async () => {
await page.click('#file-download-iso', { modifiers: [metaKey()] })
await page.click('#file-download', { modifiers: [metaKey()] })
},
expectedRequests: [
{ n: 'File Download', p: { url: 'https://awesome.website.com/file.iso' } },
],
rejectRequests: [
{ n: 'File Download', p: { url: 'https://awesome.website.com/file.pdf' } },
]
})
})
test('ignores malformed value but enables the feature', async ({ page }) => {
await openPage(page, { fileDownloads: 'iso' })
await expectPlausibleInAction(page, {
action: async () => {
await page.click('#file-download-iso', { modifiers: [metaKey()] })
await page.click('#file-download', { modifiers: [metaKey()] })
},
expectedRequests: [
{ n: 'File Download', p: { url: 'https://awesome.website.com/file.pdf' } },
],
rejectRequests: [
{ n: 'File Download', p: { url: 'https://awesome.website.com/file.iso' } },
]
})
})
})

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>plausible-web.js tests</title>
</head>
<body>
<a id="file-download" href="https://awesome.website.com/file.pdf">Download</a>
<a id="file-download-iso" href="https://awesome.website.com/file.iso">Download ISO</a>
<script>
window.plausible=window.plausible||function(){(window.plausible.q = window.plausible.q || []).push(arguments)}
window.plausible.init = function(overrides) { window.plausible.o = overrides || {} }
var config = { domain: 'example.com' }
const script = document.createElement('script')
script.src = `/tracker/js/plausible-web.js?script_config=${encodeURIComponent(JSON.stringify(config))}`
var r = document.getElementsByTagName("script")[0]
r.parentNode.insertBefore(script, r)
</script>
</body>
</html>

View File

@ -5,15 +5,16 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>plausible-main.js tests</title>
<title>plausible-web.js tests</title>
</head>
<body>
<a id="file-download" href="https://awesome.website.com/file.pdf">Download</a>
<a id="file-download-iso" href="https://awesome.website.com/file.iso">Download ISO</a>
<a id="outbound-link" href="https://example.com">Outbound link</a>
<a id="manual-pageview" onclick="plausible('pageview', { u: '/:test-plausible-main' })">Manual pageview</a>
<a id="manual-pageview" onclick="plausible('pageview', { u: '/:test-plausible-web' })">Manual pageview</a>
<a id="custom-event" onclick="plausible('Custom event', { props: { author: 'Karl' } })">Custom event</a>
@ -44,7 +45,7 @@
// Load the script with the passed config
const config = params.get('script_config')
const script = document.createElement('script')
script.src = `/tracker/js/plausible-main.js?script_config=${encodeURIComponent(config)}`
script.src = `/tracker/js/plausible-web.js?script_config=${encodeURIComponent(config)}`
var r = document.getElementsByTagName("script")[0]
r.parentNode.insertBefore(script, r);

View File

@ -10,7 +10,7 @@ import { ScriptConfig } from './support/types'
const DEFAULT_CONFIG: ScriptConfig = {
domain: 'example.com',
endpoint: `${LOCAL_SERVER_ADDR}/api/event`,
local: true
captureOnLocalhost: true
}
test('does not track form submissions when the feature is disabled', async ({
@ -70,7 +70,7 @@ test.describe('form submissions feature is enabled', () => {
await page.fill('input[type="text"]', 'Any Name')
await page.click('input[type="submit"]')
},
shouldIgnoreRequest: isViewOrEngagementEvent,
shouldIgnoreRequest: pageviewOrEngagementEvent,
expectedRequests: [
{
n: 'Form Submission',
@ -101,7 +101,7 @@ test.describe('form submissions feature is enabled', () => {
await ensurePlausibleInitialized(page)
await page.click('input[type="submit"]')
},
shouldIgnoreRequest: isViewOrEngagementEvent,
shouldIgnoreRequest: pageviewOrEngagementEvent,
expectedRequests: [
{
n: 'Form Submission',
@ -140,7 +140,7 @@ test.describe('form submissions feature is enabled', () => {
await page.click('button#dynamically-insert-form')
await page.click('input[type="submit"]')
},
shouldIgnoreRequest: isViewOrEngagementEvent,
shouldIgnoreRequest: pageviewOrEngagementEvent,
expectedRequests: [
{
n: 'Form Submission',
@ -174,7 +174,7 @@ test.describe('form submissions feature is enabled', () => {
await page.fill('input[type="email"]', 'invalid email')
await page.click('input[type="submit"]')
},
shouldIgnoreRequest: isViewOrEngagementEvent,
shouldIgnoreRequest: pageviewOrEngagementEvent,
expectedRequests: [
{
n: 'Form Submission',
@ -276,7 +276,7 @@ test.describe('form submissions feature is enabled', () => {
await ensurePlausibleInitialized(page)
await page.click('input[type="submit"]')
},
shouldIgnoreRequest: isViewOrEngagementEvent,
shouldIgnoreRequest: pageviewOrEngagementEvent,
expectedRequests: [
{
n: 'Form Submission',
@ -290,7 +290,7 @@ test.describe('form submissions feature is enabled', () => {
await page.fill('input[type="email"]', 'customer@example.com')
await page.keyboard.press('Enter')
},
shouldIgnoreRequest: isViewOrEngagementEvent,
shouldIgnoreRequest: pageviewOrEngagementEvent,
expectedRequests: [
{
n: 'Form Submission',
@ -301,16 +301,15 @@ test.describe('form submissions feature is enabled', () => {
})
})
/**
* This function mitigates test flakiness due to the test runner triggering the submit action
* before the tracker script has attached the event listener.
* This flakiness will happen in the real world as well:
* forms submitted before the tracker script attaches the event listener will not be tracked.
* This function ensures that the tracker script has attached the event listener before test is run.
* Note that this race condition happens in the real world as well:
* forms submitted before the tracker script is initialized will not be tracked.
*/
function ensurePlausibleInitialized(page: Page) {
return page.waitForFunction(() => (window as any).plausible?.l === true)
}
const isViewOrEngagementEvent = ({ n }) =>
const pageviewOrEngagementEvent = ({ n }) =>
['pageview', 'engagement'].includes(n)
/**

View File

@ -1,5 +1,5 @@
/*
Tests for plausible-main.js script variant
Tests for plausible-web.js script variant
Unlike in production, we're manually interpolating the script config in this file to
better test the script in isolation of the plausible codebase.
@ -18,12 +18,12 @@ import { LOCAL_SERVER_ADDR } from './support/server'
const DEFAULT_CONFIG = {
domain: 'example.com',
endpoint: `${LOCAL_SERVER_ADDR}/api/event`,
local: true
captureOnLocalhost: true
}
async function openPage(page, config, options = {}) {
const configJson = JSON.stringify({ ...DEFAULT_CONFIG, ...config })
let path = `/plausible-main.html?script_config=${configJson}`
let path = `/plausible-web.html?script_config=${configJson}`
if (options.beforeScriptLoaded) {
path += `&beforeScriptLoaded=${options.beforeScriptLoaded}`
}
@ -34,7 +34,7 @@ async function openPage(page, config, options = {}) {
await page.waitForFunction('window.plausible !== undefined')
}
test.describe('plausible-main.js', () => {
test.describe('plausible-web.js', () => {
test.beforeEach(({ page }) => {
// Mock file download requests
mockRequest(page, 'https://awesome.website.com/file.pdf')
@ -43,33 +43,32 @@ test.describe('plausible-main.js', () => {
test('triggers pageview and engagement automatically', async ({ page }) => {
await expectPlausibleInAction(page, {
action: () => openPage(page, {}),
expectedRequests: [{ n: 'pageview', d: 'example.com', u: expecting.stringContaining('plausible-main.html')}]
expectedRequests: [{ n: 'pageview', d: 'example.com', u: expecting.stringContaining('plausible-web.html')}]
})
await expectPlausibleInAction(page, {
action: () => hideAndShowCurrentTab(page, {delay: 2000}),
expectedRequests: [{n: 'engagement', d: 'example.com', u: expecting.stringContaining('plausible-main.html')}],
expectedRequests: [{n: 'engagement', d: 'example.com', u: expecting.stringContaining('plausible-web.html')}],
})
})
test('does not trigger any events when `local` config is disabled', async ({ page }) => {
await expectPlausibleInAction(page, {
action: () => openPage(page, { local: false }),
action: () => openPage(page, { captureOnLocalhost: false }),
expectedRequests: [],
refutedRequests: [{ n: 'pageview' }]
})
})
test('does not track pageview props, outbound links, file downloads or tagged events without features being enabled', async ({ page }) => {
test('does not track pageview props, outbound links or file downloads without features being enabled', async ({ page }) => {
await expectPlausibleInAction(page, {
action: async () => {
await openPage(page, {})
await page.click('#file-download', { modifiers: [metaKey()] })
await page.click('#tagged-event')
await page.click('#outbound-link')
},
expectedRequests: [{ n: 'pageview', p: expecting.toBeUndefined() }],
refutedRequests: [{ n: 'File Download' }, { n: 'Purchase' }, { n: 'Outbound Link: Click' }],
refutedRequests: [{ n: 'File Download' }, { n: 'Outbound Link: Click' }],
// Webkit captures engagement events differently, so we ignore them in this test
shouldIgnoreRequest: (payload) => payload.n === 'engagement'
})
@ -82,8 +81,8 @@ test.describe('plausible-main.js', () => {
await page.click('#outbound-link')
},
expectedRequests: [
{ n: 'pageview', d: 'example.com', u: expecting.stringContaining('plausible-main.html') },
{ n: 'Outbound Link: Click', d: 'example.com', u: expecting.stringContaining('plausible-main.html'), p: { url: 'https://example.com/' } },
{ n: 'pageview', d: 'example.com', u: expecting.stringContaining('plausible-web.html') },
{ n: 'Outbound Link: Click', d: 'example.com', u: expecting.stringContaining('plausible-web.html'), p: { url: 'https://example.com/' } },
]
})
})
@ -117,7 +116,7 @@ test.describe('plausible-main.js', () => {
plausible.init({ customProperties: () => ({ "title": document.title }) })
})
},
expectedRequests: [{ n: 'pageview', p: { "title": "plausible-main.js tests" } }]
expectedRequests: [{ n: 'pageview', p: { "title": "plausible-web.js tests" } }]
})
})
@ -167,10 +166,10 @@ test.describe('plausible-main.js', () => {
})
})
test('manual mode does not track pageviews', async ({ page }) => {
test('autoCapturePageviews=false mode does not track pageviews', async ({ page }) => {
await expectPlausibleInAction(page, {
action: async () => {
await openPage(page, { manual: true })
await openPage(page, { autoCapturePageviews: false })
await hideAndShowCurrentTab(page, { delay: 200 })
},
expectedRequests: [],
@ -178,21 +177,21 @@ test.describe('plausible-main.js', () => {
})
})
test('manual mode after manual pageview continues tracking', async ({ page }) => {
test('autoCapturePageviews=false mode after manual pageview continues tracking', async ({ page }) => {
await expectPlausibleInAction(page, {
action: async () => {
await openPage(page, { manual: true })
await openPage(page, { autoCapturePageviews: false })
await page.click('#manual-pageview')
await hideAndShowCurrentTab(page, { delay: 200 })
},
expectedRequests: [
{ n: 'pageview', u: '/:test-plausible-main', d: 'example.com' },
{ n: 'engagement', u: '/:test-plausible-main', d: 'example.com' },
{ n: 'pageview', u: '/:test-plausible-web', d: 'example.com' },
{ n: 'engagement', u: '/:test-plausible-web', d: 'example.com' },
],
})
})
test('does not send `h` parameter when `hash` config is disabled', async ({ page }) => {
test('does not send `h` parameter when `hashBasedRouting` config is disabled', async ({ page }) => {
await expectPlausibleInAction(page, {
action: () => openPage(page, {}),
expectedRequests: [{ n: 'pageview', h: expecting.toBeUndefined() }]
@ -201,22 +200,13 @@ test.describe('plausible-main.js', () => {
test('sends `h` parameter when `hash` config is enabled', async ({ page }) => {
await expectPlausibleInAction(page, {
action: () => openPage(page, { hash: true }),
action: () => openPage(page, { hashBasedRouting: true }),
expectedRequests: [{ n: 'pageview', h: 1 }]
})
})
test('tracking tagged events (when feature enabled)', async ({ page }) => {
await openPage(page, { taggedEvents: true })
await expectPlausibleInAction(page, {
action: () => page.click('#tagged-event'),
expectedRequests: [{ n: 'Purchase', p: { foo: 'bar' }, $: expecting.toBeUndefined() }]
})
})
test('tracking tagged events with revenue (when enabled)', async ({ page }) => {
await openPage(page, { taggedEvents: true, revenue: true })
test('tracking tagged events with revenue', async ({ page }) => {
await openPage(page, {})
await expectPlausibleInAction(page, {
action: () => page.click('#tagged-event'),
@ -279,7 +269,7 @@ test.describe('plausible-main.js', () => {
})
})
},
expectedRequests: [{ n: 'pageview', d: 'example.com', u: expecting.stringContaining('plausible-main.html') }]
expectedRequests: [{ n: 'pageview', d: 'example.com', u: expecting.stringContaining('plausible-web.html') }]
})
})
@ -294,7 +284,7 @@ test.describe('plausible-main.js', () => {
})
})
},
expectedRequests: [{ n: 'pageview', d: 'example.com', u: expecting.stringContaining('plausible-main.html')}]
expectedRequests: [{ n: 'pageview', d: 'example.com', u: expecting.stringContaining('plausible-web.html')}]
})
})
})

View File

@ -31,7 +31,7 @@ export async function initializePageDynamically(
await route.fulfill({
body: TEMPLATE.replace(
"<%= plausible_script_url %>",
`/tracker/js/plausible-main.js?script_config=${encodeURIComponent(
`/tracker/js/plausible-web.js?script_config=${encodeURIComponent(
JSON.stringify(scriptConfig)
)}`
).replace("<body></body>", `<body>${bodyContent}</body>`),

View File

@ -23,7 +23,7 @@ export function runLocalFileServer() {
let code = compileFile(variant, { returnCode: true })
if (name === 'plausible-main.js') {
if (name === 'plausible-web.js') {
code = code.replace('"<%= @config_js %>"', req.query.script_config)
}

View File

@ -1,14 +1,10 @@
export type Options = {
hash: boolean;
local: boolean;
exclusions: boolean;
manual: boolean;
revenue: boolean;
pageviewProps: boolean;
hashBasedRouting: boolean;
outboundLinks: boolean;
fileDownloads: boolean;
taggedEvents: boolean;
formSubmissions: boolean;
captureOnLocalhost: boolean;
autoCapturePageviews: boolean;
};
export type ScriptConfig = {