How to Auto-Discover Test Scenarios by Crawling: Why the Best Approach Crawls While Testing
Every guide on this topic tells you the same thing: crawl your site first, build a map of pages, then generate test cases from that map. That approach works for static sites with predictable navigation. It falls apart for modern web apps where half the pages only exist after a user clicks something. There is a better pattern: let the test agent discover pages as it navigates, and generate test cases on the fly for each new URL it encounters. This guide explains exactly how that works, with implementation details from a real open-source tool.
“Generates real Playwright code, not proprietary YAML. Open-source and free vs $7.5K/mo competitors.”
Assrt vs competitors
1. The Problem with Crawl-First, Test-Second
The traditional approach to auto-discovering test scenarios follows a two-phase pipeline. Phase one: a spider or crawler visits your root URL, follows every link, submits every form, and builds a complete map of your application. Phase two: a test generator reads that map and creates scenarios for each page.
This sounds clean in theory. In practice, it has three serious problems.
First, the crawl phase is slow. Research on automated web application crawling has found that fully automated crawling approaches can take multiple days to complete on large applications. That makes it impractical in continuous development environments where you want feedback on every pull request.
Second, the crawler misses dynamic pages. A single-page application might render entirely different content based on authentication state, query parameters, or client-side routing. A traditional crawler that just follows href attributes will never reach the checkout confirmation page, the settings panel that only appears after onboarding, or the error state that triggers after a failed API call.
Third, the crawl results are stale by the time tests run. If the crawler found 200 pages yesterday, and a developer pushed a change that restructured the navigation today, the generated tests are targeting a map that no longer matches reality.
2. Opportunistic Discovery: Crawling as a Side Effect of Testing
There is an alternative pattern that solves all three problems. Instead of crawling first and testing second, you let the test agent discover pages while it is already running tests. Every time the agent navigates to a new URL during a test scenario, that URL gets queued for analysis. The crawl and the test happen simultaneously.
This is how Assrt works. When you point it at a URL and ask it to generate a test plan, it does not spider your site. It opens a real browser, takes screenshots at three scroll positions (0px, 800px, and 1600px), captures the accessibility tree at each position, and feeds up to 8,000 characters of that content to an AI model that generates 5 to 8 test cases.
Then, as those test cases execute, something interesting happens. Every time the test agent clicks a link, submits a form, or navigates to a new route, that new URL gets intercepted and added to a discovery queue. The agent finishes the current test scenario, then processes the queue: visiting each discovered URL, taking a snapshot, and generating 1 to 2 additional test cases for it.
The result is that testing and discovery feed each other. A test that clicks through a checkout flow discovers the order confirmation page. A test that logs in discovers the dashboard. The agent's own behavior becomes the crawl.
See opportunistic discovery in action
Point Assrt at your staging URL and watch it discover pages as it tests. No setup, no configuration, no sitemap required.
Get Started →3. How the URL Queue Works Under the Hood
The discovery mechanism in Assrt is built around a simple queue with deduplication. The implementation lives in the test agent (specifically, a function called queueDiscoverPage in agent.ts). Here is what happens each time the agent navigates:
- The URL is normalized (protocol, trailing slashes, query parameter ordering).
- The agent checks whether this URL has already been discovered. If it has, the URL is skipped.
- The agent checks whether the maximum number of discovered pages has been reached. If it has, the URL is skipped.
- The agent checks the URL against a list of skip patterns (more on this in the next section). If it matches, the URL is skipped.
- If the URL passes all three checks, it is added to a set of discovered URLs and pushed to a pending queue.
After each test scenario completes, a function called flushDiscovery processes the pending queue. For each URL in the queue, the agent takes a snapshot of the page (accessibility tree plus screenshot), emits a page_discovered event, and calls an AI model to generate test cases for that page.
This is deliberately simple. There is no recursive link extraction, no sitemap parsing, no depth-first search. The crawl surface is exactly whatever the test agent touches during execution. That means it naturally follows real user paths through the application rather than exhaustively enumerating every possible route.
4. Skip Patterns: URLs the Crawler Knows to Avoid
Not every URL the agent encounters should become a test target. Navigating to a logout endpoint would destroy the session state that other tests depend on. Hitting an API route directly would produce a JSON response, not a testable UI. Assrt defines six skip patterns that filter URLs before they enter the discovery queue:
- /logout — prevents session destruction mid-test
- /api/ — skips raw API endpoints that return data, not UI
- javascript: — ignores inline JavaScript pseudo-URLs
- about:blank — skips blank pages that have nothing to test
- data: — ignores data URIs (embedded content, not pages)
- chrome: — skips browser-internal pages
These patterns are applied using case-insensitive regex matching. The logout pattern is particularly important because, in an opportunistic discovery model, the agent maintains a single browser session across all test scenarios. Cookies and authentication state carry over between tests. If the agent followed a logout link, every subsequent test would fail because the session would be gone.
This is a detail that crawl-first tools do not need to worry about, because their crawl phase and test phase are separate. When the crawl is the test, protecting session state becomes a first-class concern.
5. Micro Case Generation: 1-2 Tests Per Discovered Page
When a discovered page is processed, the agent does not try to generate a comprehensive test suite for it. It generates 1 to 2 test cases, each limited to 3 to 4 actions. These are intentionally small and focused.
The generation prompt explicitly instructs the AI model to reference actual buttons, links, and inputs visible on the page. It prohibits generating login/signup cases (since the agent is likely already authenticated), CSS or layout tests (since the agent tests via accessibility tree, not visual rendering), and performance tests (which require different instrumentation).
This micro-case approach serves two purposes. First, it keeps execution time bounded. If the agent discovered 15 new pages and generated 8 cases each, the test run would take an impractical amount of time. With 1 to 2 cases per page, the discovery phase adds minutes, not hours. Second, it prioritizes breadth over depth. A single sanity check on 15 pages catches more regressions than an exhaustive suite on 3 pages.
The generated cases follow the same #Case N: name format used throughout Assrt. They are real Playwright test steps, not proprietary markup or YAML. You can copy them into your own test suite, modify them, and run them independently. There is no vendor lock-in.
Test cases you actually own
Every test case Assrt generates is real Playwright code. Export it, version it, run it outside Assrt. Zero lock-in.
Get Started →6. Hard Caps and Why They Matter
Opportunistic discovery without limits would be a crawl by another name. Assrt enforces three hard caps to keep the process fast and predictable:
| Constraint | Value | Why it exists |
|---|---|---|
| Maximum discovered pages | 20 | Prevents runaway discovery on large sites with thousands of routes |
| Maximum concurrent discoveries | 3 | Limits parallel page analysis to avoid overwhelming the AI model |
| Maximum steps per scenario | 60 | Prevents infinite loops in complex or broken navigation flows |
| Accessibility tree text limit | 8,000 chars | Prevents token overflow when feeding page content to the AI model |
| Cases per discovered page | 1-2 | Keeps discovery fast by prioritizing breadth over depth |
These numbers are not arbitrary. A cap of 20 pages means even on a large application, the discovery phase finishes in a predictable window. Three concurrent discoveries balance throughput against the cost of parallel AI calls. The 8,000 character limit on accessibility tree content ensures the model receives enough context to generate useful tests without hitting token limits.
For comparison, traditional crawl-based tools often provide no cap at all, or set it so high (tens of thousands of pages) that the crawl itself becomes the bottleneck. The entire point of opportunistic discovery is that you do not need to visit every page. You need to visit the pages that matter, which are the ones real user flows actually reach.
7. Getting Started with Assrt
Assrt is open-source and free. You can start testing with opportunistic discovery in under a minute. There are two ways to use it:
Via the MCP server (for Claude Code or IDE users)
If you use Claude Code, Cursor, or another tool that supports the Model Context Protocol, Assrt runs as an MCP server. Point it at any URL and it will generate a plan, execute it, and discover additional pages along the way:
npx assrt-mcpThen use the assrt_plan tool to generate test scenarios, or assrt_test to generate and execute in one step. The test agent handles discovery automatically.
Via the web app
Visit app.assrt.ai, paste your URL, and click generate. The web app uses the same underlying engine with a visual interface for watching tests execute in real time. You can see discovered pages appear as the agent navigates, and watch test cases get generated and executed live.
Frequently Asked Questions
Does Assrt parse my sitemap.xml to find pages?
No. Assrt does not use sitemaps, robots.txt, or any pre-crawl phase. It discovers pages by intercepting navigation events during test execution. Every URL the test agent navigates to gets queued for analysis. This means it only discovers pages that are reachable through actual user interactions, which is usually more useful than a complete site map.
What happens when the agent hits the 20-page discovery limit?
New URLs are silently skipped. The agent continues executing its existing test scenarios without interruption. The 20-page cap applies to discovered pages only; it does not limit navigation within test scenarios. If a test case requires navigating through 30 pages to complete a flow, it will still work. The cap only prevents the agent from queuing new pages for independent analysis.
Can I control which pages get discovered?
The skip patterns are built into the agent and filter out logout endpoints, API routes, JavaScript pseudo-URLs, blank pages, data URIs, and browser-internal pages. You cannot currently add custom skip patterns, but you can control discovery indirectly by writing test scenarios that navigate to specific areas of your application. The agent will discover pages adjacent to wherever your tests go.
How is this different from a traditional web crawler that generates tests?
Traditional crawlers operate in two separate phases: crawl everything, then generate tests from the crawl results. That means the crawl does not benefit from test execution context (like being logged in), and the tests do not adapt to what the crawl finds in real time. Assrt merges both phases into one. The test agent maintains authentication state, follows dynamic client-side routes, and generates cases for pages it actually reached through realistic interactions.
Are the generated test cases tied to Assrt, or can I export them?
Every test case Assrt generates is real Playwright code using standard Playwright APIs. There is no proprietary format, no YAML, no custom DSL. You can copy the generated cases directly into your own Playwright test suite and run them with npx playwright test. The test plans are also saved locally to /tmp/assrt/scenario.md after every run, so you always have a local copy.
Does discovery slow down the test run significantly?
Discovery is limited to 3 concurrent page analyses and generates only 1-2 cases per page. In practice, the discovery phase adds a few minutes to a test run, not hours. The hard cap of 20 pages ensures the overhead stays bounded regardless of application size. Discovery processing happens between scenario executions, so it does not interrupt running tests.
Auto-discover what to test. No sitemap needed.
Point Assrt at any URL. It generates test scenarios, discovers pages as it navigates, and produces real Playwright code you own. Free and open-source.