Test cases for search functionality: search, filter, and sort in one pass
Most test cases for search functionality stop at 'type a word, see results.' The bugs are in the empty state, the special characters, the filter combinations, and the state that doesn't survive a reload. Here's how to test all of it in plain English.
Test cases for search functionality: search, filter, and sort in one pass
Search is the feature everyone demos and nobody tests properly. The demo is "type a product name, see the product" — one query, one obvious result, applause. The real thing is a small system: an input with debounce and maybe autocomplete, a results list with an empty state and a no-results state, a set of filters that combine in ways nobody enumerated, a sort order, pagination, and a URL that's supposed to carry all of it so a shared link or a page reload lands you back on the same results. Every one of those seams is where a real user's search quietly returns the wrong thing.
Search the web for test cases for search functionality and you get the same 100-row spreadsheet on a dozen sites: "verify search with valid keyword," "verify search with invalid keyword," "verify case insensitivity." Those aren't wrong, they're just the demo written down. They test the input box. They don't test the system — the filter that stops applying after you paginate, the sort that resets when you reload, the special character that 500s the search endpoint, the empty state that renders undefined for a user with no history. This is the playbook for the whole system, in plain English, no scripts.
What "testing search" actually has to cover
The input box is the part that works. Here's the surface that doesn't:
- The three list states, not one. Results, no results (a valid query that matches nothing), and empty (no query yet, or a cleared query). Teams test the first, occasionally the second, and almost never the third — which is why the initial search screen so often ships with a broken or placeholder-filled empty state.
- Input the search box didn't expect. Special characters (
%,&,#, quotes, a lone backslash), a query that's only spaces, an extremely long string, a leading/trailing space, and — if your backend speaks SQL or a query DSL — the characters that mean something to it. The bar isn't "does it find results," it's "does it fail safely and predictably." - Filters that combine. One filter is easy. The bug is in the intersection: apply two filters that together match nothing (does it show the no-results state, or the unfiltered list?), apply a filter then change the search term (does the filter persist or silently drop?), clear one filter of several (do the rest stay applied?).
- Sort, and sort-plus-filter. Sorting works in isolation. Then you filter, and the sort resets to default without telling anyone; or you sort, paginate, and page two comes back in the original order.
- State that survives the URL. Search + filters + sort + page should live in the URL (or wherever you keep them) so that a reload, a shared link, and the browser back button all reproduce the exact same results. This is the single most under-tested property of any search UI, and the one users notice immediately when it breaks.
- Debounce and race conditions. Type fast, and the results for an earlier keystroke can arrive after the results for a later one and overwrite them — the last-response-wins race that shows results for "ca" when the box says "cat." Autocomplete has the same problem, one layer up.
- Pagination consistency. Page two of a filtered, sorted search is still filtered and sorted. The result you saw on page one doesn't reappear on page two because the underlying set shifted mid-browse.
Most teams cover item 1 (the results case) and ship. Items 3, 5, and 6 arrive as bug reports phrased as "search is weird sometimes," which is the least actionable sentence in your inbox because it depends entirely on the sequence of clicks. The prompts below drive those sequences on purpose.
Prompt 1: the three states and the input you didn't expect
Step 4 is where the security-adjacent bugs surface: a search box that passes a lone backslash or a quote straight into a query and gets back a 500 is telling you the input isn't being escaped, and that's worth knowing before someone less friendly finds it. The agent watches the network tab, so an error the UI swallowed into a generic "no results" still gets reported as the server error it actually was — a distinction a screenshot can't make and a "verify invalid keyword" checklist row never captures.
Prompt 2: filters that combine, and the state that has to persist
Step 5 is the highest-leverage check here. A search UI that keeps its state in component memory instead of the URL looks perfect until a user reloads, shares a link, or hits back — and then it's a support ticket that says "the link I sent showed different results than what I saw." Testing it means actually reloading and actually opening the URL in a new context, which is exactly the kind of multi-step, stateful sequence that's tedious to do by hand every release and trivial to describe to an agent once. It's the same state-survives-navigation property that multi-step forms live or die on.
Prompt 3: sort, pagination, and the debounce race
Step 4 is the debounce race, and it's genuinely hard to catch by hand because it depends on typing faster than the responses come back — you have to get unlucky in exactly the right way. An agent types deterministically and reads the final rendered results against the final query, so the race that shows "ca" results under a "cat" query surfaces as a reported mismatch instead of a bug someone half-remembers seeing once. This is the same class of non-deterministic, timing-dependent UI issue that makes streaming and async interfaces so hard to pin down.
Reading the results
Each run comes back as a Monito Session: a screenshot timeline of every query, filter, and page, the network log with the actual search requests and their responses, console output, and the agent's reasoning where it judged something like "is this empty state intentional or broken." For search specifically, the network log is where the input-handling bugs live — the 500 on a special character, the request that fired without the filter attached — and the screenshot timeline is where you see the state that didn't survive the reload. Neither is a single pass/fail bit, which is the point: "search is weird sometimes" becomes "the second filter drops when you change the query, here's the request that proves it."
None of the prompts names a filter's CSS class, a sort dropdown's ID, or a results-container selector — only what search is for. Restyle the filters, swap the pagination for infinite scroll, rename everything: the intent is identical, so the prompts are too. That's why describing intent beats scripting steps for anything as redesign-prone as a search interface, and why an agent reading the rendered page finds what a selector-bound script walks past.
The one to run right now
If you run a single check today, run the filters-and-persistence test — it catches the two bugs users notice fastest (a filter combination that silently un-filters, and state that dies on reload):
Save it as a Test Scenario, pin it to your staging Project, and wire it into CI against every preview deploy that touches search, filtering, or the results page. A full run is typically 8–13 credits — roughly $0.08–$0.13 — and your first run is free. Point it at staging, paste the prompt, and read the network log. If the impossible filter combination shows an honest empty state and the reload brings everything back, you've got a search that behaves the way users assume it already does.