How to Test Comments on Web (Complete Guide)
Comment sections are a common interaction point in blogs, e‑commerce product pages, social feeds, and SaaS dashboards. They enable users to ask questions, share feedback, and build community, but they
Why Testing Comments Is Critical for Web Applications
Comment sections are a common interaction point in blogs, e‑commerce product pages, social feeds, and SaaS dashboards. They enable users to ask questions, share feedback, and build community, but they also introduce a surface area where defects can silently degrade experience, expose data, or violate regulations. A broken comment flow can:
- Prevent legitimate users from posting, leading to lost engagement and support tickets.
- Allow malicious payloads (XSS, CSRF, spam) to persist, compromising other users.
- Violate accessibility guidelines (WCAG 2.1 AA) if keyboard navigation, ARIA labels, or contrast are missing.
- Leak personal data through improper handling of user‑generated content (e.g., displaying email addresses).
- Cause performance regressions when infinite‑scroll or lazy‑load mechanisms misbehave under large comment volumes.
Because comments often sit behind authentication, involve real‑time updates (WebSockets, Server‑Sent Events), and rely on third‑party widgets, they are prone to integration bugs that unit tests miss. A systematic test strategy—combining manual exploration, automated checks, and persona‑driven autonomous testing—helps catch those gaps before they reach production.
---
Comprehensive Test Matrix for Comment Features
| Category | Sub‑area | Happy‑Path | Error / Invalid Input | Edge / Boundary | Accessibility | Security / Privacy |
|---|---|---|---|---|---|---|
| Input | Text entry | Submit a comment with plain text (≤ max length) | Submit empty comment, whitespace only | Submit comment at exactly max length, max + 1 char | Ensure field has visible label, accessible name, proper ARIA‑describedby | Strip or escape HTML/JS, prevent script injection |
| Rich text / markdown | Apply bold, italic, list, link, image embed | Invalid markdown syntax, unclosed tags | Nesting depth limits, oversized image URL | Keyboard navigation within toolbar, screen‑reader announcement of formatting buttons | Sanitize HTML output, restrict allowed tags, enforce CSP | |
| Attachments | Upload allowed file types (png, jpg, pdf) within size limit | Upload disallowed type (exe), oversized file, corrupted file | Upload exactly at size limit, zero‑byte file | Provide accessible upload button, announce upload progress | Scan for malware, enforce Content‑Disposition, avoid storing raw file paths | |
| Submission | Button click | Click “Post” → comment appears instantly or after optimistic UI update | Click disabled button (e.g., while validation fails) | Rapid double‑click, click after navigation away | Button reachable via Tab, has accessible label, announces success/failure | Verify CSRF token, rate‑limit per user/IP, confirm server‑side validation |
| Enter key | Press Enter in focused textarea → submit (if configured) | Enter does nothing when shift‑Enter for newline | Enter with modifier keys (Ctrl+Enter) | Ensure announce of submission status via live region | Same CSRF & rate‑limit checks | |
| Display | Rendering | Comment shows author name, timestamp, formatted text, avatar | Show placeholder for missing avatar, handle long usernames | Very long comment (truncation, “show more” link), nested replies depth > 5 | Sufficient contrast, scalable fonts, ARIA‑labelled comment containers, live region for new comments | Ensure no raw user input is rendered; verify CSP headers block inline scripts |
| Pagination / Infinite scroll | Scroll to bottom loads next page, URL updates if applicable | Scroll when no more data, network error | Jump to page 100 directly via URL, rapid scroll bursts | Keyboard scrollable, focus management on newly loaded items, announce new batch | Validate that lazy‑loaded endpoints enforce same auth & rate limits | |
| Moderation | Delete / Edit | Author can edit/delete own comment; moderator can delete any | Non‑author attempts edit/delete → 403 | Edit to empty string, edit after deletion attempt | Edit/delete controls reachable via keyboard, announced via ARIA | Confirm server‑side authorization, prevent IDOR, log moderation actions |
| Notifications | Email / in‑app | User receives notification when replied to or mentioned | Notification suppressed due to user preferences | Bulk notifications for thread with > 50 replies | Notification banner accessible, dismissible, respects reduced motion | Ensure no PII leaked in email subject/body, respect GDPR opt‑out |
| Internationalization | Language | Comment submitted in UTF‑8 (e.g., emojis, CJK) displays correctly | Input with unsupported charset leads to garbled text | Very long Japanese word without spaces tests line‑break handling | Language‑specific screen‑screen‑reader announcements, proper lang attribute | Verify that translation does not reintroduce XSS via crafted Unicode |
| Performance | Load time | Page with 0‑20 comments loads < 2 s (3G simulated) | Page with 5000 comments triggers lazy‑load correctly | Simultaneous POST from 50 users, measure server CPU/memory | Ensure UI remains responsive, no blocking main thread during render | Verify that rate‑limiting does not cause denial‑of‑service for legitimate users |
*The matrix above is not exhaustive but captures the dimensions most teams overlook when they focus only on “can I post a comment?”*
---
Manual Testing Approach – Step‑by‑Step
A disciplined manual session helps uncover nuances that automated scripts may skip, especially around UX flow and contextual behavior. Follow this checklist for each comment‑enabled page:
- Preparation
- Log in with a test data: create two user accounts (regular user and moderator).
- Clear existing comments to start from a clean state.
- Enable browser devtools (Network, Console, Accessibility tab) and a screen‑reader (NVDA or VoiceOver).
- Happy‑Path Validation
- Navigate to the page, locate the comment textarea.
- Type a short comment (e.g., “Looks good!”) and submit via button.
- Verify the comment appears immediately, shows correct author, timestamp, and any avatar.
- If the UI uses optimistic update, disconnect network briefly and confirm the comment persists after reconnection.
- Input Validation
- Try submitting an empty comment; ensure inline validation message appears and is announced by the screen‑reader.
- Paste the maximum allowed characters; confirm submission works and UI does not break.
- Paste max + 1 characters; verify the system blocks submission and shows a clear error.
- Rich Text / Markdown
- Apply each formatting option (bold, italic, code block, link, image).
- Preview the rendered output; confirm no stray HTML tags appear.
- Attempt to inject
via markdown link or image URL; verify it is neutralized.
- File Attachments
- Upload a valid PNG under the size limit; confirm thumbnail appears and file can be downloaded.
- Try uploading an executable; expect rejection with an accessible error message.
- Keyboard‑Only Navigation
- Tab through all controls: textarea, formatting toolbar, submit button, cancel link.
- Ensure each element receives a visible focus indicator (minimum 2 px contrast).
- Press Enter/Space on the submit button; confirm action triggers.
- Use Shift+Enter to insert a newline when the form is configured for that behavior.
- Screen‑Reader Validation
- Move focus to the comment list; verify new comment is announced via ARIA live region (
aria-live="polite"). - Check that each comment container has an accessible name (e.g., “Comment by Jane Doe, posted 2 minutes ago”).
- Confirm that edit/delete buttons are announced with their purpose.
- Pagination / Infinite Scroll
- Scroll down until the next batch loads; watch network calls for correct endpoint and parameters.
- Disable JavaScript and reload; confirm server‑side pagination still works (fallback).
- Simulate a slow network (throttle to 3G) and observe loading spinners and error handling.
- Moderation Flows
- Log in as moderator, open a comment authored by another user, click Delete.
- Verify comment disappears from UI and a DELETE request hits the correct endpoint with proper auth headers.
- Attempt to edit another user's comment as a regular user; expect 403 response and UI unchanged.
- Error & Boundary Conditions
- Simulate a 500 server error on submit (using devtools to override response). Ensure UI shows a retry option and does not lose the comment draft.
- Disconnect internet mid‑submit; confirm optimistic UI rolls back or shows a “saving…” state.
- Rapidly click submit 10 times; verify only one request is sent (debouncing) or that server enforces idempotency.
- Accessibility Regression Checks
- Run an automated axe core scan on the page after each major interaction (submit, edit, delete).
- Manually verify color contrast ratios for text, icons, and focus outlines using the Chrome Contrast Checker.
- Test with forced colors mode (Windows High Contrast) and ensure UI remains usable.
- Data Privacy Spot‑Check
- Inspect network payloads for any unintended personal data (e.g., email, IP) sent in comment creation requests.
- Verify that the server does not echo raw user input in error messages (which could leak validation logic).
- Teardown
- Log out, clear local storage / session storage, and confirm no stale comment data persists in the browser cache.
Following this procedure on each release candidate gives confidence that the comment subsystem behaves correctly under typical and atypical conditions.
---
Automated Testing Strategies for Web Comments
While manual checks are invaluable, regression safety requires automated coverage. Below are practical patterns and tool choices that integrate well with CI pipelines.
1. Unit‑Level Validation (JavaScript/TypeScript)
If the comment component is built with React, Vue, or Svelte, write unit tests that isolate input handling and rendering logic.
// Example with React Testing Library + Jest
import { render, screen, fireEvent } from '@testing-library/react';
import CommentForm from '@/components/CommentForm';
test('submits comment when textarea not empty', () => {
render(<CommentForm onSubmit={jest.fn()} />);
const textarea = screen.getByLabelText(/comment/i);
fireEvent.change(textarea, { target: { value: 'Hello world' } });
fireEvent.click(screen.getByRole('button', { name: /post/i }));
expect(screen.getByRole('alert')).toHaveTextContent(/comment posted/i);
});
test('shows validation error on empty submit', () => {
render(<CommentForm onSubmit={jest.fn()} />);
fireEvent.click(screen.getByRole('button', { name: /post/i }));
expect(screen.getByRole('alert')).toHaveTextContent(/comment cannot be empty/i);
});
*Key points*:
- Mock the API call (
msworjest.fn) to focus on UI logic. - Assert that error messages are associated with the input via
aria-describedbyfor screen‑reader verification.
2. Integration / End‑to‑End Tests (Playwright)
Playwright excels at testing real user flows, including network interception and accessibility assertions.
// tests/comment.spec.js
const { test, expect } = require('@playwright/test');
test.describe('Comment flow', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/product/123');
await page.fill('input[name="email"]', 'user@example.com');
await page.fill('input[name="password"]', 'SecurePass!');
await page.click('button:has-text("Sign in")');
await page.waitForURL('/product/123#comments');
});
test('posts a comment and sees it appear', async ({ page }) => {
await page.fill('textarea[placeholder="Add a comment…"]', 'Great product!');
await page.click('button:has-text("Post")');
// Wait for optimistic UI update
await expect(page.locator('.comment-list .comment:last-child')).toContainText('Great product!');
// Verify network request
const [request] = await Promise.all([
page.waitForRequest(r => r.url().includes('/api/comments') && r.method() === 'POST'),
page.waitForTimeout(500) // small buffer for UI
]);
const postData = JSON.parse(request.postData());
expect(postData.body).toBe('Great product!');
});
test('rejects XSS attempt', async ({ page }) => {
const xssPayload = '<script>alert(1)</script>';
await page.fill('textarea[placeholder="Add a comment…"]', xssPayload);
await page.click('button:has-text("Post")');
// The comment should appear escaped or not at all
const commentText = await page.locator('.comment-list .comment:last-child').innerText();
expect(commentText).not.toContain('<script>');
// Optionally, ensure the script never executed by checking for absence of alert
await page.evaluate(() => window.alertCalled = false);
await page.on('dialog', dialog => {
dialog.dismiss();
window.alertCalled = true;
});
await page.waitForTimeout(300);
expect(window.alertCalled).toBeFalsy();
});
test('infinite scroll loads more comments', async ({ page }) => {
// Assume initially 5 comments are rendered
await expect(page.locator('.comment')).toHaveCount(5);
// Scroll to bottom
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await page.waitForTimeout(800); // wait for network
// After scroll, expect more comments (e.g., total 12)
await expect(page.locator('.comment')).toHaveCountGreaterThan(5);
});
});
Why Playwright?
- Auto‑waits reduce flakiness.
- Built‑in support for tracing, video, and screenshots.
- Easy to inject axe‑core for accessibility checks:
import { injectAxe, checkA11y } from 'playwright-axe';
test.afterEach(async ({ page }) => {
await injectAxe(page);
await checkA11y(page, { detailedReport: true, detailedReportOptions: { html: true } });
});
3. Contract / API Tests
Comment creation, retrieval, moderation, and deletion are typically REST or GraphQL endpoints. Use a tool like Postman/Newman or REST Assured (Java) to validate schemas, status codes, and error payloads.
# Example Newman collection snippet
{
"info": {
"name": "Comment API Contracts",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Create comment",
"request": {
"method": "POST",
"url": "{{baseUrl}}/api/comments",
"header": [{ "key": "Authorization", "value": "Bearer {{token}}" }],
"body": {
"mode": "raw",
"raw": "{\"postId\":123,\"body\":\"Test comment\"}"
}
},
"response": [
{
"name": "201 Created",
"status": "OK",
"code": 201,
"header": [{ "key": "Content-Type", "value": "application/json" }],
"body": "{\"id\":{{d__int 1}},\"postId\":123,\"body\":\"Test comment\",\"createdAt\":\"{{now ISO8601}}\"}"
},
{
"name": "400 Bad Request",
"status": "Error",
"code": 400,
"body": "{\"error\":\"Body is required\"}"
}
]
}
]
}
Run the collection in CI with newman run comment-api.json --reporters cli,junit.
4. Visual Regression
Comment UI often includes avatars, timestamps, and action buttons. Use Chromatic (for Storybook) or Percy to capture screenshots of the comment list under different states (empty, single, threaded, error). This catches accidental layout shifts caused by CSS changes or dynamic class names.
5. Performance & Load Testing
Simulate bursts of comment submissions with k6 or Artillery to validate rate‑limiting and backend throughput.
// k6 script
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 20 }, // ramp-up to 20 VUs
{ duration: '5m', target: 20 }, // steady load
{ duration: '2m', target: 0 }, // ramp-down
],
};
export default function () {
const payload = JSON.stringify({
postId: __ITER,
body: `Load test comment ${__ITER}`
});
const params = {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${open('./token.txt')}`
}
};
const res = http.post('https://api.example.com/comments', payload, params);
check(res, {
'status is 201': (r) => r.status === 201,
'response time < 800ms': (r) => r.timings.duration < 800
});
sleep(1);
}
The script checks that each POST returns 201 and stays under a latency threshold, surfacing backend saturation or missing back‑pressure.
---
Edge Cases That Only Surface in Production
Even with thorough lab testing, certain conditions manifest only under real‑world traffic, user behavior, or deployment quirks. Below are the most common “production‑only” bugs for comment systems and how to detect them early.
| Issue | Root Cause | Symptom in Prod | Detection Technique |
|---|---|---|---|
| Comment Storm | A viral post triggers thousands of comments per minute, overwhelming the write path. | Increased latency, HTTP 502/503, missing comments, duplicate entries. | Load‑test with k6 at > 10× expected peak; monitor DB write queue length and API error rates. |
| Lazy‑Load Hydration Mismatch | SSR renders initial comment batch; client‑side hydration expects a different DOM structure (e.g., missing wrapper div). | Flash of incorrect layout, console hydration warnings, broken scroll position. | Enable React StrictMode, run npm run build && serve -s build and navigate with DevTools → “Render” → “Highlight updates”. |
| Third‑Party Widget Conflict | Embedded comment widget (e.g., Disqus) loads its own CSS/JS, overriding site styles. | Buttons become invisible, z‑index issues, modal traps. | Use Chrome Coverage tab to see unused CSS; visually compare widget iframe with isolated sandbox. |
| GDPR Right‑to‑Be‑Forgotten | Delete request only removes UI row but leaves data in backups or analytics tables. | Personal data reappears in export or analytics dashboards after “deletion”. | After delete, run a GDPR export job and assert absence of the user’s comment ID in all outputs. |
| CSRF Token Rotation Mis‑match | Backend rotates CSRF tokens per session, but SPA retains old token from previous page load. | 403 errors on comment submit after navigation, intermittent for power users. | Simulate a navigation-heavy session (open 10 tabs, switch) and assert each POST returns 201. |
| Timezone‑Driven Sorting Bug | Comments sorted by createdAt stored in UTC, but frontend displays in local time without conversion, causing apparent out‑of‑order display for users near DST shift. | New comment appears above older ones in UI for certain locales. | Test with moment.tz.setDefault("America/New_York") and manually adjust system clock to simulate DST boundary. |
| Input Method Editor (IME) Interference | Users typing in Japanese, Korean, or Chinese via IME cause composition events that bypass onChange handlers, resulting in truncated or duplicated text. | Comment body shows only the first character or repeats the last syllable. | Listen for compositionstart/compositionend events; write a Cypress test that types using cy.type({ delay: 0 }) with IME simulation via cy.window().then(win => win.dispatchEvent(new CompositionEvent('compositionstart', { data: 'あ' }))). |
| Ad‑Blocker Script Stripping | Some ad‑blockers mistakenly flag comment‑related endpoints as tracking and block the requests. | Comments never appear for a subset of users; no error shown in UI. | Run the site with popular filter lists (EasyList, uBlock Origin) enabled and verify network calls succeed. |
| Session Expiry Mid‑Composition | User spends > 30 min typing a long comment; session cookie expires, causing 401 on submit. | Loss of drafted comment, user frustration. | Use Playwright to set a short session timeout, type a comment via page.type, wait beyond timeout, then submit and verify a “session expired” toast with draft preservation. |
| CDN Cache Stale JS | A feature flag toggles comment UI; old service worker serves cached JS missing new component. | New comment button absent for returning users despite deploy. | Purge CDN, simulate a returning visitor with page.context().clearCookies() and reload, then assert presence of new UI element. |
Mitigation Checklist
- Instrument end‑to‑end latency metrics per comment API (p95, p99).
- Enable feature flags with gradual rollout and a kill‑switch.
- Store drafts in
localStorageor IndexedDB with explicit save onvisibilitychangeandbeforeunload. - Validate that all user‑generated strings go through a server‑side sanitizer (DOMPurify or similar) before persisting.
- Test with real‑world input method editors using the
android-emulatororwindows‑imeutilities in CI. - Regularly run a GDPR erasure verification job as part of nightly pipelines.
---
Accessibility and Internationalization Considerations
Comments are a prime candidate for accessibility regressions because they combine dynamic content, interactive controls, and user‑generated text that may contain diverse scripts.
1. Keyboard Navigation
- Every actionable element (textarea, formatting toolbar buttons, post button, edit/delete links, “load more”) must be reachable via
Tab. - Provide a visible focus outline (minimum 2 px solid, contrast ≥ 3:1 against background).
- When a comment is posted, move focus to the newly added comment container or to an aria‑live region that announces the update.
2. ARIA & Live Regions
- Use
role="region"witharia-live="polite"on the comment list container. - Each comment item should have
aria-labelledbypointing to a combination of author name and timestamp (e.g.,2 m ago). - Edit and delete buttons need
aria-label="Edit comment by Ada"andaria-label="Delete comment by Ada"respectively.
3. Color Contrast & Text Scaling
- Verify that comment text, usernames, timestamps, and icons meet WCAG AA contrast (≥ 4.5:1 for normal text, ≥ 3:1 for large).
- Ensure the UI remains functional when the user scales text to 200 % (browser zoom or OS setting). Use CSS
remunits and avoid fixed pixel heights on containers.
4. Screen‑Reader Testing
- With NVDA (Windows) or VoiceOver (macOS/iOS), navigate to the comment area and confirm:
- The screen reader announces the number of comments (“5 comments”).
- When a new comment appears, it is read aloud (“New comment by Sam: …”).
- Editing a comment announces the transition to edit mode (“Editing comment, multiline edit box”).
- Test that custom widgets (e.g., emoji picker) are operable and labeled.
5. Internationalization (i18n) & Localization (l10n)
- Store all UI strings in message catalogs; never hard‑code English.
- Support right‑to‑left (RTL) layouts: add
dir="rtl"onor container when locale is Arabic/Hebrew; verify that the comment textarea, avatar alignment, and button order mirror correctly. - Allow Unicode characters, including emojis, and ensure they are not stripped or mangled by server‑side validation.
- Test line‑breaking for languages without spaces (Thai, Japanese, Khmer) – use zero‑width space (
) or CSSword-break: break-word. - Validate date/time formatting respects locale (e.g.,
MM/DD/YYYYvsDD/MM/YYYY).
6. Automated Accessibility Checks
Integrate axe-core into your Playwright or Cypress test suite:
// Cypress example
describe('Comment page accessibility', () => {
it('has no detectable violations', () => {
cy.visit('/product/123/comments');
cy.injectAxe();
cy.checkA11y();
});
});
Run the same checks in CI on every PR to catch regressions early.
---
Security and Privacy Testing for Comments
Comment features are a frequent injection vector. A disciplined security test plan covers both OWASP‑Top‑10 concerns and privacy regulations.
1. Cross‑Site Scripting (XSS)
- Stored XSS: Submit a payload containing
,onerror, or SVG with embedded script. Verify the server strips or escapes it, and the DOM renders it as plain text. - Reflected XSS: If the comment preview reflects the user input in the URL (e.g.,
?preview=...), ensure proper encoding. - DOM‑based XSS: Avoid setting
innerHTMLwith raw comment text; usetextContentor a templating library that auto‑escapes.
Test snippet (Playwright):
test('stored XSS is neutralized', async ({ page }) => {
const payload = `<img src=x onerror=alert('xss')>`;
await page.fill('textarea[placeholder="Add a comment…"]', payload);
await page.click('button:has-text("Post")');
const comment = await page.locator('.comment-list .comment:last-child').innerText();
expect(comment).toBe(payload); // Should appear as escaped text
// Ensure no alert fired
let alerted = false;
page.on('dialog', d => { alerted = true; d.accept(); });
await page.waitForTimeout(300);
expect(alerted).toBeFalsy();
});
2. Cross‑Site Request Forgery (CSRF)
- Require a same‑site cookie or a custom header (
X-CSRF-Token) for state‑changing endpoints. - Test that removing the token results in a 403.
test('csrf token required', async ({ request }) => {
const res = await request.post('/api/comments', {
data: JSON.stringify({ postId: 1, body: 'test' }),
headers: { 'Content-Type': 'application/json' } // deliberately omit CSRF
});
expect(res.status()).toBe(403);
});
3. SQL Injection & NoSQL Injection
- Although modern ORMs reduce risk, still parameterize queries.
- Attempt
' OR '1'='1in comment body; ensure it is treated as literal text, not as part of a query.
4. Rate Limiting & Abuse Mitigation
- Enforce per‑IP and per‑account limits (e.g., max 5 comments per minute).
- Test with a burst of requests using k6 or Artillery; verify HTTP 429 responses and that legitimate requests after the cool‑down succeed.
5. Data Privacy & GDPR
- Ensure that deletion requests purge the comment from:
- Primary datastore (e.g., PostgreSQL row).
- Search indexes (Elasticsearch).
- Backup snapshots (if using point‑in‑time recovery, confirm that backups older than retention window are eventually purged).
- Verify that export/download endpoints do not inadvertently include other users’ comments (authorization check).
6. Content Moderation & Spam
- Implement a profanity filter or ML‑based spam scorer.
- Test edge cases: homoglyphs (
comment), zero‑width joiner characters, and whitespace tricks that attempt to bypass filters.
7. Security Headers
- Serve comments with
Content‑Security‑Policy: default-src 'self'; script-src 'self'; object-src 'none';to mitigate inline script injection even if a flaw slips through. - Include
X-Content-Type-Options: nosniffandX-Frame-Options: SAMEORIGIN.
8. Automated Security Scanning
- Integrate OWASP ZAP or Nikto in a nightly job that spider the comment pages and actively tests for XSS, CSRF, and SQLi.
- Use Dependabot or Snyk to keep frontend dependencies (e.g., markdown parsers) up‑to‑date.
---
Persona‑Driven Autonomous Exploration – How SUSA Fits
Traditional test suites follow predetermined paths. Real users, however, exhibit wildly different behaviors: a curious newcomer may experiment with every UI control, an impatient power user may spam the submit button, an elderly user may rely heavily on keyboard navigation, and an adversarial actor may purposely try to break the system. Autonomous QA platforms like SUSA simulate these personas by generating varied interaction patterns without explicit test scripts.
How It Works
- Model Building – Upon launch, SUSA crawls the target web app, constructing a state graph of screens, DOM elements, and observable network calls.
- Persona Profiles – Each persona (e.g., “impatient”, “accessibility‑focused”, “elderly”) is defined by a probability distribution over actions: tap vs. long‑press, typing speed, likelihood to open dev tools, propensity to ignore error messages, etc.
- Guided Exploration – The agent selects actions based on the current state and the chosen persona, emitting events (clicks, keypresses, scrolls) and observing the resulting state transitions.
- Learning Loop – Successful flows and dead ends are recorded; subsequent runs prioritize under‑explored branches, increasing coverage over time.
What It Finds That Scripts Miss
| Persona | Typical Behavior | Bug Class Discovered | Why Scripts Miss It |
|---|---|---|---|
| Curious | Clicks every icon, opens context menus, tries drag‑and‑drop on comment avatars | Unintended modal openings, missing keyboard traps, broken drag‑drop UI | Scripts usually target happy‑path clicks; they don’t exploratory right‑click or long‑press. |
| Impatient | Rapid double‑click on Post, submits while validation is running | Race conditions causing duplicate comments, UI state desynchronization | Automated waits often serialize actions; they don’t simulate frantic user speed. |
| Elderly | Relies on Tab navigation, uses increased font size, avoids mouse | Focus loss after dynamic comment insertion, clickable areas too small, lack of visible focus outline | Scripts often use direct selectors (page.click('#post')) bypassing tab order checks. |
| Accessibility‑focused | Navigates with screen reader, expects live region announcements | Missing aria-live, announcements too verbose or too silent, custom widgets not keyboard operable | Scripts rarely assert screen‑reader output unless explicitly added; they focus on visual DOM. |
| Adversarial | Attempts XSS, CSRF token omission, oversized payloads, rapid-fire requests | Injection flaws, rate‑limit bypasses, server‑side DoS | Security tests are often isolated; adversarial behavior combines multiple vectors in a single session. |
| Novice | Repeatedly clicks help tooltip, fills form incorrectly, then clears and retries | Ambiguous error messages, unclear validation flow, loss of entered data on navigation away | Scripts follow a deterministic flow; they don’t model the trial‑and‑error learning curve. |
Practical Usage
- CI Integration – Add a step that runs
susatest-agent run --url https://staging.example.com --personas curious,impatient,elderly --duration 10m. The agent outputs a JUnit‑style XML with PASS/FAIL per discovered flow. - Baseline Comparison – Compare the flow graph from the current run against the baseline (main branch). New nodes or edges that lead
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free