-
Notifications
You must be signed in to change notification settings - Fork 53
Description
PDD-CLI Bug: E2E Tests Don't Account for Dynamic UI Text
PDD-CLI generates E2E test selectors using exact string matching for UI elements that contain dynamic content (counts, dates, user names). Tests fail when the dynamic content changes.
Why this matters: Tests become flaky, failing whenever dynamic values change, even though the functionality is correct.
Concrete Example
For a page that displays action counts:
// PDD generated test (WRONG):
test('shows actions section', async ({ page }) => {
await page.goto('/dashboard');
// Expects exact text match
await expect(page.getByText('Actions')).toBeVisible();
});But the actual UI renders dynamic content:
// dashboard.tsx (actual implementation)
export function Dashboard({ actionCount }: Props) {
return (
<div>
<h2>Actions ({actionCount} configured)</h2> {/* Dynamic count */}
</div>
);
}What went wrong: PDD generated exact match for "Actions" but UI renders "Actions (3 configured)" or "Actions (5 configured)" depending on data.
Impact: Test fails with locator.getByText('Actions') not found even though the heading exists.
Why PDD Makes This Mistake
PDD-CLI currently:
- Uses exact string matching by default
- Doesn't identify which text is static vs dynamic
- Doesn't consider data-driven UI variations
But it should:
- Recognize patterns that indicate dynamic content (counts, dates, names)
- Use flexible matching for dynamic text
- Prefer data-testid for elements with dynamic content
How to Prevent This in PDD-CLI
What PDD should do differently:
-
Detect dynamic content patterns: Recognize
{variable},{count}, template strings in UI code. -
Use regex or partial matching:
// Instead of exact match page.getByText('Actions') // Use pattern matching page.getByText(/Actions \(\d+ configured\)/)
-
Prefer data-testid for dynamic content:
// In component <h2 data-testid="actions-heading">Actions ({count} configured)</h2> // In test page.getByTestId('actions-heading')
Example improvement:
Current: See "Actions ({actionCount} configured)" in code
→ Generate: getByText('Actions')
→ Test fails
Improved: See "Actions ({actionCount} configured)" in code
→ Detect dynamic content
→ Generate: getByText(/Actions \(\d+ configured\)/)
→ Or: getByTestId('actions-heading')
Severity
P2 - Medium Priority
- Frequency: High - common in data-driven UIs
- Impact: Flaky tests, false negatives
- Detectability: Medium - fails inconsistently based on data
- Prevention cost: Low - regex matching is straightforward
Category
test-generation
Related Issues
- Add failing tests for issue #409: Environment Variable Pollution #416 - Exact string matches before seeing UI (same root cause)
- Resource leak: Temp directories not cleaned up when git clone fails #418 - Verbose button text assumptions (similar text matching issue)
- Additional suggestions for pdd connect UI improvements #420 - Text matching vs semantic selectors (alternative approach)
For Contributors: Discovered in frontend/e2e/crm.spec.ts where heading rendered as "Actions (N configured)", fixed in commit 34a651d5.