mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-03 08:53:36 +00:00
merge: resolve conflicts with upstream/v0.13.0rc
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { Folder, LucideIcon } from 'lucide-react';
|
import { Folder, LucideIcon } from 'lucide-react';
|
||||||
import * as LucideIcons from 'lucide-react';
|
import * as LucideIcons from 'lucide-react';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn, sanitizeForTestId } from '@/lib/utils';
|
||||||
import { getAuthenticatedImageUrl } from '@/lib/api-fetch';
|
import { getAuthenticatedImageUrl } from '@/lib/api-fetch';
|
||||||
import type { Project } from '@/lib/electron';
|
import type { Project } from '@/lib/electron';
|
||||||
|
|
||||||
@@ -37,10 +37,15 @@ export function ProjectSwitcherItem({
|
|||||||
const IconComponent = getIconComponent();
|
const IconComponent = getIconComponent();
|
||||||
const hasCustomIcon = !!project.customIconPath;
|
const hasCustomIcon = !!project.customIconPath;
|
||||||
|
|
||||||
|
// Combine project.id with sanitized name for uniqueness and readability
|
||||||
|
// Format: project-switcher-{id}-{sanitizedName}
|
||||||
|
const testId = `project-switcher-${project.id}-${sanitizeForTestId(project.name)}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onContextMenu={onContextMenu}
|
onContextMenu={onContextMenu}
|
||||||
|
data-testid={testId}
|
||||||
className={cn(
|
className={cn(
|
||||||
'group w-full aspect-square rounded-xl flex items-center justify-center relative overflow-hidden',
|
'group w-full aspect-square rounded-xl flex items-center justify-center relative overflow-hidden',
|
||||||
'transition-all duration-200 ease-out',
|
'transition-all duration-200 ease-out',
|
||||||
@@ -60,7 +65,6 @@ export function ProjectSwitcherItem({
|
|||||||
'hover:scale-105 active:scale-95'
|
'hover:scale-105 active:scale-95'
|
||||||
)}
|
)}
|
||||||
title={project.name}
|
title={project.name}
|
||||||
data-testid={`project-switcher-${project.id}`}
|
|
||||||
>
|
>
|
||||||
{hasCustomIcon ? (
|
{hasCustomIcon ? (
|
||||||
<img
|
<img
|
||||||
|
|||||||
@@ -125,6 +125,34 @@ export const isMac =
|
|||||||
(/Mac/.test(navigator.userAgent) ||
|
(/Mac/.test(navigator.userAgent) ||
|
||||||
(navigator.platform ? navigator.platform.toLowerCase().includes('mac') : false));
|
(navigator.platform ? navigator.platform.toLowerCase().includes('mac') : false));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitize a string for use in data-testid attributes.
|
||||||
|
* Creates a deterministic, URL-safe identifier from any input string.
|
||||||
|
*
|
||||||
|
* Transformations:
|
||||||
|
* - Convert to lowercase
|
||||||
|
* - Replace spaces with hyphens
|
||||||
|
* - Remove all non-alphanumeric characters (except hyphens)
|
||||||
|
* - Collapse multiple consecutive hyphens into a single hyphen
|
||||||
|
* - Trim leading/trailing hyphens
|
||||||
|
*
|
||||||
|
* @param name - The string to sanitize (e.g., project name, feature title)
|
||||||
|
* @returns A sanitized string safe for CSS selectors and test IDs
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* sanitizeForTestId("My Awesome Project!") // "my-awesome-project"
|
||||||
|
* sanitizeForTestId("test-project-123") // "test-project-123"
|
||||||
|
* sanitizeForTestId(" Foo Bar ") // "foo-bar"
|
||||||
|
*/
|
||||||
|
export function sanitizeForTestId(name: string): string {
|
||||||
|
return name
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/\s+/g, '-')
|
||||||
|
.replace(/[^a-z0-9-]/g, '')
|
||||||
|
.replace(/-+/g, '-')
|
||||||
|
.replace(/^-|-$/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a UUID v4 string.
|
* Generate a UUID v4 string.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
getKanbanColumn,
|
getKanbanColumn,
|
||||||
authenticateForTests,
|
authenticateForTests,
|
||||||
handleLoginScreenIfPresent,
|
handleLoginScreenIfPresent,
|
||||||
|
sanitizeForTestId,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
|
|
||||||
const TEST_TEMP_DIR = createTempDirPath('manual-review-test');
|
const TEST_TEMP_DIR = createTempDirPath('manual-review-test');
|
||||||
@@ -131,7 +132,9 @@ test.describe('Feature Manual Review Flow', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify we're on the correct project (project switcher button shows project name)
|
// Verify we're on the correct project (project switcher button shows project name)
|
||||||
await expect(page.getByTestId(`project-switcher-project-${projectName}`)).toBeVisible({
|
// Use ends-with selector since data-testid format is: project-switcher-{id}-{sanitizedName}
|
||||||
|
const sanitizedProjectName = sanitizeForTestId(projectName);
|
||||||
|
await expect(page.locator(`[data-testid$="-${sanitizedProjectName}"]`)).toBeVisible({
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
authenticateForTests,
|
authenticateForTests,
|
||||||
handleLoginScreenIfPresent,
|
handleLoginScreenIfPresent,
|
||||||
waitForNetworkIdle,
|
waitForNetworkIdle,
|
||||||
|
sanitizeForTestId,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
|
|
||||||
const TEST_TEMP_DIR = createTempDirPath('project-creation-test');
|
const TEST_TEMP_DIR = createTempDirPath('project-creation-test');
|
||||||
@@ -77,10 +78,10 @@ test.describe('Project Creation', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for project to be set as current and visible on the page
|
// Wait for project to be set as current and visible on the page
|
||||||
// The project name appears in the project switcher button with title attribute
|
// The project name appears in the project switcher button
|
||||||
// (The button uses data-testid with projectId, not projectName)
|
// Use ends-with selector since data-testid format is: project-switcher-{id}-{sanitizedName}
|
||||||
const projectSwitcherButton = page.locator(`button[title="${projectName}"]`).first();
|
const sanitizedProjectName = sanitizeForTestId(projectName);
|
||||||
await expect(projectSwitcherButton).toBeVisible({
|
await expect(page.locator(`[data-testid$="-${sanitizedProjectName}"]`)).toBeVisible({
|
||||||
timeout: 15000,
|
timeout: 15000,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
authenticateForTests,
|
authenticateForTests,
|
||||||
handleLoginScreenIfPresent,
|
handleLoginScreenIfPresent,
|
||||||
waitForNetworkIdle,
|
waitForNetworkIdle,
|
||||||
|
sanitizeForTestId,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
|
|
||||||
// Create unique temp dir for this test run
|
// Create unique temp dir for this test run
|
||||||
@@ -156,11 +157,11 @@ test.describe('Open Project', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for a project to be set as current and visible on the page
|
// Wait for a project to be set as current and visible on the page
|
||||||
// The project name appears in the project switcher button with title attribute
|
// The project name appears in the project switcher button
|
||||||
// (The button uses data-testid with projectId, not projectName)
|
// Use ends-with selector since data-testid format is: project-switcher-{id}-{sanitizedName}
|
||||||
if (targetProjectName) {
|
if (targetProjectName) {
|
||||||
const projectSwitcherButton = page.getByRole('button', { name: targetProjectName }).first();
|
const sanitizedName = sanitizeForTestId(targetProjectName);
|
||||||
await expect(projectSwitcherButton).toBeVisible({
|
await expect(page.locator(`[data-testid$="-${sanitizedName}"]`)).toBeVisible({
|
||||||
timeout: 15000,
|
timeout: 15000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,22 @@
|
|||||||
import { Page, Locator } from '@playwright/test';
|
import { Page, Locator } from '@playwright/test';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitize a string for use in data-testid selectors.
|
||||||
|
* This mirrors the sanitizeForTestId function in apps/ui/src/lib/utils.ts
|
||||||
|
* to ensure tests use the same sanitization logic as the component.
|
||||||
|
*
|
||||||
|
* @param name - The string to sanitize (e.g., project name)
|
||||||
|
* @returns A sanitized string safe for CSS selectors
|
||||||
|
*/
|
||||||
|
export function sanitizeForTestId(name: string): string {
|
||||||
|
return name
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/\s+/g, '-')
|
||||||
|
.replace(/[^a-z0-9-]/g, '')
|
||||||
|
.replace(/-+/g, '-')
|
||||||
|
.replace(/^-|-$/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an element by its data-testid attribute
|
* Get an element by its data-testid attribute
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user