feat(FN-1640): add Frontend UX Design built-in workflow template
- Add Frontend UX Design template for verifying UI/UX design implementation - Include WCAG 2.1 compliance checks, design system adherence, and user flow validation - Add template to WorkflowStepManager with category-based organization - Update documentation with new template description - Add tests for template API endpoints and workflow step manager
This commit is contained in:
@@ -5622,6 +5622,23 @@ Task with acceptance criteria
|
||||
expect(steps.filter((step) => step.templateId === "browser-verification")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("should materialize frontend-ux-design built-in template when creating a task", async () => {
|
||||
const task = await store.createTask({
|
||||
description: "Task with frontend UX design review",
|
||||
enabledWorkflowSteps: ["frontend-ux-design"],
|
||||
});
|
||||
|
||||
expect(task.enabledWorkflowSteps).toEqual(["WS-001"]);
|
||||
|
||||
const step = await store.getWorkflowStep("WS-001");
|
||||
expect(step).toMatchObject({
|
||||
id: "WS-001",
|
||||
templateId: "frontend-ux-design",
|
||||
name: "Frontend UX Design",
|
||||
toolMode: "readonly",
|
||||
});
|
||||
});
|
||||
|
||||
it("should not set enabledWorkflowSteps when empty array provided", async () => {
|
||||
const task = await store.createTask({
|
||||
description: "Task without workflow steps",
|
||||
@@ -5880,6 +5897,19 @@ Task with acceptance criteria
|
||||
});
|
||||
});
|
||||
|
||||
it("should resolve frontend-ux-design built-in template from getWorkflowStep", async () => {
|
||||
const step = await store.getWorkflowStep("frontend-ux-design");
|
||||
|
||||
expect(step).toMatchObject({
|
||||
id: "frontend-ux-design",
|
||||
templateId: "frontend-ux-design",
|
||||
name: "Frontend UX Design",
|
||||
mode: "prompt",
|
||||
phase: "pre-merge",
|
||||
toolMode: "readonly",
|
||||
});
|
||||
});
|
||||
|
||||
// ── Workflow Step Phase ──────────────────────────────────────────────
|
||||
|
||||
it("should default phase to 'pre-merge' when creating a workflow step", async () => {
|
||||
|
||||
@@ -365,6 +365,33 @@ Use these agent-browser commands for verification:
|
||||
|
||||
Note: Refs (@e1, @e2) are invalidated after page navigation. Re-snapshot after clicking links or form submissions.`,
|
||||
},
|
||||
{
|
||||
id: "frontend-ux-design",
|
||||
name: "Frontend UX Design",
|
||||
description: "Verify visual polish and consistency with existing UI patterns and design tokens",
|
||||
category: "Quality",
|
||||
icon: "layout-grid",
|
||||
toolMode: "readonly",
|
||||
prompt: `You are a UX design reviewer. Verify frontend changes maintain visual polish and consistency with existing UI patterns and design tokens.
|
||||
|
||||
Design System Review:
|
||||
1. **Visual Hierarchy** — Check that the changes maintain consistent heading levels, content flow, and information architecture
|
||||
2. **Spacing and Typography** — Verify consistent spacing (margins, padding, gaps) and typography scale usage
|
||||
3. **Color and Token Consistency** — Check that CSS custom properties and design tokens are used correctly; no hardcoded color values that bypass the design system
|
||||
4. **Component Reuse** — Verify existing UI components are reused instead of creating one-off styling; identify any duplication that could be refactored
|
||||
5. **Responsive Behavior** — Check that layouts adapt properly across viewport sizes and maintain usability on mobile
|
||||
6. **Fit with Design Language** — Verify the visual style matches existing patterns (border radius, shadows, transitions, icon style, etc.)
|
||||
|
||||
Files to Review:
|
||||
- Modified UI components (React, Vue, Angular, HTML)
|
||||
- CSS/SCSS/styled-component files
|
||||
- Design token or theme configuration files
|
||||
|
||||
Output Requirements:
|
||||
- If design is consistent and polished: call task_done() with success status
|
||||
- If issues found: describe each finding with specific file paths and suggested corrections via task_log()
|
||||
- Prioritize issues by impact: layout breaks > visual inconsistency > style preferences`,
|
||||
},
|
||||
];
|
||||
|
||||
export interface PrInfo {
|
||||
|
||||
@@ -98,6 +98,8 @@ function getTemplateIcon(iconName: string | undefined) {
|
||||
return Eye;
|
||||
case "globe":
|
||||
return Globe;
|
||||
case "layout-grid":
|
||||
return LayoutGrid;
|
||||
default:
|
||||
return CheckCircle;
|
||||
}
|
||||
|
||||
@@ -59,21 +59,47 @@ vi.mock("../../api", () => ({
|
||||
icon: "globe",
|
||||
toolMode: "coding",
|
||||
},
|
||||
{
|
||||
id: "frontend-ux-design",
|
||||
name: "Frontend UX Design",
|
||||
description: "Verify visual polish and consistency with existing UI patterns and design tokens",
|
||||
prompt: "Test prompt",
|
||||
category: "Quality",
|
||||
icon: "layout-grid",
|
||||
toolMode: "readonly",
|
||||
},
|
||||
],
|
||||
})),
|
||||
createWorkflowStepFromTemplate: vi.fn(() => Promise.resolve({
|
||||
id: "WS-010",
|
||||
templateId: "browser-verification",
|
||||
name: "Browser Verification",
|
||||
description: "Verify web application functionality using browser automation",
|
||||
mode: "prompt",
|
||||
phase: "pre-merge",
|
||||
prompt: "Test prompt",
|
||||
toolMode: "coding",
|
||||
enabled: true,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
})),
|
||||
createWorkflowStepFromTemplate: vi.fn((templateId?: string) => {
|
||||
if (templateId === "frontend-ux-design") {
|
||||
return Promise.resolve({
|
||||
id: "WS-011",
|
||||
templateId: "frontend-ux-design",
|
||||
name: "Frontend UX Design",
|
||||
description: "Verify visual polish and consistency with existing UI patterns and design tokens",
|
||||
mode: "prompt",
|
||||
phase: "pre-merge",
|
||||
prompt: "Test prompt",
|
||||
toolMode: "readonly",
|
||||
enabled: true,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
});
|
||||
}
|
||||
return Promise.resolve({
|
||||
id: "WS-010",
|
||||
templateId: "browser-verification",
|
||||
name: "Browser Verification",
|
||||
description: "Verify web application functionality using browser automation",
|
||||
mode: "prompt",
|
||||
phase: "pre-merge",
|
||||
prompt: "Test prompt",
|
||||
toolMode: "coding",
|
||||
enabled: true,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
});
|
||||
}),
|
||||
fetchScripts: vi.fn(() => Promise.resolve({ test: "pnpm test", lint: "pnpm lint" })),
|
||||
fetchModels: vi.fn(() => Promise.resolve({
|
||||
models: [
|
||||
@@ -678,6 +704,58 @@ describe("WorkflowStepManager templates tab", () => {
|
||||
expect(addToast).toHaveBeenCalledWith("Added Browser Verification workflow step", "success");
|
||||
});
|
||||
});
|
||||
|
||||
it("renders frontend-ux-design template", async () => {
|
||||
vi.mocked(fetchWorkflowSteps).mockResolvedValueOnce([]);
|
||||
|
||||
render(<WorkflowStepManager isOpen={true} onClose={onClose} addToast={addToast} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId("tab-templates")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByTestId("tab-templates"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId("template-frontend-ux-design")).toBeInTheDocument();
|
||||
expect(screen.getByText("Frontend UX Design")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("displays the LayoutGrid icon for frontend-ux-design template", async () => {
|
||||
vi.mocked(fetchWorkflowSteps).mockResolvedValueOnce([]);
|
||||
|
||||
render(<WorkflowStepManager isOpen={true} onClose={onClose} addToast={addToast} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId("tab-templates")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByTestId("tab-templates"));
|
||||
|
||||
const templateCard = await screen.findByTestId("template-frontend-ux-design");
|
||||
expect(templateCard.querySelector(".lucide-layout-grid")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("can add frontend-ux-design template as a workflow step", async () => {
|
||||
vi.mocked(fetchWorkflowSteps).mockResolvedValue([]);
|
||||
|
||||
render(<WorkflowStepManager isOpen={true} onClose={onClose} addToast={addToast} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId("tab-templates")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByTestId("tab-templates"));
|
||||
|
||||
const templateCard = await screen.findByTestId("template-frontend-ux-design");
|
||||
fireEvent.click(within(templateCard).getByTestId("add-template-frontend-ux-design"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(createWorkflowStepFromTemplate).toHaveBeenCalledWith("frontend-ux-design", undefined);
|
||||
expect(addToast).toHaveBeenCalledWith("Added Frontend UX Design workflow step", "success");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("WorkflowStepManager theme class structure", () => {
|
||||
|
||||
@@ -11024,6 +11024,8 @@ describe("GET /workflow-step-templates", () => {
|
||||
expect(ids).toContain("security-audit");
|
||||
expect(ids).toContain("performance-review");
|
||||
expect(ids).toContain("accessibility-check");
|
||||
expect(ids).toContain("browser-verification");
|
||||
expect(ids).toContain("frontend-ux-design");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11100,6 +11102,37 @@ describe("POST /workflow-step-templates/:id/create", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("creates workflow step from frontend-ux-design template", async () => {
|
||||
const created = {
|
||||
id: "WS-003",
|
||||
name: "Frontend UX Design",
|
||||
description: "Verify visual polish and consistency with existing UI patterns and design tokens",
|
||||
prompt: expect.stringContaining("UX design reviewer"),
|
||||
toolMode: "readonly",
|
||||
enabled: true,
|
||||
createdAt: "2026-01-01",
|
||||
updatedAt: "2026-01-01",
|
||||
};
|
||||
(store.listWorkflowSteps as ReturnType<typeof vi.fn>).mockResolvedValueOnce([]);
|
||||
(store.createWorkflowStep as ReturnType<typeof vi.fn>).mockResolvedValueOnce(created);
|
||||
|
||||
const res = await REQUEST(buildApp(), "POST", "/api/workflow-step-templates/frontend-ux-design/create", JSON.stringify({}), {
|
||||
"Content-Type": "application/json",
|
||||
});
|
||||
|
||||
expect(res.status).toBe(201);
|
||||
expect(res.body.name).toBe("Frontend UX Design");
|
||||
expect(res.body.toolMode).toBe("readonly");
|
||||
expect(store.createWorkflowStep).toHaveBeenCalledWith({
|
||||
templateId: "frontend-ux-design",
|
||||
name: "Frontend UX Design",
|
||||
description: "Verify visual polish and consistency with existing UI patterns and design tokens",
|
||||
prompt: expect.stringContaining("UX design reviewer"),
|
||||
toolMode: "readonly",
|
||||
enabled: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("returns 404 for non-existent template", async () => {
|
||||
const res = await REQUEST(buildApp(), "POST", "/api/workflow-step-templates/nonexistent/create", JSON.stringify({}), {
|
||||
"Content-Type": "application/json",
|
||||
|
||||
Reference in New Issue
Block a user