How to Write Test Cases for Forgot Password (With Examples)
How to Write Test Cases for Forgot Password (With Examples)
How to Write Test Cases for Forgot Password (With Examples)
Forgot‑password functionality is a critical gate‑keeper for account recovery, yet it is often under‑tested because the flow appears simple. In reality, a robust test suite must verify that legitimate users can reset their credentials quickly, that malicious actors cannot abuse the mechanism, and that edge‑case inputs do not cause crashes or leak information. This guide walks you through the complete process of designing, prioritizing, and executing test cases for a forgot‑password feature, providing a concrete matrix of 20+ examples, a short checklist, and practical tips for combining manual exploratory testing with automated regression scripts. By the end you will have a ready‑to‑use test‑case template that you can adapt to any web or mobile application.
1. Understanding the Forgot Password Flow
Before writing test cases you need a clear mental model of the typical reset‑password sequence. Most implementations follow these logical steps:
- User entry – The user supplies an identifier (usually email or username) on a “Forgot password?” page.
- Validation – The system checks that the identifier matches an existing account and that the account is in a recoverable state (not locked, not marked for deletion).
- Token generation – A cryptographically‑random, single‑use token is created and stored (often hashed) together with an expiration timestamp.
- Notification – The token (or a URL containing it) is sent to the user via email, SMS, or an in‑app message.
- User interaction – The user clicks the link, arrives at a reset‑password page, and enters a new password that satisfies policy rules.
- Verification – The system validates the token, ensures it has not been used or expired, updates the password hash, invalidates any existing sessions, and confirms success.
- Post‑reset actions – The user is redirected to a login page or a “password changed” screen, and a security notification is sent.
Each step introduces distinct test concerns: input validation, business logic, cryptographic security, usability, and auditability. Keeping this flow in mind helps you avoid gaps when you enumerate test cases.
1.1 Typical Variations
- Identifier type – Some apps accept email only, others allow username or phone number.
- Delivery channel – Email is common, but SMS, push notifications, or even secure messaging apps may be used.
- Additional verification – Certain systems require answering a security question, entering a CAPTCHA, or confirming via a second factor before sending the token.
- Password reuse rules – The new password may be forbidden from matching the last N passwords or from containing the user’s name.
Understanding which variations apply to your product shapes the set of test cases you will need.
1.2 Security Goals
A forgot‑password flow must satisfy three core security properties:
- Confidentiality – Only the legitimate account holder can obtain the reset token.
- Integrity – An attacker cannot forge or reuse a token to change another user’s password.
- Availability – Legitimate users are not denied service by rate‑limiting or lock‑out mechanisms that are too aggressive.
Your test cases should explicitly target each property.
2. Anatomy of a Test Case
A well‑structured test case makes it easy to review, automate, and trace back to requirements. The following fields are essential:
| Field | Description |
|---|---|
| ID | Unique identifier (e.g., FP‑001) that enables traceability and easy reference in defect reports. |
| Title | Concise, readable summary of what is being verified (e.g., “Valid email triggers reset link”). |
| Preconditions | State that must be true before execution (e.g., “User exists with email alice@example.com, account is active, no pending reset”). |
| Steps | Numbered actions the tester performs, including any data entry, navigation, or API calls. |
| Expected Result | Observable outcome that determines pass/fail (e.g., “System sends an email containing a single‑use reset link within 30 seconds”). |
| Actual Result | Filled in after execution; used to log defects. |
| Priority | Typically P0 (critical), P1 (high), P2 (medium), P3 (low) based on risk and impact. |
| Traceability | Link to the originating requirement, user story, or design spec (e.g., “REQ‑AUTH‑07”). |
| Notes | Optional field for environment specifics, data cleanup, or observations. |
When you write a test case, fill in every field before execution. Leaving a field blank invites ambiguity and makes later traceability harder.
2.1 Writing Clear Steps
Steps should be imperative, atomic, and free of assumptions. For example:
- Navigate to
https://app.example.com/forgot. - Enter
alice@example.cominto the Email field. - Click the Submit button.
- Wait for the success toast message to appear.
Avoid bundling multiple actions into a single step; otherwise, debugging a failure becomes guesswork.
2.2 Choosing Expected Results
Expected results must be observable and measurable. Instead of “system behaves correctly,” specify:
- “An HTTP 200 response is returned with JSON
{“status”:“sent”}. - “The email inbox of
alice@example.comcontains a message with subject “Reset your password” and a link matching the patternhttps://app.example.com/reset?token=.*.” - “No error dialog is displayed.”
Concrete expectations enable both manual verification and automated assertions.
3. Positive Test Cases
Positive tests confirm that the happy path works for legitimate users. Below are categories of positive scenarios, each with representative test cases.
3.1 Valid Identifier Submission
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑001 | Valid email triggers reset link | User exists, email alice@example.com, account active | 1. Open forgot‑password page. 2. Enter alice@example.com.3. Click Submit. | System returns success message; email with reset link is delivered within 30 s. |
| FP‑002 | Username (if supported) triggers reset link | Username bob123 maps to existing account | Same as FP‑001 using username field. | Same as FP‑001. |
| FP‑003 | Phone number (if supported) triggers reset link | Phone +1‑555‑123‑4567 registered, SMS enabled | Enter phone number, click Submit. | SMS with reset link received within 30 s. |
3.2 Token Validity and Expiration
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑004 | Token works within validity window | Reset link sent (FP‑001) not yet clicked | 1. Open email, copy link. 2. Paste link in browser. 3. Enter new password NewPass!23.4. Click Reset. | Password updated; user redirected to login page; success toast shown. |
| FP‑005 | Token rejected after expiration | Reset link sent, system clock advanced > expiry (e.g., 24 h) | Same as FP‑004 but after waiting for expiry. | Error message: “Link has expired. Please request a new reset link.” |
| FP‑006 | Token single‑use enforcement | Reset link sent, not yet used | 1. Use link to reset password successfully (FP‑004). 2. Attempt to use same link again. | Second attempt yields error: “Invalid or already used token.” |
3.3 Password Policy Compliance
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑007 | Accepts password meeting policy | Token valid, password policy: ≥8 chars, 1 upper, 1 digit, 1 symbol | Enter Secure9! on reset page, submit. | Password changed; success message. |
| FP‑008 | Rejects password missing required character class | Same as FP‑007 | Enter secure (no upper, digit, symbol). | Inline validation error: “Password must contain at least one uppercase letter, one digit, and one symbol.” |
| FP‑009 | Rejects password too short | Same as FP‑007 | Enter Ab1! (4 chars). | Error: “Password must be at least 8 characters long.” |
| FP‑010 | Prevents reuse of recent passwords | User’s last 3 passwords stored: Old1!, Old2@, Old3# | Attempt to set new password to Old1!. | Error: “You cannot reuse your last three passwords.” |
3.4 User Experience Feedback
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑011 | Success toast appears after reset | Token valid | Complete FP‑004 | Toast “Password changed successfully” displayed for ≥ 3 seconds. |
| FP‑012 | Email notification sent after reset | Token valid | Complete FP‑004 | User receives email “Your password has been changed” within 1 minute. |
| FP‑013 | Session invalidation after reset | User has active session on another device | Perform FP‑004, then try to access a protected page on other device. | Redirect to login page; session token invalid. |
These positive cases establish that the core flow works under normal conditions and that the system gives appropriate feedback.
4. Negative Test Cases
Negative tests verify that the system correctly handles invalid or malicious input. They are essential for preventing information leakage, abuse, and denial‑of‑service.
4.1 Invalid or Non‑existent Identifiers
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑014 | Non‑existent email returns generic message | No account with nonexist@example.com | Enter email, click Submit. | Message: “If the address exists, you will receive a reset link.” (no hint whether address exists). |
| FP‑015 | Email with wrong domain returns same generic | Same as FP‑014 | Enter alice@wrongdomain.com. | Same generic message. |
| FP‑016 | Username with special chars returns generic | Username bob!$ not registered | Enter username, click Submit. | Same generic message. |
| FP‑017 | Blank identifier field | Form loaded | Leave email empty, click Submit. | Inline validation: “Email is required.” |
| FP‑018 | Whitespace‑only identifier | Same as FP‑017 | Enter spaces, click Submit. | Same validation error. |
4.2 Rate Limiting and Abuse Protection
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑019 | Rate limit per‑minute throttling on submit | No prior attempts in current minute | Rapidly click Submit 10 times with same email. | After 5 attempts, system shows “Too many requests; try again later.” |
| FP‑020 per‑hour lockout after failures | No lockout in place | Submit invalid email 15 times within hour. | After 10 failures, system displays “Account temporarily locked; try again in 60 min.” | |
| FP‑021 CAPTCHA after repeated failures | Same as FP‑020 | After 5 failed attempts, system presents CAPTCHA. | User must solve CAPTCHA before next submit attempt. |
4.3 Token Tampering and Replay
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑022 Modified token rejected | Valid token obtained (FP‑004) | 1. Copy reset link. 2. Change one character in token query param. 3. Navigate to altered link. | Error: “Invalid token.” | |
| FP‑023 Token replay after use | Token used successfully (FP‑004) | Re‑use same link after password change. | Error: “Token already used.” | |
| FP‑024 Token with future timestamp rejected | System allows setting custom clock (test env) | Generate token with expiry + 30 days, use immediately. | Error: “Invalid token.” | |
| FP‑025 Token replay across accounts | Two accounts A and B, token for A | Attempt to use A’s token to reset B’s password. | Error: “Token does not belong to this account.” |
4.4 Information Leakage Checks
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑026 No account existence hint in response | Same as FP‑014 | Submit non‑existent email. | HTTP status 200, response body identical to that for existing email (no “user not found”). | |
| FP‑027 No partial email in logs or UI | Same as FP‑014 | Submit any email, inspect network logs and UI toast. | Logs contain only hashed identifier; UI never shows the entered email in error messages. | |
| FP‑028 No token in URL referrer header | Token valid | Click reset link from email, navigate to external site. | Referer header does not contain the full reset URL (token stripped) or site uses rel=noreferrer. |
These negative cases ensure that the system does not aid attackers by revealing whether an address is registered, by allowing token reuse, or by failing to enforce rate limits.
5. Boundary and Edge‑Case Tests
Boundary conditions often expose bugs that slip through happy‑path testing. Test the limits of input length, character sets, and concurrency.
5.1 Input Length Limits
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑029 Maximum email length accepted | System defines max 254 chars (RFC 5321) | Generate email a × 240 + @example.com (254). | Enter email, click Submit. | Success; reset link sent. |
| FP‑030 Email longer than limit rejected | Same as FP‑029 | Email a × 250 + @example.com (259). | Enter email, click Submit. | Validation error: “Email address is too long.” |
| FP‑031 Minimum email length accepted | System allows 3‑char local part | Email ab@cd.com (6 chars). | Enter email, click Submit. | Success (if domain valid). |
| FP‑032 Email shorter than limit rejected | Same as FP‑031 | Email a@b.c (5 chars) – invalid domain format. | Enter email, click Submit. | Validation error: “Please enter a valid email address.” |
5.2 Character Set and Unicode
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑033 Email with plus‑sign (gmail style) | Account exists with alice+test@example.com | Enter alice+test@example.com, click Submit. | Success; reset link delivered to the same inbox. | |
| FP‑034 Email with sub‑addressing (hyphen) | Account bob‑work@example.com exists | Enter bob‑work@example.com. | Success. | |
| FP‑035 Email with Unicode characters | Account 用户@例子.cn exists (IDN) | Enter 用户@例子.cn. | Success; system normalizes to punycode internally and sends link. | |
| FP‑036 Email with leading/trailing spaces | Same as FP‑001 | Enter “ alice@example.com ” (spaces). | System trims whitespace; treats as valid email. | |
| FP‑037 Email with multiple consecutive dots | Same as FP‑001 | Enter alice..smith@example.com. | Validation error: “Email address contains invalid characters.” |
5.3 Concurrent Requests and Race Conditions
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑038 Parallel reset requests for same account | User has active session, no pending reset | 1. Open two browser tabs. 2. In each, submit FP‑001 simultaneously. 3. Observe responses. | Only one reset link is generated and sent; second request returns “A reset link has already been sent; please check your email.” | |
| FP‑039 Token generation under high load | System under simulated load (e.g., 100 req/s) | Use a load‑generator to send reset requests for distinct accounts. | All requests receive success responses; no HTTP 500 errors; each email receives a unique link. | |
| FP‑040 Password change while reset link pending | User requests reset, then attempts to change password via settings before using link | 1. Trigger FP‑001. 2. Without clicking email, navigate to Settings → Change Password and submit new password. | Settings change succeeds; the previously sent reset link becomes invalid (error if used). |
These boundary cases test validation logic, Unicode handling, and concurrency safeguards that are often missed in scripted tests.
6. Security‑Focused Test Cases
Beyond functional correctness, the forgot‑password flow must resist specific attack vectors. The following cases target common weaknesses.
6.1 Token Entropy and Predictability
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑041 Token length ≥ 32 bytes | System generates token via cryptographically‑secure RNG | Request reset for any account, capture token from email. | Token string (base64‑url) length ≥ 43 chars (≈32 bytes). | |
| FP‑042 Token contains sufficient entropy | Same as FP‑041 | Collect 1000 tokens, compute Shannon entropy. | Entropy ≈ log₂(N) where N is token space; should be > 60 bits. | |
| FP‑043 Token not derivable from user data | Same as FP‑041 | Attempt to predict token using username, email, timestamp. | No statistical correlation; prediction success rate ≈ random guess. |
6.2 Replay and Man‑in‑the‑Middle Mitigations
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑044 HTTPS enforced for reset link | Token valid | Capture reset link; verify URL scheme is https://. | Link uses HTTPS; if HTTP, test fails. | |
| FP‑045 HSTS header on reset‑page domain | Same as FP‑044 | Perform a curl -I request to reset‑page domain. | Response includes Strict-Transport-Security header with max‑age≥31536000. | |
| FP‑046 Token bound to IP address (optional) | System implements IP‑binding | Request reset from IP A, obtain link. Attempt to use link from IP B. | Error: “Token invalid for this IP address.” (if feature enabled). |
6.3 Logging and Alerting
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑047 Failed reset attempts logged | No prior attempts | Submit invalid email 5 times. | Security log contains entries: FAILED_RESET email=… reason=INVALID_FORMAT. | |
| FP‑048 Successful reset triggers audit entry | Token valid | Complete FP‑004. | Audit log: PASSWORD_RESET userId=123 outcome=SUCCESS timestamp=…. | |
| FP‑049 Rate‑limit exceeded triggers alert | Same as FP‑019 | Exceed threshold (e.g., 20 requests/min). | Monitoring system receives alert: RESET_RATE_LIMIT_EXCEEDED. |
These security tests give you confidence that the mechanism does not become a weak point in your overall authentication strategy.
7. Prioritization and Traceability
A large test suite needs a rational ordering so that the most critical defects are found early, especially when time is limited.
7.1 Risk‑Based Scoring Model
Assign each test case a Risk Score = (Impact × Likelihood). Impact reflects the severity of a failure (e.g., account takeover = 5, UI glitch = 1). Likelihood estimates how often the condition occurs in production (e.g., malformed input = 3, token reuse = 2). Prioritize tests with the highest scores.
| Score Range | Priority Label | Typical Content |
|---|---|---|
| 20‑25 | P0 (Critical) | Token reuse, account enumeration, HTTPS missing |
| 15‑19 | P1 (High) | Rate limiting, password policy enforcement |
| 10‑14 | P2 (Medium) | Edge‑case input lengths, Unicode handling |
| 5‑9 | P3 (Low) | Cosmetic messages, non‑essential logging |
Apply this model to the matrix above; you will see that FP‑022, FP‑023, FP‑044, and FP‑047 typically fall into P0.
7.2 Requirements Traceability Matrix (RTM)
Link each test case to the requirement(s) it validates. Below is a simplified RTM showing a few requirements from a typical auth spec.
| Requirement ID | Description | Covered Test Cases |
|---|---|---|
| REQ‑AUTH‑07 | System shall allow password reset via email | FP‑001, FP‑002, FP‑003, FP‑004, FP‑005, FP‑006 |
| REQ‑AUTH‑08 | Reset token must be single‑use and time‑bound | FP‑005, FP‑006, FP‑022, FP‑023 |
| REQ‑AUTH‑09 | No user‑enumeration via reset endpoint | FP‑014, FP‑015, FP‑016, FP‑026 |
| REQ‑AUTH‑10 | Rate‑limit reset requests to prevent abuse | FP‑019, FP‑020, FP‑021 |
| REQ‑AUTH‑11 | Password must meet policy on reset | FP‑007, FP‑008, FP‑009, FP‑010 |
| REQ‑AUTH‑12 | Successful reset must invalidate existing sessions | FP‑013 |
| REQ‑AUTH‑13 | All reset activity must be audited | FP‑047, FP‑048, FP‑049 |
Maintaining this matrix in a spreadsheet or test‑management tool lets you quickly see which requirements lack coverage and guides test‑case creation when specs evolve.
8. Manual vs. Automated Execution
Both approaches have merit. Manual exploratory testing uncovers usability quirks and unexpected states, while automated regression guards against re‑introducing known defects.
8.1 Manual Exploratory Testing with SUSA
SUSA (the autonomous QA platform) can be pointed at your web or mobile app and will exercise the forgot‑password flow using a variety of user personas—curious, impatient, novice, adversarial, elderly, accessibility‑focused, power user, etc. Each persona follows its own behavior profile, which may reveal issues that scripted tests miss.
Typical workflow:
# Install the agent
pip install susatest-agent
# Point SUSA at a staging URL (web) or provide an APK (Android)
susatest run --url https://staging.example.com \
--personas curious impatient adversarial \
--timeout 15m \
--output report.html
During a run, SUSA will:
- Locate the “Forgot password?” link (often via text‑match or accessibility label).
- Attempt to submit various identifiers (valid, invalid, long, special‑char).
- Follow any email links it discovers (if a test mailbox is configured).
- Try to reset passwords with weak, strong, and policy‑violating new passwords.
- Observe UI messages, network responses, and any crashes or ANRs.
Because SUSA learns from each session, subsequent runs become smarter—avoiding previously dead ends and focusing on new avenues. Use its output as a starting point for manual investigation: flag any unexpected behavior, then write a focused test case (or automate it) to cover the gap.
8.2 Scripted Automation (Appium + Playwright)
After you have a solid set of test cases, encode the repetitive ones in code. Below are minimal examples for Android (Appium) and web (Playwright). Adjust selectors and data to match your application.
#### Appium (Java) – Valid Email Reset
@Test
public void testValidEmailTriggersReset() {
driver.get("https://app.example.com/forgot");
WebElement email = driver.findElement(By.id("forgotEmail"));
email.sendKeys("alice@example.com");
driver.findElement(By.id("submitBtn")).click();
// Wait for toast
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement toast = wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("toast-success")));
assertTrue(toast.getText().contains("Reset link sent"));
// In a real test you would pull the link from a mailbox API here
}
#### Playwright (TypeScript) – Token Expiration
test('reset link expires after 24h', async ({ page }) => {
await page.goto('https://app.example.com/forgot');
await page.fill('#forgotEmail', 'bob@example.com');
await page.click('#submitBtn');
// Assume we have a test mailbox that returns the latest link
const resetLink = await getLatestResetLink('bob@example.com');
await page.goto(resetLink);
// Simulate time travel: set system clock ahead via mock API (test‑only)
await page.route('**/api/set-clock', route => route.fulfill({ json: { offsetHours: 25 } }));
await page.waitForTimeout(500); // let mock apply
await page.fill('#newPassword', 'NewPass!23');
await page.click('#resetBtn');
const error = await page.locator('.error-message').innerText();
expect(error).toContain('Link has expired');
});
These snippets illustrate how to automate the most common positive and negative paths. Store test data (emails, passwords) in a secure vault or generate them on‑the‑fly to avoid hard‑coding secrets.
8.3 CI Integration
Add the automated tests to your pipeline so they run on every pull request. A typical GitHub Actions snippet:
name: Forgot Password Regression
on: [pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run Playwright tests
run: npx playwright test --project=chromium
- name: Upload report
if: always()
uses: actions/upload-artifact@v3
with:
name: playwright-report
path: playwright-report/
For mobile, replace the Playwright step with an Appium execution using a Docker image that contains the Android emulator and the Appium server.
Combining SUSA’s exploratory runs (perhaps nightly) with the CI‑gated automated suite gives you both breadth and depth.
9. Worked Test Matrix (20+ Cases)
Below is a consolidated table that you can copy into your test‑management tool. It includes ID, short title, preconditions, steps, and expected result. Feel free to extend it with your own project‑specific variations.
| ID | Title | Preconditions | Steps | Expected Result |
|---|---|---|---|---|
| FP‑001 | Valid email triggers reset link | User alice@example.com exists, active | 1. Open forgot‑password page. 2. Enter alice@example.com.3. Click Submit. | Success toast; email with reset link delivered within 30 s. |
| FP‑002 | Username triggers reset link (if supported) | Username bob123 maps to existing account | Same as FP‑001 using username field. | Same as FP‑001. |
| FP‑003 | Phone number triggers reset link (if supported) | Phone +1‑555‑123‑4567 registered, SMS enabled | Enter phone number, click Submit. | SMS with reset link received within 30 s. |
| FP‑004 | Token works within validity window | Reset link sent (FP‑001) not yet clicked | 1. Open email, copy link. 2. Paste link in browser. 3. Enter new password NewPass!23.4. Click Reset. | Password updated; redirected to login; success toast shown. |
| FP‑005 | Token rejected after expiration | Reset link sent, system clock advanced > expiry (e.g., 24 h) | Same as FP‑004 but after waiting for expiry. |
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