HOW TO TEST
How to Test a Search Feature.
Core Features A complete testing guide for application search: exact/partial matching, special characters, no-results handling, filters, sorting, autocomplete, typo tolerance, performance, keyboard accessibility, and API-layer parameter validation.
Search is one of the most-used and most-broken features in applications. Users expect it to find what they typed, handle typos gracefully, and respond instantly — failures here directly reduce engagement and revenue. This guide covers the complete search surface: exact and partial matching, case sensitivity, special characters, no-results states, filter combinations, sort orders, pagination, relevance ranking, autocomplete, typo tolerance, performance under large datasets, keyboard accessibility for all interactive elements, and API-level parameter validation including injection prevention. All test cases are written for a Cypress/Playwright engineer.
Risks
Search queries not sanitised — SQL or NoSQL injection
Search inputs passed directly to database queries without parameterisation enable SQL injection (for SQL backends) or NoSQL operator injection (for MongoDB with $where or $regex operators). A single unparameterised query exposes the entire data store.
Search results expose data beyond the user's permission
Search may surface records from other users, tenants, or restricted data categories if the query does not scope results to the authenticated user's access level. This is particularly common in multi-tenant applications.
No-results state missing or misleading
A search that returns zero results with no user-visible message, or that shows a spinner indefinitely, causes users to assume the feature is broken rather than simply returning no matches.
Performance degradation on broad or wildcard queries
A query like a single letter ('a'), a wildcard ('*'), or an empty string can trigger full-table or full-index scans, causing timeouts or spikes that degrade the service for all users.
Filter and sort combinations not validated at API level
If the server does not validate filter/sort parameters, an attacker can craft requests with arbitrary sort fields (including internal or sensitive columns) or invalid filter operators that expose data or cause query errors.
Stale search index showing deleted or unpublished content
If the search index is asynchronously updated, deleted or unpublished items may continue to appear in results for seconds to minutes after removal. Users can click through to 404 pages or access content that should no longer be visible.
Autocomplete leaking sensitive data
Autocomplete endpoints that suggest results from other users' private data, admin-only fields, or deleted records expose information the current user should not see.
Test Scenarios
Exact match returns the expected result
CriticalfunctionalFully automatedSearch for the exact title or name of a known entity. Assert the entity appears in the results, ideally as the first result. Assert the result card shows accurate title, description, and link.
Partial match returns relevant results
HighfunctionalFully automatedSearch using the first 3–5 characters of a known entity name. Assert the entity appears in results. Assert no irrelevant results dominate the top positions.
Search is case-insensitive
HighfunctionalFully automatedSearch the same term in all lowercase, all uppercase, and mixed case. Assert each returns identical results. Case differences must not produce different result sets.
No-results query displays an informative empty state
HighfunctionalFully automatedSearch for a string that has no possible matches (e.g. random UUID). Assert the UI shows a 'no results found' message, not an empty list, error, or infinite spinner.
Special characters in search query are handled safely
CriticalsecurityFully automatedSearch using <, >, &, ', ", \, %, and SQL-special characters. Assert the application neither crashes nor returns a 500. Assert query is parameterised (no injection). Assert results are returned or a no-match state is shown.
Filter combinations correctly narrow results
HighfunctionalFully automatedApply one filter, then two, then conflicting filters. Assert results are correctly narrowed with each filter. Assert zero-result state appears for contradictory filter combinations rather than an error.
Sort order correctly reorders results
HighfunctionalFully automatedApply each available sort option (newest, oldest, A-Z, Z-A, relevance, price). Assert results are reordered correctly for each. Assert ties are broken consistently.
Typo-tolerant search returns relevant results for common misspellings
MediumfunctionalFully automatedSearch with a deliberate single-character typo of a known entity. Assert the entity still appears in results (if the application claims typo tolerance). If typo tolerance is not claimed, assert this is documented.
Autocomplete suggestions are relevant and keyboard-accessible
HighfunctionalFully automatedType 3 characters into the search field. Assert autocomplete suggestions appear within 300 ms, are keyboard-navigable (arrow keys + Enter), and selecting a suggestion triggers the correct search.
Search responds within threshold even for broad queries
HighperformanceFully automatedSearch for a single letter ('a') or a very common term that matches many results. Assert the response time is under the defined threshold (e.g. 500 ms for the API, 1 s for the full page). Assert no timeouts.
Search results are scoped to the authenticated user's access
CriticalsecurityFully automatedAs a low-privilege user, search for terms that appear in records owned by other users or tenants. Assert those records do NOT appear in results. Verify by comparing against an admin search.
Search UI is fully keyboard-accessible
HighaccessibilityManual onlyTab to the search field, type a query, navigate results with arrow keys, select a result with Enter. Assert focus states are visible on all interactive elements and screen readers announce result counts.
Empty search query returns expected behaviour
Highedge-caseFully automatedSubmit an empty search query (or a query of only spaces). Assert the application either shows all results, shows a prompt to enter a term, or returns a controlled empty state — not a 500 error or raw exception.
Detailed Test Cases
Preconditions
- At least 3 entities exist in the search index with distinct titles
- Specific target entity title known (e.g. 'Acme Widget Pro')
Steps
- 1.GET /api/search?q=Acme+Widget+Pro
- 2.Assert HTTP 200
- 3.Assert results array is non-empty
- 4.Assert results[0].title === 'Acme Widget Pro' (or contains the full title)
- 5.Assert results[0].id matches the known entity ID
- 6.Repeat via the UI: type 'Acme Widget Pro' in the search box, press Enter
- 7.Assert the first result card shows the correct entity
Expected result
First result matches the exact query; entity ID is correct.
Edge Cases
Search query with only whitespace
A query of five spaces should either return all results (treating it as an empty search) or show a 'please enter a search term' message — not crash or return a 500.
Extremely long search query (2,000+ characters)
A query exceeding URL or database field length limits should be rejected with a clear error (413/400) or truncated gracefully, not cause a 500 or server crash.
Search for a term that matches every entity
A search for the most common word in the dataset should return paginated results, not attempt to return all matching records in a single response.
Search immediately after creating a new entity
The new entity may not be indexed immediately. If the index is asynchronous, the search should not return the entity until it is indexed. Tests that assume immediate indexing will produce flaky results.
Unicode and emoji in search queries
Queries with emoji (🔍), Arabic, Hebrew RTL text, or CJK characters should be handled without crashes. Some tokenisers break on multi-byte characters.
Search while filters are selected returns only matching-category results
If a filter is active and the user changes the search query, results must still respect the active filter. A common bug: changing the query resets the filters silently.
Navigating back after clicking a search result
After navigating to a result and pressing Back, the search query and active filters should be restored (via URL state or browser history state), not cleared.
Search with leading/trailing spaces in the query
' widget ' (with spaces) should return the same results as 'widget' if the server trims the query. Inconsistent trimming causes confusing 'no results' for queries with accidental spaces.
Autocomplete showing results from deleted entities
If an entity is deleted but the autocomplete index is not updated synchronously, the deleted entity appears as a suggestion. Selecting it navigates to a 404.
Concurrent search requests from the same user
Typing quickly creates multiple in-flight search requests. Only the most recent response should be displayed (debounce + request cancellation). Showing an older response as the final result is a common autocomplete bug.
Automation Ideas
Parameterised API search assertion matrix
Drive {query, expectedResultId, expectedStatus} rows through the search API. Confirms exact matches, no-results, and error cases in a single data-driven test file.
Tools: playwright, cypress, postman
Injection payload sweep
Loop through a list of SQL and XSS payloads as search queries, asserting HTTP 200 (safe handling) and no response body containing error text or reflected script tags.
Tools: playwright, owasp-zap
Search performance benchmark
Use k6 to send 50 concurrent single-character search queries and assert p95 response time is under 500 ms. Run this as a nightly performance regression gate.
Tools: k6, grafana
Filter combination coverage via API
Generate all N×M combinations of filter values and query terms, send to the API, and assert HTTP 200 with valid (never 500) responses. Focus on edge combinations that the UI never exposes.
Tools: postman, playwright
Permission boundary test
Create two users via API, assign data to User A only, authenticate as User B, and search for User A's data. Assert zero results. Run as a security regression on every release.
Tools: playwright, cypress
Autocomplete ARIA compliance assertion
Use Playwright to type a partial query, intercept the autocomplete render, and assert aria-activedescendant, role='listbox', and role='option' are correctly set. Combine with axe-core for a full accessibility check.
Tools: playwright, axe-core
Search index freshness test
Create an entity via the API, wait for the index TTL, then search for it. Assert it appears in results within the documented indexing latency window. Fail if it takes longer than the SLA.
Tools: playwright, cypress
Common Bugs
Case-sensitive search treating 'Widget' and 'widget' as different
The search index collation is case-sensitive. Users searching in lowercase miss results with uppercase-initial titles. Extremely common with MySQL BINARY comparisons or Elasticsearch keyword fields.
Filters silently reset when search query changes
Changing the search term clears all active filters. Users who spent time configuring filters (date range, category, price band) lose their selection on every keystroke.
Sort parameter ignored — results always by relevance
The sort parameter is accepted by the API but ignored; results always come back in default relevance order. The sort UI appears to work because the labels change, but the data doesn't.
No-results for a query that has 0 results shows a spinner indefinitely
The UI sets a loading state when a search fires but only clears it when results arrive. A zero-result response clears the data array but forgets to clear the loading flag.
Autocomplete fires on every keystroke without debounce
Each keypress fires a separate API request. For a 10-character query, 10 requests are in flight simultaneously. The most common response is not the last one, causing stale suggestions to replace fresh ones.
Search results include soft-deleted entities
The search query does not filter on deletedAt IS NULL. Soft-deleted records appear in search results and clicking them navigates to 404 pages.
Long search queries break the URL sharing feature
The search state is stored in the URL query parameter. A query over 2,000 characters produces a URL that exceeds browser or server URL length limits, breaking sharing and direct links.
Search returning HTML-unescaped query in the results header
The results header reads 'Showing results for {query}' where {query} is interpolated from the URL parameter without escaping. A search for '<b>bold</b>' renders bold text in the header — stored XSS if saved.
Useful Tools
End-to-end search flows including autocomplete keyboard navigation, network interception, and ARIA assertions.
Search E2E tests with cy.intercept for stubbing slow or error responses, and cy.request for API search assertions.
Load testing search under concurrent requests — verify performance thresholds at scale.
Active scan for injection vulnerabilities in the search endpoint.
WCAG 2.1 AA audit of the search UI — input labels, autocomplete ARIA, focus management.
API-level search testing: filter combinations, sort validation, injection payloads, and edge cases.
Monitor search response times and error rates during load tests. Spot latency regressions before production.
// Related resources
Glossary terms
- XSS (Cross-Site Scripting)
- SQL Injection
- Accessibility
- WCAG
- ARIA Attributes
- Latency
- Response Time
- Load Testing
- Boundary Value Analysis
- Equivalence Partitioning
- Exploratory Testing
- Regression Test
- Smoke Test
- Test Data Management
- Schema Validation
- Pagination
- Filtering
- Sorting
- Full-Text Search
- Autocomplete
- Caching
- Negative Testing