Skip to content

Commit ef2dcba

Browse files
committed
fix: improve project-switcher data-testid for uniqueness and special chars
The data-testid generation was using only the sanitized project name which could produce collisions and didn't handle special characters properly. Changes: - Combine stable project.id with sanitized name: project-switcher-{id}-{name} - Expand sanitization to remove non-alphanumeric chars (except hyphens) - Collapse multiple hyphens and trim leading/trailing hyphens - Update E2E tests to use ends-with selector for matching This ensures test IDs are deterministic, unique, and safe for CSS selectors.
1 parent 327aef8 commit ef2dcba

4 files changed

Lines changed: 24 additions & 4 deletions

File tree

apps/ui/src/components/layout/project-switcher/components/project-switcher-item.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,28 @@ export function ProjectSwitcherItem({
3737
const IconComponent = getIconComponent();
3838
const hasCustomIcon = !!project.customIconPath;
3939

40+
// Create a sanitized project name for test ID:
41+
// - Convert to lowercase
42+
// - Replace spaces with hyphens
43+
// - Remove all non-alphanumeric characters except hyphens
44+
// - Collapse multiple hyphens into single hyphen
45+
// - Trim leading/trailing hyphens
46+
const sanitizedName = project.name
47+
.toLowerCase()
48+
.replace(/\s+/g, '-')
49+
.replace(/[^a-z0-9-]/g, '')
50+
.replace(/-+/g, '-')
51+
.replace(/^-|-$/g, '');
52+
53+
// Combine project.id with sanitized name for uniqueness and readability
54+
// Format: project-switcher-{id}-{sanitizedName}
55+
const testId = `project-switcher-${project.id}-${sanitizedName}`;
56+
4057
return (
4158
<button
4259
onClick={onClick}
4360
onContextMenu={onContextMenu}
61+
data-testid={testId}
4462
className={cn(
4563
'group w-full aspect-square rounded-xl flex items-center justify-center relative overflow-hidden',
4664
'transition-all duration-200 ease-out',
@@ -60,7 +78,6 @@ export function ProjectSwitcherItem({
6078
'hover:scale-105 active:scale-95'
6179
)}
6280
title={project.name}
63-
data-testid={`project-switcher-${project.id}`}
6481
>
6582
{hasCustomIcon ? (
6683
<img

apps/ui/tests/features/feature-manual-review-flow.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ test.describe('Feature Manual Review Flow', () => {
131131
}
132132

133133
// Verify we're on the correct project (project switcher button shows project name)
134-
await expect(page.getByTestId(`project-switcher-project-${projectName}`)).toBeVisible({
134+
// Use ends-with selector since data-testid format is: project-switcher-{id}-{sanitizedName}
135+
await expect(page.locator(`[data-testid$="-${projectName}"]`)).toBeVisible({
135136
timeout: 10000,
136137
});
137138

apps/ui/tests/projects/new-project-creation.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ test.describe('Project Creation', () => {
7878

7979
// Wait for project to be set as current and visible on the page
8080
// The project name appears in the project switcher button
81-
await expect(page.getByTestId(`project-switcher-project-${projectName}`)).toBeVisible({
81+
// Use ends-with selector since data-testid format is: project-switcher-{id}-{sanitizedName}
82+
await expect(page.locator(`[data-testid$="-${projectName}"]`)).toBeVisible({
8283
timeout: 15000,
8384
});
8485

apps/ui/tests/projects/open-existing-project.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,9 @@ test.describe('Open Project', () => {
157157

158158
// Wait for a project to be set as current and visible on the page
159159
// The project name appears in the project switcher button
160+
// Use ends-with selector since data-testid format is: project-switcher-{id}-{sanitizedName}
160161
if (targetProjectName) {
161-
await expect(page.getByTestId(`project-switcher-project-${targetProjectName}`)).toBeVisible({
162+
await expect(page.locator(`[data-testid$="-${targetProjectName}"]`)).toBeVisible({
162163
timeout: 15000,
163164
});
164165
}

0 commit comments

Comments
 (0)