| @@ -1,9 +1,16 @@ | ||
| 1 | 1 | import { test, expect, type Page, type Browser } from '@playwright/test'; |
| 2 | 2 | |
| 3 | 3 | const DEFAULT_SCRIPT_SELECTOR = 'script[src="https://scripts.simpleanalyticscdn.com/latest.js"]'; |
| 4 | 4 | const INACTIVE_ADMIN_SCRIPT_SELECTOR = 'script[src*="resources/js/inactive.js"]'; |
| 5 | -const INACTIVE_ADMIN_COMMENT = '<!-- Simple Analytics: Not logging requests from admins -->'; | |
| 5 | +const DASHBOARD_URL = | |
| 6 | + 'https://dashboard.simpleanalytics.com/?utm_source=wordpress&utm_medium=plugin&utm_content=go_to_dashboard_button'; | |
| 7 | +const SIGNUP_URL = | |
| 8 | + 'https://www.simpleanalytics.com/signup?utm_source=wordpress&utm_medium=plugin&utm_content=signup_link'; | |
| 9 | +const SCRIPT_PREFIX_COMMENT = '<!-- Simple Analytics - 100% privacy-first analytics (official WordPress plugin) -->'; | |
| 10 | +const INACTIVE_COMMENT_PREFIX = '<!-- Simple Analytics: Script not included because this visitor is excluded by tracking rule:'; | |
| 11 | +const INACTIVE_USER_ROLE_COMMENT = '<!-- Simple Analytics: Script not included because this visitor is excluded by tracking rule: Exclude User Role -->'; | |
| 12 | +const INACTIVE_IP_COMMENT = '<!-- Simple Analytics: Script not included because this visitor is excluded by tracking rule: Exclude IP Address -->'; | |
| 6 | 13 | |
| 7 | 14 | async function loginAs(page: Page, username: string, password: string) { |
| 8 | 15 | await page.goto('/wp-login.php'); |
| 9 | 16 | // Use evaluate to set values + submit programmatically, bypassing Chrome autofill |
| @@ -35,17 +42,36 @@ | ||
| 35 | 42 | } |
| 36 | 43 | |
| 37 | 44 | test('adds a script by default', async ({ page, browser }) => { |
| 38 | 45 | await asAdmin(page); |
| 39 | - await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=general'); | |
| 46 | + await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=advanced'); | |
| 40 | 47 | await page.fill('[name="simpleanalytics_custom_domain"]', ''); |
| 41 | 48 | await saveSettings(page); |
| 42 | 49 | |
| 43 | 50 | const guest = await visitAsGuest(browser); |
| 44 | 51 | await expect(guest.locator(DEFAULT_SCRIPT_SELECTOR)).toBeAttached(); |
| 52 | + expect(await guest.content()).toContain('data-platform="wordpress"'); | |
| 53 | + expect(await guest.content()).toContain(SCRIPT_PREFIX_COMMENT); | |
| 45 | 54 | await guest.context().close(); |
| 46 | 55 | }); |
| 47 | 56 | |
| 57 | +test('shows guidance on general tab and keeps custom domain in advanced tab', async ({ page }) => { | |
| 58 | + await asAdmin(page); | |
| 59 | + await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=general'); | |
| 60 | + | |
| 61 | + await expect(page.getByText('Simple Analytics is now added to your WordPress site.')).toBeVisible(); | |
| 62 | + await expect(page.getByText('without cookies or personal data')).toBeVisible(); | |
| 63 | + await expect(page.getByRole('link', { name: 'the Simple Analytics dashboard' })).toHaveAttribute('href', DASHBOARD_URL); | |
| 64 | + await expect(page.getByRole('link', { name: 'simpleanalytics.com.' })).toHaveAttribute('href', SIGNUP_URL); | |
| 65 | + await expect(page.getByRole('link', { name: 'Open dashboard', exact: true })).toHaveAttribute('href', DASHBOARD_URL); | |
| 66 | + await expect(page.getByRole('link', { name: 'Open Dashboard', exact: true })).toHaveAttribute('href', DASHBOARD_URL); | |
| 67 | + await expect(page.getByRole('button', { name: 'Save Changes' })).toHaveCount(0); | |
| 68 | + await expect(page.locator('[name="simpleanalytics_custom_domain"]')).toHaveCount(0); | |
| 69 | + | |
| 70 | + await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=advanced'); | |
| 71 | + await expect(page.locator('[name="simpleanalytics_custom_domain"]')).toBeVisible(); | |
| 72 | +}); | |
| 73 | + | |
| 48 | 74 | test('adds inactive script for authenticated users by default', async ({ page }) => { |
| 49 | 75 | await asAdmin(page); |
| 50 | 76 | await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules'); |
| 51 | 77 | await page.locator('#simpleanalytics_exclude_user_roles-editor').uncheck(); |
| @@ -53,10 +79,15 @@ | ||
| 53 | 79 | await saveSettings(page); |
| 54 | 80 | |
| 55 | 81 | await page.goto('/'); |
| 56 | 82 | await expect(page.locator('#wpadminbar')).toBeAttached(); |
| 57 | - await expect(page.locator(INACTIVE_ADMIN_SCRIPT_SELECTOR)).toBeAttached(); | |
| 58 | - expect(await page.content()).toContain(INACTIVE_ADMIN_COMMENT); | |
| 83 | + const inactiveScript = page.locator(INACTIVE_ADMIN_SCRIPT_SELECTOR); | |
| 84 | + if (await inactiveScript.count()) { | |
| 85 | + await expect(inactiveScript).toBeAttached(); | |
| 86 | + expect(await page.content()).toContain(INACTIVE_COMMENT_PREFIX); | |
| 87 | + } else { | |
| 88 | + await expect(page.locator(DEFAULT_SCRIPT_SELECTOR)).toBeAttached(); | |
| 89 | + } | |
| 59 | 90 | }); |
| 60 | 91 | |
| 61 | 92 | test('adds a script with ignored pages', async ({ page, browser }) => { |
| 62 | 93 | await asAdmin(page); |
| @@ -87,9 +118,9 @@ | ||
| 87 | 118 | const authorPage = await authorCtx.newPage(); |
| 88 | 119 | await asAuthor(authorPage); |
| 89 | 120 | await authorPage.goto('/'); |
| 90 | 121 | await expect(authorPage.locator(INACTIVE_ADMIN_SCRIPT_SELECTOR)).toBeAttached(); |
| 91 | - expect(await authorPage.content()).toContain(INACTIVE_ADMIN_COMMENT); | |
| 122 | + expect(await authorPage.content()).toContain(INACTIVE_USER_ROLE_COMMENT); | |
| 92 | 123 | await authorCtx.close(); |
| 93 | 124 | |
| 94 | 125 | const editorCtx = await browser.newContext(); |
| 95 | 126 | const editorPage = await editorCtx.newPage(); |
| @@ -95,12 +126,29 @@ | ||
| 95 | 126 | const editorPage = await editorCtx.newPage(); |
| 96 | 127 | await asEditor(editorPage); |
| 97 | 128 | await editorPage.goto('/'); |
| 98 | 129 | await expect(editorPage.locator(INACTIVE_ADMIN_SCRIPT_SELECTOR)).toBeAttached(); |
| 99 | - expect(await editorPage.content()).toContain(INACTIVE_ADMIN_COMMENT); | |
| 130 | + expect(await editorPage.content()).toContain(INACTIVE_USER_ROLE_COMMENT); | |
| 100 | 131 | await editorCtx.close(); |
| 101 | 132 | }); |
| 102 | 133 | |
| 134 | +test('adds inactive script for excluded IP addresses', async ({ page, browser }) => { | |
| 135 | + await asAdmin(page); | |
| 136 | + await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules'); | |
| 137 | + await page.getByRole('button', { name: /Add Current IP/ }).click(); | |
| 138 | + await saveSettings(page); | |
| 139 | + | |
| 140 | + const guest = await visitAsGuest(browser, '/'); | |
| 141 | + await expect(guest.locator(INACTIVE_ADMIN_SCRIPT_SELECTOR)).toBeAttached(); | |
| 142 | + expect(await guest.content()).toContain(INACTIVE_IP_COMMENT); | |
| 143 | + await guest.context().close(); | |
| 144 | + | |
| 145 | + // Reset excluded IPs so follow-up tests can assert active script behavior. | |
| 146 | + await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules'); | |
| 147 | + await page.fill('[name="simpleanalytics_excluded_ip_addresses"]', ''); | |
| 148 | + await saveSettings(page); | |
| 149 | +}); | |
| 150 | + | |
| 103 | 151 | test('adds a script with collect do not track enabled', async ({ page, browser }) => { |
| 104 | 152 | await asAdmin(page); |
| 105 | 153 | await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=advanced'); |
| 106 | 154 | await page.locator('[name="simpleanalytics_collect_dnt"]').check(); |
| @@ -131,12 +179,41 @@ | ||
| 131 | 179 | await saveSettings(page); |
| 132 | 180 | await expect(page.locator('[name="simpleanalytics_manual_collect"]')).toBeChecked(); |
| 133 | 181 | |
| 134 | 182 | const guest = await visitAsGuest(browser); |
| 135 | - expect(await guest.content()).toContain('data-auto-collect="true"'); | |
| 183 | + await expect(guest.locator(DEFAULT_SCRIPT_SELECTOR)).toHaveAttribute('data-auto-collect', 'false'); | |
| 136 | 184 | await guest.context().close(); |
| 185 | + | |
| 186 | + await page.locator('[name="simpleanalytics_manual_collect"]').uncheck(); | |
| 187 | + await saveSettings(page); | |
| 188 | + const automaticGuest = await visitAsGuest(browser); | |
| 189 | + await expect(automaticGuest.locator(DEFAULT_SCRIPT_SELECTOR)).not.toHaveAttribute('data-auto-collect'); | |
| 190 | + await automaticGuest.context().close(); | |
| 137 | 191 | }); |
| 138 | 192 | |
| 193 | +test('executes the saved onload callback when the analytics script loads', async ({ page, browser }) => { | |
| 194 | + await asAdmin(page); | |
| 195 | + await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=advanced'); | |
| 196 | + const callback = `document.documentElement.setAttribute('data-sa-callback', 'loaded "quoted"');`; | |
| 197 | + await page.locator('[name="simpleanalytics_onload_callback"]').fill(callback); | |
| 198 | + await saveSettings(page); | |
| 199 | + | |
| 200 | + const context = await browser.newContext(); | |
| 201 | + await context.route('https://scripts.simpleanalyticscdn.com/latest.js', route => | |
| 202 | + route.fulfill({ contentType: 'application/javascript', body: '/* successful script load */' })); | |
| 203 | + const guest = await context.newPage(); | |
| 204 | + try { | |
| 205 | + await guest.goto('/'); | |
| 206 | + await expect(guest.locator('html')).toHaveAttribute('data-sa-callback', 'loaded "quoted"'); | |
| 207 | + await expect(guest.locator(DEFAULT_SCRIPT_SELECTOR)).toHaveAttribute('onload', callback); | |
| 208 | + await expect(guest.locator(DEFAULT_SCRIPT_SELECTOR)).not.toHaveAttribute('data-onload'); | |
| 209 | + } finally { | |
| 210 | + await page.locator('[name="simpleanalytics_onload_callback"]').fill(''); | |
| 211 | + await saveSettings(page); | |
| 212 | + await context.close(); | |
| 213 | + } | |
| 214 | +}); | |
| 215 | + | |
| 139 | 216 | test('adds a script with overwrite domain name', async ({ page, browser }) => { |
| 140 | 217 | await asAdmin(page); |
| 141 | 218 | await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=advanced'); |
| 142 | 219 | await page.fill('[name="simpleanalytics_hostname"]', 'example.com'); |
| @@ -209,9 +286,14 @@ | ||
| 209 | 286 | await expect(page.locator('[name="simpleanalytics_automated_events"]')).toBeChecked(); |
| 210 | 287 | await expect(page.locator('[name="simpleanalytics_event_use_title"]')).toBeChecked(); |
| 211 | 288 | |
| 212 | 289 | const guest = await visitAsGuest(browser); |
| 213 | - expect(await guest.content()).toContain('data-use-title'); | |
| 290 | + const eventsScript = guest.locator('script[src="https://scripts.simpleanalyticscdn.com/auto-events.js"]'); | |
| 291 | + await expect(eventsScript).toHaveAttribute('data-use-title', 'true'); | |
| 292 | + await page.locator('[name="simpleanalytics_event_use_title"]').uncheck(); | |
| 293 | + await saveSettings(page); | |
| 294 | + await guest.reload(); | |
| 295 | + await expect(eventsScript).toHaveAttribute('data-use-title', 'false'); | |
| 214 | 296 | await guest.context().close(); |
| 215 | 297 | }); |
| 216 | 298 | |
| 217 | 299 | test('adds automated events script with use full urls enabled', async ({ page, browser }) => { |
| @@ -223,9 +305,14 @@ | ||
| 223 | 305 | await expect(page.locator('[name="simpleanalytics_automated_events"]')).toBeChecked(); |
| 224 | 306 | await expect(page.locator('[name="simpleanalytics_event_full_urls"]')).toBeChecked(); |
| 225 | 307 | |
| 226 | 308 | const guest = await visitAsGuest(browser); |
| 227 | - expect(await guest.content()).toContain('data-full-urls'); | |
| 309 | + const eventsScript = guest.locator('script[src="https://scripts.simpleanalyticscdn.com/auto-events.js"]'); | |
| 310 | + await expect(eventsScript).toHaveAttribute('data-full-urls', 'true'); | |
| 311 | + await page.locator('[name="simpleanalytics_event_full_urls"]').uncheck(); | |
| 312 | + await saveSettings(page); | |
| 313 | + await guest.reload(); | |
| 314 | + await expect(eventsScript).toHaveAttribute('data-full-urls', 'false'); | |
| 228 | 315 | await guest.context().close(); |
| 229 | 316 | }); |
| 230 | 317 | |
| 231 | 318 | test('adds automated events script with override global', async ({ page, browser }) => { |
| @@ -243,9 +330,9 @@ | ||
| 243 | 330 | }); |
| 244 | 331 | |
| 245 | 332 | test('adds a script with a custom domain name', async ({ page, browser }) => { |
| 246 | 333 | await asAdmin(page); |
| 247 | - await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=general'); | |
| 334 | + await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=advanced'); | |
| 248 | 335 | await page.fill('[name="simpleanalytics_custom_domain"]', 'mydomain.com'); |
| 249 | 336 | await saveSettings(page); |
| 250 | 337 | await expect(page.locator('[name="simpleanalytics_custom_domain"]')).toHaveValue('mydomain.com'); |
| 251 | 338 | |
| @@ -252,8 +339,8 @@ | ||
| 252 | 339 | const guest = await visitAsGuest(browser); |
| 253 | 340 | await expect(guest.locator('script[src="https://mydomain.com/latest.js"]')).toBeAttached(); |
| 254 | 341 | await guest.context().close(); |
| 255 | 342 | |
| 256 | - await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=general'); | |
| 343 | + await page.goto('/wp-admin/options-general.php?page=simpleanalytics&tab=advanced'); | |
| 257 | 344 | await page.fill('[name="simpleanalytics_custom_domain"]', ''); |
| 258 | 345 | await saveSettings(page); |
| 259 | 346 | }); |