/** * Smoke tests for the Shaarli Pro theme. * * These tests require a running Shaarli instance with the shaarli-pro theme * activated. Set SHAARLI_URL before running. * * Example: * SHAARLI_URL=http://localhost:8080 npx playwright test */ 'use strict'; const { test, expect } = require('@playwright/test'); /** * Verify the current page resolves to a Shaarli instance. * Returns true if Shaarli elements are found, skips the test otherwise. */ async function ensureShaarli(page, testInfo) { // Check for Shaarli-specific markers (linklist container, sidebar, or the search overlay) const shaarliMarkers = page.locator('#linklist, .shaarli-sidebar, #search-overlay, .search-overlay, meta[name="generator"][content*="Shaarli"]'); await shaarliMarkers.first().waitFor({ state: 'attached', timeout: 3000 }).catch(() => {}); const count = await shaarliMarkers.count(); if (count === 0) { // Diagnose: what's actually running on this URL? const title = await page.title(); const bodyText = await page.locator('body').textContent({ timeout: 2000 }).catch(() => '(timeout)'); const snippet = (bodyText || '').substring(0, 200); throw new Error( `SHAARLI_URL (${testInfo.project.use.baseURL}) does not appear to be a Shaarli instance.\n` + `Page title: "${title}"\n` + `Page content: "${snippet}"\n\n` + `Make sure:\n` + ` 1. Shaarli is running and accessible at this URL\n` + ` 2. The "shaarli-pro" theme is activated in Shaarli settings\n` + ` 3. No other application is using this port` ); } return true; } test.describe('Shaarli Pro theme smoke tests', () => { test('homepage loads and shows the main layout', async ({ page }, testInfo) => { await page.goto('/'); await expect(page.locator('body')).toBeVisible(); await ensureShaarli(page, testInfo); // Header should be present (the theme uses
) const header = page.locator('header.header-main'); await expect(header).toBeVisible({ timeout: 5000 }); // Sidebar should be present const sidebar = page.locator('.sidebar'); await expect(sidebar).toBeVisible(); }); test('search overlay opens with the S shortcut', async ({ page }, testInfo) => { await page.goto('/'); await ensureShaarli(page, testInfo); const search = page.locator('.search-overlay, #search-overlay'); await expect(search).not.toBeVisible(); await page.keyboard.press('s'); await expect(search).toBeVisible({ timeout: 3000 }); await page.keyboard.press('Escape'); await expect(search).not.toBeVisible({ timeout: 2000 }); }); test('theme toggle changes data-theme attribute', async ({ page }, testInfo) => { await page.goto('/'); await ensureShaarli(page, testInfo); const toggle = page.locator('[data-theme-toggle], .theme-toggle, #theme-toggle'); if (await toggle.count() === 0) { test.skip('No theme toggle found on this page'); return; } const initialTheme = await page.locator('html').getAttribute('data-theme'); await toggle.click(); await page.waitForTimeout(200); const newTheme = await page.locator('html').getAttribute('data-theme'); expect(newTheme).not.toEqual(initialTheme); }); test('skip-link is present for keyboard users', async ({ page }, testInfo) => { await page.goto('/'); await ensureShaarli(page, testInfo); await expect(page.locator('.skip-link')).toBeVisible(); await expect(page.locator('.skip-link')).toHaveAttribute('href'); }); test('bulk selection button is present on link list', async ({ page }, testInfo) => { await page.goto('/'); await ensureShaarli(page, testInfo); const bulkButton = page.locator('[data-bulk-select], .bulk-select-toggle, #bulk-select'); if (await bulkButton.count() === 0) { test.skip('No bulk selection button found (user may not be logged in)'); return; } await expect(bulkButton).toBeVisible(); }); });