@flusterduck/test-suite
v0.7.18
Published
Playwright-based frustration simulation test suite
Readme
@flusterduck/test-suite
Playwright-based frustration simulation CLI. Programmatically triggers the behavioral patterns that Flusterduck detects so you can verify your SDK integration, test alert thresholds, and regression-test scoring pipelines.
Installation
npm install --save-dev @flusterduck/test-suite@playwright/test ships as a dependency, so you only need to install browsers: npx playwright install chromium.
CLI usage
npx flusterduck-test --url https://your-app.com --key fd_pub_...Loads the URL in a headless Chromium browser and runs the full simulation suite against it. The target page needs the Flusterduck SDK installed already: the CLI never talks to Flusterduck itself, it just drives the DOM the way a frustrated visitor would, and the SDK already on the page detects and reports as normal. --key isn't sent anywhere; it's echoed in the report as a reminder of which dashboard to go check.
| Flag | Description |
|---|---|
| --url <url> | Target URL to test. Required. |
| --key <fd_pub_xxx> | Publishable key, shown in the report for reference. |
| --mobile | Simulate a mobile device with touch. Adds the tap-miss, pinch-zoom, and swipe simulations. |
| --headed | Show the browser window instead of running headless. |
| --verbose | Print per-element details. |
| --json | Output machine-readable JSON. |
| --threshold <n> | Exit with code 1 if fewer than n signals were simulated. |
| --help, -h | Show usage. |
Programmatic usage
Simulations run against a live Playwright Page, so you drive the browser yourself:
import { chromium } from '@playwright/test';
import { runAllSimulations, simulateRageClicks } from '@flusterduck/test-suite';
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://your-app.com');
// Run every simulation in sequence
const results = await runAllSimulations(page, {
context,
baseUrl: 'https://your-app.com',
});
// Or run one simulation directly
const rageResult = await simulateRageClicks(page);
await browser.close();Available simulations
| Function | Triggers |
|---|---|
| simulateRageClicks | 3+ rapid clicks on one target |
| simulateDeadClicks | Clicks on unresponsive elements |
| simulateThrashCursor | Erratic mouse movement |
| simulateFormHesitation | Long pause in a form field |
| simulateFormAbandonment | Interact then leave without submitting |
| simulateLoopNavigation | Visit same page 3+ times |
| simulateScrollBounce | Scroll to bottom then back immediately |
| simulateTabThrash | Rapid Tab key use |
| simulateMobileTapMiss | Touch on non-interactive area |
| simulatePinchZoom | Pinch gesture on non-zoomable content |
| simulateSwipe | Failed swipe gesture |
Result format
interface SimulationResult {
signal: string;
element?: string;
simulated: boolean;
details: string;
timestamp: number;
}simulated is false when a simulation found nothing to act on (no matching elements, a timed-out step) rather than actually driving the page.
