Skip to content

Commit aa43cec

Browse files
committed
fix: comprehensive code review improvements for perfect implementation
AlertForm.tsx: - Add data-coordinates attribute for consistent coordinate access - Add data-testid="alert-retry-button" for retry button AlertFormPage.ts: - Add retryButton locator - Update getDisplayedCoordinates to use data-coordinates attribute - Add NaN validation for coordinate parsing - Add expectNoSubmissionError method for symmetry ProjectSelectionPage.ts: - Update continueToAlertForm to wait for container instead of input - Add NaN validation for getSelectedProjectCount - Fix expectProjectsLoaded to check if loading indicator exists before waiting - Add expectSelectedProjectsSummaryVisible method - Add expectNoSelectedProjectsSummary method for conditionally rendered element All page object methods now: - Use data-testid selectors consistently - Properly handle conditionally rendered elements with toHaveCount(0) - Include NaN validation for numeric parsing - Have symmetric assert/expectNot method pairs
1 parent 03355dc commit aa43cec

File tree

4 files changed

+42
-17
lines changed

4 files changed

+42
-17
lines changed

docs/SKIPPED_TESTS_ROADMAP.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,8 +568,10 @@ Update key components:
568568
| ProjectSelection | `loading-indicator` | Loading spinner |
569569
| AlertForm | `alert-form` | Container |
570570
| AlertForm | `coordinates-display` | Location coordinates |
571+
| AlertForm | `data-coordinates` | Coordinate data attribute |
571572
| AlertForm | `selected-projects-display` | Selected projects info |
572573
| AlertForm | `alert-submit-button` | Submit button |
574+
| AlertForm | `alert-retry-button` | Retry button |
573575
| AlertForm | `alert-error-message` | Submission error |
574576
| AlertForm | `alert-validation-error` | Validation error |
575577

src/components/AlertForm.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ export const AlertForm = ({
271271
<p
272272
className="font-mono text-sm"
273273
data-testid="coordinates-display"
274+
data-coordinates={`${coordinates.lat},${coordinates.lng}`}
274275
>
275276
{coordinates.lat}, {coordinates.lng}
276277
</p>
@@ -396,6 +397,7 @@ export const AlertForm = ({
396397
setSubmissionState("idle");
397398
setErrorMessage("");
398399
}}
400+
data-testid="alert-retry-button"
399401
>
400402
{t("alert.tryAgain")}
401403
</Button>

tests/pages/AlertFormPage.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export class AlertFormPage extends BasePage {
2424
// Buttons
2525
readonly submitButton: Locator;
2626
readonly backButton: Locator;
27+
readonly retryButton: Locator;
2728

2829
// Feedback elements
2930
readonly validationError: Locator;
@@ -48,6 +49,7 @@ export class AlertFormPage extends BasePage {
4849
// Buttons
4950
this.submitButton = page.locator('[data-testid="alert-submit-button"]');
5051
this.backButton = page.getByRole('button', { name: /back/i });
52+
this.retryButton = page.locator('[data-testid="alert-retry-button"]');
5153

5254
// Validation error (inline format error for alert name)
5355
this.validationError = page.locator('[data-testid="alert-validation-error"]');
@@ -126,17 +128,15 @@ export class AlertFormPage extends BasePage {
126128
* Get the displayed coordinates from the summary section
127129
*/
128130
async getDisplayedCoordinates(): Promise<{ lat: number; lng: number }> {
129-
const text = await this.coordinatesDisplay.textContent();
130-
if (!text) throw new Error('Coordinates not displayed');
131+
const coordsAttr = await this.coordinatesDisplay.getAttribute('data-coordinates');
132+
if (!coordsAttr) throw new Error('Coordinates not found in data attribute');
131133

132-
// Parse coordinates - they might be displayed as "lat: X, lng: Y" or "X, Y"
133-
const matches = text.match(/([-]?\d+\.\d+)[^-\d]+([-]?\d+\.\d+)/);
134-
if (!matches) throw new Error(`Cannot parse coordinates from: ${text}`);
134+
const [lat, lng] = coordsAttr.split(',').map(Number);
135+
if (isNaN(lat) || isNaN(lng)) {
136+
throw new Error(`Invalid coordinates format: ${coordsAttr}`);
137+
}
135138

136-
return {
137-
lat: parseFloat(matches[1]),
138-
lng: parseFloat(matches[2]),
139-
};
139+
return { lat, lng };
140140
}
141141

142142
/**
@@ -214,6 +214,11 @@ export class AlertFormPage extends BasePage {
214214
}
215215
}
216216

217+
async expectNoSubmissionError() {
218+
// Element is conditionally rendered, so check it doesn't exist
219+
await expect(this.submissionError).toHaveCount(0);
220+
}
221+
217222
async expectSuccessState() {
218223
// Check if button shows success message
219224
await expect(this.submitButton).toContainText(/success|created/i);

tests/pages/ProjectSelectionPage.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,23 @@ export class ProjectSelectionPage extends BasePage {
9191
*/
9292
async getSelectedProjectCount(): Promise<number> {
9393
const countAttr = await this.continueButton.getAttribute('data-selected-count');
94-
return countAttr ? parseInt(countAttr, 10) : 0;
94+
if (!countAttr) return 0;
95+
96+
const count = parseInt(countAttr, 10);
97+
if (isNaN(count)) {
98+
throw new Error(`Invalid selected count value: ${countAttr}`);
99+
}
100+
return count;
95101
}
96102

97103
/**
98104
* Continue to the alert form
99105
*/
100106
async continueToAlertForm() {
101107
await this.continueButton.click();
102-
// Wait for alert form to appear (look for form elements)
103-
const alertNameInput = this.page.locator('#alertName');
104-
await alertNameInput.waitFor({ state: 'visible', timeout: 10000 });
108+
// Wait for alert form container to appear
109+
const alertForm = this.page.locator('[data-testid="alert-form"]');
110+
await alertForm.waitFor({ state: 'visible', timeout: 10000 });
105111
}
106112

107113
/**
@@ -129,10 +135,11 @@ export class ProjectSelectionPage extends BasePage {
129135
*/
130136

131137
async expectProjectsLoaded() {
132-
// Wait for loading to finish
133-
await this.loadingIndicator.waitFor({ state: 'hidden', timeout: 10000 }).catch(() => {
134-
// Ignore if loading indicator was never shown
135-
});
138+
// Wait for loading to finish if loading indicator exists
139+
const loadingCount = await this.loadingIndicator.count();
140+
if (loadingCount > 0) {
141+
await this.loadingIndicator.waitFor({ state: 'hidden', timeout: 10000 });
142+
}
136143
// Verify at least one checkbox is visible
137144
await this.getProjectCheckboxes().first().waitFor({ state: 'visible', timeout: 10000 });
138145
}
@@ -169,4 +176,13 @@ export class ProjectSelectionPage extends BasePage {
169176
const checkboxes = this.getProjectCheckboxes();
170177
await expect(checkboxes).toHaveCount(count);
171178
}
179+
180+
async expectSelectedProjectsSummaryVisible() {
181+
await expect(this.selectedProjectsSummary).toBeVisible();
182+
}
183+
184+
async expectNoSelectedProjectsSummary() {
185+
// Element is conditionally rendered, so check it doesn't exist
186+
await expect(this.selectedProjectsSummary).toHaveCount(0);
187+
}
172188
}

0 commit comments

Comments
 (0)