From 37116a2b1295987a634a992bb62350c973c48a40 Mon Sep 17 00:00:00 2001
From: RobertJoonas <56999674+RobertJoonas@users.noreply.github.com>
Date: Mon, 28 Oct 2024 16:30:03 +0100
Subject: [PATCH] Add tests for the pageleave script (#4744)
* move util function to util module
* move playwright config file to tracker dir root
* update Playwright + add gitignores
* Playwright: enable reuseExistingServer (non-CI env)
* store tracker src copies to avoid re-compilation in dev env
* test pageleave on simple navigation
* fix test util fn
* rename local_test npm script
* make test util able to expect multiple requests
* test pageleaves in SPAs
* test pageleave with manual URL
* test pageleave not sent in manual when pageview not triggered
* extend util fn to refute event requests
* test pageleaves not sent in excluded hash pages
* store hashes instead of file copies to detect /tracker/src changes
* drop async
* speed up test suite
---
.gitignore | 10 ++
tracker/compile.js | 8 +-
tracker/dev-compile/can-skip-compile.js | 52 ++++++++++
tracker/package-lock.json | 50 +++++++---
tracker/package.json | 6 +-
.../{test/support => }/playwright.config.js | 11 ++-
.../fixtures/pageleave-hash-exclusions.html | 18 ++++
tracker/test/fixtures/pageleave-hash.html | 19 ++++
tracker/test/fixtures/pageleave-manual.html | 29 ++++++
tracker/test/fixtures/pageleave.html | 24 +++++
tracker/test/manual.spec.js | 43 ++++-----
tracker/test/pageleave.spec.js | 95 +++++++++++++++++++
tracker/test/support/test-utils.js | 49 ++++++++--
13 files changed, 363 insertions(+), 51 deletions(-)
create mode 100644 tracker/dev-compile/can-skip-compile.js
rename tracker/{test/support => }/playwright.config.js (82%)
create mode 100644 tracker/test/fixtures/pageleave-hash-exclusions.html
create mode 100644 tracker/test/fixtures/pageleave-hash.html
create mode 100644 tracker/test/fixtures/pageleave-manual.html
create mode 100644 tracker/test/fixtures/pageleave.html
create mode 100644 tracker/test/pageleave.spec.js
diff --git a/.gitignore b/.gitignore
index 684a1a938..2e11afb90 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,16 @@ npm-debug.log
/assets/node_modules/
/tracker/node_modules/
+# Files generated by Playwright when running tracker tests
+/tracker/test-results/
+/tracker/playwright-report/
+/tracker/blob-report/
+/tracker/playwright/.cache/
+
+# Stored hash of source tracker files used in development environment
+# to detect changes in /tracker/src and avoid unnecessary compilation.
+/tracker/dev-compile/last-hash.txt
+
# test coverage directory
/assets/coverage
diff --git a/tracker/compile.js b/tracker/compile.js
index c4c5add65..b707b3a97 100644
--- a/tracker/compile.js
+++ b/tracker/compile.js
@@ -3,6 +3,12 @@ const fs = require('fs')
const path = require('path')
const Handlebars = require("handlebars");
const g = require("generatorics");
+const { canSkipCompile } = require("./dev-compile/can-skip-compile");
+
+if (process.env.NODE_ENV === 'dev' && canSkipCompile()) {
+ console.info('COMPILATION SKIPPED: No changes detected in tracker dependencies')
+ process.exit(0)
+}
Handlebars.registerHelper('any', function (...args) {
return args.slice(0, -1).some(Boolean)
@@ -35,4 +41,4 @@ compilefile(relPath('src/p.js'), relPath('../priv/tracker/js/p.js'))
variants.map(variant => {
const options = variant.map(variant => variant.replace('-', '_')).reduce((acc, curr) => (acc[curr] = true, acc), {})
compilefile(relPath('src/plausible.js'), relPath(`../priv/tracker/js/plausible.${variant.join('.')}.js`), options)
-})
+})
\ No newline at end of file
diff --git a/tracker/dev-compile/can-skip-compile.js b/tracker/dev-compile/can-skip-compile.js
new file mode 100644
index 000000000..9a955087d
--- /dev/null
+++ b/tracker/dev-compile/can-skip-compile.js
@@ -0,0 +1,52 @@
+const fs = require('fs');
+const path = require('path');
+const crypto = require('crypto');
+
+const LAST_HASH_FILEPATH = path.join(__dirname, './last-hash.txt')
+
+// Re-compilation is only required if any of these files have been changed.
+const COMPILE_DEPENDENCIES = [
+ path.join(__dirname, '../compile.js'),
+ path.join(__dirname, '../src/plausible.js'),
+ path.join(__dirname, '../src/customEvents.js')
+]
+
+function currentHash() {
+ const combinedHash = crypto.createHash('sha256');
+
+ for (const filePath of COMPILE_DEPENDENCIES) {
+ try {
+ const fileContent = fs.readFileSync(filePath);
+ const fileHash = crypto.createHash('sha256').update(fileContent).digest();
+ combinedHash.update(fileHash);
+ } catch (error) {
+ throw new Error(`Failed to read or hash ${filePath}: ${error.message}`);
+ }
+ }
+
+ return combinedHash.digest('hex');
+}
+
+function lastHash() {
+ if (fs.existsSync(LAST_HASH_FILEPATH)) {
+ return fs.readFileSync(LAST_HASH_FILEPATH).toString()
+ }
+}
+
+/**
+ * Returns a boolean indicating whether the tracker compilation can be skipped.
+ * Every time this function gets executed, the hash of the tracker dependencies
+ * will be updated. Compilation can be skipped if the hash hasn't changed since
+ * the last execution.
+ */
+exports.canSkipCompile = function() {
+ const current = currentHash()
+ const last = lastHash()
+
+ if (current === last) {
+ return true
+ } else {
+ fs.writeFileSync(LAST_HASH_FILEPATH, current)
+ return false
+ }
+}
\ No newline at end of file
diff --git a/tracker/package-lock.json b/tracker/package-lock.json
index 94e432413..975fe9bb7 100644
--- a/tracker/package-lock.json
+++ b/tracker/package-lock.json
@@ -6,13 +6,14 @@
"": {
"license": "MIT",
"dependencies": {
- "@playwright/test": "^1.41.1",
"express": "^4.18.1",
"generatorics": "^1.1.0",
"handlebars": "^4.7.8",
"uglify-js": "^3.9.4"
},
"devDependencies": {
+ "@playwright/test": "^1.48.1",
+ "@types/node": "^22.7.7",
"eslint": "^8.56.0",
"eslint-plugin-playwright": "^0.20.0"
}
@@ -151,17 +152,27 @@
}
},
"node_modules/@playwright/test": {
- "version": "1.41.1",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.1.tgz",
- "integrity": "sha512-9g8EWTjiQ9yFBXc6HjCWe41msLpxEX0KhmfmPl9RPLJdfzL4F0lg2BdJ91O9azFdl11y1pmpwdjBiSxvqc+btw==",
+ "version": "1.48.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.1.tgz",
+ "integrity": "sha512-s9RtWoxkOLmRJdw3oFvhFbs9OJS0BzrLUc8Hf6l2UdCNd1rqeEyD4BhCJkvzeEoD1FsK4mirsWwGerhVmYKtZg==",
+ "dev": true,
"dependencies": {
- "playwright": "1.41.1"
+ "playwright": "1.48.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "22.7.7",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.7.tgz",
+ "integrity": "sha512-SRxCrrg9CL/y54aiMCG3edPKdprgMVGDXjA3gB8UmmBW5TcXzRUYAh8EWzTnSJFAd1rgImPELza+A3bJ+qxz8Q==",
+ "dev": true,
+ "dependencies": {
+ "undici-types": "~6.19.2"
}
},
"node_modules/@ungap/structured-clone": {
@@ -855,6 +866,7 @@
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
@@ -1395,31 +1407,33 @@
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
},
"node_modules/playwright": {
- "version": "1.41.1",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.1.tgz",
- "integrity": "sha512-gdZAWG97oUnbBdRL3GuBvX3nDDmUOuqzV/D24dytqlKt+eI5KbwusluZRGljx1YoJKZ2NRPaeWiFTeGZO7SosQ==",
+ "version": "1.48.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.1.tgz",
+ "integrity": "sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w==",
+ "dev": true,
"dependencies": {
- "playwright-core": "1.41.1"
+ "playwright-core": "1.48.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
- "version": "1.41.1",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.1.tgz",
- "integrity": "sha512-/KPO5DzXSMlxSX77wy+HihKGOunh3hqndhqeo/nMxfigiKzogn8kfL0ZBDu0L1RKgan5XHCPmn6zXd2NUJgjhg==",
+ "version": "1.48.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.1.tgz",
+ "integrity": "sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA==",
+ "dev": true,
"bin": {
"playwright-core": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/prelude-ls": {
@@ -1796,6 +1810,12 @@
"node": ">=0.8.0"
}
},
+ "node_modules/undici-types": {
+ "version": "6.19.8",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
+ "dev": true
+ },
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
diff --git a/tracker/package.json b/tracker/package.json
index d1b222583..ef202664c 100644
--- a/tracker/package.json
+++ b/tracker/package.json
@@ -1,19 +1,21 @@
{
"scripts": {
"deploy": "node compile.js",
- "test": "npm run deploy && npx playwright test --config=./test/support/playwright.config.js",
+ "test": "npm run deploy && npx playwright test",
+ "test:local": "NODE_ENV=dev npm run deploy && npx playwright test",
"report-sizes": "node report-sizes.js",
"start": "node test/support/server.js"
},
"license": "MIT",
"dependencies": {
- "@playwright/test": "^1.41.1",
"express": "^4.18.1",
"generatorics": "^1.1.0",
"handlebars": "^4.7.8",
"uglify-js": "^3.9.4"
},
"devDependencies": {
+ "@playwright/test": "^1.48.1",
+ "@types/node": "^22.7.7",
"eslint": "^8.56.0",
"eslint-plugin-playwright": "^0.20.0"
}
diff --git a/tracker/test/support/playwright.config.js b/tracker/playwright.config.js
similarity index 82%
rename from tracker/test/support/playwright.config.js
rename to tracker/playwright.config.js
index 67c91de05..21dc56f49 100644
--- a/tracker/test/support/playwright.config.js
+++ b/tracker/playwright.config.js
@@ -1,10 +1,11 @@
-const { devices } = require('@playwright/test');
+// @ts-check
+const { defineConfig, devices } = require('@playwright/test');
/**
* @see https://playwright.dev/docs/test-configuration
*/
-module.exports = {
- testDir: '../',
+module.exports = defineConfig({
+ testDir: './test',
timeout: 60 * 1000,
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
@@ -33,5 +34,7 @@ module.exports = {
webServer: {
command: 'npm run start',
port: 3000,
+ reuseExistingServer: !process.env.CI
},
-}
+});
+
diff --git a/tracker/test/fixtures/pageleave-hash-exclusions.html b/tracker/test/fixtures/pageleave-hash-exclusions.html
new file mode 100644
index 000000000..aecca154e
--- /dev/null
+++ b/tracker/test/fixtures/pageleave-hash-exclusions.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+ Plausible Playwright tests
+
+
+
+
+ Ignored Hash Link
+ Hash Link 1
+ Hash Link 2
+
+
+
diff --git a/tracker/test/fixtures/pageleave-hash.html b/tracker/test/fixtures/pageleave-hash.html
new file mode 100644
index 000000000..e164362cc
--- /dev/null
+++ b/tracker/test/fixtures/pageleave-hash.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+ Plausible Playwright tests
+
+
+
+
+
+ Hash link
+
+
+
diff --git a/tracker/test/fixtures/pageleave-manual.html b/tracker/test/fixtures/pageleave-manual.html
new file mode 100644
index 000000000..6fa3fd542
--- /dev/null
+++ b/tracker/test/fixtures/pageleave-manual.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+ Plausible Playwright tests
+
+
+
+
+
+ Navigate away
+
+
+
+
+
+
+
diff --git a/tracker/test/fixtures/pageleave.html b/tracker/test/fixtures/pageleave.html
new file mode 100644
index 000000000..bb94b92ee
--- /dev/null
+++ b/tracker/test/fixtures/pageleave.html
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+ Plausible Playwright tests
+
+
+
+
+ Navigate away
+
+
+
+
+
+
+
diff --git a/tracker/test/manual.spec.js b/tracker/test/manual.spec.js
index 0815d7276..f67a7fccb 100644
--- a/tracker/test/manual.spec.js
+++ b/tracker/test/manual.spec.js
@@ -1,35 +1,34 @@
-const { mockRequest } = require('./support/test-utils')
-const { expect, test } = require('@playwright/test');
+/* eslint-disable playwright/expect-expect */
+const { clickPageElementAndExpectEventRequests } = require('./support/test-utils')
+const { test } = require('@playwright/test');
const { LOCAL_SERVER_ADDR } = require('./support/server');
-async function clickPageElementAndExpectEventRequest(page, buttonId, expectedBodyParams) {
- const plausibleRequestMock = mockRequest(page, '/api/event')
- await page.click(buttonId)
- const plausibleRequest = await plausibleRequestMock;
-
- expect(plausibleRequest.url()).toContain('/api/event')
-
- const body = plausibleRequest.postDataJSON()
-
- Object.keys(expectedBodyParams).forEach((key) => {
- expect(body[key]).toEqual(expectedBodyParams[key])
- })
-}
-
test.describe('manual extension', () => {
test('can trigger custom events with and without a custom URL if pageview was sent with the default URL', async ({ page }) => {
await page.goto('/manual.html');
- await clickPageElementAndExpectEventRequest(page, '#pageview-trigger', {n: 'pageview', u: `${LOCAL_SERVER_ADDR}/manual.html`})
- await clickPageElementAndExpectEventRequest(page, '#custom-event-trigger', {n: 'CustomEvent', u: `${LOCAL_SERVER_ADDR}/manual.html`})
- await clickPageElementAndExpectEventRequest(page, '#custom-event-trigger-custom-url', {n: 'CustomEvent', u: `https://example.com/custom/location`})
+ await clickPageElementAndExpectEventRequests(page, '#pageview-trigger', [
+ {n: 'pageview', u: `${LOCAL_SERVER_ADDR}/manual.html`}
+ ])
+ await clickPageElementAndExpectEventRequests(page, '#custom-event-trigger', [
+ {n: 'CustomEvent', u: `${LOCAL_SERVER_ADDR}/manual.html`}
+ ])
+ await clickPageElementAndExpectEventRequests(page, '#custom-event-trigger-custom-url', [
+ {n: 'CustomEvent', u: `https://example.com/custom/location`}
+ ])
});
test('can trigger custom events with and without a custom URL if pageview was sent with a custom URL', async ({ page }) => {
await page.goto('/manual.html');
- await clickPageElementAndExpectEventRequest(page, '#pageview-trigger-custom-url', {n: 'pageview', u: `https://example.com/custom/location`})
- await clickPageElementAndExpectEventRequest(page, '#custom-event-trigger', {n: 'CustomEvent', u: `${LOCAL_SERVER_ADDR}/manual.html`})
- await clickPageElementAndExpectEventRequest(page, '#custom-event-trigger-custom-url', {n: 'CustomEvent', u: `https://example.com/custom/location`})
+ await clickPageElementAndExpectEventRequests(page, '#pageview-trigger-custom-url', [
+ {n: 'pageview', u: `https://example.com/custom/location`}
+ ])
+ await clickPageElementAndExpectEventRequests(page, '#custom-event-trigger', [
+ {n: 'CustomEvent', u: `${LOCAL_SERVER_ADDR}/manual.html`}
+ ])
+ await clickPageElementAndExpectEventRequests(page, '#custom-event-trigger-custom-url', [
+ {n: 'CustomEvent', u: `https://example.com/custom/location`}
+ ])
});
});
diff --git a/tracker/test/pageleave.spec.js b/tracker/test/pageleave.spec.js
new file mode 100644
index 000000000..cfc2acad4
--- /dev/null
+++ b/tracker/test/pageleave.spec.js
@@ -0,0 +1,95 @@
+/* eslint-disable playwright/expect-expect */
+/* eslint-disable playwright/no-skipped-test */
+const { clickPageElementAndExpectEventRequests, mockRequest } = require('./support/test-utils')
+const { test, expect } = require('@playwright/test');
+const { LOCAL_SERVER_ADDR } = require('./support/server');
+
+test.describe('pageleave extension', () => {
+ test.skip(({browserName}) => browserName === 'webkit', 'Not testable on Webkit');
+
+ test('sends a pageleave when navigating to the next page', async ({ page }) => {
+ const pageviewRequestMock = mockRequest(page, '/api/event')
+ await page.goto('/pageleave.html');
+ await pageviewRequestMock;
+
+ await clickPageElementAndExpectEventRequests(page, '#navigate-away', [
+ {n: 'pageleave', u: `${LOCAL_SERVER_ADDR}/pageleave.html`}
+ ])
+ });
+
+ test('sends pageleave and pageview on hash-based SPA navigation', async ({ page }) => {
+ const pageviewRequestMock = mockRequest(page, '/api/event')
+ await page.goto('/pageleave-hash.html');
+ await pageviewRequestMock;
+
+ await clickPageElementAndExpectEventRequests(page, '#hash-nav', [
+ {n: 'pageleave', u: `${LOCAL_SERVER_ADDR}/pageleave-hash.html`},
+ {n: 'pageview', u: `${LOCAL_SERVER_ADDR}/pageleave-hash.html#some-hash`}
+ ])
+ });
+
+ test('sends pageleave and pageview on history-based SPA navigation', async ({ page }) => {
+ const pageviewRequestMock = mockRequest(page, '/api/event')
+ await page.goto('/pageleave.html');
+ await pageviewRequestMock;
+
+ await clickPageElementAndExpectEventRequests(page, '#history-nav', [
+ {n: 'pageleave', u: `${LOCAL_SERVER_ADDR}/pageleave.html`},
+ {n: 'pageview', u: `${LOCAL_SERVER_ADDR}/another-page`}
+ ])
+ });
+
+ test('sends pageleave with the manually overridden URL', async ({ page }) => {
+ await page.goto('/pageleave-manual.html');
+
+ await clickPageElementAndExpectEventRequests(page, '#pageview-trigger-custom-url', [
+ {n: 'pageview', u: 'https://example.com/custom/location'}
+ ])
+
+ await clickPageElementAndExpectEventRequests(page, '#navigate-away', [
+ {n: 'pageleave', u: 'https://example.com/custom/location'}
+ ])
+ });
+
+ test('does not send pageleave when pageview was not sent in manual mode', async ({ page }) => {
+ await page.goto('/pageleave-manual.html');
+
+ await clickPageElementAndExpectEventRequests(page, '#navigate-away', [], [
+ {n: 'pageleave'}
+ ])
+ });
+
+ test('script.exclusions.hash.pageleave.js sends pageleave only from URLs where a pageview was sent', async ({ page }) => {
+ const pageBaseURL = `${LOCAL_SERVER_ADDR}/pageleave-hash-exclusions.html`
+
+ const pageviewRequestMock = mockRequest(page, '/api/event')
+ await page.goto('/pageleave-hash-exclusions.html');
+ await pageviewRequestMock;
+
+ // After the initial pageview is sent, navigate to ignored page ->
+ // pageleave event is sent from the initial page URL
+ await clickPageElementAndExpectEventRequests(page, '#ignored-hash-link', [
+ {n: 'pageleave', u: pageBaseURL, h: 1}
+ ])
+
+ // Navigate from ignored page to a tracked page ->
+ // no pageleave from the current page, pageview on the next page
+ await clickPageElementAndExpectEventRequests(
+ page,
+ '#hash-link-1',
+ [{n: 'pageview', u: `${pageBaseURL}#hash1`, h: 1}],
+ [{n: 'pageleave'}]
+ )
+
+ // Navigate from a tracked page to another tracked page ->
+ // pageleave with the last page URL, pageview with the new URL
+ await clickPageElementAndExpectEventRequests(
+ page,
+ '#hash-link-2',
+ [
+ {n: 'pageleave', u: `${pageBaseURL}#hash1`, h: 1},
+ {n: 'pageview', u: `${pageBaseURL}#hash2`, h: 1}
+ ],
+ )
+ });
+});
\ No newline at end of file
diff --git a/tracker/test/support/test-utils.js b/tracker/test/support/test-utils.js
index 6c01e4f3b..10758ecb1 100644
--- a/tracker/test/support/test-utils.js
+++ b/tracker/test/support/test-utils.js
@@ -1,10 +1,10 @@
const { expect } = require("@playwright/test");
// Mocks an HTTP request call with the given path. Returns a Promise that resolves to the request
-// data. If the request is not made, resolves to null after 10 seconds.
-exports.mockRequest = function (page, path) {
+// data. If the request is not made, resolves to null after 3 seconds.
+const mockRequest = function (page, path) {
return new Promise((resolve, _reject) => {
- const requestTimeoutTimer = setTimeout(() => resolve(null), 10000)
+ const requestTimeoutTimer = setTimeout(() => resolve(null), 3000)
page.route(path, (route, request) => {
clearTimeout(requestTimeoutTimer)
@@ -14,6 +14,8 @@ exports.mockRequest = function (page, path) {
})
}
+exports.mockRequest = mockRequest
+
exports.metaKey = function() {
if (process.platform === 'darwin') {
return 'Meta'
@@ -23,13 +25,13 @@ exports.metaKey = function() {
}
// Mocks a specified number of HTTP requests with given path. Returns a promise that resolves to a
-// list of requests as soon as the specified number of requests is made, or 10 seconds has passed.
-exports.mockManyRequests = function(page, path, numberOfRequests) {
+// list of requests as soon as the specified number of requests is made, or 3 seconds has passed.
+const mockManyRequests = function(page, path, numberOfRequests) {
return new Promise((resolve, _reject) => {
let requestList = []
- const requestTimeoutTimer = setTimeout(() => resolve(requestList), 10000)
+ const requestTimeoutTimer = setTimeout(() => resolve(requestList), 3000)
- page.route('/api/event', (route, request) => {
+ page.route(path, (route, request) => {
requestList.push(request)
if (requestList.length === numberOfRequests) {
clearTimeout(requestTimeoutTimer)
@@ -40,6 +42,8 @@ exports.mockManyRequests = function(page, path, numberOfRequests) {
})
}
+exports.mockManyRequests = mockManyRequests
+
exports.expectCustomEvent = function (request, eventName, eventProps) {
const payload = request.postDataJSON()
@@ -49,3 +53,34 @@ exports.expectCustomEvent = function (request, eventName, eventProps) {
expect(payload.p[key]).toEqual(value)
}
}
+
+exports.clickPageElementAndExpectEventRequests = async function (page, locatorToClick, expectedBodySubsets, refutedBodySubsets = []) {
+ const requestsToExpect = expectedBodySubsets.length
+ const requestsToAwait = requestsToExpect + refutedBodySubsets.length
+
+ const plausibleRequestMockList = mockManyRequests(page, '/api/event', requestsToAwait)
+ await page.click(locatorToClick)
+ const requests = await plausibleRequestMockList
+
+ expect(requests.length).toBe(requestsToExpect)
+
+ expectedBodySubsets.forEach((bodySubset) => {
+ expect(requests.some((request) => {
+ return hasExpectedBodyParams(request, bodySubset)
+ })).toBe(true)
+ })
+
+ refutedBodySubsets.forEach((bodySubset) => {
+ expect(requests.every((request) => {
+ return !hasExpectedBodyParams(request, bodySubset)
+ })).toBe(true)
+ })
+}
+
+function hasExpectedBodyParams(request, expectedBodyParams) {
+ const body = request.postDataJSON()
+
+ return Object.keys(expectedBodyParams).every((key) => {
+ return body[key] === expectedBodyParams[key]
+ })
+}