Skip to content

Fix E2E test failures: rate limiting, auth persistence, test isolation, and app bug#755

Open
devin-ai-integration[bot] wants to merge 1 commit into
devin/1770110364-playwright-cucumber-bddfrom
devin/1778609824-fix-e2e-tests
Open

Fix E2E test failures: rate limiting, auth persistence, test isolation, and app bug#755
devin-ai-integration[bot] wants to merge 1 commit into
devin/1770110364-playwright-cucumber-bddfrom
devin/1778609824-fix-e2e-tests

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented May 12, 2026

Summary

Fixes all 36-38 E2E test failures across the Playwright + Cucumber BDD test suite, bringing the pass rate from ~32% to 100% (53/53 scenarios passing).

Root Causes & Fixes

App bug (1 fix):

  • Rate limiting too aggressive (backend/src/server.js): The 100 req/15min limit caused 429 errors mid-test-run. Made configurable via RATE_LIMIT_MAX env var (default still 100 for production safety).
  • Login button enabled for whitespace-only email (frontend/src/pages/LoginPage.tsx): Changed !email to !email.trim().

Test issues (multiple fixes):

  • Auth state lost on navigation: page.goto() caused full page reloads, triggering /api/auth/me which failed under rate limiting. Fixed by using sidebar navigation (client-side SPA routing) instead of full reloads, and waiting for MuiAppBar after login to confirm auth state has settled.
  • Login redirect assertion: Changed from waitForURL to waitForFunction for SPA pushState navigation.
  • MUI dropdown selection: Targeted .MuiMenuItem-root:has-text() to avoid backdrop intercept.
  • Delete dialog handling: Changed to page.once('dialog') registered before the delete click.
  • Client table assertion: isClientInTable() used td:has-text() which matched description column substrings. Fixed to td:first-child:has-text().
  • Delete work entry assertion: Checked total row count instead of specific client. Fixed to check for the specific client name.
  • Shared data pollution: Scenarios asserting exact totals or empty state now use unique client names/emails for proper isolation.

Review & Testing Checklist for Human

  • Run RATE_LIMIT_MAX=10000 node backend/src/server.js and npm run dev (frontend), then cd e2e && npx cucumber-js --config cucumber.js to verify all 53 scenarios pass
  • Verify the login page still works correctly in the browser (whitespace-only email should disable the button)
  • Check that the RATE_LIMIT_MAX env var defaults to 100 when not set (production behavior unchanged)

Notes

  • The rate limit fix is backwards-compatible: default behavior is unchanged (100/15min). Only when RATE_LIMIT_MAX is explicitly set does the limit change.
  • Sidebar navigation via .MuiDrawer-docked targets only the permanent (desktop) drawer, avoiding false matches with the hidden mobile drawer.

Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/02c26fc9532f4c64b7f66c46709fb063


Open in Devin Review

…n, and app bug

App fixes:
- Make rate limit configurable via RATE_LIMIT_MAX env var (was 100/15min, causing 429s during test runs)
- Fix login button accepting whitespace-only email (trim check)

Test fixes:
- Use sidebar navigation (client-side) instead of page.goto() to avoid full reloads losing auth state
- Wait for MuiAppBar after login to ensure auth state settles before proceeding
- Fix login redirect assertion to use waitForFunction for SPA navigation
- Target .MuiMenuItem-root for MUI dropdown selection to avoid backdrop intercept
- Use page.once('dialog') before delete clicks for proper dialog handling
- Fix isClientInTable to check only first column (td:first-child) to avoid description substring matches
- Fix delete work entry assertion to check specific client, not total row count
- Use unique emails/clients for scenarios needing data isolation (dashboard empty, reports totals, delete entry)
- Add networkidle waits after mutation operations for proper state refresh

All 53 scenarios now pass (was 36-38 failures).
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor Author

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment thread backend/src/server.js
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
max: parseInt(process.env.RATE_LIMIT_MAX || '100', 10)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 parseInt of invalid RATE_LIMIT_MAX silently disables rate limiting

If RATE_LIMIT_MAX is set to a non-numeric string (e.g., "abc"), parseInt returns NaN, and since totalHits > NaN is always false in JavaScript, no request is ever rate-limited. Similarly, if set to "0", parseInt("0", 10) returns 0—and in express-rate-limit v7 (backend/package.json), max: 0 is documented to disable rate limiting entirely. Because "0" is truthy, the || '100' fallback doesn't activate. In both cases, rate limiting is silently disabled, removing a security control against brute-force or DoS attacks. There is no input validation or bounds checking on the parsed value.

Suggested change
max: parseInt(process.env.RATE_LIMIT_MAX || '100', 10)
max: Math.max(1, parseInt(process.env.RATE_LIMIT_MAX || '100', 10) || 100)
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants